查找算法的总结

声明:以下内容来源于网络资料的学习和整理


一、查找技术分类

1、静态查找表技术(顺序查找、二分查找、分块查找)

2、动态查找表技术(二叉查找树)

3、哈希表技术(哈希表技术)

 

二、查找技术说明

    衡量查找算法优劣的标准——平均搜索长度(ASL)=,其中Ci为查找第i个数需要进行比较的次数(比如开始对比一个数组中的第i个数,则前面已经对比了i-1个数字),Pi表示查找第i个数的概率(一般会平均,即1/n)。

 

A、静态查找表技术

1顺序查找

(1)平均查找长度为:(n+1)/2,即时间复杂度为O(n)。

2二分查找

(1)必须是有序表,而且只适用于顺序存储结构;性能只有在均匀分布的时候才是最优的。

(2)查找长度:每经过一次比较,查找范围都要缩小一半,因此最大查找长度为MSL=[log2 n]+1。当n足够大时,可近似的表示为log2(n),即时间复杂度为O(log2(n))。

(3)二分查找要求查找表按关键字有序,而排序是一种很费时的运算;而且二分查找法要求表是顺序存储的,为保持表的有序性,在进行插入和删除操作时,都必须移动大量记录。因此,二分查找的高查找效率是以牺牲排序为代价的,它特别适合于一经建立就很少移动、而又经常需要查找的线性表。

(4)代码示例

//k为待查找的数字,R为数据集合,函数返回k在R[]中的位置
int binsearch(int R[], int k)
{int low = 0, high = n-1;//R长度为nint mid;int find = 0;while ((low <= high) && (!find)){mid = (low + high) / 2;               /*求区间中间位置*/if (k == R[mid])find = 1;                         /*查找到*/elseif (k>R[mid])low = mid + 1;                /*在后半区查找,修改low*/elsehigh = mid - 1;               /*在前半区查找,修改high*/}if (find)return (mid);  /*查找成功,返回找到的元素位置*/elsereturn (-1);   /*查找失败,返回-1*/
}


3、分块查找(索引顺序查找)

(1)分块查找要求把线性表分成若干块,块与块之间必须有序(即假如升序排列,那么第一块的最大值,必须小于第二块的最小值),但是在每一块中记录的关键字不一定有序。假设这种排序是按关键字值递增排序的,抽取各块中的最大关键字及该块的起始位置构成一个索引表,按块的顺序存放在一个数组中,显然这个数组是有序的。

(2)分块查找过程分两步进行:

a、首先查找索引表,确定待查记录所在块(可用二分查找法或顺序查找法);

b、在相应块(子表)中用顺序查找法查找记录。   

(3)分块查找的效率介于顺序查找和折半查找之间,对于数据量巨大的线性表,它是一种较好的方法。在表中插入或删除一个记录时,只要找到该记录所属的块,就可以在该块内进行插入和删除运算,插入和删除无需移动大量记录。分块查找的主要代价是:需要增加一个辅助数组的存储空间和将初始表分块排序的运算。

(4)代码示例:

struct idtable
{int  key;//这里指的是该块的最大值int  addr;//该快的最大值在数组中的位置
};
struct idtable  ID[b];  /*b为块数*/int blksearch(int R[], struct idtable ID[], int k)
{int i;int low1=0, high1=b-1;//low1、high1为索引表的区间下、上界int low2, high2;int mid;   while (low1 <= high1){mid = (low1 + high1) / 2;if (k <= ID[mid].key)high1 = mid - 1;elselow1 = mid + 1;}/*查找完毕,low1存放找到的块号*/if (low1 < b){low2 = ID[low1].addr;              /*low2为待查值所在的那个表的起始地址*/if (low1 == b - 1)high2 = N - 1;                 /*N为查找表的长度,high2为块在表中的末地址*/elsehigh2 = ID[low1 + 1].addr - 1;for (i = low2; i <= high2; i++)    /*在块内顺序查找*/if (R[i].key == k)return i;}else                                   /*若low1>=b,则k大于查找表R中的所有关键字*/return -1;

B动态查找表技术


C、哈希表技术

1、哈希表的定义

