码迷,mamicode.com
首页 > 其他好文 > 详细

深夜聊Hash

时间:2015-04-13 18:17:02      阅读:170      评论:0      收藏:0      [点我收藏+]

标签:

 

      我是Hash,我的老爹也叫Hash,听说英语中Hash代表无用信息,不知道我老爹的老爹是不是没文化,取个名字都像在说我老爹是个没用的东西.....

      我是Hash,我的脾气特倔,我只往一个方向走,也就是说我是不可逆的,任何想让我变弯的,都在耍流氓。可能会有朋友问啥叫不可逆,举个例子哈,你爸生了你,反过来,你能生你爸吗?????

      我是Hash,人称查找小王子,因为我快如闪电,当然了还有我英俊潇洒,风流倜傥的超高颜值。话说回来,我查找小王子的名号可不是盖的,什么循环查找啊,二分查找啊,都是浮云,只要我动动手指头,你想要啥就有啥。好吧,我已经听见有哥们向我吹口哨了,话不多说,我就来剖析剖析我的原理......

     我是Hash,我有两大群小伙伴,一个叫数据,一个叫容器。数据是汉子团体,容器是妹子团体,汉子团体想快速找到妹子配对成功,这不,一伙人都来找我,叫我给他们出主意,没办法,谁叫我人缘好呢!!

     数据汉子们是一伙数量达number=10000的寂寞空虚冷的学生,这里我就先取他们的两个属性,名字和学号。如下:

public class Student
{
private String name;
private int schoolnumber;
private Student tail;           //汉子后面还接汉子,同志们,以下情节绝不是你想象的样子.......
public Student(String name, int schoolnumber) {
this.name = name;
this.schoolnumber = schoolnumber;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSchoolnumber() {
return schoolnumber;
}
public void setSchoolnumber(int schoolnumber) {
this.schoolnumber = schoolnumber;
}
public Student getTail() {
return tail;
}
public void setTail(Student tail) {
this.tail = tail;
}
}

    介绍完汉子们,就来瞧瞧妹子们,容器妹子是一伙数量达uplimit=8000,及其有限的高质量数组,如下:

private Student a[]=new Student[uplimit];

    看完了两头,就看我如何发功,将他们配对成功,首先选取最简单的Hash函数,取模,如下:

public int dohash(int i){
int hashId=i%hashvalue;    //这里的i代表汉子学生的学号,hashvalue代表取模值为8000,也就是容器妹子的数量,注意哦,这就是单向操作,不可逆
return hashId;
}

    接着就看我如何插入,注意哦,由于妹子实在是珍惜动物,我每调用一次Hash函数,就可能出现多位汉子对应一位妹子,所以汉子们只好在妹子后面接起了长龙,俗称冲突。我今天就采用链表的方式解决冲突,如下:

public void insert()
{
long time1=System.currentTimeMillis();
for(int i=0;i<number;i++)
{
Student student=new Student("Jack"+i,i);
int hashId=dohash(student.getSchoolnumber());
if(a[hashId]==null){
a[hashId]=student;
}else{
previous=a[hashId];        //这里previous代表前一个学生汉子,tail代表下一个学生汉子
tail=a[hashId].getTail();
while(tail!=null){              
previous=tail;
tail=tail.getTail();
}
previous.setTail(student);
}
}
System.out.println("插入10000个数据所用时间为"+(System.currentTimeMillis()-time1)+"毫秒.....");
}

      这里让我们看看用时多少:插入10000个数据所用时间为35毫秒.....

