一、为什么要用哈希表

树的操作通常需要O(N)的时间级,而哈希表中无论存有多少数据,它的插入和查找(有时包括删除)只需要接近常量级的时间,即O(1)的时间级。

但是哈希表也有一定的缺点:它是基于数组的,数组创建后难以扩展。而某些哈希表在基本填满时,性能下降明显,所以事先必须清楚哈希表中将要存储多少数据。而且目前没有一种简便的方法可以对哈希表进行有序(从大到小或者从小到大)的遍历,除非哈希表本身是有序的,但事实上这是违背哈希原则的。

综合以上:当不需要有序遍历数据,而且可以提前预测需要存储的数据项的数目,使用哈希表的结构是十分方便的。

二、哈希化

把巨大的整数(关键字)范围压缩到一个可接受的数组范围内,便于存储和查找。通常来说,我们要存储5000个数据,但数据的关键字范围可能是0-200000。我们不可能去开辟200000的数组去存储这5000个数据,这就需要一个函数把关键字和数组下标对应起来。这就是哈希函数。通常的做法是取余操作。i=N%size;i为下标,N为关键字,size为数组大小。不过通常来说,size设为要存储数据项数目的两倍。

如果哈希表存满时,需要扩展哈希表。我们需要新建一个更大的数组来存储数据,然后把原表中数据一一取出放入新表中。需要注意的是数据放入新表时需要重新用哈希函数计算哈希值,不能直接进行数组的复制,因为哈希函数的size已经变了。

通常而言我们把哈希数组的容量设为一个质数。首先来说假如关键字是随机分布的,那么无所谓一定要模质数。但在实际中往往关键字有某种规律,例如大量的等差数列,那么公差和模数不互质的时候发生碰撞的概率会变大,而用质数就可以很大程度上回避这个问题。对于除法哈希表h(k)=k mod m,注意二进制数对取余就是该二进制数最后r位数。这样一来,Hash函数就和键值(用二进制表示)的前几位数无关了,这样我们就没有完全用到键值的信息,这种选择m的方法是不好的。所以好的方法就是用质数来表示m,使得这些质数,不太接近2的幂或者10的幂。

三、解决冲突

首先一般哈希表是不允许重复的关键字,否则查找函数只能返回最先查到的关键字,无法找到所有的对应数据项。如果重写查找函数让它可以找到所有的对应数据项,这又会使得无论是否是重复关键字,查找操作都要搜索整个表,非常耗时。

存储过程中可能出现存储的数据项关键字不同,但计算出来的哈希值是相同的,这就是冲突。

通常采用以下两种方法来解决冲突。

1、开放地址法

直接在哈希表中找到一个空位,把冲突的数据项存进去。

2、链地址法

把哈希表中存储的数据格式设为链表,这样可以把冲突的数据放入对应位置的链表中即可。

四、开放地址法的java实现

根据在查找下一个空位置时采用的方法,可以把开放地址法分为三种:线性探测、二次探测和再哈希法。

1、线性探测法

线性探测就是根据数组下标一个挨着一个去检测,直到找到一个空位置。

java实现:

DataItem类定义了哈希表存储的数据内容和关键字。

  1. package hash;
  2.  
  3. class DataItem //hash表中存放的数据格式
  4. {
  5. private int iData; // 设为关键字
  6. //--------------------------------------------------------------
  7. public DataItem(int ii) // 构造器
  8. { iData = ii; }
  9. //--------------------------------------------------------------
  10. public int getKey() //获取关键字
  11. { return iData; }
  12. //--------------------------------------------------------------
  13. } // end class DataItem
  14. ////////////////////////////////////////////////////////////////

