You are on page 1of 8

Akash Kulkarni

Section F
HW 2

1) The three best hash functions are A, D and F.


(i)A is a good hash function because most buckets have the same probability of being
chosen by the hash function. The region that has different probability is small and that
probability is small, so that there is no clustering at that point.
(ii)D is a good hash function, because approximately half the buckets have the
same(high) probability of being chosen by the hash function. As a result, there is not
much crowding. It is better than B(which also has half the buckets having the same
probability of being chosen by the hash function) because the buckets with the similar
probability of being chosen are spaced apart, so that there is no clustering in one big part
of the table.
(iii)F is a good hash function as it has relatively equal probability of a key hashing on to a
particular bucket. Unlike C, the equal probability is much higher than the unequal
probability, preventing clustering at a point. In C, there is also equal probability of a key
hashing onto a particular bucket, except at the edges, where there will be clustering,
because of high probability at these points. That is why F is preferred.

2. (a) -1st hashcode is 17 = 17%5 = 2. This is empty, so we can insert it.


-2nd hashcode is 12 = 12%5 = 2. This is non-empty, hence we must insert it into
Postion 3(Linear Probing)
-3rd hashcode is 128 = 128%5 = 3. This cell is non-empty, so we must insert into
Position 4(Linear Probing)
-4th hashcode is 10 = 10%5 = 0. This cell is empty, so we can insert.
-5th hashcode is 7 = 7%5 = 2. This cell is non-empty, so we must insert into
Position 1(Linear Probing).

A new table of size 10 is now formed as our previous table is full, and values are
rehashed.

-6th hashcode is 14 = 14%10 = 4. This cell is empty, so we can insert.


-7th hashcode is 129 = 129%10 = 9. This cell is non-empty, so we insert into
Position 1(Linear Probing).
-8th hashcode is 132 = 132%10 = 2. This cell is non-empty, so we insert into
Position 3.(Linear Probing)
-9th hashcode is 127 = 127%10 = 7. This cell is non-empty, so we insert into
Position 5.(Linear Probing)
-10th hashcode is 96 = 96%10 = 6. This cell is empty, so we can insert.

A new table of size 20 is now formed as our previous table is full, and values are
Rehashed.

-11th hashcode is 42 = 42%20 = 2 This cell is non-empty so we can insert.


(b) (a) -1st hashcode is 17 = 17%5 = 2. This is empty, so we can insert it.
-2nd hashcode is 12 = 12%5 = 2. This is non-empty, hence we must insert it into
Postion 3(Quadraticr Probing)
-3rd hashcode is 128 = 128%5 = 3. This cell is non-empty, so we must insert into
Position 4(Quadratic Probing)
-4th hashcode is 10 = 10%5 = 0. This cell is empty, so we can insert.
-5th hashcode is 7 = 7%5 = 2. This cell is non-empty, so we must insert into
Position 1(Quadratic Probing).

A new table of size 10 is now formed as our previous table is full, and values are
rehashed.

-6th hashcode is 14 = 14%10 = 4. This cell is empty, so we can insert.


-7th hashcode is 129 = 129%10 = 9. This cell is non-empty, so we insert into
Position 3(Quadratic Probing).
-8th hashcode is 132 = 132%10 = 2. This cell is non-empty, so we insert into
Position 9.(Quadratic Probing)
-9th hashcode is 127 = 127%10 = 7. This cell is non-empty, so we insert into
Position 1.(Quadratic Probing)
-10th hashcode is 96 = 96%10 = 6. This cell is non-empty, so we can insert into
Position 5(Quadratic Probing).

A new table of size 20 is now formed as our previous table is full, and values are
Rehashed.

