博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
有序表查找
阅读量:3733 次
发布时间:2019-05-22

本文共 2913 字,大约阅读时间需要 9 分钟。

有序表的定义

        有序表:对于以数组方式存储的数据,如果已经按其关键字值的大小顺序排列好,则称为有序数组或有序表。因此,使用有序表查找的前提是线性表中的记录必须是关键码有序(通常从小到大有序),线性表必须采用顺序存储

折半查找

        折半查找(Binary Search):又称二分查找。 
折半查找的基本思想是:
  • 在有序表中,取中间记录作为比较对象,若给定值与中间记录的关键字相等,则查找成功;
  • 若给定值小于中间记录的关键字,则在中间记录的左半区继续查找;
  • 若给定值大于中间记录的关键字,则在中间记录的右半区继续查找;
  • 不断重复上述过程,直到查找成功,或所查区域无记录,查找失败为止。
int Binary_Search(int *a,int n,int key)//n为元素最高下标而不是数组长度{    int low,mid,high;    low = 0;           //最低下标    high = n;          //最高下标    mid = (low + high) / 2;//折半    while(low <= high)    {        if(key < a[mid])            high = mid - 1;        else if(key >a[mid])            low = mid + 1;        else            return mid;    }     return 0;}//使用该算法的前提是:顺序存储及元素有序

        已知具有n个结点的完全二叉树的深度为[log2n]+1(括号表示不大于x的最大整数)。尽管折半查找判定二叉树并不是完全二叉树,但同样的推导可以得出,该算法的最坏情况是查找到关键字或者查找失败的次数为[log2n]+1。因此该算法的平均时间复杂度为O(logn)。

int Binary_Search(int a[], int value, int low, int high){//递归版本    int mid = low+(high-low)/2;    if(a[mid]==value)        return mid;    if(a[mid]>value)        return Binary_Search(a, value, low, mid-1);    if(a[mid]

        折半查找适用于静态查找表。而对于经常需要执行插入和删除操作的数据集来说,维护有序的排序付出的代价太高,不建议使用。

插值查找

     
  插值查找( Interpolation Search)是根据要查找的关键字key与查找表中最大最小记录的关键字比较后的有序表查找算法,其核心就在于插值的计算公式(key-a[low])/(a[high]-a[low])。对于折半查找我们可知,它始终从中间位置开始查找,而插值查找即在这一点上进行了改进,它根据离所求值的距离进行搜索的。具体实现过程如下:
        二分查找中折半操作为mid = (low+high) / 2;对其进行略微变形为 mid = low + 1/2(high - low);这里即是考虑对这个1/2进行改进。
即将1/2改为(key-a[low])/(a[high]-a[low])。这样做的好处是缩短了到目标关键字的距离,也相应地缩短了查找所需次数。
        它的时间复杂度也为O(logn),但同时需要注意的是,对于表长较大,而关键字分布又比较均匀的查找表来说,插值查找算法的平均性能比折半查找要好很多。而对于数组中分布着类似{0,1,2,3000,3001.....999998,999999}这种极端不均匀的数据,插值查找不适合于这样的情况。
/* 插值查找 */int Interpolation_Search(int *a,int n,int key){	int low,high,mid;	low=1;	/* 定义最低下标为记录首位 */	high=n;	/* 定义最高下标为记录末位 */	while(low<=high)	{		mid=low+ (high-low)*(key-a[low])/(a[high]-a[low]); /* 插值 */		if (key
a[mid])/* 若查找值比插值大 */ low=mid+1; /* 最低下标调整到插值下标大一位 */ else return mid; /* 若相等则说明mid即为查找到的位置 */ } return 0;}

斐波那契查找

        
                                   

        斐波那契查找算法的核心在于:

  • 当key为a[mid]时,查找成功。
  • 当key < a[mid]时,新范围为下标low到mid-1,即此时范围个数为F[k-1]-1个。
  • 当key > a[mid]时,新范围为下标mid+1到high,即此时范围个数为F[k-2]-1个。

const int max_size=20;//斐波那契数组的长度/*构造一个斐波那契数组*/ void Fibonacci(int * F){    F[0]=0;    F[1]=1;    for(int i=2;i
F[k]-1)//计算n位于斐波那契数列的位置 ++k; int * temp;//将数组a扩展到F[k]-1的长度 temp=new int [F[k]-1];//必须满足条件n>F[k]-1。 memcpy(temp,a,n*sizeof(int));//即如果待排序数组的长度等于斐波那契数据项的值,那么一定会使将数组填充到斐波那契下一个数据项的有值长度。  for(int i=n;i
temp[mid]) { low=mid+1; k-=2; } else { if(mid
=n则说明是扩展的数值,返回n-1 } } delete [] temp; return -1;}
       斐波那契查找的思想本质上就是采用黄金分割的方法来选择分割点,其平均时间复杂度为O(logn)。但就平均性能来说,斐波那契查找要优于折半查找。但如果是最坏情况即始终在一边查找,那么它的查找效率要低于折半查找。

小结

        折半查找是进行加法和除法运算(mid = (low+high)/ 2),而插值查找采用复杂的四则运算(mid = low+(high - low)*(key - a[low])/ (a[high] - a[low])),斐波那契查找只是最简单的加减运算(mid = low + F[k-1]-1),在海量的数据查找情况下,这些细微的差别可能会影响查找性能。最后,我们可以知道,
上面三种有序表的查找本质上是分割点的选择不同,分别适合于不同特定场景。
        参考书籍 《大话数据结构》
你可能感兴趣的文章
Java集合 ArrayList原理
查看>>
Git的基本操作
查看>>
简述128陷阱
查看>>
spring boot中thymeleaf配置说明
查看>>
在spring boot项目中修改包名要注意的一些问题
查看>>
编写类实现从后台向前台返回所要求的数据
查看>>
spring boot的学习(1.创建一个初始的spring boot项目)
查看>>
Python的入门学习
查看>>
⑤mpvue 小程序框架 :初始化项目 分析项目结构
查看>>
⑦mpvue Flyio实现前后台交互
查看>>
⑫HTML5与之前HTML的区别
查看>>
操作系统:Java模拟CPU调度算法(非抢占短进程优先、可抢占优先权调度、多级反馈队列调度)
查看>>
【前端】在页面中还原英雄联盟客户端?
查看>>
【前端】HTML+CSS 纯干货 基础知识分享!
查看>>
【前端】JavaScript 纯干货 基础知识分享!
查看>>
【前端】jQuery 纯干货 基础知识分享!
查看>>
【前端】Vue 纯干货 基础知识分享!
查看>>
3.1servlet入门和MVC模型
查看>>
3.2servlet功能和会话技术
查看>>
3.3servlet三大作用域
查看>>