几种经典查找算法

几种经典查找算法

  • 顺序查找法
  • 二分查找法
    • 判定树
  • 二叉查找树(BST)
  • 索引查找
  • B-树
  • B+树
  • 散列表(hash)查找

顺序查找法

顺序查找的平均查找长度为:
在这里插入图片描述在这里插入图片描述
时间复杂度为0(n);

二分查找法

int binsearch(datatype* a,int n,datatype target)
{int left=0;int right=n-1;int mid=(left+right)/2;while(left<=right){if(target<a[mid]){right=mid-1;mid=(left+right)/2;}else if(target>a[mid]){left=mid+1;mid=(left+right)/2;}elsereturn mid;}if(left>right)return -1;
}

我们来在主函数中测试一下:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
typedef char datatype;
int binsearch(datatype*,int,datatype);
int main()
{char arr[10]={'a','c','e','g','i','k','m','o','q','s'};char x='m';char y='z';int xn=binsearch(arr,10,x);int yn=binsearch(arr,10,y);printf("%c:%d\n",x,xn);printf("%c:%d\n",y,yn);return 0;
}
int binsearch(datatype* a,int n,datatype target)
{int left=0;int right=n-1;int mid=(left+right)/2;while(left<=right){if(target<a[mid]){right=mid-1;mid=(left+right)/2;}else if(target>a[mid]){left=mid+1;mid=(left+right)/2;}elsereturn mid;}if(left>right)return -1;
}

在这里插入图片描述
结果正确。

下面是递归算法:

int binsearch2(datatype* a,int L,int R,datatype tar)
{if(L<R)return -1;int mid=(L+R)/2;if(a[mid]==tar)return mid;else{if(tar>a[mid])return binsearch2(a,mid+1,R,tar);elsereturn binsearch2(a,L,mid-1,tar);}
}

判定树

二分查找法的平均查找长度和查找效率可以从判定树来看:
若把当前查找范围内居中的记录的位置作为根结点,前半部分与后半部分的记录的位置 分别构成根结点的左子树与右子树,于是就得到了一棵成为“判定树”的二叉树。(此处的位置不是下标,位置从1开始)
例如:数组【2,5,7,11,14,16,19,23,27,32,50】,其判定树为:
在这里插入图片描述我们发现:成功的查找过程正好等于走了一条从根结点到被查找结点的路径,经历的比较次数恰好是被查找结点在二叉树中所处的层数。

由此,我们可以得到二分查找法的平均查找长度:
在这里插入图片描述则上述案例的ASL为:(1 * 1 + 2 * 2 + 4 * 3 + 4 * 4)/ 11 = 23/11
时间复杂度为O(logn)。

二分查找法适用于:一经建立就很少改动(插入、删除),而又经常需要查找的查找表。
要使用二分查找法,必须满足:必须采用顺序存储结构,元素按值有序排列。

二叉查找树(BST)

二叉查找树可以同时兼顾查找和插入、删除操作的效率。
二叉树平衡的情况下,时间复杂度为:O(logn),退化的二叉树查找时间复杂度为:O(N)。

void searchBST(BTNodeptr p,int n)
{BTNodeptr cur=p;while(cur!=NULL){if(n>cur->val){cur=cur->right;}else if(n<cur->val){cur=cur->left;            }else{printf("%d ",cur->val);break;}}
}

这个查找算法经过一些微改,还可以用于打印根结点到某结点的路径等。

索引查找

类似于牛津字典旁边的ABCD……把首字母一样的分为一类,首字母即为所谓的“索引”。当然,在实际运用的过程中,索引可以根据具体情况具体分析。
索引表是一个DataType*类型的数组,索引表数组的每一个元素都是一个数组,当然你也可以用链表来记录每一个索引下的数据。这里的代码以数组中的数组为例(因为可以两次运用二分查找法,如果内部用链表的话内部的查找就只能用顺序查找了)。

