在初学数据结构的时候,大家总会对hash函数的理解不那么透彻,只知道它是一种很有优越性的存储结构,而不知其所以然.最近又深入了解了一下hash函数的原理,感到收获颇丰,那么hash函数是怎么应运而生的呢,我来谈谈个人的理解.
在应用数组的时候,我们会发现数组有这样的特性:
1.查找方便,可以通过下标直接查找,速度快,效率高;
2.在增加和删除元素时,需要新建一个数组,在时间和空间上的代价都很大.
考虑到数组存在的缺点,我们会自然地联想到另一种数据结构--链表,链表有如下特点:
1.由于链表是由一个一个结点连接起来而组成的,所以在删除和增加元素时,只需改变指定位置的及前后的两个结点,效率较高。
2.链表在查找时,需遍历链表,时间代价大。
鉴于以上两种数据结构均存在弊端,如果可以即能像数组一样方便的查找,又能像链表一样高效率的存储和删除,那么问题便迎刃而解,由此我们引入了Hashmap这种数据结构,它可以理解为是链表和数组的结合体,我们可以利用数组和链表,自定义一个hash结构。步骤如下:
1.创建一个合适长度的数组;
2.定义一个结点类,里面封装所要存储的信息的属性,以及指向下一个结点的“指针”;
3.每当要加入数据时,根据新结点中的一个序号属性,对该属性取模(例如:num%arr.length),取模后得到数字,及是该新结点对应的数组坐标。如果数组中该坐标对应的位置已经有一个结点或者一条结点链,那么将新数组加到末尾。
4.当数组中某个下标对应的链表的长度达到一个规定的值(称为 阀值),则扩充数组容量,重新按照3中 的方法进行排列。
package netjava.cn;
/**
* 结点类
* @author Administrator
*
*/
public class Node {
private int num;
private String name;
private String pwd;
private Node next;
public Node(int num,String name,String pwd){
this.num = num;
this.name = name;
this.pwd = pwd;
}
public void setNext(Node next){
this.next = next;
}
public Node getNext(){
return this.next;
}
public int getNum() {
return num;
}
public String getName() {
return name;
}
public String getPwd() {
return pwd;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return "序号:"+num+">姓名:"+name+">密码:"+pwd;
}
}
package netjava.cn;
/**
* 头结点的定义
* @author Administrator
*
*/
public class Combine {
public Combine(Node node) {
this.node = node;
}
//链表首结点
private Node node;
//链表长度
private int length = 1;
/**得到链表中最一个结点*/
public Node lastNode(){
Node n = node;
while(n.getNext() != null){
n = n.getNext();
}
return n;
}
/**打印一条链上的所有结点*/
public void printNode(){
Node n = node;
System.out.println(n);
while(n.getNext() != null){
n = n.getNext();
System.out.println(n);
}
}
/**增加链表的长度*/
public int addLength(){
return length++;
}
/*得到首结点*/
public Node getNode() {
return node;
}
public int getLength() {
return length;
}
public void setLength(int length) {
this.length = length;
}
}
package netjava.cn;
import java.util.Random;
public class DefineHash {
private int length = 10;
private int limit = 10;
private Combine[] arr = new Combine[length];// 存放头结点的数组
public static void main(String[] args) {
DefineHash hash = new DefineHash();
Combine[] arr = hash.buildArr();
hash.print(arr);
Node n0 = new Node(23, "后来的", "密码@!!");
hash.add(n0);
Node n1= new Node(24, "后来的", "密码@!!");
hash.add(n1);
for (int i = 0; i < 100; i++) {
Node n = new Node(25+i, "后来的", "密码@!!");
hash.add(n);
}
}
/** 初始化数组 */
public Combine[] buildArr() {
// 创建初始容量为length的数组
arr = new Combine[length];
// 随机得到50条需要存储的信息
Random random = new Random();
for (int i = 0; i < 4; i++) {
// 随机生成num
int next = random.nextInt(50);
// 创建结点
Node node = new Node(next, "poppy", "12345678");
// 根据num取模,得到数组中的位置
int index = next % length;
// index位置已有元素时
if (arr[index] != null) {
Combine com = arr[index];
// 使链表的长度+1
com.addLength();
// 将结点加到末尾
Node pre = com.lastNode();
pre.setNext(node);
} else { // index位置无元素时,赋初始值
arr[index] = new Combine(node);
}
}
return arr;
}
/** 加入数据 */
public Combine[] add(Node node) {
// 得到帐号
int num = node.getNum();
// 根据num取模,得到数组中的位置
int index = num % length;
// index位置已有元素时,将结点加到末尾
if (arr[index] != null) {
Combine com = arr[index];
// 链表长度未达到阀值
if (com.getLength() < limit) {
System.out.println("未阀值");
Node pre = com.lastNode();
pre.setNext(node);
com.addLength();
} else { // 链表长度得到阀值,重新排序
System.out.println("阀值");
Combine[] c = reSort(arr);
arr =c;
}
} else { // index位置无元素时,赋初始值
arr[index] = new Combine(node);
}
return arr;
}
/** 删除数据 */
public void delete(Node node) {
}
/** 查找数据 */
public void find(Node node) {
}
/** 重新排列 */
public Combine[] reSort(Combine[] arr) {
System.out.println("开始重拍!!!");
length *= 2;// 数组容量扩大到2倍
limit *= 2;// 将上限扩大2倍
Combine[] larr = new Combine[length];
// 遍历数组,得到每个跟结点
for (int i = 0; i < arr.length; i++) {
if (arr[i] != null) {
Combine combine = arr[i];
// 得到原根结点
Node n = combine.getNode();
int num = n.getNum();
int index = num % length;
//新数组上index已有结点
if(larr[index] != null){
Combine com = larr[index];
com.addLength();//长度+1
com.lastNode().setNext(n);
}else{//新数组上Index没有结点
larr[index] = combine;
}
}
}
this.print(larr);
System.out.println("last");
System.out.println(larr.length+"新书组长度");
return larr;
}
/** 打印hash表 */
public void print(Combine[] arr) {
for (int i = 0; i < arr.length; i++) {
if (arr[i] != null) {
System.out.println(i + ">>>>>");
arr[i].printNode();
}
}
}
}
<!--EndFragment-->