HashTable类作为哈希表的实现

  1. package hash;
  2.  
  3. class HashTable //定义哈希表
  4. {
  5. private DataItem[] hashArray; // 数组形式
  6. private int arraySize; //哈希表的大小
  7. private DataItem nonItem; // 删除数据时,将被删除的数据设为nonItem
  8. //-------------------------------------------------------------
  9. public HashTable(int size) //构造器,指定哈希表的大小
  10. {
  11. arraySize = size;
  12. hashArray = new DataItem[arraySize];
  13. nonItem = new DataItem(-1); // 把nonItem的关键字设为-1
  14. }
  15. //-------------------------------------------------------------
  16. public void displayTable() //显示哈希表
  17. {
  18. System.out.print("Table: ");
  19. for(int j=0; j<arraySize; j++)
  20. {
  21. if(hashArray[j] != null)
  22. System.out.print(hashArray[j].getKey() + " ");
  23. else
  24. System.out.print("** "); //该位置没有存数据
  25. }
  26. System.out.println("");
  27. }
  28. //-------------------------------------------------------------
  29. public int hashFunc(int key)
  30. {
  31. return key % arraySize; // 哈希函数
  32. }
  33. //-------------------------------------------------------------
  34. public void insert(DataItem item) // 插入数据
  35. // 默认表未满,事实上哈希表是不允许存满的,哈希表的大小比实际存储的数据数要大。
  36. {
  37. int key = item.getKey(); // 获取数据项的关键字,用于计算哈希值
  38. int hashVal = hashFunc(key); // 计算哈希值
  39. // 当前位置存有数据并且该数据未被删除
  40. while(hashArray[hashVal] != null &&
  41. hashArray[hashVal].getKey() != -1)
  42. {
  43. ++hashVal; // 查找下一个位置
  44. hashVal %= arraySize; // 到达表的末尾时,hashVal值变成1,。构成循环,从而可以查找整个表
  45. }
  46. hashArray[hashVal] = item; // 找到位置
  47. } // end insert()
  48. //-------------------------------------------------------------
  49. public DataItem delete(int key) // 根据关键字删除数据
  50. {
  51. int hashVal = hashFunc(key); // 根据关键字计算哈希值
  52.  
  53. while(hashArray[hashVal] != null) // 该位置存有数据
  54. { // 两者的关键字是否相同
  55. if(hashArray[hashVal].getKey() == key)
  56. {
  57. DataItem temp = hashArray[hashVal]; // 保存删除的数据项,用于返回
  58. hashArray[hashVal] = nonItem; // 删除
  59. return temp; // 返回删除的数据项
  60. }
  61. ++hashVal; // 关键字不相同,继续查找下一个
  62. hashVal %= arraySize; //循环
  63. }
  64. return null; // 未找到
  65. } // end delete()
  66. //-------------------------------------------------------------
  67. public DataItem find(int key) // 表中是否存在该关键字的数据项
  68. {
  69. int hashVal = hashFunc(key);
  70.  
  71. while(hashArray[hashVal] != null)
  72. {
  73. if(hashArray[hashVal].getKey() == key)
  74. return hashArray[hashVal];
  75. ++hashVal;
  76. hashVal %= arraySize;
  77. }
  78. return null;
  79. }
  80. //-------------------------------------------------------------
  81. } // end class HashTable
  82. ////////////////////////////////////////////////////////////////

HashTableApp类中包含了主程序

  1. package hash;
  2. import java.io.*;
  3.  
  4. class HashTableApp
  5. {
  6. public static void main(String[] args) throws IOException
  7. {
  8. DataItem aDataItem;
  9. int aKey, size, n, keysPerCell;
  10. System.out.print("Enter size of hash table: ");
  11. size = getInt();//从控制台获取一个整数作为哈希表的大小
  12. System.out.print("Enter initial number of items: ");
  13. n = getInt(); //随机生成n个数作为数据存入哈希表
  14. keysPerCell = 10;//随机生成函数的因子
  15.  
  16. HashTable theHashTable = new HashTable(size);//初始化
  17.  
  18. for(int j=0; j<n; j++) // 生成并插入
  19. {
  20. aKey = (int)(java.lang.Math.random() *
  21. keysPerCell * size);
  22. aDataItem = new DataItem(aKey);//封装为哈希表中的数据格式
  23. theHashTable.insert(aDataItem);//插入
  24. }
  25.  
  26. while(true)
  27. {
  28. System.out.print("Enter first letter of ");
  29. System.out.print("show, insert, delete, or find: ");
  30. char choice = getChar();
  31. switch(choice)
  32. {
  33. case 's':
  34. theHashTable.displayTable();
  35. break;
  36. case 'i':
  37. System.out.print("Enter key value to insert: ");
  38. aKey = getInt();
  39. aDataItem = new DataItem(aKey);
  40. theHashTable.insert(aDataItem);
  41. break;
  42. case 'd':
  43. System.out.print("Enter key value to delete: ");
  44. aKey = getInt();
  45. theHashTable.delete(aKey);
  46. break;
  47. case 'f':
  48. System.out.print("Enter key value to find: ");
  49. aKey = getInt();
  50. aDataItem = theHashTable.find(aKey);
  51. if(aDataItem != null)
  52. {
  53. System.out.println("Found " + aKey);
  54. }
  55. else
  56. System.out.println("Could not find " + aKey);
  57. break;
  58. default:
  59. System.out.print("Invalid entry\n");
  60. } // end switch
  61. } // end while
  62. } // end main()
  63. //--------------------------------------------------------------
  64. public static String getString() throws IOException
  65. {
  66. InputStreamReader isr = new InputStreamReader(System.in);
  67. BufferedReader br = new BufferedReader(isr);
  68. String s = br.readLine();
  69. return s;
  70. }
  71. //--------------------------------------------------------------
  72. public static char getChar() throws IOException
  73. {
  74. String s = getString();
  75. return s.charAt(0);
  76. }
  77. //-------------------------------------------------------------
  78. public static int getInt() throws IOException
  79. {
  80. String s = getString();
  81. return Integer.parseInt(s);
  82. }
  83. //--------------------------------------------------------------
  84. } // end class HashTableApp
  85. ////////////////////////////////////////////////////////////////