typedef struct node
{char index;//存放每个索引int num;//存放该索引下的元素个数char* stuff[100];//这个里面放该索引下的内容//也可用链表://DataType* link;
}NODE;
void indexsearch(NODE a[],int n,char* target)
{char index=target[0];int left=0;int right=n-1;int mid;while(left<=right){//索引如果有序的话,可以直接用二分查找法mid=(left+right)/2;if(target>a[mid].index){left=mid+1;}else if(target<a[mid].index){right=mid-1;}elsebreak;}//有两种情况会跳出循环,第一种是找到了匹配的索引,通过break跳出//第二种是没找到,通过left>right跳出循环,这一种可以直接返回没找到//因为索引都没找到,那内容肯定更找不到了if(left>right){printf("no find");return;}//如果找到索引了,就在索引里再用二分查找(顺序存储)int left=0;int right=a[mid].num-1;while(left<=right){mid2=(left+right)/2;int cmp=strcmp(target,a[mid].stuff[mid2]);if(cmp>0)left=mid+1;else if(cmp<0)right=mid-1;else{//找到了,根据具体要求做具体操作就行}}
}

这个示例代码的作用类似字典,即索引表为单词首字母,然后现在索引表中找目标查找单词的索引,如果没找到(比如x开头的单词基本没有),那就直接返回,如果找到了,那就在找到的那部分索引中继续查找。

B-树

B-树的基本原理强烈大家去看b站
在这里插入图片描述
这个博主的视频!!!!ppt看了好久没搞明白但是博主动画一做就立马明白了真的讲的很清楚!

笔记这部分配图均来自上述博主及ppt,非本人原创↓
在这里插入图片描述一棵n阶B-树的特点:

  1. 根结点最少要有两个分支,最少要有一个元素
  2. 各个除根结点外分支节点最多有m个分支,m-1个元素;最少有【m/2】(向上取整)个分支,【m/2】-1个元素。
  3. 所有的叶结点都在同一层。教材们对B-树叶结点说法不统一,有些说上面红框子是叶子结点(也叫失败节点)。有些说是红框的上一层是叶结点。
  4. 各节点内部的元素是有序的

B树麻烦的地方在于它的插入
比如说,我们现在要在一个已有的3阶B-树中插入元素20
在这里插入图片描述经过比较,发现20比23小,那就应该插在它的左边:
在这里插入图片描述插入之后,发现这个节点的元素个数是2,没有超过每个结点的最大元素个数2,所以性质并未被破坏,则无需调整。

但是,我们再来插入17:
在这里插入图片描述
通过比较,发现应该插入14的右边
在这里插入图片描述
此时发现,该结点有3个元素,超出3阶B-树的最大元素个数,那么这个时候就需要分裂节点

以第【m/2】(上取整)个元素为中间结点,分为14左边,14,和14右边。

将14上移至父节点,而原来14的左边和右边,分别变为14在父节点中的左分支和右分支:
在这里插入图片描述但如果,调整之后,父节点又超过最大元素了,怎么办呢?
我们现在来插入元素53:
在这里插入图片描述那么这个时候,需要以53为分割点,进行上移:
在这里插入图片描述这个时候【36,53,70】这个节点又溢出了,那我们继续分裂这个节点。
这个时候要注意,此时分裂节点时,被分裂的就不仅是一个元素了,而是一个子树

在这里插入图片描述
ok此时父节点没有发生溢出。但如果根结点也溢出了,就需要再向上分裂,此时树层数加一。

B+树

在这里插入图片描述B+树的特点:
(前三点与B-树同)

  1. m阶B+树的各个分支节点最多有m棵子树
  2. 除根结点外,每个分支节点最少有【m/2】(上取整)棵子树
  3. 根结点至少有两棵子树(除非他就是叶子结点)

从第四点开始,就是B+树不同于B-树的地方:

  1. 具有n棵子树的结点中,必有n个元素(B-树只有n-1个
  2. 每个叶结点存放着记录的关键字以及指向记录的指针。(B-树是在每个结点中存储记录
  3. 所有分支节点可以看做是索引的索引,结点中仅包含它的各个孩子中的最大值或最小值以及指向孩子结点的指针。

这是B-树和B+树的区别:在这里插入图片描述

散列表(hash)查找

上述查找方式,多多少少都要进行关键字的比较,从而增加了时间复杂度。
那么有没有一种查找方式,不用经过任何关键字的比较,或者经过很少次关键字的比较,就能够达到目的的方法?

有,那就是哈希表,也叫散列表。
在这里插入图片描述
i ≠ j 但是,H(i) = H(j),也就是关键字不同,但散列地址相同,那么这种现象叫散列冲突

一个好的散列表应该具备的特点是:

  1. 散列函数的定义域必须包括将要存储的全部关键字;
    若散列表允许有m个位置时,则函数的值为[0,……,m-1](地址空间)
  2. 利用散列函数计算出来的地址应能尽可能均匀分布在整个地址空间中。
  3. 散列函数应该尽可能简单,应该在较短的时间内计算出结果。

建立散列表的步骤有:

  1. 确定散列的地址空间
  2. 构造合适的散列函数
  3. 选择处理冲突的方法

散列函数的构造方法有很多,我们最常用的就是:除留余数法

H(k)= k MOD p (p为小于等于m的素数)

冲突的处理方法也有很多,我们常用的是:链地址法,就是散列地址一样的链在后面。有点像日本鲤鱼旗那种感觉。。。
在这里插入图片描述
但是链表的查找效率比较低,所以我们可以换成一颗颗二叉搜索树。
下面的函数用于,查找哈希表中的某一个值,如果该值存在,则返回它的地址,如果不存在,则插入:

#define MAX 100
typedef struct node
{int data;struct node* next;
}NODE;
//因为有时经常需要按照一定的规律插入哈希表
//因此我们将哈希表每个位置的链表的头结点都设置为哨兵位
//这样方便头插
NODE* Hashtab[MAX];
NODE* find(int key)
{unsigned int h;NODE* cur;h=hash(key);//这是散列函数,根据具体情况做for(cur=Hashtab[h];cur->next!=NULL;cur=cur->next){if(cur->next.data==key)return cur->next;}//如果函数能进行到这个地方,就说明没找到,那就需要插入了,我们这里就进行尾插就行NODE* new=(NODE*)malloc(sizeof(NODE));new->data=key;new->next=NULL;cur->next=new;cur=new;return cur;
}

OK,今天的分享就到这里了。

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

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

相关文章

vxe-table表格新增节点

做前端的朋友可以参考下&#xff1a;也可结合实际需求查看相应的官方文档 效果图 附上完整代码 <template><div><vxe-toolbar ref"toolbarRef" :refresh"{queryMethod: searchMethod}" export print custom><template #buttons>&…

算法训练营第六十天(延长12天添加图论) | LeetCode 647 回文子串、LeetCode 516 最长回文子序列

LeetCode 67 回文子串 思路很简单&#xff0c;每一个dp[i]等于dp[i-1]加上当前字符向前直到0各个长度字符串回文串个数即可 代码如下&#xff1a; class Solution {public boolean isValid(String s) {int l 0, r s.length() - 1;while (l < r) {if (s.charAt(l) ! s.ch…

如何通过抖音自动评论精准获客实现业务增长?这些方法值得一试!

在当今竞争激烈的商业环境中&#xff0c;企业若想脱颖而出&#xff0c;就必须掌握精准获客的艺术。精准获客&#xff0c;即通过精确的市场定位和营销策略&#xff0c;吸引并保留最有可能成为客户的目标群体。它不仅能提高转化率&#xff0c;还能有效降低营销成本&#xff0c;是…

搭建自己的AI模型应用网站:JavaScript + Flask-Python + ONNX

1. 前言 本文作者以一个前端新手视角&#xff0c;部署自己的神经网络模型作为后端&#xff0c;搭建自己的网站实现应用的实战经历。目前实现的网页应用有&#xff1a; AI 语音服务主页AI 语音识别AI 语音合成AI CP号码生成器 欢迎大家试用感受&#xff0c;本文将以博客基于G…

机器人运动学笔记

一、建模 参考资料&#xff1a;https://zhuanlan.zhihu.com/p/137960186 1、三维模型和连杆、关节定义 2、设置z轴 SDH和MDH会不一样&#xff0c;主要的区别在于SDH中坐标系在连杆末端&#xff0c;MDH中坐标系在连杆首端。虽然这里只是给出z轴&#xff0c;但是由于后面原点位…

【C++】Template模板

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; &#x1f525;c系列专栏&#xff1a;C/C零基础到精通 &#x1f525; 给大…

【计算机视觉】人脸算法之图像处理基础知识(五)

图像的几何变换 3.图像的旋转 图像的旋转就是让图像按照某一点旋转到指定的角度。需要确定3个参数&#xff1a;图像的旋转中心、旋转角度和缩放因子。在openv中通过getRotationMatrix2D()函数来实现图像的旋转。 import cv2 import numpy as npimgpath "images/img1.j…

CrossOver和PD虚拟机谁更强大?CrossOver和PD虚拟机应该怎么选择

在当前的虚拟化技术和应用程序兼容性解决方案中&#xff0c;CrossOver和PD虚拟机&#xff08;Parallels Desktop&#xff09;都是备受用户喜爱的选择。对于需要在非原生系统上运行应用程序的用户而言&#xff0c;选择合适的工具尤为重要。那么&#xff0c;CrossOver和PD虚拟机谁…

Java SSTI服务端模版注入漏洞原理与利用

文章目录 前言Velocity基础语法基础示例命令执行 靶场实践漏洞代码漏洞验证检测工具 FreeMarker基础示例漏洞示例CMS案例 Thymeleaf基础示例漏洞示例安全方案 总结 前言 SSTI&#xff08;Server Side Template Injection&#xff09;全称服务端模板注入漏洞&#xff0c;在 Jav…

挑战5分钟内基于Springboot+SpringMVC+Mybatis-plus快速构建web后端三层架构

目标 在清晨的代码编辑器上&#xff0c;一场新的挑战即将开始。程序员们肃立于安静的办公室&#xff0c;眼神专注地盯着屏幕&#xff0c;等待着编译器的一声提示。 随着编译器输出的激动人心的"start!"的提示&#xff0c;战斗的序幕拉开了。Bug如潮水般涌来&#x…

python保存文件后打不开的原因是什么

引入数据集&#xff0c;奇怪的是怎么也打不开&#xff0c;显示不存在这个文件&#xff1a; 但是&#xff0c;我将文件改个名字&#xff0c;就打开了&#xff0c;难道csv的文件命名必须有一定合法性&#xff1f; import pandas users pandas.read_csv("H:\python\data an…

正运动邀您共聚2024深圳激光展,助力激光加工与智能制造!

■展会名称 2024深圳激光展 ■展会日期 2024年6月19日 - 21日 ■展馆地点 深圳国际会展中心&#xff08;新馆&#xff09; ■展位号 9H - D101 6月19至21日&#xff0c;深圳激光展将在中国深圳国际会展中心(新馆)举办。 激光加工在消费电子、光伏锂电新能源、半导体等行…

树莓派4B_OpenCv学习笔记9:图片的腐蚀与膨胀

今日继续学习树莓派4B 4G&#xff1a;&#xff08;Raspberry Pi&#xff0c;简称RPi或RasPi&#xff09; 本人所用树莓派4B 装载的系统与版本如下: 版本可用命令 (lsb_release -a) 查询: Opencv 版本是4.5.1&#xff1a; 图像的膨胀与腐蚀一般用于灰度图或者二值图,今日便来学习…

湘潭大学软件工程数据库2(题型,复习资源和计划)

文章目录 选择题关系范式事务分析E-R 图sql作业题答案链接&#xff08;仅限有官方答案的版本&#xff09;结语 现在实验全部做完了&#xff0c;实验和作业占比是百分之 40 &#xff0c;通过上图可以看出来&#xff0c;重点是 sql 语言 所以接下来主要就是学习 sql 语句怎么书写…

软考 系统架构设计师系列知识点之杂项集萃(36)

接前一篇文章&#xff1a;软考 系统架构设计师系列知识点之杂项集萃&#xff08;35&#xff09; 第58题 对软件体系结构风格的研究和实践促进了对设计的复用。Garlan和Shaw对经典体系结构风格进行了分类。其中&#xff0c;&#xff08; &#xff09;属于数据流体系结构风格&am…

孝子黄香与颍川□董超

“香九龄&#xff0c;能温席&#xff0c;孝于亲&#xff0c;所当执。”家喻户晓、妇孺皆知的《三字经》让孝子黄香名扬千秋&#xff0c;成为“二十四孝”中闻名于世的“扇枕温衾”故事的主角。 黄香&#xff08;公元68—122年&#xff09;&#xff0c;字文强&#xff0c;东汉江…

【Apache Doris】Compaction 原理 | 实践全析

【Apache Doris】Compaction 原理 | 实践全析 一、Compaction 前文概要二、Compaction 版本策略三、Compaction 类型说明四、Compaction 工程实现五、Compaction 生产实践 作者 &#xff5c; 俞剑波 一、Compaction 前文概要 LSM-Tree 简介 LSM-Tree&#xff08; Log Structu…

【Vue】Pinia管理用户数据

Pinia管理用户数据 基本思想&#xff1a;Pinia负责用户数据相关的state和action&#xff0c;组件中只负责触发action函数并传递参数 步骤1&#xff1a;创建userStore 1-创建store/userStore.js import { loginAPI } from /apis/user export const useUserStore defineStore(…

大众点评js逆向过程(未完)

1、这里mtgsig已经被拼到url中 2、进入后mtgsig已经计算完&#xff0c; ir he(this[b(4326)], !1), 就是加密函数 32 次 796 1143 ->508 -> 754 -> 1151 160 注意IC这个数组 控制流平坦化进行AST 解析 AST网址

uniapp开发微信小程序问题汇总

1. 自定义校验规则validateFunction失效 2. 微信小程序不支持<Br>换行 在 <text></text> 标签中使用\n(必须 text 标签&#xff0c;view 标签无效 ) 3. 微信小程序无法使用本地静态资源图片的解决方法 (1) 将图片上传到服务器&#xff0c;小程序访问该图片…