位置: 编程技术 - 正文

详解常用查找数据结构及算法(Python实现)(查找的算法有哪些)

编辑:rootadmin

推荐整理分享详解常用查找数据结构及算法(Python实现)(查找的算法有哪些),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:查找个数,什么是查找值,数据值,查找值怎么使用,常用查找方法,常用查找函数有哪些,常用查找函数有哪些,常用查找函数有哪些,常用查找函数有哪些,内容如对您有帮助,希望把文章链接给更多的朋友!

一、基本概念

查找(Searching)就是根据给定的某个值,在查找表中确定一个其关键字等于给定值的数据元素(或记录)。

查找表(Search Table):由同一类型的数据元素(或记录)构成的集合

关键字(Key):数据元素中某个数据项的值,又称为键值。

主键(Primary Key):可唯一地标识某个数据元素或记录的关键字。

查找表按照操作方式可分为:

静态查找表(Static Search Table):只做查找操作的查找表。它的主要操作是: 查询某个“特定的”数据元素是否在表中 检索某个“特定的”数据元素和各种属性 动态查找表(Dynamic Search Table):在查找中同时进行插入或删除等操作: 查找时插入数据 查找时删除数据

二、无序表查找

也就是数据不排序的线性查找,遍历数据元素。

算法分析:最好情况是在第一个位置就找到了,此为O(1);最坏情况在最后一个位置才找到,此为O(n);所以平均查找次数为(n+1)/2。最终时间复杂度为O(n)

三、有序表查找

查找表中的数据必须按某个主键进行某种排序!

1. 二分查找(Binary Search)

算法核心:在查找表中不断取中间元素与查找值进行比较,以二分之一的倍率进行表范围的缩小。

2. 插值查找

二分查找法虽然已经很不错了,但还有可以优化的地方。

有的时候,对半过滤还不够狠,要是每次都排除十分之九的数据岂不是更好?选择这个值就是关键问题,插值的意义就是:以更快的速度进行缩减。

插值的核心就是使用公式:

value = (key - list[low])/(list[high] - list[low])

用这个value来代替二分查找中的1/2。

上面的代码可以直接使用,只需要改一句。

插值算法的总体时间复杂度仍然属于O(log(n))级别的。其优点是,对于表内数据量较大,且关键字分布比较均匀的查找表,使用插值算法的平均性能比二分查找要好得多。反之,对于分布极端不均匀的数据,则不适合使用插值算法。

3. 斐波那契查找

由插值算法带来的启发,发明了斐波那契算法。其核心也是如何优化那个缩减速率,使得查找次数尽量降低。

使用这种算法,前提是已经有一个包含斐波那契数据的列表

F = [1, 1, 2, 3, 5, 8, , , , , , ,...]

算法分析:斐波那契查找的整体时间复杂度也为O(log(n))。但就平均性能,要优于二分查找。但是在最坏情况下,比如这里如果key为1,则始终处于左侧半区查找,此时其效率要低于二分查找。

总结:二分查找的mid运算是加法与除法,插值查找则是复杂的四则运算,而斐波那契查找只是最简单的加减运算。在海量数据的查找中,这种细微的差别可能会影响最终的查找效率。因此,三种有序表的查找方法本质上是分割点的选择不同,各有优劣,应根据实际情况进行选择。

四、线性索引查找

对于海量的无序数据,为了提高查找速度,一般会为其构造索引表。

索引就是把一个关键字与它相对应的记录进行关联的过程。

一个索引由若干个索引项构成,每个索引项至少包含关键字和其对应的记录在存储器中的位置等信息。

索引按照结构可以分为:线性索引、树形索引和多级索引。

线性索引:将索引项的集合通过线性结构来组织,也叫索引表。

线性索引可分为:稠密索引、分块索引和倒排索引

1.稠密索引

稠密索引指的是在线性索引中,为数据集合中的每个记录都建立一个索引项。

这其实就相当于给无序的集合,建立了一张有序的线性表。其索引项一定是按照关键码进行有序的排列。

这也相当于把查找过程中需要的排序工作给提前做了。

1.分块索引

