散列函数:除法映射 f(k)=k%D
解决溢出:使用链表
在该散列的组织中,每个桶仅含有一个指针节点,所有的元素都存储在该指针指向的链表中,为了保证查找方便,指针指向的链表元素的大小应该按顺序排列。
首先声明一个链表类ListNode
public class ListNode {
int val;
ListNode next;
public ListNode(int val) {
this.val = val;
}
}
初始化散列——LinkedListHash类
ListNode[] buckets;
int bucketsLen;
public LinkedListHash(int bucketsLen) {
this.bucketsLen = bucketsLen;
buckets = new ListNode[bucketsLen];
for (int i = 0; i < bucketsLen; i++) {
buckets[i] = new ListNode(i);
buckets[i].next = new ListNode((int) Double.POSITIVE_INFINITY);
}
}
查找
在搜索关键值为value的元素时,首先要计算其起始桶。起始桶号为value%bucketsLen,然后搜索该桶对应的链表.
public boolean search(int value) {
int loc = value % bucketsLen;
ListNode listNode = buckets[loc];
while (listNode.next != null) {
if (listNode.next.val < value)
listNode = listNode.next;
else if (listNode.next.val == value)
return true;
else
break;
}
return false;
}
插入
在插入时,首先要保证不含有相同关键字的元素。由于每次插入都要进行一次搜索,因此把链表按照升序排列比无序排列更加有效。
public void insert(int value) {
int loc = value % bucketsLen;
ListNode listNode = buckets[loc];
while (listNode.next != null) {
if (listNode.next.val == value)
return;
else if (listNode.next.val > value)
insertFollow(listNode, new ListNode(value));
else
listNode = listNode.next;
}
}
public void insertFollow(ListNode followNode, ListNode insertNode) {
/**
* followNode:在该节点后插入节点
* insertNode:待插入节点
*/
insertNode.next = followNode.next;
followNode.next = insertNode;
}
删除
删除关键字为value的元素,首先要访问起始桶对应的链表,找到该元素,然后删除。如果为找到该元素,则会报错。
public void delete(int value) {
int loc = value % bucketsLen;
ListNode listNode = buckets[loc];
while (listNode.next != null) {
if (listNode.next.val < value)
listNode = listNode.next;
else if (listNode.next.val == value) {
ListNode tmpNode = listNode.next;
listNode.next = tmpNode.next;
return;
} else
break;
}
throw new NoSuchElementException();
}