得到质数
为啥?因为想让各个映射的数据分布更均匀,不扎堆!重复的也不会在一个index上重复一堆!
判断扩容的数据是否为质数,如果不是,那就强试:
getPrime(num) {while (!this.isPrime(num)) {num += 1;}return num;}
然后逻辑放到扩容的那个步骤里,对this.limit赋值那里进行保底!
完整封装-链式地址法——用的链表
const {DoublyLinkedList, DoublyList} = require("./linked-list");class Hash {constructor(str, size) {if (typeof str !== "string" || typeof size !== "number" ||str.trim().length === 0 || size <= 0 || size % 1 > 0) {throw new Error("Hash class的初始化参数不合规范!");}this.str = str;this.size = size;this.getHashCode();}//计算hashCode,扩大映射的那个值getHashCode() {const {str, size} = this;//需要字典:默认unicode//需要性能,秦九韶算法:提取公因式,循环累乘:let hashCode = 0;for (let i = 0; i < str.length; i++) {//幂运算的底数,最好是质数:套路论:37用的多。hashCode = hashCode * 37 + str.charCodeAt(i);}this.hashCode = hashCode % size;}}const hash1 = new Hash("abc", 7);const hash2 = new Hash("bcde", 7);const hash3 = new Hash("cab", 7);console.log(hash1, hash2, hash3);class HashTable {constructor(size) {this.table = [];this.count = 0; //存了多少个。// 跟size对比,装载因子 >0.75,性能->扩容。// 或<0.25时,内存大,count小,就减小数组的长度。自优化!this.limit = size; //table长度}//存储的数据是{kye,...data},key是唯一标识字段,可以得出index的根据,// data,是要存入的数据put(obj) {if (!obj || typeof obj !== "object" || !obj.key) {throw new Error("要存入的数据,必须要是个带有key字段属性的object!");}const i = new Hash(obj.key, this.limit).hashCode;const current = this.table[i];if (current) {//这里很纠结的,首先,我解耦了要存的数据是个对象这种复杂类型,并且我没用数组//链表存储时候,链表的查询方法indexOf那里,对比的是DoubleList里的data//所以这里的对比就很真实对比了,要么对比简单数据的值,要么对比复杂对象的内存地址//如果数据本身拷贝过,那就完了!而且data的值就是obj这个参数的值!//这里就会限定死了如何匹配查找时,要传入的匹配参照就必须是原本的obj,而不是key//当然,我确实需要扩展一下 DoubleLinkedList的indexOf方法,更健壮。//当初封装的时候,我一直都有这方面的疑惑的,为啥不是凭借关键字段来匹配?//后来觉得,没必要的,尽可能地简单字段。同时就算是复杂的数据的内存地址,那就全等于喽!if (current.key === obj.key) {this.table[i] = obj;} else if (current.key) {const doublyLinkedList = new DoublyLinkedList(new DoublyList(current));doublyLinkedList.append(obj);this.table[i] = doublyLinkedList;this.count += 1;this.largerResize(); //扩容} else {const index = current.indexOf(obj.key, "key");if (index < 0) {current.append(obj);this.count += 1;this.largerResize(); //扩容} else {current.update(index, obj);}}} else {this.table[i] = obj;this.count += 1;this.largerResize(); //扩容}}get(key) {const index = new Hash(key, this.limit).hashCode;const current = this.table[index];if (current === undefined || current === null) return null;if (current.key) return current;const ind = current.indexOf(key, "key");if (ind < 0) return null;return current.get(ind).data;}remove(key) {const index = new Hash(key, this.limit).hashCode;const current = this.table[index];if (current === undefined || current === null) return null;if (current.key) {this.table[index] = null;this.smallerResize(); //缩容return current;}const ind = current.indexOf(key, "key");if (ind < 0) return null;this.count -= 1;const val = current.removeAt(ind);if (current.length === 0) {this.table[index] = null;}this.smallerResize(); //缩容return val;}largerResize() {const test = this.count / this.limit;if (test > 0.75) {this.resize(this.limit * 2);}}smallerResize() {const test = this.count / this.limit;if (test < 0.2 && this.limit > 20) {this.resize(Math.floor(this.limit / 2));}}resize(size) {this.limit = this.getPrime(size); //这里进行质数担保const storage = this.table;this.table = [];this.count = 0;storage.map(val => {if (val) {if (val.key) {this.put(val);this.count++;} else if (!val.key) {let current = val.header;while (current) {this.put(current.data);this.count++;}}}});}isPrime(num) {let res = true, i = 2;while (res && i <= Math.sqrt(num)) {num % i === 0 && (res = false);}return res;}getPrime(num) { //质数担保while (!this.isPrime(num)) {num += 1;}return num;}isEmpty() {return this.count === 0;}get size() {return this.count;}}
