题目总体上还是不太难……只是,一个晚上都卡在第四题,做Java实现去了……
up date: 最后Java实现了一个上午,终于把第四题做好了。基本思想和Solution Manual是一样的,只是我允许相同key的情况——因为我认为,即使是带着相同的key,data也有可能不同。
11.2-1:
11.2-2:
11.2-3:
For every node, it's a linked list; therefore, by keeping the list sorted, the running time would change like this:
Operation | Original | New: keep sorted list |
Insertion | O(1) | O(n/m) |
Deletion | O(1+n/m) | O(n/m) |
Successful Search | O(1+n/m) | O(1+n/m) |
Unsuccessful Search | O(1) | O(1) |
The problem is, when searching in a linked list, the traversing of every elements in this linked is still needed, no matter sorted or not.
11.2-4:
package hashing;
import java.util.LinkedList;
import java.util.Random;
/* Author Songyy
* Start Time: 2011年3月8日22:43:34
* Second Time: 2011年3月9日9:30:00
* Third Time: 2011年3月9日11:40:36
* End Time: 2011年3月9日13:25:03
*
*
* Info:
* This is to implement Question 11.2-4 in CLRS, 2nd ed.
*
* Basic Idea:
* 1. Basic data structure:
* a hash table; each node has:
* -- flag: true means it's a start of a hash chain
* -- Double link on every chain
* (the empty node list can be treated as a stack of free space, but still need double link for update)
* next empty node: a node reference:
* -- pointed to the last occupied element whose's next is an empty node;
* -- null if the table is full
* 2. Basic Operation:
* -- Insertion x:
* node = table[hash[x.key]];
* if flag==true:
* find a new empty node;
* update link;
* copy the data into that new node;
* else:
* if it's empty:
* unlink from the stack
* set up new chain
* copy data
* if it's not:
* copy old data to a new empty node
* update chain
* set up new chain
* copy new data into this node
* -- Search key:
* node = table[key]
* if flag==false: return false;
* else: compare this key with others in the chain
* -- Deletion x:
* // assumption: x is a node in the table already. i.e., this node must exist in the table
* free the x from the linked chain
* x.flag = false;
* add x to the list of the free space (to the beginning of the empty node list)
*/
class LinkedListHashTableNode {
LinkedListHashTableNode former, next;
HashObject data;
/**
* False means it's used as a linked list, while true means it's used as a
* hash table node
*/
boolean flag;
public LinkedListHashTableNode() {
flag = false;
former = null;
next = null;
data = null;
}
public LinkedListHashTableNode(HashObject x) {
this();
data = x;
}
public void cloneNode(LinkedListHashTableNode toNode) {
toNode.former = former;
toNode.next = next;
toNode.data = data;
toNode.flag = flag;
}
}
class HashObject {
Object data;
int key;
public HashObject(int key) {
this.key = key;
}
}
public class LinkedListHashTable {
public static final int MAXSIZE = 100;
private LinkedListHashTableNode table[] = new LinkedListHashTableNode[MAXSIZE];
private LinkedListHashTableNode emptyNode;
public LinkedListHashTable() {
// first initialize the table
for (int i = 0; i < MAXSIZE; i++) {
table[i] = new LinkedListHashTableNode();
}
// set up the link for the empty node list
// the first's former and the last's next node are null
for (int i = 1; i < MAXSIZE; i++) {
table[i].former = table[i - 1];
table[i - 1].next = table[i];
}
// the start of the empty node
emptyNode = table[0];
}
private int hash(int key) {
return key % MAXSIZE;
}
/**
* @param x
* @return true if insert succeed, false if the table is full
*/
public boolean insert(HashObject x) {
// check if the table is full
if (emptyNode == null)
return false;
LinkedListHashTableNode node = table[hash(x.key)];
// if the node is the beginning of a chain
if (node.flag == true) {
// find new empty node
LinkedListHashTableNode tempEmptyNode = emptyNode;
emptyNode = emptyNode.next;
// unlink the supposed empty node
tempEmptyNode.former = null;
tempEmptyNode.next = null;
// update chain
tempEmptyNode.next = node.next;
node.next = tempEmptyNode;
tempEmptyNode.former = node;
if (tempEmptyNode.next != null)
tempEmptyNode.next.former = tempEmptyNode;
// copy data
tempEmptyNode.data = x;
} else {
// if the node is empty
if (node.data == null) {
// if it's the emptyNode, update emptyNode
if (node == emptyNode) {
emptyNode = emptyNode.next;
}
// unlink this node from the empty node list
if (node.former != null) {
node.former.next = node.next;
}
if (node.next != null) {
node.next.former = node.former;
}
node.next = null;
node.former = null;
// set up a new chain
node.former = null;
node.next = null;
node.flag = true;
// copy data
node.data = x;
}
// if not empty, it's in another chain
else {
// copy the old data to a new emptyNode
// ** find a new empty node
LinkedListHashTableNode tempEmptyNode = emptyNode;
emptyNode = emptyNode.next;
// ** copy from the node to tempEmptyNode
tempEmptyNode.former = node.former;
tempEmptyNode.next = node.next;
tempEmptyNode.data = node.data;
// update chain
// -- node is not the beginning of the chain, thus have a former
node.former.next = tempEmptyNode;
if (node.next != null)
node.next.former = tempEmptyNode;
// set up new chain
node.former = null;
node.next = null;
node.flag = true;
// copy data
node.data = x;
}
}
return true;
}
/**
* @param key
* @return - null if unfound
*/
public LinkedListHashTableNode search(int key) {
LinkedListHashTableNode node = table[hash(key)];
if (node.flag == false) {
return null;
} else {
while (node != null) {
if (node.data.key == key)
return node;
node = node.next;
}
}
return null;
}
/**
* @param x
* - x is a node from that table, thus has the information about
* former/ next
* @return - false if no need to delete
*/
public boolean delete(LinkedListHashTableNode x) {
// x don't have data, thus don't need to delete
if (x.data == null)
return false;
// else, x must be in the chain
// ** x is at the beginning of a chain
if (x.flag == true) {
// ** if x doesn't have a next, then simply delete it
if(x.next==null){
x.flag = false;
}
// ** if x has a next, then need to copy it's next to x's position,
// then delete its next
else{
// temp is at the beginning of the chain
LinkedListHashTableNode temp = x;
// x becomes the second element in the chain then
x = x.next;
temp.data = x.data;
}
}
// ** unlink x from the chain first
if (x.former != null){
x.former.next = x.next;
}
if (x.next != null){
x.next.former = x.former;
}
// ** make x to be empty
x.data = null;
x.former = null;x.next = null;
// ** then add x to be the first element in emptyNode list
x.next = emptyNode;
if(emptyNode!=null){
emptyNode.former = x;
}
emptyNode = x;
return true;
}
public static void main(String[] args) {
LinkedListHashTable a = new LinkedListHashTable();
LinkedList<Integer> l = new LinkedList<Integer>();
Random rand = new Random();
for (int i = 0; i < 100; i++) {
int t = rand.nextInt(10000);
System.out.println(t % 100);
l.add(t);
if (a.insert(new HashObject(t)) == false)
System.out.println("List Full!");
}
while (!l.isEmpty()) {
int t = l.pop();
if (a.search(t) == null) {
System.out.println("Error: element " + t + "unfound.");
}
}
// int test = 12, t = test;
// for(int i=0;i<100;i++){
// a.insert(new HashObject(t));
// }
}
}
11.2-5:
If |U| > m*n, then for the mapping from U to hash table of size m, it's at least a m*n to n mapping, and thus it's possible for one slot to have n elements.