   哈希表是通过关键字进行某种计算(映射)来确定该记录的存储位置的一种查找表。

2、冲突解决方法

   不同的关键字,根据哈希函数被映射到同一个存储地址,这种现象被称为冲突。冲突是不可避免的,因为关键字的取值集合远远大于表空间的地址集合,我们只能尽量减少冲突的发生。在构造哈希函数时,主要面临两个问题:一是构造较好的哈希函数,把关键字集合中元素尽可能均匀地分布到地址空间中去,减少冲突的发生,另一个就是找到解决冲突的方法。 解决冲突的方法中比较常用的是链地址法,即为每一个哈希地址建立一个链表,当冲突发生时,将具有相同哈希地址的记录链接到同一链表中。

3、哈希算法的过程:首先得建立哈希表(一般都有从文件中读取吧?),其次才是查找。

4、完整代码示例:

#include<stdio.h>
#include<stdlib.h>struct keyNum
{int key;//关键字struct keyNum *next;
};struct keyNum*  hash[100];
struct keyNum*  insertHash(struct keyNum*, int m);//关键字插入链表
int searchHash(struct keyNum*, int m);//查找链表中是否存在值为m的整数
void print(struct keyNum*);//打印链表void main()
{printf("关键字列表请保存在data.txt文件中,其中第一个值为关键字的个数\n其他值为具体的关键字,各个关键字之间用空格隔开\n");int i, k, m, n, num, flag, l, j;FILE *p=NULL;struct keyNum *head = NULL;p = fopen("C:\\Users\\Horrobo\\Desktop\\data.txt", "r");if (p == NULL){printf("cannot open file 2.txt");exit(0);}fscanf(p, "%d", &num);//data.txt第一个值为关键字的个数,因此num读入的是关键字的个数,这里默认num小于100的for (i = 0; i<num; i++)//由于hash[]只有100个指针,因此关键字映射后最多只能有100个不相同的。hash[i] = NULL;for (i = 0; i<num; i++){   //fscanf()遇到空格停止读取?fscanf(p, "%d", &k);//获取关键字m = k % (num + 1);//计算得到关键字的哈希值hash[m] = insertHash(hash[m], k);//将关键字k插入到哈希值为m的链表中}printf("-----------------------------------------------\n请选择要进行的操作:\n1、打印采用链地址法得到的哈希表\n");printf("2、进行关键字查找\n3、退出\n------------------------------------------------\n");scanf("%d", &flag);while ((flag == 1) || (flag == 2)){if (flag == 1)//打印哈希表{printf("采用链地址法得到的哈希表为:\n");for (i = 0; i<num + 1; i++){printf("第%d行:", i);print(hash[i]);printf("\n");}}else //查找{printf("请输入要查找的整数值:\n");scanf("%d", &n);for (i = 0; i<num + 1; i++)//只是返回一个标志值,后面再根据标志来执行操作,这个流程值得参考哦{l = searchHash(hash[i], n);if (l == 1){j = i;break;}}if (l == 1)printf("整数值%d在哈希表中,位置为链表%d\n", n, j);//只是找出位于第几链表而已。else printf("整数值%d不在哈希表中!\n");}printf("-----------------------------------------------\n请选择要进行的操作:\n1、打印采用链地址法得到的哈希表\n");printf("2、进行关键字查找\n3、退出\n------------------------------------------------\n");scanf("%d", &flag);}
}struct keyNum * insertHash(struct keyNum*head, int m)
{struct keyNum *p0, *p1, *p2=NULL, *temp;//这些都仅仅是结构体指针,而不是结构体,它所指向的内容才是结构体内容。就把它理解为类型 int*指针就好temp = (struct keyNum*)malloc(sizeof(struct keyNum));temp->key = m;p1 = head;p0 = temp;//要插入的节点(值为m);if (head == NULL)//1,原来的链表为空,插入到head后{head = p0;p0->next = NULL;}else//原来的链表不为空{while ((p0->key>p1->key) && (p1->next != NULL))//移动到适当位置 起码有两个节点了,否则p1->next != NULL这个就不满足了。因为P1=head,是第一个节点的指针{//判断语句从head开始,查询链表(p1->next != NULL,p1=p1->next),看是否满足条件(p0->key>p1->key)                             p2 = p1;p1 = p1->next;}if (p0->key <= p1->key){if (head == p1)head = p0;//2,插入到第一个节点之前else p2->next = p0;//3,插入到p2指向的节点之后p0->next = p1;}else//4,插入到结尾处{p1->next = p0;p0->next = NULL;}}return(head);
}int searchHash(struct keyNum*head, int m)//查找链表head中是否存在m
{int k = 0;struct keyNum*p;p = head;if (head != NULL)do{if (p->key == m) //存在m{k = 1;break;}p = p->next;} while (p != NULL);return(k);//存在m值则返回1,否则返回0;
}void print(struct keyNum*head)//打印链表head
{struct keyNum*p;p = head;if (head != NULL){do{printf(" -> %d ", p->key);p = p->next;} while (p != NULL);}elseprintf("null");
}/*
struct keyNum * insertHash(struct keyNum*head, int k)//
{struct keyNum *p = (struct keyNum *)malloc(sizeof(struct keyNum));//1.首先开创一个结构体区间,给里面的相应内容赋值p->key = k;struct keyNum * temp = NULL;if (head == NULL)//2、判断是否是空指针,如果是,则将刚才创建的结构体区间作为头//具体的实现方法,就是将传过来的空指针指向刚才创建的结构体空间(yes){head = p;p->next = NULL;}else//如果不是,则在原来的链条的尾巴上添加新的节点(上面已经创建好的节点)//具体的实现方法,就是将head指针指向刚才所创建的结构体空间?(NO):head并不是指向尾巴节点的指针,而是整个链条的首指针!!!!{head->next = p;p->next = NULL;}return head;
}
*/

总结:

(1)顺序查找的查找效率很低;但是对于待查记录的存储结构没有任何要求,既适用于顺序存储,又适用于链式存储;当待查表中的记录个数较少时,采用顺序查找法较好。

(2)折半查找的平均查找长度较小,查找速度快;但它只能用于顺序存储,不能用于链式存储;且要求表中的记录是有序的。对于不常变动的有序表,采用折半查找法是较为理想的。

(3)分块查找的平均查找长度介于顺序查找和折半查找之间;跟顺序查找一样,对记录的存储结构没什么要求,既可以用于顺序存储,也可用于链式存储;要求表中元素是逐段有序的,即块与块之间的记录按关键字有序。当待查表的数据量较大时,分块查找的优越性更为突出。

(4)哈希法是一种直接计算地址的方法,通过对关键字值进行某种运算来确定待查记录的存储地址。在查找过程中不需要进行比较,因此,其查找时间与表中记录的个数无关。当所选择的哈希函数能得到均匀的地址分布时,其查找效率比前面的三种方法都要快。哈希法的查找效率取决于以下三个因素:哈希函数、处理冲突的方法及装填因子。

 

P.s.线性表包括顺序存储表(比如数组)、链式存储表(链表)。

另外在编程的过程中,也体会到了以下内容:指向结构体的指针P或者head,无论是通过赋值还是开创的空间的强制转换,head->next,p->next都是p结构体内next。




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

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

相关文章

一个C程序的编译过程(Linux环境下Gcc)

一 以下是C程序一般的编译过程&#xff1a; 从图中看到&#xff1a; 将编写的一个c程序&#xff08;源代码 &#xff09;转换成可以在硬件上运行的程序&#xff08;可执行代码 &#xff09;&#xff0c;需要进行编译阶段 和链接这两个阶段。 其中&#xff0c; 1. 编译阶段先通…

python3 django连接mysql 数据库

详情参考&#xff1a; https://blog.csdn.net/weixin_33127753/article/details/89100552 https://imshusheng.com/python/216.html 报错环境 python3.6&#xff0c;django2.2&#xff0c;PyMySQL0.9.3……django.core.exceptions.ImproperlyConfigured: mysqlclient 1.3.13 or…

redis 主从复制 [转]

一、Redis的Replication&#xff1a; 这里首先需要说明的是&#xff0c;在Redis中配置Master-Slave模式真是太简单了。相信在阅读完这篇Blog之后你也可以轻松做到。这里我们还是先列出一些理论性的知识&#xff0c;后面给出实际操作的案例。 下面的列表清楚的解释了Redis…

动态查找表之二叉搜索树

一、二叉搜索树&#xff08;BST&#xff09; 二叉搜索树&#xff08;二叉排序树&#xff09;定义如下&#xff1a; &#xff08;1&#xff09;一棵空树&#xff1b; &#xff08;2&#xff09;或者不是空树&#xff1a; 1&#xff09;若左子树不空&#xff0c;则左子树上所有…

Mysql数据导入导出

导出导入数据库导出mysqldump方法mysqldump -u用户名 -p密码名 database [table]> 目标文件导入mysql -uroot -prootuse databasesource 目标文件&#xff1b;PS: 这种方法是导出整个表数据&#xff0c;并且带着建表信息&#xff0c;假如导入的数据库有同名的表&#xff0c;…

2-10 就业课(2.0)-oozie:9、oozie与hue的整合,以及整合后执行MR任务

5、hue整合oozie 第一步&#xff1a;停止oozie与hue的进程 通过命令停止oozie与hue的进程&#xff0c;准备修改oozie与hue的配置文件 第二步&#xff1a;修改oozie的配置文件&#xff08;老版本的bug&#xff0c;新版本已经不需要了&#xff09;这一步我们都不需要做了 修改ooz…

Screen Painter 程序设计

一、Screen 的创建及维护, TCode:SE51 输入程序名称&#xff0c;单击【建立】&#xff0c; 程序1000为SAP预留屏幕号&#xff0c;屏幕号必须定义1000外的其他数字&#xff0c;且最多不超过四位&#xff0c; 本例定义屏幕为SAP预留屏幕号为&#xff1a;100 * 属性设置&#xff1…

完全图解VS2017安装过程并演示VS2017创建Linux项目和调试

VS2017个人免费版即社区官方下载地址为&#xff1a;https://download.microsoft.com/download/D/1/4/D142F7E7-4D7E-4F3B-A399-5BACA91EB569/vs_Community.exe 这是一个很小的在线下载安装器。VS2017安装变得人性化了&#xff0c;根据组件的分类&#xff0c;供安装用户选择&…

spring--打印hello--注解component--自动创建对象

1.创建 GroupId----项目目录&#xff08;com.javaspring&#xff09; Artifactid---项目名称(spring01qiuckstart) Version--版本默认 2.默认打开的pom.xml文件 编辑---编写spring核心项目依赖 <?xml version"1.0" encoding"UTF-8"?> <project …

菜鸟学数据库(四)——超键、候选键、主键、外键

这些年的一些经历告诉我&#xff0c;很多初学者搞不清超键、候选键等&#xff0c;被数据库中的各种键搞的一头雾水。下面就跟大家一起聊聊数据库中的那些键。 首先看看各种键的定义&#xff1a; 超键(super key):在关系中能唯一标识元组的属性集称为关系模式的超键 候选键(ca…

嵌入式C语言之struct内存分配分析

本文源于微信号《嵌入式ARM》。链接&#xff1a;http://mp.weixin.qq.com/s/j2mk6jY79nrJge2cDZVH_A 对结构MyStruct采用sizeof会出现什么结果呢&#xff1f;sizeof(MyStruct)为多少呢&#xff1f; 也许你会这样求&#xff1a;sizeof(MyStruct)sizeof(double)sizeof(char)sizeo…

open和fopen的区别

open和fopen的区别&#xff1a; 1.非缓冲文件系统缓冲文件系统是借助文件结构体指针来对文件进行管理&#xff0c;通过文件指针来对文件进行访问&#xff0c;既可以读写字符、字符串、格式化数据&#xff0c;也可以读写二进制数 据。非缓冲文件系统依赖于操作系统&#xff0c;通…

PostMessage发送字符串和结构体

2019独角兽企业重金招聘Python工程师标准>>> 1.首先定义消息变量 #define WM_POST_MSG WM_USER 2 2.增加消息处理函数 afx_msg LRESULT UpdateStatic(WPARAM wParam, LPARAM lParam); 3.增加消息映射 ON_MESSAGE(WM_POST_MSG,UpdateStatic) 当调用PostMessage函…

求一个数组的最长递减子序列 比如{9,4,3,2,5,4,3,2}的最长递减子序列为{9,5,4,3,2}...

目前想到的一个方法&#xff0c;就是用栈来寻找&#xff0c;说下思想&#xff1a;&#xff08;栈中的data为元素所在的位置&#xff0c;这意味着出栈和进栈的都是索引值&#xff0c;所以比较的时候根据索引找到其值后比较&#xff09; &#xff08;1&#xff09;栈为空&#xf…

SPI、I2C、UART(即串口)三种串行总线详解

以下内容均来源于网络资源的学习与整理&#xff0c;如有侵权请告知删除。 参考博客 几个串口协议学习整理 UART IIC SPI_mainn的博客-CSDN博客 SPI、I2C、UART三种串行总线的原理、区别及应用_嵌入式Linux,的博客-CSDN博客 RS-232 和 UART 之间有什么区别&#xff1f; - 知乎…

select()函数以及FD_ZERO、FD_SET、FD_CLR、FD_ISSET

从别人的博客中转载过来了这一篇文章&#xff0c;经过重新编辑排版之后展现于此&#xff0c;做一个知识点保存与学习。select函数用于在非阻塞中&#xff0c;当一个套接字或一组套接字有信号时通知你&#xff0c;系统提供select函数来实现多路复用输入/输出模型&#xff0c;原型…

网络4 交换机终端命令

1、switch> 是用户模式 en/enable switch# 是特权模式 conf t/ configure temral switch(config)#是全局模式 int f0/1 /interface f0/1 switch (config-if)# 是接口模式2、show version 显示系统ISO 名称ctrlE 把光标移动到命令行结尾处ctrlA 把光标移动…

解决Office系列安装不上的办法

安装Office时提示“扩展属性不一致”的解决办法&#xff1a;使用系统自带的输入法&#xff0c;Win空格键就搞定了。转载于:https://blog.51cto.com/dreamerhan/1313823

用数据辅助设计-搜索中的实践

设计时不能单凭经验和直觉&#xff0c;因为涉及到的目标人群、场景、操作习惯的不同。为了获取更准确、有效的信息去辅助、检测设计&#xff0c;设计师会选择定性&#xff08;用户访谈、焦点小组&#xff09;和定量&#xff08;调研问卷、网站数据分析&#xff09;的方式进行用…

在IBM服务器安装Windows server 2012的心得

一个简单的问题被我搞复杂了&#xff01; 前些日子&#xff0c;由于连接服务器时卡顿、没有反应&#xff0c;我把服务器强制重启了&#xff0c;之后很不幸地&#xff0c;系统开机进入界面后&#xff0c;不断地转圈圈&#xff0c;一段时间后提示“你的电脑遇到问题&#xff0c;…