-11th hashcode is 42 = 42
(c) -1st hashcode is 17. So it will be inserted into 17%5 = position 2.
-2nd hashcode is 12. So it will be chained onto position 12%2 = 2.
-3rd hashcode is 128. So it will be inserted into position 128%5 = 3.
-4th hashcode is 10. It will be inserted into position 10%5 = 0.
-5th hashcode is 7. It will be chained into position 7%5 = 2.
-6th hashcode is 14. It will be inserted into position 14%5 = 4.
-7th hashcode is 129. It will be chained onto position 129%5 = 4
-8th hashcode is 132. It will be chained onto position 132%5 = 2.
-9th hashcode is 127. It will be chained onto position 127%5 = 2.
-10th hashcode is 96. It will be inserted into position 96%5 = 1.
-11th hashcode is 42. It will be chained onto position 42%5 = 2
3. (a) boolean isCyclic(List l){
if( head == null)
return true;
Hashmap table<Int> = new Hashmap();
Node n = head;
while(n.next! = null){
if(table.containsKey(n.hashValue())
return true;
table.add(n.hashvalue(),n);
n = n.next;
}
return false;
}

I assume that there exists a hash function from the address of a node to an integer,
that is distinctly based on the address of a node. Hence if the list is cyclic, a node will
repeat and a collision will occur in the hash table, and the function will return true.
Otherwise, if the list is acyclic, the end of the list will be encountered when the last
node refers to null. Then, the algorithm will return false. Hence the algorithm
terminates in any case.

(b) If there are n elements, the number of operations required are


(i) Acyclic list : At each node, two operations are performed
Checking if node was visited and if not, storing address of node in hashtable.
Operations = 2 + 2 + ……… + 2 (n times, i.e. until end of list/or until rep is found)
= 2n
Thus, f(n) = 2n.
For c = 1, c.f(n) >= n for every n>0. Thus, f є Ω(n).
Similarly, for c = ½, c.f(n) <=n, for every n> 0. Thus, f є O(n).
As f є Ω(n). and f є O(n), f ε θ(n).

(c) Hash tables take up a lot of space. In the worst case, the algorithm will take up 2n
space. This is because, each node has to be mapped to a unique cell in the array. As there
are n nodes n units of storage are needed. But, assuming a load factor of 0.5(as is the case
with most hash tables), we need 2n units of storage.
The space our algorithm use does in fact depend on our hash function. For a function
with a lot of collisions, we will need more space. But, for a well-crafted one-to-one hash
function, we will need less space.

(d) void isCyclic(List l){


if(l.head == null)
return true;
Node n1 = l.head;
Node n2 = l.head;
if(n1.next == null || n1.next.next == null)
return false;
while(n1.next ! = null && n1.next.next != null){
n1 = n1.next.next;
n2 = n2.next;
if(n1 == n2)
return true;
}
return false;
}
This algorithm runs in the same time as the previous algorithm Ө(n) and does so in
Constant storage.

(e) The algorithm(determining whether a linked list is cyclic) works in both cases:
(i) If the list is acyclic, the reference n1 will eventually hit null, exit the loop and
return false. (see diagram) For an empty list, the algorithm returns false.

(ii)If the list is cyclic, reference n1 and n2 will eventually point to the same value.
Proof: Let n be the length of the list, and L be the length of the loop. As reference
n1 enters the loop, it is bound to stay in the loop. The same applies to refernce n2.
As n1 is incremented twice while n2 is incremented once, they will eventually
cross. Let n2 enter cyclic loop L. Then, n1 will be pointing to reference 2(n-L),
and n2 will be pointing to node n-L.
Thus, we must prove that there exists a k such that after k increments, both n1
And n2 will point to the same node. i.e.
(n-L) + (2(n-L) + 2k)%L = (n-L) + (n-L + k)%L
(2(n-L) + 2k)%L = (n-L+k)%L
By observation, we find that k = cL – n satisfies this property. Where
c>n/L. As a result, the two references eventually point to the same node, and
Algorithm returns true..
Once they do, the function will return true. See diagram below.

(f) Given n elements in the list, we consider two cases:


(i) List is Acyclic : As list is acyclic, n1 eventually hits null. As n1 is incremented
By 1 each time number of steps until we hit null is n/2.
For c = 4, c.f(n) >= n for every n>0. Thus, f є Ω(n).
Similarly, for c = 1, c.f(n) <=n, for every n> 0. Thus, f є O(n).
As f є Ω(n). and f є O(n), f ε θ(n).

(ii) List is cyclic : The worst case in this scenario is when the whole list is a cycle
i.e. node ‘n’ refers to node ‘1’. Thus, we have one big cycle of length n.
Let n be the node ref n1 is pointing to after k number of steps. Let n’ be the node
Ref n2 is pointing to after k number of steps. Thus, we must find k such that
(k*2)%n = (k)%2. , k>0.
We observe that k = 2n satisfies this property. Thus, f (n) = 2n.
For c = 1, c.f(n) >= n for every n>0. Thus, f є Ω(n).
Similarly, for c = 1/4 , c.f(n) <=n, for every n> 0. Thus, f є O(n).
As f є Ω(n). and f є O(n), f ε θ(n).

As the algorithm runs in θ(n). for both cases, the algorithm as a whole runs in
θ(n).

You might also like