查找算法(折半查找)

提示:折半查找在考试和面试可能性高


加粗样式

一、折半查找原理

折半查找(二分查找):只适用于有序(升序或降序)的顺序表。不能用于链表。

理解二分查找:

下图中有一个升序表,假设我需要查找元素35,我如何实现折半查找;
在这里插入图片描述
设置low,mid,high三个指针分别指向:
low指向顺序表第一个元素; 作为每次二分查找左边界的标志;
high指向顺序表顺序表最后一个元素;作为每次二分查找右边界的标志;
mid指向low和high中间的元素;作为每次和待查找的元素比较的标志;

此时low=0; high=10; mid=(low+high)/2=5;
第一轮查找,直接比较mid指针(下标为5)所指的元素(25) 和 待查找的元素35,发现 25<35,
由此可知,待查找元素35应该在mid指针的右侧,即下图中红色区域内;
在这里插入图片描述
我们已知low为左边界的标志,我们此时要查找的元素可能在红色区域内,而此时我们的low指针在红色区域之外,所以此时我们需要缩小查找范围,使得low指针在红色区域之内,我们将low指向mid+1,因为mid已经比较过了,不符合,所以可以直接将low=mid+1,然后进行第二轮查找;图片如下所示:
此时low=mid+1=6; high=10;
mid=(low+high)/2=8;
在这里插入图片描述

第二轮查找,比较mid指针(下标为8)所指的元素(38) 和 待查找的元素35,发现 38>35,
由此可知,待查找元素35应该在mid指针的左侧,即下图中绿色区域内;
在这里插入图片描述

我们已知high为右边界的标志,我们此时要查找的元素可能在绿色区域内,而此时我们的high指针在绿区域之外,所以此时我们需要缩小查找范围,使得high指针在绿色区域之内,我们将high指向high-1,因为mid已经比较过了,不符合,所以可以直接将high=mid-1,然后进行第三轮查找;图片如下所示:
此时low=6; high=mid-1=7;
mid=(low+high)/2=6;
在这里插入图片描述
第三轮查找,比较mid指针(下标为6)所指的元素(30) 和 待查找的元素35,发现 30<35,
由此可知,待查找元素35应该在mid指针的右侧,即下图中紫色区域内;
在这里插入图片描述
我们已知low为左边界的标志,我们此时要查找的元素可能在红色区域内,而此时我们的low指针在红色区域之外,所以此时我们需要缩小查找范围,使得low指针在紫色区域之内,我们将low指向mid+1,因为mid已经比较过了,不符合,所以可以直接将low=mid+1,然后进行第二轮查找;图片如下所示:
此时low=mid+1=7; high=7;
mid=(low+high)/2=7;
在这里插入图片描述

第四轮查找,比较mid指针(下标为7)所指的元素(35) 和 待查找的元素35,发现 相等,
由此可知,待查找元素35的下标为7,此位置即为寻找位置;

那么我如果我查找的元素是34呢,前三轮比较和上面的步骤一致,在进行第四轮查找时,
比较mid指针(下标为7)所指的元素(35) 和 待查找的元素34,发现 35>34,
由此可知,待查找元素34应该在mid指针的左侧,那么high的值将变为high=mid-1=6;
此时low=7,high=6,左边界大于右边界时,说明查找失败,顺序表中不存在该元素;

代码实现

通过上面的解释,我们很容易就可以写出实现的代码,
第一种方法用循环实现每一轮比较,
循环结束的条件就是找到元素,返回元素位置;亦或者是low>high(左边界大于有边界),查找失败;

第二种方法是递归实现;代码如下。自行查看即可;

/*
 * 程序名:binsearch.c,此程序演示折半查找。
 * 作者:C语言技术网(www.freecplus.net) 日期:20210325
*/
#include <stdio.h>
#include <string.h>

// 迭代实现。
// 在sstable中查找key,失败返回-1,成功返回key在sstable中的数组下标。
int Bin_Search1(int *sstable,unsigned int len,int key)
{
  int low,high,mid;
  low=0; high=len-1;    // 初始化low和high的值,设置初始区间。

  while (low<=high)
  {
    mid=(low+high)/2;   // 计算mid的值,取中间位置。

    if (sstable[mid]==key) return mid;     // 找到了待查找的元素。
    else if (sstable[mid]>key) high=mid-1; // 继续在前半区间进行查找。
    else low=mid+1;                        // 继续在后半区间进行查找。
  }

  return -1;
}

// 递归实现。
// 在sstable中查找key,失败返回-1,成功返回key在sstable中的数组下标。
int Bin_Search2(int *sstable,int key,int low,int high)
{
  if (low>high) return -1;  

  int mid=(low+high)/2;   // 计算mid的值,取中间位置。

  if (sstable[mid]==key) return mid;         // 找到了待查找的元素。
  else if (sstable[mid]>key) Bin_Search2(sstable,key,low,mid-1); // 继续在前半区间进行查找。
  else Bin_Search2(sstable,key,mid+1,high);  // 继续在后半区间进行查找。
}

int main()
{
  // 有序的顺序表。
  int sstable1[]={1,2,3,4,5,6,7,8,9,12};
  int len=sizeof(sstable1)/sizeof(int);

  // 迭代
  printf("result1=%d\n",Bin_Search1(sstable1,len,0));
  printf("result1=%d\n",Bin_Search1(sstable1,len,1));
  printf("result1=%d\n",Bin_Search1(sstable1,len,7));
  printf("result1=%d\n",Bin_Search1(sstable1,len,10));
  printf("result1=%d\n",Bin_Search1(sstable1,len,12));
  printf("result1=%d\n",Bin_Search1(sstable1,len,15));
  printf("\n");

  // 递归
  printf("result2=%d\n",Bin_Search2(sstable1, 0,0,len-1));
  printf("result2=%d\n",Bin_Search2(sstable1, 1,0,len-1));
  printf("result2=%d\n",Bin_Search2(sstable1, 7,0,len-1));
  printf("result2=%d\n",Bin_Search2(sstable1,10,0,len-1));
  printf("result2=%d\n",Bin_Search2(sstable1,12,0,len-1));
  printf("result2=%d\n",Bin_Search2(sstable1,15,0,len-1));

  return 0;
}

折半查找-效率分析

如何获取折半查找的判定树:
在这里插入图片描述
查找判定树的性质:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值