给大量的无序数据集合进行分块处理,使得块内无序,块与块之间有序。

这其实是有序查找和无序查找的一种中间状态或者说妥协状态。因为数据量过大,建立完整的稠密索引耗时耗力,占用资源过多;但如果不做任何排序或者索引,那么遍历的查找也无法接受,只能折中,做一定程度的排序或索引。

分块索引的效率比遍历查找的O(n)要高一些,但与二分查找的O(logn)还是要差不少。

1.倒排索引

不是由记录来确定属性值,而是由属性值来确定记录的位置,这种被称为倒排索引。其中记录号表存储具有相同次关键字的所有记录的地址或引用(可以是指向记录的指针或该记录的主关键字)。

倒排索引是最基础的搜索引擎索引技术。

五、二叉排序树

二叉排序树又称为二叉查找树。它或者是一颗空树,或者是具有下列性质的二叉树:

若它的左子树不为空,则左子树上所有节点的值均小于它的根结构的值; 若它的右子树不为空,则右子树上所有节点的值均大于它的根结构的值; 它的左、右子树也分别为二叉排序树。

构造一颗二叉排序树的目的,往往不是为了排序,而是为了提高查找和插入删除关键字的速度。

二叉排序树的操作:

1.查找:对比节点的值和关键字,相等则表明找到了;小了则往节点的左子树去找,大了则往右子树去找,这么递归下去,最后返回布尔值或找到的节点。

2.插入:从根节点开始逐个与关键字进行对比,小了去左边,大了去右边,碰到子树为空的情况就将新的节点链接。

3.删除:如果要删除的节点是叶子,直接删;如果只有左子树或只有右子树,则删除节点后,将子树链接到父节点即可;如果同时有左右子树,则可以将二叉排序树进行中序遍历,取将要被删除的节点的前驱或者后继节点替代这个被删除的节点的位置。

二叉排序树总结:

二叉排序树以链式进行存储,保持了链接结构在插入和删除操作上的优点。 在极端情况下,查询次数为1,但最大操作次数不会超过树的深度。也就是说,二叉排序树的查找性能取决于二叉排序树的形状,也就引申出了后面的平衡二叉树。 给定一个元素集合,可以构造不同的二叉排序树,当它同时是一个完全二叉树的时候,查找的时间复杂度为O(log(n)),近似于二分查找。 当出现最极端的斜树时,其时间复杂度为O(n),等同于顺序查找,效果最差。

六、 平衡二叉树

平衡二叉树(AVL树,发明者的姓名缩写):一种高度平衡的排序二叉树,其每一个节点的左子树和右子树的高度差最多等于1。

平衡二叉树首先必须是一棵二叉排序树!

平衡因子(Balance Factor):将二叉树上节点的左子树深度减去右子树深度的值。

对于平衡二叉树所有包括分支节点和叶节点的平衡因子只可能是-1,0和1,只要有一个节点的因子不在这三个值之内,该二叉树就是不平衡的。

最小不平衡子树:距离插入结点最近的,且平衡因子的绝对值大于1的节点为根的子树。

平衡二叉树的构建思想:每当插入一个新结点时,先检查是否破坏了树的平衡性,若有,找出最小不平衡子树。在保持二叉排序树特性的前提下,调整最小不平衡子树中各结点之间的连接关系,进行相应的旋转,成为新的平衡子树。

下面是由[1,2,3,4,5,6,7,,9]构建平衡二叉树

七、多路查找树(B树)

多路查找树(muitl-way search tree):其每一个节点的孩子可以多于两个,且每一个结点处可以存储多个元素。 对于多路查找树,每个节点可以存储多少个元素,以及它的孩子数的多少是关键,常用的有这4种形式:2-3树、2-3-4树、B树和B+树。

2-3树

2-3树:每个结点都具有2个孩子,或者3个孩子,或者没有孩子。

详解常用查找数据结构及算法(Python实现)(查找的算法有哪些)

一个2结点包含一个元素和两个孩子(或者没有孩子,不能只有一个孩子)。与二叉排序树类似,其左子树包含的元素都小于该元素,右子树包含的元素都大于该元素。

