基于拉链法实现散列表

package chapter4;

import edu.princeton.cs.algs4.Queue;
import edu.princeton.cs.algs4.SeparateChainingHashST;
import edu.princeton.cs.algs4.StdIn;
import edu.princeton.cs.algs4.StdOut;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class ChainingHashTable<Key extends Comparable<Key>,Value> {

    private int length;
    private int N;
    private ChainingTable<Key, Value>[] chainingTables;

    ChainingHashTable(){
        this(997);
    }

    public ChainingHashTable(int m){
        this.length = m;
        chainingTables = new ChainingTable[m];
        for(int i = 0 ; i < m; i++){
            chainingTables[i] = new ChainingTable<>();
        }
    }


    private void resize(int newLength){
        ChainingHashTable<Key,Value> temp = new ChainingHashTable(newLength);
        for(int i = 0; i < this.length; i++){
            for(Key key : this.chainingTables[i].keys()){
                temp.put(key, this.chainingTables[i].get(key));
            }
        }
        this.chainingTables = temp.chainingTables;
        this.N = temp.N;
        this.length = newLength;
    }


    public Value get(Key key){
        if(key == null){
            throw new IllegalArgumentException("key is null");
        }
        return this.chainingTables[hashCode(key)].get(key);
    }

    public void put(Key key, Value val){
        if(key == null){
            throw new IllegalArgumentException("key is null");
        }
        if(this.N > 10*this.length){
            resize(2*this.length);
        }

        if(!this.chainingTables[hashCode(key)].contains(key)){
            this.N++;
        }
        this.chainingTables[hashCode(key)].put(key,val);
    }

    // return keys in symbol table as an Iterable
    public Iterable<Key> keys() {
        Queue<Key> queue = new Queue<Key>();
        for (int i = 0; i < this.length; i++) {
            for (Key key : this.chainingTables[i].keys())
                queue.enqueue(key);
        }
        return queue;
    }

    private int hashCode(Key key){
        // s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
        //去掉高位,再平均分布到数组当中
        //length最好为素数,防止出现整除,影响分布均匀性
        return (key.hashCode() & 0x7fffffff) % this.length;
    }

    public void delete(Key key){
        if(this.chainingTables[hashCode(key)].contains(key)){
            this.N--;
        }
        this.chainingTables[hashCode(key)].delete(key);
        if(this.N < 2*this.length && this.length >= 4){
            resize(this.length/2);
        }
    }


    public static void main(String[] args) {
        SeparateChainingHashST<String, Integer> st = new SeparateChainingHashST<String, Integer>();
        for (int i = 0;  i < 10 ; i++) {

            String key = StdIn.readString();
            st.put(key, i);
        }

        // print keys
        for (String s : st.keys())
            StdOut.println(s + " " + st.get(s));

    }
}

class ChainingTable<Key extends Comparable<Key>,Value>{
    private int length;
    private Node head;

    ChainingTable(){
        this.head = null;
        this.length = 0;
    }
    
    private class Node{
        private Node next;
        private Key key;
        private Value value;

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

        public Value getValue() {
            return value;
        }
    }
    
    public Value get(Key key){
        Node temp = this.head;
        while(temp != null){
            if(temp.key.compareTo(key) == 0)
                return temp.getValue();
            temp = temp.next;
        }
        return null;
    }

    public void put(Key key, Value value){
        if(this.head == null){
            this.head = new Node(key,value);
        }else {
            Node temp = this.head;
            while(temp.next != null){
                temp = temp.next;
                if(temp.key.compareTo(key) == 0)
                    temp.value = value;
            }
            temp.next = new Node(key,value);
            this.length++;
        }

    }

    public void delete(Key key){
        if(this.head.key.compareTo(key) == 0){
            this.head = this.head.next;
            this.length--;
        }else{
            Node temp = this.head;
            Node preNode = null;
            while(temp != null){
                if(temp.key.compareTo(key) == 0 && preNode != null){
                    preNode.next = temp.next;
                    this.length--;
                }
                preNode = temp;
                temp = temp.next;
            }
        }
    }

    public boolean contains(Key key){
        Node temp = this.head;
        while(temp != null){
            if(temp.key.compareTo(key) == 0)
                return true;
            temp = temp.next;
        }
        return false;
    }

    public  List<Key> keys(){
        List<Key> keys = new ArrayList<>();
        Node temp = this.head;
        while(temp != null){
            keys.add(temp.key);
            temp = temp.next;
        }
        return keys;
    }


}

拉链法时数组加链表实现的散列表,主要时hashcode来保证数据的分布,java给不同类型的变量都实现了hashcode。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
链地址是一种散列表的解决方案。它的实现思路是,对于哈希冲突的键值,将它们存储在同一个链表中。下面是一个使用链地址实现散列表查找的示例: 首先,定义一个链表节点结构体,包含键值对和指向下一个节点的指针: ``` struct ListNode { int key; int value; ListNode* next; }; ``` 然后,定义散列表结构体,包含一个指向链表头节点的指针数组: ``` const int TABLE_SIZE = 100; struct HashTable { ListNode* table[TABLE_SIZE]; }; ``` 在初始化散列表时,需要将每个链表的头节点初始化为空: ``` void init(HashTable& ht) { for (int i = 0; i < TABLE_SIZE; i++) { ht.table[i] = nullptr; } } ``` 插入操作时,按照键值的哈希值将节点插入到相应的链表中: ``` void insert(HashTable& ht, int key, int value) { int index = hash(key); ListNode* node = new ListNode{key, value, nullptr}; if (ht.table[index] == nullptr) { ht.table[index] = node; } else { ListNode* p = ht.table[index]; while (p->next != nullptr) { p = p->next; } p->next = node; } } ``` 查找操作时,先计算键值的哈希值,然后在相应的链表中查找节点: ``` bool find(HashTable& ht, int key, int& value) { int index = hash(key); ListNode* p = ht.table[index]; while (p != nullptr) { if (p->key == key) { value = p->value; return true; } p = p->next; } return false; } ``` 需要注意的是,哈希函数的设计对散列表的性能影响非常大。一个好的哈希函数应该将键值均匀地分布在散列表中,尽量减少哈希冲突的发生。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值