题目总体上还是不太难……只是,一个晚上都卡在第四题,做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.