一个3结点包含两个元素和三个孩子(或者没有孩子,不能只有一个或两个孩子)。

2-3树中所有的叶子都必须在同一层次上。

其插入操作如下:

其删除操作如下:

2-3-4树

其实就是2-3树的扩展,包括了4结点的使用。一个4结点包含小中大三个元素和四个孩子(或没有孩子)。

其插入操作:

其删除操作:

B树

B树是一种平衡的多路查找树。节点最大的孩子数目称为B树的阶(order)。2-3树是3阶B树,2-3-4是4阶B树。

B树的数据结构主要用在内存和外部存储器的数据交互中。

B+树

为了解决B树的所有元素遍历等基本问题,在原有的结构基础上,加入新的元素组织方式后,形成了B+树。

B+树是应文件系统所需而出现的一种B树的变形树,严格意义上将,它已经不是最基本的树了。

B+树中,出现在分支节点中的元素会被当做他们在该分支节点位置的中序后继者(叶子节点)中再次列出。另外,每一个叶子节点都会保存一个指向后一叶子节点的指针。

所有的叶子节点包含全部的关键字的信息,及相关指针,叶子节点本身依关键字的大小自小到大顺序链接

B+树的结构特别适合带有范围的查找。比如查找年龄在~岁之间的人。

八、散列表(哈希表)

散列表:所有的元素之间没有任何关系。元素的存储位置,是利用元素的关键字通过某个函数直接计算出来的。这个一一对应的关系函数称为散列函数或Hash函数。

采用散列技术将记录存储在一块连续的存储空间中,称为散列表或哈希表(Hash Table)。关键字对应的存储位置,称为散列地址。

散列表是一种面向查找的存储结构。它最适合求解的问题是查找与给定值相等的记录。但是对于某个关键字能对应很多记录的情况就不适用,比如查找所有的“男”性。也不适合范围查找,比如查找年龄~之间的人。排序、最大、最小等也不合适。

因此,散列表通常用于关键字不重复的数据结构。比如python的字典数据类型。

设计出一个简单、均匀、存储利用率高的散列函数是散列技术中最关键的问题。

但是,一般散列函数都面临着冲突的问题。

冲突:两个不同的关键字,通过散列函数计算后结果却相同的现象。collision。

8.1 散列函数的构造方法

好的散列函数:计算简单、散列地址分布均匀

1.直接定址法

例如取关键字的某个线性函数为散列函数:

f(key) = a*key + b (a,b为常数)

2.数字分析法

抽取关键字里的数字,根据数字的特点进行地址分配

3.平方取中法

将关键字的数字求平方,再截取部分

4.折叠法

将关键字的数字分割后分别计算,再合并计算,一种玩弄数字的手段。

5.除留余数法

最为常见的方法之一。

对于表长为m的数据集合,散列公式为:

f(key) = key mod p (p<=m)

mod:取模(求余数)

该方法最关键的是p的选择,而且数据量较大的时候,冲突是必然的。一般会选择接近m的质数。

6.随机数法

选择一个随机数,取关键字的随机函数值为它的散列地址。

f(key) = random(key)

总结,实际情况下根据不同的数据特性采用不同的散列方法,考虑下面一些主要问题:

计算散列地址所需的时间 关键字的长度 散列表的大小 关键字的分布情况 记录查找的频率

8.2 处理散列冲突

1、开放定址法

就是一旦发生冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将记录存入。

公式是:

这种简单的冲突解决办法被称为线性探测,无非就是自家的坑被占了,就逐个拜访后面的坑,有空的就进,也不管这个坑是不是后面有人预定了的。

线性探测带来的最大问题就是冲突的堆积,你把别人预定的坑占了,别人也就要像你一样去找坑。

改进的办法有二次方探测法和随机数探测法。

2、再散列函数法

发生冲突时就换一个散列函数计算,总会有一个可以把冲突解决掉,它能够使得关键字不产生聚集,但相应地增加了计算的时间。

3、链接地址法 碰到冲突时,不更换地址,而是将所有关键字为同义词的记录存储在一个链表里,在散列表中只存储同义词子表的头指针,如下图:

