肆 简单数据结构--3.哈希表

69 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路

3.哈希表

哈希表又称为散列表,原理是每个元素都能通过哈希函数得到一个哈希值,通过该哈希值进行访问该元素,如key-value的形式访问,key是哈希值,value是该key映射的元素值。理论上查找一个元素的时间复杂度是O(1)

一般的哈希函数:hash(x) = (x % p + p) %p

p一般取大于最大数据量的第一个质数。

有一组数,个数为 8,1 3 5 7 13 20 50 101 ,则P取11, 11是大于8的第一个质数。 然后分别求出这8个数的哈希值。 hash(1) = 1 hash(3) = 3 hash(5) = 5 hash(7) = 7 hash(13) = 2 hash(20) = 9 hash(50) = 4 hash(101) = 2

发现通过哈希函数有两组值是一样的,这被称为“冲突”,数组的一个位置只能存一个数,要解决冲突,有俩种方法:

(1)链地址法(拉链法)

(2)开放寻址法

链地址法(拉链法)

将数据存储在哈希值对应的单链表中

解决冲突的方法:在同一个key处,采用单链表的结构,插在原有数据的后面。

代码如下

 import java.io.*;
 import java.util.*;
 ​
 public class Main{
     static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
     static BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
     static final int N = 100003; //假设数据局最多为100000个
     static int[] hash = new int[N];//哈希表表头
     static int[] data = new int[N];//所有单链表共用一个数组空间--存数据的数组
     static int[] next = new int[N];//next数组
     static int idx = 1; // static 标识的数组的自动初始化为0的
     public static void insert(int x) {
         //头插法
         int k = (x % N + N) % N;
         data[idx] = x;
         next[idx] = hash[k];
         hash[k] = idx;
         idx++;
     }
     public static void find(int x) throws IOException{
         int k = (x % N + N) % N;
         k = hash[k];
         boolean flag = false;
         while(k != 0) {
             if(data[k] == x) {
                 flag = true;
                 break;
             }
             k = next[k];
         }
         if(flag) {
             out.write("find out");
         }else {
             out.write("No find");
         }
         out.flush();
     }
     public static void main(String[] args) throws Exception{
         int n = Integer.parseInt(in.readLine());
         for(int i = 0; i < n; ++i) {
             String[] s = in.readLine().split(" ");
             switch(s[0]) {
             case "i" : insert(Integer.parseInt(s[1]));break;
             case "q" : find(Integer.parseInt(s[1]));break;
             }
         }
     }
 }

数据类型使用情况:

使用了三个一维数组

data数组用于存储数据元素。

hash数组用于存储每个哈希值链表的头指针。

next数组用于存储每个数据元素的下一个数据元素在data的位置。

使用了两个方法

insert插入方法采用了头插法,即每次插入的数据放置在链表的头部。

find寻找方法,通过哈希函数计算出哈希值,通过哈希值在hash数组中找到数组的头部,从头部开始在next数组中遍历。

开放寻址法

在拉链法中我们用了单链表来解决冲突,如果不使用单链表应该如何解决冲突呢。,在插入的时候,如果相应的哈希值对应的位置已经被占用了,就往后看,直到找到一个空的位置,这个找新位置又有不同的方法。