解码查找算法与哈希表

news/2025/10/7 20:46:32/文章来源:https://www.cnblogs.com/YouEmbedded/p/19123844

查找基础概念

查找的定义

查找(又称搜索)是从一组数据中,找出 “关键字与目标值匹配” 的记录的操作;若找到则返回记录的位置(如数组下标),若未找到则返回 “不存在” 标识(如-1)。

查找效率的影响因素

  • 数据存储特点:数据是否有序、存储结构是顺序表(数组)还是链表,或哈希表等;
  • 查找算法本身:算法的时间复杂度(比较次数、操作次数)。

常见查找算法

线性查找(顺序查找)

核心思想

从数据序列的起始位置开始,逐个遍历元素,与目标值逐一比较,直到找到匹配元素或遍历结束。

算法步骤(序列:[3, 9, 8, 2, 1, 4, 6, 5, 7],目标值:6

image

image

适用场景

  • 数据存储结构:顺序表(数组)(通过下标递增遍历)、链表(通过指针p = p->next遍历);
  • 数据状态:有序或无序均可(无需预处理)。

时间复杂度

  • 最坏情况:O(n)(目标值在序列末尾,或目标值不存在,需遍历所有元素);
  • 最优情况:O(1)(目标值在序列首位)。

优缺点

  • 优点:实现简单,无需数据预处理(无序数据也可查);
  • 缺点:数据量较大时,效率低(比较次数多)。

代码(C 语言,数组实现)

// arr:待查找数组;size:数组长度;target:目标值;返回值:目标值下标(-1表示不存在)
int LinearSearch(int arr[], int size, int target) {for (int i = 0; i < size; ++i) {if (arr[i] == target) {return i; // 找到,返回下标}}return -1; // 未找到
}

二分查找(折半查找)

核心前提

待查找数据序列必须已排序(升序或降序,本文以升序为例);若无序,需先排序再查找。

核心思想

“从中间找,排除一半”:通过不断将查找区间缩小为原来的一半,快速定位目标值(类似字典查字:先翻中间,确定目标在左半本还是右半本)。

算法步骤(有序序列:[1, 2, 3, 4, 5, 6, 7, 8, 9],目标值:6

image

image

适用场景

二分查找仅适用于顺序表(数组),不适用于链表,链表通过二叉查找树实现二分查找。

时间复杂度

  • 每轮排除一半数据,时间复杂度为O(logn)(如n=1024时,最多仅需 10 次比较,效率远高于线性查找)。

优缺点与选择依据

  • 优点:查找速度快(尤其数据量大时);
  • 缺点:需数据已排序,且添加元素时需插入合适位置(维护成本高);
  • 选择依据:
    • 若 “查找操作频繁,添加操作少”(如静态数据:历史成绩表),选二分查找;
    • 若 “添加操作频繁,查找操作少”(如动态数据:实时新增的日志),选线性查找。

代码(C 语言,升序数组)

int BinarySearch(int arr[], int size, int target) {int low = 0;int high = size - 1;while (low <= high) {int mid = (low + high) / 2; // 中间位置(避免溢出也可写为low + (high - low)/2)if (arr[mid] == target) {return mid; // 找到,返回下标} else if (arr[mid] < target) {low = mid + 1; // 目标在右半区间} else {high = mid - 1; // 目标在左半区间}}return -1; // 未找到
}

哈希表

当数据量极大时(如百万级用户数据),线性查找和二分查找效率仍不足,此时需用哈希表(又称散列表)—— 一种 “支持快速查找” 的数据结构,查找时间复杂度可接近O(1)

哈希表基础

  • 哈希表的定义

哈希表是一种 “key-value(键值对)” 存储结构,通过一个哈希函数将 “关键字 key” 映射到 “哈希表的索引(地址)”,使每个 key 对应唯一的索引,从而实现 “按 key 快速定位 value”。

  • 例:key = 学生学号,value = 学生信息(姓名、分数),通过哈希函数将学号映射到数组下标,直接访问下标即可获取学生信息。

哈希函数(核心)

  • 定义:将 key 转换为哈希表索引的函数,记为H(key)
  • 要求:计算简单、映射均匀(尽量避免不同 key 映射到同一索引,即 “哈希冲突”);
  • 常见哈希函数类型
    • 直接定址法H(key) = a*key + b(a、b 为常数);
      • 例:key = 员工工号(1001,1002,1003),取a=1,b=-1000,则H(1001)=1H(1002)=2,直接映射到下标 1、2;
      • 适用场景:key 范围小且连续。
    • 除留余数法H(key) = key % p(p 为小于等于哈希表长度的最大质数);
      • 例:哈希表长度 = 10,p=7(小于 10 的最大质数),key=15,则H(15)=15%7=1,映射到下标 1;
      • 适用场景:key 范围大且不连续(最常用的哈希函数)。
    • 数字分析法:取 key 的 “数字特征明显的部分” 作为索引;
      • 例:key = 手机号(138xxxx1234),后 4 位唯一,取H(key)=后4位,映射到下标 1234;
      • 适用场景:key 的某部分数字重复率低。

哈希冲突(不可避免)

  • 定义:不同的 key 通过哈希函数计算出相同的索引(如H(7)=0H(14)=0,key=7 和 14 映射到同一索引 0);
  • 解决方法
    • 开放定址法:若索引H(key)已被占用,按一定规则寻找下一个空索引;
      • 线性探测:H_i = (H(key) + i) % m(i=0,1,...,m-1;m 为哈希表长度);
        • 例:哈希表长度 m=10,H (7)=0(已占用),则 i=1 时H_1=(0+1)%10=1,若 1 空则存 1,否则 i=2 找 H_2=2,以此类推;
      • 二次探测:H_i = (H(key) + i²) % m(避免线性探测的 “聚集问题”,即连续占用);
    • 链地址法:将映射到同一索引的 key,用链表串联起来;
      • 例:哈希函数H(key)=key%3,key=1、4、7,H(1)=1H(4)=1H(7)=1,则在索引 1 处存储链表:1 → 4 → 7
      • 优点:无聚集问题,处理冲突效率高(最常用的冲突解决方法)。

哈希查找

核心思想

通过哈希函数计算目标 key 的索引,直接访问该索引:

  • 若索引对应位置为空:目标 key 不存在;
  • 若索引对应位置有数据:比较 key 是否匹配,匹配则返回 value;若不匹配(哈希冲突),按冲突解决方法遍历查找。

算法步骤(以链地址法为例,哈希表:索引 0→[0,3,6],索引 1→[1,4,7],索引 2→[2,5,8],目标 key=4)

  • 计算哈希函数:H(4)=4%3=1,确定索引 1;
  • 访问索引 1 的链表,遍历链表元素1、4
  • 找到 key=4,匹配成功,返回对应的 value;
  • 若目标 key=9:H(9)=9%3=0,访问索引 0 的链表[0,3,6],遍历后无 9,返回 “不存在”。

时间复杂度

  • 理想情况(无哈希冲突):O(1)(直接访问索引);
  • 实际情况(有冲突):O(1 + α)(α 为 “负载因子”,即哈希表中元素个数 / 哈希表长度,α 越小,冲突越少,效率越高,通常 α 控制在 0.7 以下)。

优缺点与适用场景

  • 优点:查找速度极快(接近 O (1)),适合大规模数据;
  • 缺点:哈希函数设计复杂、需处理冲突、内存占用可能较高(需预留哈希表空间);
  • 适用场景:高频查找、大规模数据(如数据库索引、缓存系统、用户信息查询)。

代码C 语言,链地址法哈希表)

  • 定义
typedef struct Node {int key;int value;struct Node* next;
} Node;// 哈希表(数组+链表,size为数组长度)
typedef struct HashTable {int size;Node** table;
} HashTable;
  • 初始化
// 初始化哈希表
HashTable* initHashTable(int size) {HashTable* ht = (HashTable*)malloc(sizeof(HashTable));ht->size = size;// 初始化数组,每个元素为NULL(空链表)ht->table = (Node**)calloc(size, sizeof(Node*));return ht;
}
  • 哈希函数
// 哈希函数(除留余数法,p为小于size的最大质数,此处简化取size)
int hashFunc(int key, int size) {return key % size;
}
  • 插入
// 插入键值对到哈希表
void insert(HashTable* ht, int key, int value) {int idx = hashFunc(key, ht->size);// 创建新节点Node* newNode = (Node*)malloc(sizeof(Node));newNode->key = key;newNode->value = value;newNode->next = NULL;// 链地址法:新节点插入链表头部if (ht->table[idx] == NULL) {ht->table[idx] = newNode;} else {newNode->next = ht->table[idx];ht->table[idx] = newNode;}
}
  • 查找
// 哈希查找(返回value,未找到返回-1)
int hashSearch(HashTable* ht, int key) {int idx = hashFunc(key, ht->size);Node* p = ht->table[idx]; // 指向对应索引的链表头// 遍历链表查找keywhile (p != NULL) {if (p->key == key) {return p->value; // 找到,返回value}p = p->next;}return -1; // 未找到
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/930819.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

完整教程:MySQL 如何判断某个表中是否存在某个字段

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

2025/10/7

2025/10/7休息一天

NVMe IP现状扫盲 - 指南

NVMe IP现状扫盲 - 指南pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", &qu…

山西正规网站建设推广如何分析网站流量

项目介绍 ChatTTS是一款专为优化对话场景而生的语音生成模型&#xff0c;尤其匹配大型语言模型&#xff08;LLM&#xff09;的交互需求&#xff0c;以及生成对话式音频、视频旁白等应用场景&#xff0c;无缝覆盖中英文双语。 通过汲取约100,000小时的高质量中英语音数据进行深…

字体设计教程网站好变装chinacd wordpress

泛型&#xff08;宽泛的&#xff0c;不确定的类型&#xff09; 使用场景&#xff1a;定义一个函数或类时&#xff0c;无法确定要使用的具体类型&#xff08;返回值、参数、属性的类型不能确定&#xff09;泛型使用时相当于一个参数 functiondemo<T>(arg: T): T{return …

第二次课动手动脑合集

文档: https://files.cnblogs.com/files/blogs/847696/动手动脑2.zip?t=1759839965&download=true 1.生成随机数 import java.util.Arrays; public class RandomGenerator { public static void main(String[] a…

网站时间轴品牌策划经典案例

示意图的特点 示意图表示的是大体上描述或表示物体的形状、相对大小、物体与物体之间的联系(关系),描述某器材或某机械的大体结构和工作的基本原理,描述某个工艺过程简单图示都叫做示意图。 示意图的特点就是简单明了,它突出了重点,忽略很多次要的细节。老师上课时在黑板…

课后实验2

public class MethodOverload { public static void main(String[] args) { System.out.println("The square of integer 7 is " + square(7)); System.out.println("\nThe square of double 7.5 is &q…

网站qq在线代码公主岭网站建设

非常高兴有机会向大家介绍CleanMyMac X 2024这款专业的Mac清理软件。它以其强大的清理能力、系统优化效果、出色的用户体验以及高度的安全性&#xff0c;在Mac清理软件市场中独树一帜。 CleanMyMac X2024全新版下载如下: https://wm.makeding.com/iclk/?zoneid49983 一、主要…

centos8的防火墙管理

开放一个tcp端口 firewall-cmd --zone=public --add-port=83/tcp --permanent 查看防火墙的状态 systemctl start firewalld.service

UCB-CS70_离散数学_个人笔记:Proofs 和 EECS 的联系及几种常见证明方法 - Zeeh

Proofs are very powerful and are in some ways like computer programs. Indeed, there is a deep historic link between these two concepts that we will touch upon in this course — the invention of compute…

提升学历哪种方式含金量高网站外链优化

用护眼灯还需要开灯吗&#xff1f;在使用护眼台灯时&#xff0c;同时开启室内的主照明十分必要。如果关闭其他灯具&#xff0c;仅保留护眼台灯&#xff0c;那么只有台灯周围的小片区域能够被照亮&#xff0c;而房间的其他部分则处于相对昏暗的状态。这种明显的光线差异会造成视…

如何生成和制作PDF文件 - 实践

如何生成和制作PDF文件 - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco"…

网站的建设与维护实践报告创客网站建设

Postgresql的事务里面ddl可以回滚,这点和oracle不太一样。其中postgresql alter table事务操作中&#xff0c;包括回滚的整个过程中表对象的relfilenode不变&#xff0c;但是postgresql truncate事务操作中&#xff0c;一旦执行truncate操作表对象的relfilenode在当前会话就变了…

【使用JAVA调用deepseek】构建自能回复

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

1.2 马尔可夫决策过程(Markov Decision Process, MDP)

定义 强化学习(Reinforcement Learning, RL)方法适用于智能体(agent)以离散时间步与环境交互的问题(@fig-agentenv)。 在时间 \(t\),智能体处于状态 \(s_t\),并决定执行一个动作 \(a_t\)。在下一时刻,它进入新…

博弈论dp复习笔记

Stones 题目概述 集合 \(A\),小 \(X\) 和小 \(Y\) 选择其中一个数 \(x\),然后将石堆拿走 \(x\) 个,谁不能操作谁输,一开始石堆石头数量为 \(k\). 数据范围:\(1\leq k\leq 10^5,1\leq n\leq 100,1\leq a_i\leq 10^…

10.7阅读笔记

正当我对着空白的IDE发愁“该如何开始”时,这本书的《曳光弹开发》这一章给了我明确的方向。 ​​1. 曳光弹 vs. 原型—— 两种启动策略​​ 这是我第一次接触这两个概念,它们解决的是不同的问题。 ​​原型:用于探…

如果你的微信支付界面出现“摇一摇”,说明你的隐私正在泄露

你刚付完款,手机自己跳出摇一摇,红包没抢着,位置先被商家锁定。这不是错觉。<ignore_js_op>微信去年悄悄上线附近优惠,四月起推得更猛。很多人第一次见,以为中毒,其实是后台把付款记录和基站信号打包,算出…

多线程和网络总结

近期Python网络编程与多线程/多进程学习复盘 一、核心知识收获 1. 多线程与多进程编程多线程应用:实现图片下载(DownloadHanlder类继承Thread,重写run方法处理下载逻辑),利用线程并行处理网络IO任务,提高下载效率…