哈希集合和哈希表——分离链表法

哈希表的核心:

1、使用散列函数将键转化为数组索引
2、碰撞处理,即处理两个键的散列值相同时的情况

分离链接法

基本原理和步骤:

1、初始化一个链表数组(即哈希表)
2、将键转化为数组索引:

将键key转化为哈希码(hashCode()),然后调用哈希函数(hash())转化为数组的索引

3、碰撞处理:

每个数组的元素是一个链表,得到索引后进入链表,可以用equals()比较链表中的key与传入的key是否存在,进而处理冲突

image
4、完成哈希表的remove(),contains(),isEmpty(),get(),put()等操作。

代码实现

由于需要key、value两个值和一个指向下一节点的next,所以需要自定义链表

点击查看自定义链表代码
public class SequentialSearchST<Key, Value> {
    private Node first;

    private class Node {//链表节点
        Key key;
        Value value;
        Node next;

        public Node(Key key, Value value, Node next) {
            this.key = key;
            this.value = value;
            this.next = next;
        }
    }

    public Value get(Key key) {
        for (Node node = first; node != null; node = node.next) {
            if (node.key.equals(key)) {
                return node.value;
            }
        }
        return null;
    }

    public void put(Key key, Value value) {
            /*if (get(key) != null) {//当key存在时
                Node node = first;
                while (node != null) {
                    if (node.key.equals(key)) {
                        node.value = value;
                        break;
                    }
                    node = node.next;
                }
            } else {//当key不存在时
                Node node = first;
                while (node.next != null) {
                    node = node.next;
                }
                node.next = new Node(key, value, null);
            }*/
        for (Node node = first; node != null; node = node.next) {
            if (node.key.equals(key)) {//命中
                node.value = value;
                return;
            }
        }
        first = new Node(key, value, first);//未命中
    }
    public void remove(Key key){//这里的删除并不是删除节点,而是将键对应的值改为null
        for (Node node=first; node!=null ; node=node.next) {
            if(node.key.equals(key)) {
                node.value=null;
                return;
            }
        }
    }
}

1、初始化哈希表(一般初始化数组的长度为素数,这样能使键值对分布更平均,减少查询时间,提高效率)

  private int M;//键值对总数
    private int N;//散列表大小
    private SequentialSearchST<Key, Value>[] st;

    public SeparateChainingHashTable() {
        this(97);
    }

    public SeparateChainingHashTable(int M) {//创建M条链表
        this.M = M;
        st = (SequentialSearchST<Key, Value>[]) new SequentialSearchST[M];
        for (int i = 0; i < M; i++) {
            st[i] = new SequentialSearchST<>();
        }
    }

2、将键转化为数组索引(hashCode()使用key类型自己的,一般Java已经帮你写好了,比如String已经默认实现了hashCode())

public int hash(Key key) {
		//通过%M可以不发生数组索引越界
        return key.hashCode() % M;
    }

3、处理碰撞以及各种方法的实现

3.1、get() 方法实现

点击查看get()代码
public Value get(Key key) {
        return (Value) st[hash(key)].get(key);
    }

public Value get(Key key) {
        for (Node node = first; node != null; node = node.next) {
            if (node.key.equals(key)) {
                return node.value;
            }
        }
        return null;
    }

3.2、remove() 方法实现

remove() 方法的实现有两种方式

  1. 第一种是删去整个节点
  2. 第二种是将key键对应的值赋为null,达到删除节点的效果。
点击查看remove()代码
public void remove(Key key){
        st[hash(key)].remove(key);
        N--;
    }
    
public void remove(Key key){//这里的删除并不是删除节点,而是将键对应的值改为null
        for (Node node=first; node!=null ; node=node.next) {
            if(node.key.equals(key)) {
                node.value=null;
                return;
            }
        }
    }

3.3、put() 方法实现

点击查看代码
public void put(Key key, Value value) {
        st[hash(key)].put(key, value);
        N++;
    }
     public void put(Key key, Value value) {
     for (Node node = first; node != null; node = node.next) {
            if (node.key.equals(key)) {//命中
                node.value = value;
                return;
            }
        }
        first = new Node(key, value, first);//未命中
		//下面这段是第一次写出来的,可以忽略不看
            /*if (get(key) != null) {//当key存在时
                Node node = first;
                while (node != null) {
                    if (node.key.equals(key)) {
                        node.value = value;
                        break;
                    }
                    node = node.next;
                }
            } else {//当key不存在时
                Node node = first;
                while (node.next != null) {
                    node = node.next;
                }
                node.next = new Node(key, value, null);
            }*/
    }

3.4、isEmpty() 方法实现

点击查看isEmpty()代码
public boolean isEmpty() {
        return N == 0;
    }
posted @ 2021-11-05 17:09  Jyang~  阅读(440)  评论(0)    收藏  举报