哈希表的实现

哈希表可以表述为,是一种可以根据关键字快速查询数据的数据结构

目录

一. 哈希表有哪些优点?

二. 实现哈希表

1. 哈希表原理

2. 实现简单的哈希表

3. 哈希表的代码实现


一. 哈希表有哪些优点?

不论哈希表中数据有多少,增加,删除,改写数据的复杂度平均都是O(1),效率非常高

二. 实现哈希表

1. 哈希表原理

如果说每一个数据它都对应着一个固定的位置,那我们查找特定一个数据时,就可以直接查看这个数据对应的位置是否存在数据。一个形象的例子就是学生在教室中的位置,开学的时候,老师会给学生每一个人分配一个位置,而且不允许学生随便乱坐位置,以后老师要查看今天李刚同学有没有上课,直接看李刚同学的位置是不是有人就可以判断,没必要点了全班同学的名才可以知道李刚同学来了没有。

2. 实现简单的哈希表

根据上面的原理,首先,我们要分配一片空间用来存储我们数据,比如是一个空的数组

然后,有数据存进来的时候,按照特定规则得出这个数据在数组中的位置,将数据存进这个位置

我们就以存进一个整型数据为例,特定规则就是取余

根据计算出来的值,将这些数据放入对应的位置,我们的数组变为

我们已经把数据插入到了哈希表中,现在,我们要查找一个数据,只要按照取余规则计算出这个数据在数组中对应的位置,然后查看数组的这个位置,就可以取出这个数据了,比如我们要从哈希表中取出52,根据取余规则,52的计算出来的位置是8,数组中8这个位置是空的,52不在哈希表中,找不到52的数据;从哈希表中取出77,77计算出来的位置是0,数组中0这个位置有值,而且值就是77,从哈希表中取出77的值。

至此,我们知道实现了一个很简单的哈希表的原理,其实还存在很多问题,这个我们接下来讨论,这儿先把我们前面的一些概念用专业的术语替换一下,前面我们所说的特定规则,我们称之为哈希函数,用特定股则计算出来的值称之为哈希值。

3. 哈希表的代码实现

package datastructure.hash;

import java.util.Arrays;
import java.util.NoSuchElementException;

public class MyHashMap {
    private class Node{
        private  int key;
        private int value;
        Node next;

        public Node(int key, int value, Node next) {
            this.key = key;
            this.value = value;
            this.next = next;
        }
    }
    private int size;
    //默认的哈希表的长度
    private static final int DEFSAULT_CAPACITY=16;
    //默认负载因子
    private static final double LOAD_FACTOR=0.75;
    //取模用于取得索引
    private int M;
    //实际存储的数组
    private Node[]data;
    public MyHashMap(){
        this(DEFSAULT_CAPACITY);
    }
    public MyHashMap(int initCAp){
        this.data=new Node[initCAp];
        this.M=initCAp;
    }
    //哈希函数
    public int hash(int key){
        return Math.abs(key)%M;
    }
    //在当前哈希表添加一个键值对key=value
    public int add(int key,int value){
        //先对key取模,取得所在的索引
        int index=hash(key);
        //遍历链表找到所在的索引,查看当前的key是否存在
        for (Node i=data[index];i!=null;i=i.next){
            if (i.key==key){
                int oldVal=i.value;
                i.value=value;
                return oldVal;
            }
        }
        //此时链表中没有,新建头节点插入
        Node node=new Node(key,value,data[index]);
        data[index]=node;
        size++;
        //添加一个元素后,查看是否需要扩容
        if (data.length*DEFSAULT_CAPACITY<=size){
            resize();
        }
        return value;
    }

