服务器之家

服务器之家 > 正文

Java数据结构之实现哈希表的分离链接法

时间:2021-09-22 11:15     来源/作者:TanGBx

哈希表的分离链接法

原理

Hash Table可以看作是一种特殊的数组。他的原理基本上跟数组相同,给他一个数据,经过自己设置的哈希函数变换得到一个位置,并在这个位置当中放置该数据。哦对了,他还有个名字叫散列

0 1
数据1 数据2

就像这个数组,0号位置放着数据1,1号位置放数据2
而我们的哈希表则是通过一个函数f(x) 把数据1变成0,把数据2变成1,然后在得到位置插入数据1和数据2。
非常重要的是哈希表的长度为素数最好!!
而且当插入数据大于一半的时候我们要进行扩充!!!

冲突问题产生

现在这个表就是2个数据,所以不会产生什么冲突,但是若一个数据他通过f(x)计算得到的位置也是0呢?是不是就跟数据1产生了冲突,因为数据1已经占据了这个位置,你无法进行插入操作。对不对。

所以我们该如何解决这个问题呢,诶,我们肯定是想两个都可以插入是不是,就像一个炸串一样把他串起来。如图

Java数据结构之实现哈希表的分离链接法

a b c就像一个炸串,而如何实现这个炸串就有多种方式。这里我们用线性表来实现

线性表实现

我们可以用java自带的List ArrayList等表,这边也给出单链表的实现方式。

  1. public class MyArray<AnyType> {

我们首先得创建一个内部类用来存放数据,以及保存下个节点

  1. class ArrayNode<AnyType>{
  2. public AnyType data;
  3. public ArrayNode<AnyType> next;
  4. public ArrayNode(AnyType data){this(data,null);}
  5. private ArrayNode(AnyType data,ArrayNode<AnyType> next){
  6. this.data=data;
  7. this.next=next;
  8. }
  9. }//save type node;

设置我们这个线性表所需要的对象,例如size和一个头节点,以及我们要进行初始化,判断这个表是否为空等。

  1. private int theSize;//array list size
  2. private ArrayNode<AnyType> head; //head node every data behind it
  3. //init MyArray
  4. public MyArray(){doClear();}
  5. public void clear(){doClear();}
  6. private void doClear(){
  7. theSize=0;
  8. head=new ArrayNode<>(null);
  9. }
  10. //get size and is empty
  11. public int size(){return theSize;}
  12. public boolean isEmpty(){return theSize==0;}

接下来我们需要实现他的基本操作,是否包含,插入,获得以及删除。

  1. //contain
  2. public boolean contains(AnyType x){
  3. ArrayNode<AnyType> newNode=head;//get a new node=head
  4. while (newNode.next!=null) {
  5. newNode=newNode.next;
  6. if (newNode.data == x)
  7. return true;
  8. }
  9. return false;
  10. }
  11. //get the data in idx from array
  12. public AnyType get(int idx){return get(idx,head).data;}
  13. private ArrayNode<AnyType> get(int idx,ArrayNode<AnyType> node){
  14. if(idx<0||idx>size())
  15. throw new IndexOutOfBoundsException();//out of length
  16. ArrayNode<AnyType> newNode=node;
  17. //find start head.next
  18. for (int i = 0; i < idx; i++)
  19. newNode=newNode.next;
  20. return newNode;
  21. }
  22. //set data into array
  23. public void set(AnyType x){set(x,head);}
  24. private void set(AnyType x,ArrayNode<AnyType> node){
  25. ArrayNode<AnyType> newNode=node;
  26. while (newNode.next!=null)
  27. newNode=newNode.next;
  28. theSize++;
  29. newNode.next=new ArrayNode<>(x);
  30. }
  31. //remove
  32. public void remove(AnyType x){remove(x,head);}
  33. private void remove(AnyType x,ArrayNode<AnyType> node){
  34. if(!contains(x))
  35. return;
  36. while (node.next!=null){
  37. node=node.next;
  38. if (node.next.data==x)
  39. break;
  40. }
  41. ArrayNode<AnyType> oldNode=node.next;
  42. node.next=null;
  43. node.next=oldNode.next;
  44. }
  45. }

