May
10
What the —- is Bloom Filter ?
May 10, 2013 | Leave a Comment
Bloom filter is the very important data structure computer scientists, programmers, Big-Data geeks needs to know. Currently I am reading the book called
“Map-Reduce Design Patterns” – Donald Miner and Adam Shook
Following is my short notes about Bloom Filter which I took while I was reading the above mentioned book.
Bloom Filter:
=========
Following variables are used in the more detailed explanation of a Bloom filter,
m – The number of bits in the filter
n – The number of members in the set
p – The desired false positive rate
k – The number of different hash functions used to map some element to one of the m bits with a uniform random distribution.
A Bloom filter is represented by a continuous string of m bits initialized to zero. For each element in n, k hash function values are taken modulo m to achieve an index from zero to m – 1. The bits of the Bloom filter at the resulting indices are set to one. This operation is often called training a Bloom filter. As elements are added to the Bloom filter, some bits may already be set to one from previous elements in the set. When testing whether a member is an element of the set, the same hash functions are used to check the bits of the array. If a single bit of all the hashes is set to zero, the test returns “no.” If all the bits are turned on, the test returns “maybe.” If the member was used to train the filter, the k hashs would have set all the bits to one. The result of the test cannot be a definitive “yes” because the bits may have been turned on by a combination of other elements. If the test returns “maybe” but should have been “no,” this is known as a false positive. Thankfully, the false positive rate can be controlled if n is known ahead of time, or at least an approximation of n.
Use-Cases:
=========
1. Representing a Data Set – A data set with millions of elements can take up gigabytes of memory, as well as the expensive I/O required simply to pull the data set off disk. A Bloom filter can drastically reduce the number of bytes required to represent this data set, allowing it to fit in memory and decrease the amount of time required to read. The obvious downside to representing a large data set with a Bloom filter is the false positives.
2. Reduce Queries to External Database – One very common use case of Bloom filters is to reduce the number of queries to databases that are bound to return many empty or negative results. By doing an initial test using a Bloom filter, an application can throw away a large number of negative results
before ever querying the database. If latency is not much of a concern, the positive Bloom filter tests can be stored into a temporary buffer. Once a certain limit is hit, the buffer can then be iterated through to perform a bulk query against the database. This will reduce the load on the system and keep it more stable. This method is exceptionally useful if a large number of the queries are bound to return negative results. If most results are positive answers, then a Bloom filter may just be a waste of precious memory.
3. Google BigTable – Google’s BigTable design uses Bloom filters to reduce the need to read a file for non-existent data. By keeping a Bloom filter for each block in memory, the service can do an initial check to determine whether it is worthwhile to read the file. If the test returns a negative value, the service can return immediately. Positive tests result in the service opening the file to validate whether the data exists or not. By filtering out negative queries, the performance of this database increases drastically.
Downsides;
==========
1. The false positive rate is the largest downside in using the Bloom Filter.
2. Traditionally, you cannot remove elements from a Bloom filter set after training the elements. Removing an element would require bits to be set to zero, but it is extremely likely that more than one element hashed to a particular bit. Setting it to zero would destroy any future tests of other elements.
3. When using a Bloom filter in a distributed application like MapReduce, it is difficult to actively train a Bloom filter in the sense of a database. After a Bloom filter is trained and erialized to HDFS, it can easily be read and used by other applications. However, further training of the Bloom filter would require expensive I/O operations, whether it be sending messages to every other process using the Bloom filter or implementing some sort of locking mechanism.
Tweaking Your Bloom Filter:
========================
Before training a Bloom filter with the elements of a set, it can be very beneficial to know an approximation of the number of elements. If you know this ahead of time, a Bloom filter can be sized appropriately to have a hand-picked false positive rate.
The following Java helper function calculates the optimal m.
/**
* Gets the optimal Bloom filter sized based on the input parameters and the
* optimal number of hash functions.
*
* @param numElements
*
The number of elements used to train the set.
* @param falsePosRate
*
The desired false positive rate.
* @return The optimal Bloom filter size.
*/
public static int getOptimalBloomFilterSize(int numElements,
float falsePosRate) {
return (int) (-numElements * (float) Math.log(falsePosRate)
/ Math.pow(Math.log(2), 2));
}
Sugi.
Apr
16
String Substitution Puzzle
April 16, 2013 | Leave a Comment
Given a string S, and a list of strings of positive length, F1,R1,F2,R2,…,FN,RN, proceed to find in order the occurrences (left-to-right) of Fi in S and replace them with Ri. All strings are over alphabet { 0, 1 }. Searching should consider only contiguous pieces of S that have not been subject to replacements on prior iterations. An iteration of the algorithm should not write over any previous replacement by the algorithm.
Input sample:
Your program should accept as its first argument a path to a filename. Each line in this file is one test case. Each test case will contain a string, then a semicolon and then a list of comma separated strings.eg.
10011011001;0110,1001,1001,0,10,11
Output sample:
For each line of input, print out the string after substitutions have been made.eg.
11100110
For the curious, here are the transitions for the above example: 10011011001 => 10100111001 [replacing 0110 with 1001] => 10100110 [replacing 1001 with 0] => 11100110 [replacing 10 with 11] => 11100110
SOURCE CODE I WROTE:
====================
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
*
* @author Sugi Venugeethan
* This class contains main method and two other methods for search and replace.
*
*/
public class StringSubstituion {
static Map
static StringBuilder orig_string = null;
public static void main(String[] args) {
if (args[0].length() == 0) {
//System.err.println(“Provide input file”);
System.exit(1);
}
try {
FileInputStream stream = new FileInputStream(args[0]);
DataInputStream in = new DataInputStream(stream);
BufferedReader reader = new BufferedReader(
new InputStreamReader(in));
String line = null;
List
while ((line = reader.readLine()) != null) {
// Parse the line, call a function to start search, print output
// for current line
String[] input1 = null;
String[] input2 = null;
String originalString = null;
input1 = line.split(“;”);
if (input1.length > 1)
originalString = input1[0];
else {
System.exit(1);
//System.out.println(“Please provide proper input, original input is missing”);
}
input2 = line.split(“,”);
if (input2.length > 1) {
int count = 0;
for (String pattern : input2) {
if (count == 0) {
String[] temp = pattern.split(“;”);
if (temp.length < 2) {
System.exit(1);
//System.err.println("");
}
auxInputs.add(temp[1]);
count += 1;
} else
auxInputs.add(pattern);
}
} else {
System.exit(1);
//System.out.println("Please provide proper input, search patterns are missing");
}
orig_string = new StringBuilder(originalString);
System.out.println(searchAndReplace(auxInputs));
auxInputs.clear();
shaded.clear();
}
reader.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
/**
*
* @param List of Search and Replace pairs.
* @return modified String Builder object.
*/
private static StringBuilder searchAndReplace(List
// Iterate all search, replace pairs
int searchIndex = 0;
String searchFor = null;
String replaceString = null;
int index = 0; // To track first iteration of the loop.
for (int count = 0; count < searchReplace.size() - 1; count++) {
try {
searchFor = searchReplace.get(count);
searchIndex = orig_string.indexOf(searchFor, 0);
count += 1;
replaceString = searchReplace.get(count);
} catch (Exception ex) {
continue;
}
if (index == 0 || !shaded.containsKey(searchIndex)) {
orig_string = orig_string.replace(searchIndex, searchIndex + replaceString.length(), replaceString);
if(searchFor.length() > replaceString.length())
{
int diffToDelete = searchFor.length() – replaceString.length();
int deleteStartPosition = searchIndex + 1;
orig_string.delete(deleteStartPosition, deleteStartPosition + diffToDelete);
}
//System.out.println(orig_string);
shaded.put(searchIndex, searchIndex + replaceString.length() – 1);
index += 1;
}
else {
// Use advanced search and replace.
// If null is returned for a pair, move to next pair with
// original String
if (advancedSearchAndReplace(searchFor, replaceString, searchIndex) == null)
continue;
}
}
return orig_string;
}
/**
*
* @param searchFor
* @param replaceWith
* @param currentIndex
* @return modified StringBuilder object.
*/
private static StringBuilder advancedSearchAndReplace(String searchFor, String replaceWith, int currentIndex) {
while (orig_string.length() – (currentIndex) >= replaceWith.length()) {
int index = 0;
try {
// if we find exact position which is not shaded, replace it,
// return Stringbuilder
index = orig_string.indexOf(searchFor, currentIndex + 1);
if (shaded.containsKey(index)) {
// update the currentIndex and continue the loop.
currentIndex = shaded.get(index) + 1;
} else {
// if we find exact position which is not shaded, replace
// it, return Stringbuilder
orig_string = orig_string.replace(index, index + replaceWith.length(),replaceWith);
if(searchFor.length() > replaceWith.length())
{
int diffToDelete = searchFor.length() – replaceWith.length();
int deleteStartPosition = index + 1;
orig_string.delete(deleteStartPosition, deleteStartPosition + diffToDelete);
}
//System.out.println(orig_string);
shaded.put(index, index + replaceWith.length() – 1);
return orig_string;
}
} catch (NullPointerException ex) {
return null;
}
}
return null;
}
}
Apr
13
Guarded Block – Some More Explanation
April 13, 2013 | Leave a Comment
Related posts – http://sugionline.com/blog/?p=372
http://sugionline.com/blog/?p=374
Most often different threads need to co-ordinate among themselves to finish a task. Guarded block is a block of code which can execute only when certain flag is set or certain condition is satisfied by some other thread. For example,
public void guardedJoy() {
// Simple loop guard. Wastes
// processor time. Don’t do this!
while(!joy) {}
System.out.println(“Joy has been achieved!”);
}
In above code snippet, while will be iterating continuously until the joy flag gets modified. So efficient way is to use Object.wait() method which like other suspension methods sleep, join throws interrupted exception.
Let us chance above snippet into
public synchronized guardedJoy() {
// This guard only loops once for each special event, which may not
// be the event we’re waiting for.
while(!joy) {
try {
wait();
} catch (InterruptedException e) {}
}
System.out.println(“Joy and efficiency have been achieved!”);
}
Why is this version of guardedJoy synchronized? Suppose d is the object we’re using to invoke wait. When a thread invokes d.wait, it must own the intrinsic lock for d — otherwise an error is thrown. Invoking wait inside a synchronized method is a simple way to acquire the intrinsic lock.
When wait is invoked, the thread releases the lock and suspends execution. At some future time, another thread will acquire the same lock and invoke Object.notifyAll, informing all threads waiting on that lock that something important has happened:
public synchronized notifyJoy() {
joy = true;
notifyAll();
}
How notify() differs from notifyAll() ?
Note: There is a second notification method, notify, which wakes up a single thread. Because notify doesn’t allow you to specify the thread that is woken up, it is useful only in massively parallel applications — that is, programs with a large number of threads, all doing similar chores. In such an application, you don’t care which thread gets woken up.
Excellent, neat example to explain guarded block. Following code contains a class called Drop which explains guarded block sample. It has two synchronized methods for producer-consumer model. So using same object’s intrinsic lock either put or take executes for producer or consumer scenario.
boolean variable exists which needs to be set by different other components (producer and consumer) and co-ordination is very important in below code which is achieved in the guarded block through wait() and notifyAll() method.
public class Drop {
// Message sent from producer
// to consumer.
private String message;
// True if consumer should wait
// for producer to send message,
// false if producer should wait for
// consumer to retrieve message.
private boolean empty = true;
public synchronized String take() {
// Wait until message is
// available.
while (empty) {
try {
wait();
} catch (InterruptedException e) {}
}
// Toggle status.
empty = true;
// Notify producer that
// status has changed.
notifyAll();
return message;
}
public synchronized void put(String message) {
// Wait until message has
// been retrieved.
while (!empty) {
try {
wait();
} catch (InterruptedException e) {}
}
// Toggle status.
empty = false;
// Store message.
this.message = message;
// Notify consumer that status
// has changed.
notifyAll();
}
}
The producer thread, defined in Producer, sends a series of familiar messages. The string “DONE” indicates that all messages have been sent. To simulate the unpredictable nature of real-world applications, the producer thread pauses for random intervals between messages.
import java.util.Random;
public class Producer implements Runnable {
private Drop drop;
public Producer(Drop drop) {
this.drop = drop;
}
public void run() {
String importantInfo[] = {
“Mares eat oats”,
“Does eat oats”,
“Little lambs eat ivy”,
“A kid will eat ivy too”
};
Random random = new Random();
for (int i = 0;
i < importantInfo.length;
i++) {
drop.put(importantInfo[i]);
try {
Thread.sleep(random.nextInt(5000));
} catch (InterruptedException e) {}
}
drop.put(“DONE”);
}
}
The consumer thread, defined in Consumer, simply retrieves the messages and prints them out, until it retrieves the “DONE” string. This thread also pauses for random intervals.
import java.util.Random;
public class Consumer implements Runnable {
private Drop drop;
public Consumer(Drop drop) {
this.drop = drop;
}
public void run() {
Random random = new Random();
for (String message = drop.take();
! message.equals(“DONE”);
message = drop.take()) {
System.out.format(“MESSAGE RECEIVED: %s%n”, message);
try {
Thread.sleep(random.nextInt(5000));
} catch (InterruptedException e) {}
}
}
}
Finally, here is the main thread, defined in ProducerConsumerExample, that launches the producer and consumer threads.
public class ProducerConsumerExample {
public static void main(String[] args) {
Drop drop = new Drop();
(new Thread(new Producer(drop))).start();
(new Thread(new Consumer(drop))).start();
}
}
For more ref – http://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html
-Sugi.
Apr
13
DeadLock Example
April 13, 2013 | Leave a Comment
DeadLock :- When deadlock can happen ? When two or more threads waiting for each other. A small and quick example which I liked is following.
Refer Intrinsic lock blog post as well – http://sugionline.com/blog/?p=372
Refer more at – http://docs.oracle.com/javase/tutorial/essential/concurrency/deadlock.html
Following example illustrates how the deadlock can happen when two threads are waiting for each other’s intrinsic lock to execute a synchronized method of respective objects.
public class Deadlock {
static class Friend {
private final String name;
public Friend(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public synchronized void bow(Friend bower) {
System.out.format(“%s: %s”
+ ” has bowed to me!%n”,
this.name, bower.getName());
bower.bowBack(this); // Causing deadlock when waiting for other thread’s lock which is being currently used in bow //method.
}
public synchronized void bowBack(Friend bower) {
System.out.format(“%s: %s”
+ ” has bowed back to me!%n”,
this.name, bower.getName());
}
}
public static void main(String[] args) {
final Friend alphonse =
new Friend(“Alphonse”);
final Friend gaston =
new Friend(“Gaston”);
new Thread(new Runnable() {
public void run() { alphonse.bow(gaston); }
}).start();
new Thread(new Runnable() {
public void run() { gaston.bow(alphonse); }
}).start();
}
}
Above class is simple, neat example. There are two synchronized method and inside one it tries to call the another method. Using same objects lock can be easy. But deadlock happens when you try to call another synchronized method by acquiring the lock of another object which is currently being held in bow method.
-Sugi.
Apr
13
I am reading Re-entrant synchronization, I recalled and made a note of several facts which I am sharing as blog post. If you wish to read more please refer
http://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html
1. Every object has an intrinsic lock associated with it. By convention, a thread that needs exclusive and consistent access to an object’s fields has to acquire the object’s intrinsic lock before accessing them, and then release the intrinsic lock when it’s done with them.
2. When a thread invokes a synchronized method, it automatically acquires the intrinsic lock for that method’s object and releases it when the method returns. The lock release occurs even if the return was caused by an uncaught exception.
3. You might wonder what happens when a static synchronized method is invoked, since a static method is associated with a class, not an object. In this case, the thread acquires the intrinsic lock for the Class object associated with the class.
4. How will you access several synchronized blocks or methods with same lock acquired by a thread before ?
|
—- Answer is Re-entrant synchronization which is defined as follows.
5. Reentrant Synchronization
Recall that a thread cannot acquire a lock owned by another thread. But a thread can acquire a lock that it already owns. Allowing a thread to acquire the same lock more than once enables reentrant synchronization. This describes a situation where synchronized code, directly or indirectly, invokes a method that also contains synchronized code, and both sets of code use the same lock. Without reentrant synchronization, synchronized code would have to take many additional precautions to avoid having a thread cause itself to block.
Apr
2
Huffman Code – Yet another blog post
April 2, 2013 | Leave a Comment
I am writing this blog post for my own practice. It may be helpful for others to refer. Huffman code is the compression algorithm to reduce the storage space. It is greedy algorithm design strategy.
Following code has comments which explain how huffman code for a particular character can be found from the resulting Binary Tree. We will use mainly Binary Tree and Priority Queue for the calculation of the Huffman Code.
Code is written when I was typing this blog post. Yet to check. Just grab the idea rather than looking for coding style.
import java.util.*;
// @author Sugi Venugeethan.
public class HuffManCode
{
HashMap
Queue
final static int inputCount;
public static void main(String[] args)
{
BinaryNode temp = null;
BinaryNode root = null;
// Just for checking I am populating with some data.
freqCount.put(‘a’,12);
freqCount.put(‘b’,2);
freqCount.put(‘c’,7);
freqCount.put(‘d’,13);
freqCount.put(‘e’,14);
freqCount.put(‘f’,85);
createBinaryTree();
// Now it is time to calculate Huffman codes. Priority Queue contains nodes of the
// Binary tree already.
/**
We are going to push all the present binary nodes in priority queue to leaf position. Internal nodes
will contain sum of the frequency of the their children.
To determine the Huffman Code for the particulat character, traverse the binary tree till the leaf node
which contains the character, for every left move add 0 and for every right move add 1.
**/
for(int i = 0; i < inputCount; i++)
{
temp = new BinaryNode();
temp.setLeft(pq.poll());
temp.setRight(pq.poll());
temp.setData(temp.getLeft().getData() + temp.getRight().getData());
if(!pq.add(temp))
System.out.println("Error adding new Node - Check");
}
root = pq.peek(); // We have the root of the result Binary Tree which helps to get the Huffman code.
}
private void createBinaryTree()
{
BinaryNode node = null;
Set
for(Map.Entry
{
inputCount += 1;
node = new BinaryNode(entry.getValue(),entry.getKey());
if(!pq.add(node))
{
System.out.println(“Error adding to priority queue”);
}
}
}
private class BinaryNode implements comparable
{
private int data;
private Char label = ’0′;
private BinaryNode left;
private BinaryNode right;
BinaryNode(int value,char label)
{
this.data = value;
this.label = label;
}
BinaryNode()
{
}
public BinaryNode getLeft()
{
return this.left;
}
public BinaryNode getRight()
{
return this.right;
}
public void setLeft(BinaryNode left)
{
this.left = left;
}
public void setRight(BinaryNode right)
{
this.right = right;
}
public int getData()
{
return this.data;
}
public void setData(int value)
{
this.data = value;
}
public String getLabel()
{
return this.label;
}
public int compareTo(BinaryNode node)
{
int node2Data = node.getData();
return this.getData() – node2Data; // ascending order, smalled first.
}
}
}
Enjoy !!!
-Sugi.
Apr
1
Reversing number(TDD) with %(modulo) and / (division)
April 1, 2013 | Leave a Comment
Why am I writing a blog post for such a simple question ?
=======================================================
Simple questions are asked to you only to see how well you write efficient code. I mean the code should be written in test driven way or atleast before you handover the solution to the interviewer, make sure to think about the test cases that you test with your own code.
Reversing a number can be easily done with % and / operators. % can be used to take the right most number and / can be used to reduce the input number. If I am solving in recursive way, the base case will be to stop when the input number is equal to zero.
/ is used to size of the input number. Following code explains clearly.
private int reverse(int number)
{
int reversed = 0;
while(number != 0)
{
reversed = reversed * 10 + number % 10;
number = number / 10;
}
return reversed;
}
-Sugi.
Apr
1
String to Integer (TDD) – Phone Screen Question
April 1, 2013 | Leave a Comment
When such a simple question is asked to you in the interview, it is not enough just to write the functional code to solve the problem. You will be expected to write test driven code.
Basic idea to convert String to Integer is to scan character by character, for each character multiply result (variable used to store the integer result) with 10. Subtract ’0′ (48 ASCII) from the character, add the subtraction result to the result variable. Repeat above for all the characters of the input string.
/**
init result with 0
for each character in string do this
result = result * 10
get the digit from the character (’0′ is 48 ASCII (or 0×30), so just subtract that from the character ASCII code to get the digit)
add the digit to the result
return result
**/
C code:
======
int strToInt(char* string)
{
int number = 0;
while(*string != 0)
{
number = number * 10 + *string – ’0′;
++string;
}
return number;
}
Answering above will not be enough, you should check for boundary conditions, negative numbers, special symbols in the input etc. Good solution will be following kind. Below code is original Java code from its Integer implementation.
public static int parseInt(String s, int radix)
440 throws NumberFormatException
441 {
442 if (s == null) {
443 throw new NumberFormatException(“null”);
444 }
445
446 if (radix < Character.MIN_RADIX) {
447 throw new NumberFormatException("radix " + radix +
448 " less than Character.MIN_RADIX");
449 }
450
451 if (radix > Character.MAX_RADIX) {
452 throw new NumberFormatException(“radix ” + radix +
453 ” greater than Character.MAX_RADIX”);
454 }
455
456 int result = 0;
457 boolean negative = false;
458 int i = 0, len = s.length();
459 int limit = -Integer.MAX_VALUE;
460 int multmin;
461 int digit;
462
463 if (len > 0) {
464 char firstChar = s.charAt(0);
465 if (firstChar < ’0′) { // Possible leading “-”
466 if (firstChar == ‘-’) {
467 negative = true;
468 limit = Integer.MIN_VALUE;
469 } else
470 throw NumberFormatException.forInputString(s);
471
472 if (len == 1) // Cannot have lone “-”
473 throw NumberFormatException.forInputString(s);
474 i++;
475 }
476 multmin = limit / radix;
477 while (i < len) {
478 // Accumulating negatively avoids surprises near MAX_VALUE
479 digit = Character.digit(s.charAt(i++),radix);
480 if (digit < 0) {
481 throw NumberFormatException.forInputString(s);
482 }
483 if (result < multmin) {
484 throw NumberFormatException.forInputString(s);
485 }
486 result *= radix;
487 if (result < limit + digit) {
488 throw NumberFormatException.forInputString(s);
489 }
490 result -= digit;
491 }
492 } else {
493 throw NumberFormatException.forInputString(s);
494 }
495 return negative ? result : -result;
496 }
So, whenever a simple question is asked to you, follow test driven way to write code and get through to the next interview round. Good luck.
- Sugi.
Apr
1
Separate Chaining (OO Design)
April 1, 2013 | Leave a Comment
Our famous separate chaining strategy to prevent collision in creating, maintaining a hash table can be a good problem in OO design.
We will have array of linked lists.
public class ListNode
{
private int key;
private int data;
private ListNode next;
}
Following Class refers to ListNode above.
public class HashTableNode
{
private ListNode startNode;
public void setStartNode(ListNode startNode)
{
this.startNode = startNode;
}
}
Following class which defines the data structure for the hash table will be the array of HashTableNodes above, which in turn contains chain of ListNodes forming array of linkedlist.
public class HashTable
{
private HashTableNode[] table;
HashTable(int size)
{
this.table = new HashTable[size];
}
}
-Sugi.
Mar
31
You should know about Hashing – Important facts
March 31, 2013 | Leave a Comment
In normal hash table , hash maps we use everyday following happens. It is good to know or remember some facts all the time.
Hash table is normally chosen when search pre dominates insertion and usually when no ordering is required though you can maintain insertion or access order.
Important operations are
1. Creating hash,
2. Inserting into hash
3. Deleting in hash
4. Load factor
5. Collisions
6. Collision resolution.
Hash storage:
============
Using array when number of keys are pre determined and less in number. Use keys as index directly. It is called direct addressing. Another way is to use array of linked-lists for storing. Hash function can be used to locate the element (find index), based on the key. Hash function will accept key as input and spits the value which can be used as index to locate the actual value mapped with original key.
Hash function can be modulo based or multiplication based. Example is
============
h(k) = k mod 5
maps all keys to a natural number 0-4.
Load Factor = total keys present in hash table / total keys possible.
===========
Collision happens when hash function produces same value for two different keys. Collision resolution can be done in following ways.
Direct Chaining – An array of linked list (Extra storage for list nodes and their pointers are needed)
|
—– Separate Chaining.
Open Addressing – An array based implementation (Also called Closed Hashing, as no additional storage is needed for storing)
|
—– Linear probing (linear search, rehash (key) = (n + 1) % tableSize
—– Quadratic Probing (non linear search , rehash (key) = (n + k power 2) % tableSize
—– Double Hashing (Using two hash functions, eg: if h1(key) = already occupied then use h2(key) + h1(key) or h1(key) + 2* h2(key)
Definition of probing suitable for above sentences is searching (for new spot )
==========
- Sugi.