字典的增删改查以及字典的实际应用:hash表
字典的增删改查
function defaultToString(item) {
if (item === null) {
return "NULL";
} else if (item === undefined) {
return "UNDEFINED";
} else if (typeof item === "string" || item instanceof String) {
return `${item}`;//是字符串就直接返回
}
return item.toString();//否则调用toSring
}
//字典:table[key]={key,value}键值对
class valuePair {
constructor(key, value) {
this.value = value;
this.key = key;
}
toString() {
return `[${this.key}:${this.value}]`;
}
}
class Dictionary {
constructor(toStrFn = defaultToString) {
this.toStrFn = toStrFn;
this.table = {};
}
hasKey(key) {
//JavaScript只允许我们使用字符串作为对象的键名或属性名。
//如果传入一个复杂对象作为键,需要将它转化为一个字符串
return this.table[this.toStrFn(key)] != null;
}
set(key, value) {
if (key != null && value != null) {
const tableKey = this.toStrFn(key);
//每个元素都是一个键值对
this.table[tableKey] = new valuePair(key, value);
return true;
}
return false;
}
remove(key) {
if (this.hasKey(key)) {
delete this.table[this.toStrFn(key)];
return true;
}
return false;
}
get(key) {
const valuePair = this.table[this.toStrFn(key)];
return valuePair == null ? undefined : valuePair.value;
}
keyValues() {
//以数组形式返回字典所有valuePair:[{value:'abcd',key:'oyx'},{}]
return Object.values(this.table);
}
keys() {
//返回所有键名keys
return this.keyValues().map((valuePair) => valuePair.key);
}
forEach(callbackFn) {
//这个逻辑需要注意
const valuePairs = this.keyValues(); // {1}
for (let i = 0; i < valuePairs.length; i++) {
// {2}
const result = callbackFn(valuePairs[i].key, valuePairs[i].value); // {3}
if (result === false) {
break; // {4}
}
}
}
size() {
return Object.keys(this.table).length;
}
isEmpty() {
return this.size() === 0;
}
clear() {
this.table = {};
}
toString() {
if (this.isEmpty()) {
return "";
}
const valuePairs = this.keyValues();
let objString = `${valuePairs[0].toString()}`;
for (let i = 1; i < valuePairs.length; i++) {
objString = `${objString},${valuePairs[i].toString()}`;
}
return objString;
}
}
字典的应用:hash表
区别在于增加了hashcode函数,先把key转成code值再放进去
hash表的实现
function defaultToString(item) {
if (item === null) {
return "NULL";
} else if (item === undefined) {
return "UNDEFINED";
} else if (typeof item === "string" || item instanceof String) {
return `${item}`;
}
return item.toString();
}
class valuePair {
constructor(key, value) {
this.value = value;
this.key = key;
}
toString() {
return `[${this.key}:${this.value}]`;
}
}
class HashTable {
constructor(toStrFn = defaultToString) {
this.toStrFn = toStrFn;
this.table = {};
}
djb2HashCode(key) {
const tableKey = this.toStrFn(key);
let hash = 5381;
for (let i = 0; i < tableKey.length; i++) {
hash = hash * 33 + tableKey.charCodeAt(i);
}
return hash % 1013;
}
hashCode(key) {
return this.djb2HashCode(key);
}
put(key, value) {
if (key != null && value != null) {
const position = this.hashCode(key);
this.table[position] = new valuePair(key, value);
return true;
}
return false;
}
get(key) {
const valuePair = this.table[this.hashCode(key)];
return valuePair == null ? undefined : valuePair.value;
}
remove(key) {
const hash = this.hashCode(key);
const valuePair = this.table[hash];
if (valuePair != null) {
delete this.table[hash];
return true;
}
return false;
}
}
处理hash冲突:分离链表法
处理hash冲突:生成的code一致的问题
分离链接法:为散列表的每个位置生成一个链表
//处理hash冲突:生成的code一致的问题
//分离链接法:为散列表的每个位置生成一个链表
class HashTableSeparateChaining {
constructor(toStrFn = defaultToString) {
this.toStrFn = toStrFn;
this.table = {};
}
put(key, value) {
if (key != null && value != null) {
const position = this.hashCode(key);
if (this.table[position] == null) {
this.table[position] = new LinkedList();
}
this.table[position].push(new ValuePair(key, value)); //不同点
return true;
}
return false;
}
get(key) {
//把key转成code,找到位置后遍历list找到对应值
const position = this.hashCode(key);
const linkedList = this.table[position];
if (linkedList != null && ! linkedList.isEmpty()) {
let current = linkedList.getHead();
while (current != null) {
if (current.element.key === key) {
return current.element.value;
}
current = current.next;
}
}
return undefined;
}
remove(key) {
//把key转成code,找到位置后遍历list找到对应值并删除,
//删除后判断链表是否为空,为空就删除该位置
const position = this.hashCode(key);
const linkedList = this.table[position];
if (linkedList != null && ! linkedList.isEmpty()) {
let current = linkedList.getHead();
while (current != null) {
if (current.element.key === key) {
linkedList.remove(current.element);
if (linkedList.isEmpty()) {
delete this.table[position]; //链表为空就删除该位置
}
return true;
}
current = current.next;
}
}
return false;
}
}