哈希表实现

  1. public class MyHashTable<AnyType>{
  2. //define the things that we need to use
  3. private static final int DEFAULT_SIZE = 10;
  4. private MyArray<AnyType>[] arrays;
  5. private int currentSize;

因为我实现的是学号的存储
也就是带0开头的数据 所以我用字符串
这里这个myHash就是我实现的简单哈希函数,即获得的数据字符串化,得到最后两个字符

  1. private int myHash(AnyType x){
  2. String s=x.toString();
  3. return Integer.parseInt(s.substring(s.length()-2,s.length()));
  4. }

初始化哈希表,设置的默认大小为10,然后进行素数判断,如果它不是素数,那么就找到他的下一个素数作为表的大小。

  1. //init we should ensure that the table size is prime
  2. public MyHashTable(){
  3. ensureTable(nextPrime(DEFAULT_SIZE));
  4. makeEmpty();
  5. }
  6. private void ensureTable(int x){
  7. arrays=new MyArray[x];
  8. for (int i = 0; i < arrays.length; i++)
  9. arrays[i]=new MyArray<>();
  10. }
  11. //make the array empty
  12. public void makeEmpty(){
  13. currentSize=0;
  14. for(MyArray<AnyType> myArray:arrays)
  15. myArray.clear();
  16. }
  17. //size and empty
  18. public int size(){return currentSize;}
  19. public boolean isEmpty(){return currentSize==0;}

基本方法的实现,插入,获得,删除,包含

  1. //contain x
  2. public boolean contains(AnyType x){
  3. int position=myHash(x);
  4. return arrays[position].contains(x);
  5. }
  6. //insert x
  7. public void insert(AnyType x){
  8. int position=myHash(x);
  9. if(arrays[position].contains(x))
  10. return;
  11. else if(arrays[position].size()==0)
  12. if(++currentSize>arrays.length)
  13. makeBigger();
  14. arrays[position].set(x);
  15.  
  16. }
  17. //get idx data
  18. public MyArray<AnyType> get(int idx){ return arrays[idx];}

在这里,如果插入的时候啦,实际的currentSize大于二分之一表的大小了
则进行扩充表
一般扩充表的话,我们是直接两倍两倍扩充的。

  1. //makeBigger
  2. public void makeBigger() {
  3. MyArray[] oldArray = arrays;
  4. arrays = new MyArray[2 * arrays.length];
  5. for (int i = 0; i < oldArray.length; i++)
  6. arrays[i] = oldArray[i];
  7. }

下一个素数查找,如果他是偶数,则给他加1这样可以大大减少开销。
然后进行下一个素数判断,奇数当中找素数。

  1. //nextPrime
  2. private int nextPrime(int i){
  3. if(i%2==0)
  4. i++;
  5. for (; !isPrime(i); i+=2);//ensure i is jishu
  6. return i;
  7. }

是否为素数判断,如果为2则范围true
如果是1或者为偶数则返回false
都不满足则从三开始,他的平方小于输入的数,用奇数进行操作,因为用偶数的话,前面那个2就直接判断了,所以我们用奇数,大大减少开销。
我们也可以设置他的判断条件是小于输入的二分之一,但是我们用平方进行判断大大减少了开销,而且对于奇数来说是十分有效果的。

  1. //is Prime
  2. private boolean isPrime(int i){
  3. if(i==2||i==3)
  4. return true;
  5. if(i==1||i%2==0)
  6. return false;
  7. for (int j = 3; j*j<=i ; j+=2)
  8. if (i%j==0)
  9. return false;
  10. return true;
  11. }
  12. }

测试

  1. public class test {
  2. public static void main(String[] args) {
  3. MyHashTable<String> a=new MyHashTable<>();
  4. a.insert("001");
  5. a.insert("01");
  6. for(int i=1;i<a.get(1).size()+1;i++){
  7. System.out.println(a.get(1).get(i));
  8. }
  9. }
  10. }

结果

Java数据结构之实现哈希表的分离链接法

到此这篇关于Java数据结构之实现哈希表的分离链接法的文章就介绍到这了,更多相关Java哈希表的分离链接法内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/TanGBx/article/details/117906761

相关文章

热门资讯

yue是什么意思 网络流行语yue了是什么梗
yue是什么意思 网络流行语yue了是什么梗 2020-10-11
2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全
2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全 2019-12-26
背刺什么意思 网络词语背刺是什么梗
背刺什么意思 网络词语背刺是什么梗 2020-05-22
苹果12mini价格表官网报价 iPhone12mini全版本价格汇总
苹果12mini价格表官网报价 iPhone12mini全版本价格汇总 2020-11-13
2021年耽改剧名单 2021要播出的59部耽改剧列表
2021年耽改剧名单 2021要播出的59部耽改剧列表 2021-03-05
返回顶部