    private void resize() {
        //新数组长度变为原来的一倍
        Node []nweData=new Node[data.length<<1];
        //原节点的key对应新数组的索引
        //现在取得模数因改变为新数组的长度
        for (int i=0;i<=data.length;i++){
            if (data[i]!=null){
                for (Node x=data[i];x!=null;x=x.next){
                    Node next=x.next;
                    int newIndex=hash(x.key);
                    x.next=nweData[newIndex];
                    nweData [newIndex]=x;
                    x=next;
                }

            }else {
                continue;
            }
        }
        data=nweData;
    }
//删除哈希表中key对应的节点
   public int remove(int key){
        //判断头节点是不是待删除的节点
       int indx=hash(key);
       Node head=data[indx];
       if (head.key==key){
           int val=head.value;
           data[indx]=head.next;
           head.next=head=null;
           size--;
           return val;
       }
       //当前链表的头节点不是待删除的节点
     Node pre=head;
       while (pre.next!=null){
           if (pre.next.key==key){
               //pre是待删除节点的前驱
               int val=pre.next.value;
               pre.next=pre.next.next;
               pre.next.next=pre.next=null;
               size--;
               return val;
           }
       }
       throw new  NoSuchElementException("no such key!");

   }
   //查询Key是否在哈希表中
    public  boolean containsKey(int key){
        int idex=hash(key);
        for (Node x=data[idex];x!=null;x=x.next){
            if (x.key==key){
                return true;
            }
        }
       return false;
    }
    public boolean containsValue(int value){
        //遍历哈希表
        for (int i=0;i<size;i++){
            for (Node x=data[i];x!=null;x=x.next){
                if (x.value==value){
                    return true;
                }
            }
        }
        return false;
    }


}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
当然可以,下面是一个简单的哈实现的 C 代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #define TABLE_SIZE 10 typedef struct { char *key; int value; } Entry; typedef struct { Entry **entries; } HashTable; HashTable* createHashTable() { HashTable* hashTable = malloc(sizeof(HashTable)); hashTable->entries = calloc(TABLE_SIZE, sizeof(Entry*)); return hashTable; } int hashCode(char *key) { int hash = 0; for (int i = 0; i < strlen(key); i++) { hash += key[i]; } return hash % TABLE_SIZE; } void insert(HashTable* hashTable, char *key, int value) { int index = hashCode(key); Entry* entry = malloc(sizeof(Entry)); entry->key = strdup(key); entry->value = value; if (hashTable->entries[index] == NULL) { hashTable->entries[index] = entry; } else { // Handle collision: Linear probing int newIndex = (index + 1) % TABLE_SIZE; while (hashTable->entries[newIndex] != NULL) { newIndex = (newIndex + 1) % TABLE_SIZE; } hashTable->entries[newIndex] = entry; } } int get(HashTable* hashTable, char *key) { int index = hashCode(key); if (hashTable->entries[index] != NULL && strcmp(hashTable->entries[index]->key, key) == 0) { return hashTable->entries[index]->value; } else { // Handle collision int newIndex = (index + 1) % TABLE_SIZE; while (hashTable->entries[newIndex] != NULL && strcmp(hashTable->entries[newIndex]->key, key) != 0) { newIndex = (newIndex + 1) % TABLE_SIZE; } if (hashTable->entries[newIndex] != NULL && strcmp(hashTable->entries[newIndex]->key, key) == 0) { return hashTable->entries[newIndex]->value; } else { return -1; // Key not found } } } void freeHashTable(HashTable* hashTable) { for (int i = 0; i < TABLE_SIZE; i++) { if (hashTable->entries[i] != NULL) { free(hashTable->entries[i]->key); free(hashTable->entries[i]); } } free(hashTable->entries); free(hashTable); } int main() { HashTable* hashTable = createHashTable(); // Inserting values into hash table insert(hashTable, "apple", 5); insert(hashTable, "banana", 10); insert(hashTable, "orange", 15); // Getting values from hash table printf("Value for key 'apple': %d\n", get(hashTable, "apple")); printf("Value for key 'banana': %d\n", get(hashTable, "banana")); printf("Value for key 'orange': %d\n", get(hashTable, "orange")); printf("Value for key 'watermelon': %d\n", get(hashTable, "watermelon")); freeHashTable(hashTable); return 0; } ``` 这个代码使用了线性探测法来处理哈冲突。在插入操作中,如果发生冲突,会往后查找空槽位,直到找到一个空槽位或者遍历完整个哈。在查找操作中,如果发生冲突,会往后查找直到找到对应的键或者遍历完整个哈。由于这只是一个简单的示例,所以哈的大小是固定的。在实际使用中,我们可能会采用更复杂的解决冲突的方法,并且根据需要动态调整哈的大小。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值