得到质数

为啥?因为想让各个映射的数据分布更均匀,不扎堆!重复的也不会在一个index上重复一堆!

判断扩容的数据是否为质数,如果不是,那就强试:

  1. getPrime(num) {
  2. while (!this.isPrime(num)) {
  3. num += 1;
  4. }
  5. return num;
  6. }

然后逻辑放到扩容的那个步骤里,对this.limit赋值那里进行保底!

完整封装-链式地址法——用的链表

  1. const {DoublyLinkedList, DoublyList} = require("./linked-list");
  2. class Hash {
  3. constructor(str, size) {
  4. if (
  5. typeof str !== "string" || typeof size !== "number" ||
  6. str.trim().length === 0 || size <= 0 || size % 1 > 0
  7. ) {
  8. throw new Error("Hash class的初始化参数不合规范!");
  9. }
  10. this.str = str;
  11. this.size = size;
  12. this.getHashCode();
  13. }
  14. //计算hashCode,扩大映射的那个值
  15. getHashCode() {
  16. const {str, size} = this;
  17. //需要字典:默认unicode
  18. //需要性能,秦九韶算法:提取公因式,循环累乘:
  19. let hashCode = 0;
  20. for (let i = 0; i < str.length; i++) {
  21. //幂运算的底数,最好是质数:套路论:37用的多。
  22. hashCode = hashCode * 37 + str.charCodeAt(i);
  23. }
  24. this.hashCode = hashCode % size;
  25. }
  26. }
  27. const hash1 = new Hash("abc", 7);
  28. const hash2 = new Hash("bcde", 7);
  29. const hash3 = new Hash("cab", 7);
  30. console.log(hash1, hash2, hash3);
  31. class HashTable {
  32. constructor(size) {
  33. this.table = [];
  34. this.count = 0; //存了多少个。
  35. // 跟size对比,装载因子 >0.75,性能->扩容。
  36. // 或<0.25时,内存大,count小,就减小数组的长度。自优化!
  37. this.limit = size; //table长度
  38. }
  39. //存储的数据是{kye,...data},key是唯一标识字段,可以得出index的根据,
  40. // data,是要存入的数据
  41. put(obj) {
  42. if (!obj || typeof obj !== "object" || !obj.key) {
  43. throw new Error("要存入的数据,必须要是个带有key字段属性的object!");
  44. }
  45. const i = new Hash(obj.key, this.limit).hashCode;
  46. const current = this.table[i];
  47. if (current) {
  48. //这里很纠结的,首先,我解耦了要存的数据是个对象这种复杂类型,并且我没用数组
  49. //链表存储时候,链表的查询方法indexOf那里,对比的是DoubleList里的data
  50. //所以这里的对比就很真实对比了,要么对比简单数据的值,要么对比复杂对象的内存地址
  51. //如果数据本身拷贝过,那就完了!而且data的值就是obj这个参数的值!
  52. //这里就会限定死了如何匹配查找时,要传入的匹配参照就必须是原本的obj,而不是key
  53. //当然,我确实需要扩展一下 DoubleLinkedList的indexOf方法,更健壮。
  54. //当初封装的时候,我一直都有这方面的疑惑的,为啥不是凭借关键字段来匹配?
  55. //后来觉得,没必要的,尽可能地简单字段。同时就算是复杂的数据的内存地址,那就全等于喽!
  56. if (current.key === obj.key) {
  57. this.table[i] = obj;
  58. } else if (current.key) {
  59. const doublyLinkedList = new DoublyLinkedList(
  60. new DoublyList(current));
  61. doublyLinkedList.append(obj);
  62. this.table[i] = doublyLinkedList;
  63. this.count += 1;
  64. this.largerResize(); //扩容
  65. } else {
  66. const index = current.indexOf(obj.key, "key");
  67. if (index < 0) {
  68. current.append(obj);
  69. this.count += 1;
  70. this.largerResize(); //扩容
  71. } else {
  72. current.update(index, obj);
  73. }
  74. }
  75. } else {
  76. this.table[i] = obj;
  77. this.count += 1;
  78. this.largerResize(); //扩容
  79. }
  80. }
  81. get(key) {
  82. const index = new Hash(key, this.limit).hashCode;
  83. const current = this.table[index];
  84. if (current === undefined || current === null) return null;
  85. if (current.key) return current;
  86. const ind = current.indexOf(key, "key");
  87. if (ind < 0) return null;
  88. return current.get(ind).data;
  89. }
  90. remove(key) {
  91. const index = new Hash(key, this.limit).hashCode;
  92. const current = this.table[index];
  93. if (current === undefined || current === null) return null;
  94. if (current.key) {
  95. this.table[index] = null;
  96. this.smallerResize(); //缩容
  97. return current;
  98. }
  99. const ind = current.indexOf(key, "key");
  100. if (ind < 0) return null;
  101. this.count -= 1;
  102. const val = current.removeAt(ind);
  103. if (current.length === 0) {
  104. this.table[index] = null;
  105. }
  106. this.smallerResize(); //缩容
  107. return val;
  108. }
  109. largerResize() {
  110. const test = this.count / this.limit;
  111. if (test > 0.75) {
  112. this.resize(this.limit * 2);
  113. }
  114. }
  115. smallerResize() {
  116. const test = this.count / this.limit;
  117. if (test < 0.2 && this.limit > 20) {
  118. this.resize(Math.floor(this.limit / 2));
  119. }
  120. }
  121. resize(size) {
  122. this.limit = this.getPrime(size); //这里进行质数担保
  123. const storage = this.table;
  124. this.table = [];
  125. this.count = 0;
  126. storage.map(
  127. val => {
  128. if (val) {
  129. if (val.key) {
  130. this.put(val);
  131. this.count++;
  132. } else if (!val.key) {
  133. let current = val.header;
  134. while (current) {
  135. this.put(current.data);
  136. this.count++;
  137. }
  138. }
  139. }
  140. }
  141. );
  142. }
  143. isPrime(num) {
  144. let res = true, i = 2;
  145. while (res && i <= Math.sqrt(num)) {
  146. num % i === 0 && (res = false);
  147. }
  148. return res;
  149. }
  150. getPrime(num) { //质数担保
  151. while (!this.isPrime(num)) {
  152. num += 1;
  153. }
  154. return num;
  155. }
  156. isEmpty() {
  157. return this.count === 0;
  158. }
  159. get size() {
  160. return this.count;
  161. }
  162. }