2、二次探测法

线性探测法会发生集聚现象,即冲突数据项会集聚在一起,原因是查找空数据项是一步一步移动的。

二次探测法是为了防止集聚产生的一种尝试方法,思想是探测间隔较远的单元,而不是临近的单元。具体方法是把步长设为探测次数的平方,比如第1次探测步长为1,第2次为4,第3次为9以此类推。

但是二次探测法会产生二次集聚。通常不采用该方法,因为有更好的解决方案。

3、再哈希法

方法是对冲突的关键字用另一个哈希函数计算其值,把结果作为搜索时的步长。这就使得不同的关键字步长不同,避免了集聚现象。

第二个哈希函数必须具备以下条件:

(1)与第一个哈希函数不同

(2)不能得出结果为0,否则步长为0.

通常第二个哈希函数采用如下函数:

step=constant-(key%contant)

constant是一个质数且小于数组容量,key是关键字。step范围在1-constant之间。

再哈希法要求表的容量是一个质数,这是为了使查找操作可以遍历整个表。否则假设表的容量为15,不是一个质数。而查找初始位置为4,查找步长为5,那么每次查找都是固定的三个数,即下标为9,14,4对应的数据。设为质数可以避免这种情况。

再哈希法的java实现

  1. package hashDouble;
  2.  
  3. class DataItem
  4. {
  5. private int iData; // 关键字
  6. //--------------------------------------------------------------
  7. public DataItem(int ii) // 构造器
  8. { iData = ii; }
  9. //--------------------------------------------------------------
  10. public int getKey() //获取关键字
  11. { return iData; }
  12. //--------------------------------------------------------------
  13. } // end class DataItem
  14. ////////////////////////////////////////////////////////////////
  1. package hashDouble;
  2.  
  3. class HashTable
  4. {
  5. private DataItem[] hashArray;
  6. private int arraySize;
  7. private DataItem nonItem;
  8. //-------------------------------------------------------------
  9. HashTable(int size) // 构造器
  10. {
  11. arraySize = size;
  12. hashArray = new DataItem[arraySize];
  13. nonItem = new DataItem(-1);
  14. }
  15. //-------------------------------------------------------------
  16. public void displayTable()
  17. {
  18. System.out.print("Table: ");
  19. for(int j=0; j<arraySize; j++)
  20. {
  21. if(hashArray[j] != null)
  22. System.out.print(hashArray[j].getKey()+ " ");
  23. else
  24. System.out.print("** ");
  25. }
  26. System.out.println("");
  27. }
  28. //-------------------------------------------------------------
  29. public int hashFunc1(int key)
  30. {
  31. return key % arraySize;
  32. }
  33. //-------------------------------------------------------------
  34. public int hashFunc2(int key) //再哈希
  35. {
  36. return 5 - key % 5;
  37. }
  38. //-------------------------------------------------------------
  39.  
  40. public void insert(int key, DataItem item)
  41. // 假设表未满
  42. {
  43. int hashVal = hashFunc1(key); // 计算哈希值
  44. int stepSize = hashFunc2(key); // 计算步长
  45.  
  46. while(hashArray[hashVal] != null &&
  47. hashArray[hashVal].getKey() != -1)//非空且数据未删除
  48. {
  49. hashVal += stepSize; // 加步长
  50. hashVal %= arraySize; // 循环到表头
  51. }
  52. hashArray[hashVal] = item; // 插入
  53. } // end insert()
  54. //-------------------------------------------------------------
  55. public DataItem delete(int key) // 删除
  56. {
  57. int hashVal = hashFunc1(key); //计算哈希值
  58. int stepSize = hashFunc2(key); // 计算步长
  59.  
  60. while(hashArray[hashVal] != null) // 非空
  61. {
  62. if(hashArray[hashVal].getKey() == key)//找到
  63. {
  64. DataItem temp = hashArray[hashVal];
  65. hashArray[hashVal] = nonItem;
  66. return temp;
  67. }
  68. hashVal += stepSize;
  69. hashVal %= arraySize;
  70. }
  71. return null; // 无法找到
  72. } // end delete()
  73. //-------------------------------------------------------------
  74. public DataItem find(int key) // 查找
  75. // 假设表未满
  76. {
  77. int hashVal = hashFunc1(key);
  78. int stepSize = hashFunc2(key);
  79.  
  80. while(hashArray[hashVal] != null) // 非空
  81. {
  82. if(hashArray[hashVal].getKey() == key)
  83. return hashArray[hashVal]; // 找到返回
  84. hashVal += stepSize; // 加步长
  85. hashVal %= arraySize;
  86. }
  87. return null; // can't find item
  88. }
  89. //-------------------------------------------------------------
  90. } // end class HashTable
  91. ////////////////////////////////////////////////////////////////
  1. package hashDouble;
  2. import java.io.*;
  3. class HashDoubleApp
  4. {
  5. public static void main(String[] args) throws IOException
  6. {
  7. int aKey;
  8. DataItem aDataItem;
  9. int size, n;
  10.  
  11. System.out.print("Enter size of hash table: ");
  12. size = getInt();
  13. System.out.print("Enter initial number of items: ");
  14. n = getInt();
  15.  
  16. HashTable theHashTable = new HashTable(size);
  17.  
  18. for(int j=0; j<n; j++)
  19. {
  20. aKey = (int)(java.lang.Math.random() * 2 * size);
  21. aDataItem = new DataItem(aKey);
  22. theHashTable.insert(aKey, aDataItem);
  23. }
  24.  
  25. while(true)
  26. {
  27. System.out.print("Enter first letter of ");
  28. System.out.print("show, insert, delete, or find: ");
  29. char choice = getChar();
  30. switch(choice)
  31. {
  32. case 's':
  33. theHashTable.displayTable();
  34. break;
  35. case 'i':
  36. System.out.print("Enter key value to insert: ");
  37. aKey = getInt();
  38. aDataItem = new DataItem(aKey);
  39. theHashTable.insert(aKey, aDataItem);
  40. break;
  41. case 'd':
  42. System.out.print("Enter key value to delete: ");
  43. aKey = getInt();
  44. theHashTable.delete(aKey);
  45. break;
  46. case 'f':
  47. System.out.print("Enter key value to find: ");
  48. aKey = getInt();
  49. aDataItem = theHashTable.find(aKey);
  50. if(aDataItem != null)
  51. System.out.println("Found " + aKey);
  52. else
  53. System.out.println("Could not find " + aKey);
  54. break;
  55. default:
  56. System.out.print("Invalid entry\n");
  57. } // end switch
  58. } // end while
  59. } // end main()
  60. //--------------------------------------------------------------
  61. public static String getString() throws IOException
  62. {
  63. InputStreamReader isr = new InputStreamReader(System.in);
  64. BufferedReader br = new BufferedReader(isr);
  65. String s = br.readLine();
  66. return s;
  67. }
  68. //--------------------------------------------------------------
  69. public static char getChar() throws IOException
  70. {
  71. String s = getString();
  72. return s.charAt(0);
  73. }
  74. //-------------------------------------------------------------
  75. public static int getInt() throws IOException
  76. {
  77. String s = getString();
  78. return Integer.parseInt(s);
  79. }
  80. //--------------------------------------------------------------
  81. } // end class HashDoubleApp
  82. ////////////////////////////////////////////////////////////////

