散列表(hash 算法)

知识点

  • Hash 的概念

  • List item

  • 构造方法

  • 冲突处理

为什么使用哈希表

我们上面所提到的查找算法,简单来说,就是判断现有数据集合中是否有这个元素,或者是否有满足条件的元素。

其中的 Hash 算法则可以帮助我们判断是否有这个元素,虽然功能简单,但是其 O(1) 时间复杂度是具有高性能的。通过在记录的存储地址和它的关键码之间建立一个确定的对应关系。这样,不经过比较,一次读取就能得到所查元素的查找方法。相比普通的查找算法来说,仅仅在比较的环节,就会大大减少查找或映射所需要的时间。
什么是哈希表(散列表)

我们采用散列技术将记录存储在一块连续的存储空间中,这块连续的存储空间即称为散列表。下面用一张图给大家展示一下散列表的实现过程:
在这里插入图片描述
如果还是不太明白的话,我们可以理解为数学函数,Y=F(X),X 为自变量也就是这里的 Key, F( ) 对应图中的 H( ),也就是一个映射关系,Y 因变量也就是对应的值的 存放位置,此处一定要注意哦。

此处让我们思考一下:

  • List item

散列技术仅仅是一种查找技术吗?

应该说,散列既是一种查找技术,也是一种存储技术。

散列是一种完整的存储结构吗?

散列只是通过记录的关键码定位该记录,没有完整地表达记录之间的逻辑关系,即通过关键码能推出 Key 值,但是通过关键码对应的值(即位置处的值)不能推出关键码,所以散列存储的关键码和值之间并不对称,因此散列主要是面向查找的存储结构。

散列表的缺陷
散列表并不是适用于所有的需求场景,那么哪些情况下不适合使用呢?

散列技术一般不适合在允许多个记录有同样关键码的情况下使用。

因为这种情况下,通常会有冲突存在,将会降低查找效率,体现不出散列表查找效率高的优点。

并且如果一定要在这个情况下使用的话,还需要想办法消除冲突,这将花费大量时间,那么就失去了 O(1) 时间复杂度的优势,所以在存在大量的冲突情况下,我们就要弃用散列表。

散列方法也不适用于范围查找,比如以下两个情况。

查找最大值或者最小值

因为散列表的值是类似函数的,映射函数一个变量只能对应一个值,不知道其他值,也不能查找最大值、最小值,RMQ(区间最值问题)可以采用 ST 算法、树状数组和线段树解决。

也不可能找到在某一范围内的记录

比如查找小于 N 的数有多少个,是不能实现的,原因也是映射函数一个变量只能对应一个值,不知道其他值。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

题目:
弗里的语言

小发明家弗里想创造一种新的语言,众所周知,发明一门语言是非常困难的,首先你就要克服一个困难就是,有大量的单词需要处理,现在弗里求助你帮他写一款程序,判断是否出现重复的两个单词。

要求:有重复的单词,就输出重复单词,
没有重复单词,就输出 NO,多个重复单词输出最先出现的。
import java.util.Scanner;
import java.util.Stack;

public class Main {

    static  final int h=999983;

    static String[] Value=new String [h];

    static String[] UpValue=new String [h];

    static int UpValueCount=0;

    static int   Hx(String s) {
        return (s.hashCode()%h+h)%h;
    }

    static boolean isAt(String s)
    {
        int n=Hx(s);
        if(Value[n]==null) return false;
        else if(Value[n].equals(s)) return true;
        else {
            for(int i=0;i<UpValueCount;i++)
                if(UpValue[i].equals(s)) return true;

            return false;
        }


    }

    static boolean in(String s)
    {
        int n=Hx(s);
        if(Value[n]==null) {
            Value[n]=s;
            return true;
        }
        else if(Value[n].equals(s)) return false;
        else {
            for(int i=0;i<UpValueCount;i++)
                if(UpValue[i].equals(s)) return false;

            UpValue[UpValueCount++]=s;
            return true;
        }
    }
    public static void main(String[] args)
    {

        int n;
        boolean flag=false;
        Scanner in=new Scanner(System.in);
        String ans="NO";
        n=in.nextInt();
        for(int i=0;i<n;i++)
        {
            String word;
            word=in.next();
            // System.out.println(Hx(word));
            if(flag) continue;

            if(isAt(word)){
                flag=true;
                ans=word;
            }
            else {
                in(word);

            }
        }
        System.out.println(ans);
    }

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值