      那么问题来了,想知道某位汉子是否配对成功了,先得知道当前汉子的学号,如下:

public void lookup(){
Random random=new Random();
int rint=random.nextInt(10000);
long time1=System.currentTimeMillis();
int hashId=dohash(rint);
if(a[hashId].getSchoolnumber()==rint){
System.out.println("查找的学生学号为"+rint+",姓名为"+a[hashId].getName());
System.out.println("在10000个数据中查找一个数据所用时间为"+(System.currentTimeMillis()-time1)+"毫秒.....");
return;
}else{
tail=a[hashId].getTail();
while(tail!=null){
if(tail.getSchoolnumber()==rint){
System.out.println("查找的学生学号为"+rint+",姓名为"+tail.getName());
System.out.println("在10000个数据中查找一个数据所用时间为"+(System.currentTimeMillis()-time1)+"毫秒.....");
return;
}
tail=tail.getTail();
}
System.out.println("查找的学生学号为"+rint+",不存在");
}
}

      结果怎样呢?????

     查找的学生学号为3082,姓名为Jack3082
     在10000个数据中查找一个数据所用时间为0毫秒.....

     看到了吧,我快到计算机都可以忽略为0。更不要说哪位容器妹子不想和数据汉子约会了,看我的删除大法,如下:

public void delete()
{
Random random=new Random();
int rint=random.nextInt(10000);
long time1=System.currentTimeMillis();
int hashId=dohash(rint);
if(a[hashId].getSchoolnumber()==rint){
System.out.println("删除的学生学号为"+rint+",姓名为"+a[hashId].getName());
a[hashId]=a[hashId].getTail();
System.out.println("在10000个数据中删除一个数据所用时间为"+(System.currentTimeMillis()-time1)+"毫秒.....");
return;
}else{
previous=a[hashId];
tail=a[hashId].getTail();
while(tail!=null){
if(tail.getSchoolnumber()==rint){
System.out.println("删除的学生学号为"+rint+",姓名为"+tail.getName());
previous.setTail(tail.getTail());
System.out.println("在10000个数据中删除一个数据所用时间为"+(System.currentTimeMillis()-time1)+"毫秒.....");
return;
}
previous=tail;
tail=tail.getTail();
}
System.out.println("删除的学生学号为"+rint+",不存在");
}
}

     ok,那我们来看看输出,绝对吓死你们:

     删除的学生学号为2580,姓名为Jack2580
     在10000个数据中删除一个数据所用时间为0毫秒.....

     说了这么多,我也是累了,last but not least 最重要的一点,让我唠叨唠叨完:当汉子后面挂了太多的汉子,是不是不太好,打起来了怎么办??ok,让我再做一个操作,也叫rehash,怎么实现,当汉子数量/妹子数量=number/uplimit大于1.2以上了,就该做该操作了。毫无疑问,首先得找更多的妹子集合,将原先集合里的男同胞们找出来,重新做hash操作,这时的模数就要增大了hashvalue=9000,如下:

public void rehash()
{
Student btail;
long time1=System.currentTimeMillis();
double lf=(double)number/(double)uplimit;
if(lf>1.2){
hashvalue=9000;
for(int i=0;i<uplimit;i++){
if(a[i]!=null){
int rehashid=dohash(a[i].getSchoolnumber());
if(b[rehashid]==null){
b[rehashid]=a[i];
}else{
previous=b[rehashid];
btail=b[rehashid].getTail();
while(btail!=null){
previous=btail;
btail=btail.getTail();
}
previous.setTail(a[i]);
}
tail=a[i].getTail();
while (tail!=null) {
int rehashid2=dohash(tail.getSchoolnumber());
if(b[rehashid2]==null){
b[rehashid2]=tail;
}else{
previous=b[rehashid2];
btail=b[rehashid2].getTail();
while(btail!=null){
previous=btail;
btail=btail.getTail();
}
previous.setTail(tail);
}
tail=tail.getTail();
}
}
}

}
System.out.println("在装载因子为"+lf+"的10000个数据中Rehash操作所用时间为"+(System.currentTimeMillis()-time1)+"毫秒.....");
}

      不得不说这是一个耗时的操作,结果:在装载因子为1.25的10000个数据中Rehash操作所用时间为50毫秒.....

      我是Hash,你懂我了吗??????

 

     

 

深夜聊Hash

标签:

原文地址:http://www.cnblogs.com/huangxiaomin/p/4422479.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!