五、链地址法的java实现

因为链地址法采用链表作为表中的数据格式,所以允许存储相同的关键字数据。而且我们可以把链设为有序链表。

Link类定义了链表结构

  1. package hashChain;
  2.  
  3. class Link //定义链表
  4. { // 可以动态存储数据,扩充容量
  5. private int iData; // 关键字
  6. public Link next; // 链接到下一个
  7. //-------------------------------------------------------------
  8. public Link(int it) //构造器
  9. { iData= it; }
  10. //-------------------------------------------------------------
  11. public int getKey() //获取关键字
  12. { return iData; }
  13. //-------------------------------------------------------------
  14. public void displayLink() // 显示
  15. { System.out.print(iData + " "); }
  16. } // end class Link
  17. ////////////////////////////////////////////////////////////////

SortedList定义了有序链表

  1. package hashChain;
  2.  
  3. class SortedList //有序链表
  4. {
  5. private Link first; // 链表头
  6. //-------------------------------------------------------------
  7. public void SortedList() // 构造器
  8. { first = null; }
  9. //-------------------------------------------------------------
  10. public void insert(Link theLink) // 插入并有序
  11. {
  12. int key = theLink.getKey();
  13. Link previous = null; // 前一个数据项
  14. Link current = first;
  15.  
  16. while( current != null && key > current.getKey() )//非空且关键字大于当前数据关键字
  17. {
  18. previous = current; //继续查找下一个
  19. current = current.next;
  20. }
  21. if(previous==null) // 如果表为空
  22. first = theLink; // 表头指向该数据项
  23. else // 表非空
  24. previous.next = theLink; // key<current.getKey()时,数据项应插入previous后,previous-->theLink
  25. theLink.next = current; // theLink --> current
  26. } // end insert()
  27. //-------------------------------------------------------------
  28. public void delete(int key) //删除
  29. {
  30. Link previous = null;
  31. Link current = first;
  32.  
  33. while( current != null && key != current.getKey() )//未找到
  34. {
  35. previous = current;
  36. current = current.next; // 查找下一个
  37. }
  38.  
  39. if(previous==null) // 要删除数据项为表头
  40. first = first.next; // 删除表头
  41. else // 不是表头
  42. previous.next = current.next; // 删除current
  43. } // end delete()
  44. //-------------------------------------------------------------
  45. public Link find(int key) // 查找
  46. {
  47. Link current = first;
  48.  
  49. while(current != null && current.getKey() <= key)
  50. {
  51. if(current.getKey() == key) // 找到
  52. return current; // 返回
  53. current = current.next; //未找到继续查找下一个
  54. }
  55. return null; //未找到
  56. } // end find()
  57. //-------------------------------------------------------------
  58. public void displayList()//显示
  59. {
  60. System.out.print("List (first-->last): ");
  61. Link current = first;
  62. while(current != null)
  63. {
  64. current.displayLink();
  65. current = current.next;
  66. }
  67. System.out.println("");
  68. }
  69. } // end class SortedList
  70. ////////////////////////////////////////////////////////////////

