基于单链表和分离链接法实现hashTable

52 阅读1分钟

基础hashTable实现

const defaultToString = function defaultToString(key) {
  if (typeof key === null) {
    return "NULL";
  }
  if (typeof key === undefined) {
    return "UNDEFINED";
  }
  if (key instanceof String) {
    return `${key}`;
  }
  return key.toString();
};

class ValuePair {
  constructor(key, value) {
    this.key = key;
    this.value = value;
  }
}

class HashTable {
  constructor(toStrFn = defaultToString) {
    this.toStrFn = toStrFn;
    this.table = {};
  }
  loseLoseHashCode(key) {
    if (typeof key === "number") {
      return key;
    }
    let hash = 0;
    let tableKey = this.toStrFn(key);
    for (let i = 0; i < tableKey.length; i++) {
      hash += tableKey.charCodeAt(i);
    }
    return hash % 37;
  }
  hashCode(key) {
    return this.loseLoseHashCode(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) {
    let valuePair = this.table[this.hashCode(key)];
    return valuePair === null ? "undefined" : valuePair.value;
  }
  remove(key) {
    let hashCode = this.hashCode(key);
    let valuePair = this.table[hashCode];
    if (valuePair) {
      delete this.table[hashCode];
      return true;
    }
    return false;
  }
}

单链表实现

/**
 * 单链表
 */

function defaultEquals(a, b) {
  return a === b;
}

const COMPARE = {
  LESS_THEN: -1,
  BIGGER_THEN: 1
};

function defaultCompar(a, b) {
  if (a === b) return 0;
  return a < b ? COMPARE.LESS_THEN : COMPARE.BIGGER_THEN;
}

class SingleLikedListNode {
  constructor(data) {
    this.node = data ?? null;
    this.next = null;
  }
}

class SingleLikedList {
  constructor(equals = defaultEquals) {
    this.head = null;
    this.length = 0;
    this.equals = equals;
  }
  append(data) {
    const newNode = new SingleLikedListNode(data);
    if (!this.head) {
      this.head = newNode;
    } else {
      let current = this.head;
      while (current.next) {
        current = current.next;
      }
      current.next = newNode;
    }
    this.length++;
    return this;
  }

  isEmpty() {
    return this.length === 0 && this.head == null;
  }

  // 返回链表的长度
  size() {
    return this.length;
  }

  // 查找具体位置的元素
  getNodeAt(index) {
    if (index < 0 || index >= this.length) return null;
    let node = this.head;
    for (let i = 0; i < index; i++) {
      node = node.next;
    }
    return node;
  }

  // 删除链表中指定位置的元素
  removeAt(index) {
    if (index < 0 || index >= this.length) return null;
    let current = this.head;
    let previous = null;
    if (index === 0) {
      this.head = current.next;
    } else {
      previous = this.getNodeAt(index - 1);
      current = previous.next;
      previous.next = current.next;
    }
    this.length--;
    return current.node;
  }
  // 在链表指定的位置插入元素
  insertAt(node, index) {
    if (index < 0 || index > this.length) return false;
    let newNode = new SingleLikedListNode(node);
    let current = null;
    if (index === 0) {
      if (!this.head) {
        this.head = newNode;
      } else {
        current = this.head;
        newNode.next = current;
        this.head = newNode;
      }
    } else {
      let previous = this.getNodeAt(index - 1);
      current = previous.next;
      newNode.next = current;
      previous.next = newNode;
    }
    this.length++;
    return true;
  }
  // 返回每个元素的下标
  indexOf(node) {
    let current = this.head;
    for (let i = 0; i < this.length && current; i++) {
      if (this.equals(node, current.node)) return i;
      current = current.next;
    }
    return -1;
  }
  remove(node) {
    let index = this.indexOf(node);
    this.removeAt(index);
  }
  getHead() {
    return this.head;
  }
  toString() {
    if (!this.head) {
      return "";
    }
    let str = this.head.node + "";
    let current = this.head.next;
    for (let i = 1; i < this.length && current; i++) {
      str = `${str}, ${current.node}`;
      current = current.next;
    }
    return str;
  }
}

基于单链表和分离链接法实现hashTable

// 分离链接法
class HashTableSeparateChaining extends HashTable {
  constructor(toStrFn = defaultToString) {
    super(toStrFn);
  }
  put(key, value) {
    if (key !== null && value !== null) {
      const position = this.hashCode(key);
      if (this.table[position] == null) {
        this.table[position] = new SingleLikedList();
      }
      this.table[position].append(new ValuePair(key, value));
      return true;
    }
    return false;
  }
  get(key) {
    const position = this.hashCode(key);
    const singleLinkedList = this.table[position];
    if (singleLinkedList != null && !singleLinkedList.isEmpty()) {
      let current = singleLinkedList.getHead();
      while (current) {
        if (current.node.key === key) {
          return current.node.value;
        }
        current = current.next;
      }
    }
    return undefined;
  }
  remove(key) {
    const position = this.hashCode(key);
    const singleLinkedList = this.table[position];
    if (singleLinkedList != null && !singleLinkedList.isEmpty()) {
      let current = singleLinkedList.getHead();
      while (current) {
        if (current.node.key === key) {
          singleLinkedList.remove(current.node);
          if (singleLinkedList.isEmpty()) {
            delete this.table[position];
          }
          return true;
        }
        current = current.next;
      }
    }
    return false;
  }
}