这样的好处是,不怕冲突多;缺点是降低了散列结构的随机存储性能。本质是用单链表结构辅助散列结构的不足。

4、公共溢出区法

其实就是为所有的冲突,额外开辟一块存储空间。如果相对基本表而言,冲突的数据很少的时候,使用这种方法比较合适。

8.3 散列表查找实现

下面是一段简单的实现代码:

8.4 散列表查找性能分析

如果没发生冲突,则其查找时间复杂度为O(1),属于最极端的好了。

但是,现实中冲突可不可避免的,下面三个方面对查找性能影响较大:

散列函数是否均匀 处理冲突的办法 散列表的装填因子(表内数据装满的程度)

标签: 查找的算法有哪些

本文链接地址:https://www.jiuchutong.com/biancheng/382428.html 转载请保留说明!

上一篇:详解Python装饰器由浅入深

下一篇:浅谈Python类里的__init__方法函数,Python类的构造函数(python 类的用法)

  • 企业中秋晚会活动方案
  • 去年所得税汇算清缴补所得税
  • 材料抵扣货款怎么写简单协议范本
  • 研发设备定义
  • 公司内部个人股份怎么算
  • 固定资产可以一次性摊销吗
  • 在分公司签的合同能转到总公司吗
  • 到期一次还本付息的债券投资摊余成本
  • 茶叶自产自销成本核算
  • 2019年大写二o一九
  • 工会经费2019年新政策
  • 资助的开发经费可税前扣除吗
  • 房屋出租需要缴纳个人所得税吗
  • 所得税汇算清缴退税会计分录怎么做
  • 小规模企业有了增值税吗
  • 库存商品内部划转怎么做账?
  • 包装物押金会计分录怎么做
  • 员工借款怎么入账
  • 购入材料用什么科目
  • 用友薪资管理怎么重新初始化步骤
  • 外购摩托车从销项税额中怎么抵扣?
  • 税收滞纳金算不算所得税
  • 迁移税务需要带什么资料
  • 税号里的字母是什么
  • 开发票与实际金额不符属于什么
  • 企业筹办期多久
  • 企业可以采用在产品按固定成本计算法的有
  • 主营业务成本会计科目使用说明
  • 金税盘需要报税吗
  • 股票股利和现金股利的共同点
  • 疫情期间企业贷款利率多少
  • 复制粘贴快捷键失效了怎么回事
  • 正常运行英文
  • 内置管理员无法激活
  • 计算土地增值税时增值额的扣除项目包括
  • 补缴增值税和滞纳税区别
  • php is_writable
  • 委托加工的加工费是含税的吗
  • 个体工商户筹集资金的难易程度
  • 多品种生产能力计算公式
  • macos安装多版macos并存
  • 基于web的网站设计与实现
  • vue前端开发常见问题
  • 做了几年前端基础还是很差
  • php oauth2 单点登录
  • 会展中心高新技术展览
  • 酒店业营业税税率
  • 以前年度漏记收入
  • 筹建期的费用计入什么科目
  • 扣税免除项
  • 税控发票如何入账
  • sql递减
  • 个税专项附加扣除标准调整
  • 解决问题
  • 申报前的增值税怎么算
  • 预留印鉴章是什么章
  • 固定资产基本特点
  • 旅客运输进项抵扣加计扣除怎么算
  • 多计提的工资怎么冲销
  • 农业项目土地流转
  • 没有对公业务的银行
  • 跨年材料票可以入账吗
  • 分公司可以设立公司吗
  • mysql数据库类型有哪些?如何选择合适的数据类型
  • 使用筷子就餐会不会传染乙肝病毒
  • MySQL利用视图查询员工进货数量要求输出姓名进货数量
  • win10双击打开文件设置方法
  • winxp虚拟内存怎么改
  • centos简易安装
  • win8功能大全介绍
  • windows10预览版是什么
  • list在python中的作用
  • node.js 的适用场景?
  • Drag and drop in unity
  • unity火球特效
  • jquery 通过name获取元素
  • 广东省地税局局长 吴
  • 地税登记序号查询系统
  • 小规模纳税季度申报
  • 农产品进项税额核定扣除办法
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设