HashTable定义哈希表,表中数据为SortedList形式

  1. package hashChain;
  2.  
  3. class HashTable
  4. {
  5. private SortedList[] hashArray;
  6. private int arraySize;
  7. //-------------------------------------------------------------
  8. public HashTable(int size) //构造器
  9. {
  10. arraySize = size;
  11. hashArray = new SortedList[arraySize]; // 初始化数组,数组中存储的是链表
  12. for(int j=0; j<arraySize; j++) // 初始化每个数组元素
  13. hashArray[j] = new SortedList();
  14. }
  15. //-------------------------------------------------------------
  16. public void displayTable()
  17. {
  18. for(int j=0; j<arraySize; j++)
  19. {
  20. System.out.print(j + ". ");
  21. hashArray[j].displayList();
  22. }
  23. }
  24. //-------------------------------------------------------------
  25. public int hashFunc(int key) // 计算哈希值
  26. {
  27. return key % arraySize;
  28. }
  29. //-------------------------------------------------------------
  30. public void insert(Link theLink) // 插入数据
  31. {
  32. int key = theLink.getKey(); //获取关键字
  33. int hashVal = hashFunc(key); // 计算关键字哈希值
  34. hashArray[hashVal].insert(theLink); // 插入哈希表中对应的位置
  35. } // end insert()
  36. //-------------------------------------------------------------
  37. public void delete(int key) // 根据关键字删除数据
  38. {
  39. int hashVal = hashFunc(key); // 计算关键字哈希值
  40. hashArray[hashVal].delete(key); // 删除哈希表中对应数据
  41. } // end delete()
  42. //-------------------------------------------------------------
  43. public Link find(int key) // 查找
  44. {
  45. int hashVal = hashFunc(key);
  46. Link theLink = hashArray[hashVal].find(key);
  47. return theLink;
  48. }
  49. //-------------------------------------------------------------
  50. } // end class HashTable
  51. ////////////////////////////////////////////////////////////////

主函数

  1. package hashChain;
  2. import java.io.*;
  3.  
  4. class HashChainApp
  5. {
  6. public static void main(String[] args) throws IOException
  7. {
  8. int aKey;
  9. Link aDataItem;
  10. int size, n, keysPerCell = 100;
  11. System.out.print("Enter size of hash table: ");
  12. size = getInt();
  13. System.out.print("Enter initial number of items: ");
  14. n = getInt();
  15. HashTable theHashTable = new HashTable(size);
  16.  
  17. for(int j=0; j<n; j++)
  18. {
  19. aKey = (int)(java.lang.Math.random() *
  20. keysPerCell * size);
  21. aDataItem = new Link(aKey);
  22. theHashTable.insert(aDataItem);
  23. }
  24. while(true)
  25. {
  26. System.out.print("Enter first letter of ");
  27. System.out.print("show, insert, delete, or find: ");
  28. char choice = getChar();
  29. switch(choice)
  30. {
  31. case 's':
  32. theHashTable.displayTable();
  33. break;
  34. case 'i':
  35. System.out.print("Enter key value to insert: ");
  36. aKey = getInt();
  37. aDataItem = new Link(aKey);
  38. theHashTable.insert(aDataItem);
  39. break;
  40. case 'd':
  41. System.out.print("Enter key value to delete: ");
  42. aKey = getInt();
  43. theHashTable.delete(aKey);
  44. break;
  45. case 'f':
  46. System.out.print("Enter key value to find: ");
  47. aKey = getInt();
  48. aDataItem = theHashTable.find(aKey);
  49. if(aDataItem != null)
  50. System.out.println("Found " + aKey);
  51. else
  52. System.out.println("Could not find " + aKey);
  53. break;
  54. default:
  55. System.out.print("Invalid entry\n");
  56. } // end switch
  57. } // end while
  58. } // end main()
  59. //--------------------------------------------------------------
  60. public static String getString() throws IOException
  61. {
  62. InputStreamReader isr = new InputStreamReader(System.in);
  63. BufferedReader br = new BufferedReader(isr);
  64. String s = br.readLine();
  65. return s;
  66. }
  67. //-------------------------------------------------------------
  68. public static char getChar() throws IOException
  69. {
  70. String s = getString();
  71. return s.charAt(0);
  72. }
  73. //-------------------------------------------------------------
  74. public static int getInt() throws IOException
  75. {
  76. String s = getString();
  77. return Integer.parseInt(s);
  78. }
  79. //--------------------------------------------------------------
  80. } // end class HashChainApp
  81. ////////////////////////////////////////////////////////////////

六、如何设计哈希函数

1、不使用无用数据项

关键字的选取时,要提出原始数据中的无用数据项,例如起始位、校验位、结束位等,因为这些数据位没有携带信息。

2、使用所有的有用数据位

所有的有用数据位在哈希函数中都应当有体现。不要使用前四位或者后五位等其他方法。

3、使用质数作为取模运算的基数。

若关键字完全随机分布,质数和非质数的表现差不多。但是当关键字不是随机分布时,就应该使用质数作为哈希表的大小。使用质数可以是关键字较为平均的映射到哈希表的各个位置。

七、开放地址法和链地址法的比较

开放地址法在表快满时,性能有明显下降,且对哈希表进行扩展时操作复杂。链地址法需要设计链表类,但是不会随着数据项的增多导致性能快速下降,而且可以动态扩展哈希表。

参考文献:

java数据结构与算法(第二版)

哈希表的java实现的更多相关文章

  1. 哈希表,Java中的hashCode

    哈希表: 将我们所需的键通过哈希函数转换索引,然后存储在一个数组中. 哈希表是时间和空间之间的平衡,体现空间换时间的算法思想(联想到预加载,缓存等,有时候多存储,预处理缓存一些东西,带来时间复杂度的改 ...

  2. 数据结构中的哈希表(java实现)利用哈希表实现学生信息的存储

    哈希表 解释 哈希表是一种根据关键码去寻找值的数据映射结构,该结构通过把关键码映射的位置去寻找存放值的地方 内存结构分析图 1.定义一个类为结点,存储的信息 2.定义链表的相关操作 3.定义一个数组存 ...

  3. 【算法】哈希表的诞生(Java)

    参考资料 <算法(java)>                           — — Robert Sedgewick, Kevin Wayne <数据结构>       ...

  4. Java数据结构和算法 - 哈希表

    Q: 如何快速地存取员工的信息? A: 假设现在要写一个程序,存取一个公司的员工记录,这个小公司大约有1000个员工,每个员工记录需要1024个字节的存储空间,因此整个数据库的大小约为1MB.一般的计 ...

  5. 自己动手实现java数据结构(五)哈希表

    1.哈希表介绍 前面我们已经介绍了许多类型的数据结构.在想要查询容器内特定元素时,有序向量使得我们能使用二分查找法进行精确的查询((O(logN)对数复杂度,很高效). 可人类总是不知满足,依然在寻求 ...

  6. Java知多少(79)哈希表及其应用

    哈希表也称为散列表,是用来存储群体对象的集合类结构. 什么是哈希表 数组和向量都可以存储对象,但对象的存储位置是随机的,也就是说对象本身与其存储位置之间没有必然的联系.当要查找一个对象时,只能以某种顺 ...

  7. 哈希表hashTable的Java设计

    1:哈希表的概念 2:设计原理 3:哈希表的Java设计

  8. Java哈希表入门

    Java哈希表(Hash Table) 最近做题经常用到哈希表来进行快速查询,遂记录Java是如何实现哈希表的.这里只简单讲一下利用Map和HashMap实现哈希表. 首先,什么是Map和HashMa ...

  9. 查找-------(HashCode)哈希表的原理

    这段时间 在 准备软件设计师考试    目的是想复习一下  自己以前没怎么学的知识    在这个过程中  有了很大的收获  对以前不太懂得东西  在复习的过程中  有了很大程度的提高 比如在复习 程序 ...

随机推荐

  1. jquery 同源跨域请求整理

    //同源ajax请求数据 function getData(url,paramjson,fn) { $.ajax({ type : "POST", //提交方式 url : url ...

  2. windows下webrtc的编译 2016(转)

    ====================20160124更新============================= 推荐一个FQ工具,shadowsocks,是需要付费的,一年也才不到100块,移 ...

  3. hdu3338 / 方格横纵和问题终极版,最大流斩

    此题被誉为神奇最大流,诱惑我去做了下,感觉也是通常的思路. 题意:1.用1-9去填,满足所给的行/列和要求(和那个什么游戏差不多...) 求一种合法方案,输出.如:   一看,直接就建图了,每个点在白 ...

  4. Spring Cloud系列文,Feign整合Ribbon和Hysrix

    在本博客之前的Spring Cloud系列里,我们讲述了Feign的基本用法,这里我们将讲述下Feign整合Ribbon实现负载均衡以及整合Hystrix实现断路保护效果的方式. 1 准备Eureka ...

  5. 洛谷——P2176 [USACO14FEB]路障Roadblock

    P2176 [USACO14FEB]路障Roadblock 题目描述 每天早晨,FJ从家中穿过农场走到牛棚.农场由 N 块农田组成,农田通过 M 条双向道路连接,每条路有一定长度.FJ 的房子在 1 ...

  6. luogu P2158 [SDOI2008]仪仗队

    题目描述 作为体育委员,C君负责这次运动会仪仗队的训练.仪仗队是由学生组成的N * N的方阵,为了保证队伍在行进中整齐划一,C君会跟在仪仗队的左后方,根据其视线所及的学生人数来判断队伍是否整齐(如下图 ...

  7. JDBC_完整版

    1,新建WEB项目:JDBC 2,导入驱动 将mysql-connector-java-5.0.8-bin.jar包放入web-inf目录下面的lib目录中 3,新建User类,放入entity包中 ...

  8. java IOUtils下载图片

    import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.Inp ...

  9. GOPATH设置

    go help gopath查看gopath的原文帮助信息 go env查看gopath的配置 GOPATH与工作空间 前面我们在安装Go的时候看到需要设置GOPATH变量,Go从1.1版本到1.7必 ...

  10. cygwin搭建ssh服务器

    下载cygwin的setup.exe安装包