学会二分查找

我们走进了一家餐厅,找了空桌子坐下,服务员过来递给我们一本菜单。

枇伊:“这家餐厅有一道菜价格17元,特别好吃,你帮我找一找吧。”

我刚要翻开菜单,她马上叫住了我,说到:“这家餐厅的菜单有一个特点,每页有一道菜,价格是递增的,后一页菜的价格一定比前一页贵,每页侧面都有一个突出的标签标明了页数,你试试能不能尽快的找出那道菜。”

我:“没问题交给我吧。(这人好无聊啊,吃个饭还要考我一下二分查找)”。

怎么做二分查找呢

一.基本思想

面对有序的n个数时,要在其中查找出一个数x时,最容易想到的办法是从头到尾遍历,遇到值为x的则输出。如果要查找的x在第一位,马上就可以查找出来;但要查找的x在最后一位,那就需要遍历全部n个数。有没有效率更高的算法呢?当然有,这就是二分查找。首先我们要利用n个数有序的这个性质,假定顺序为升序,并存放在数组Array[]中。取这一组数的查找范围的上边界为low,初值为low=0;查找范围的下边界为high,初值为high=n-1;中间数下标mid=(low+high)/2,若Array[mid]=x,则可以直接输出或返回。若Array[mid]>x,依据升序的原则可以判断出x在前半部分,令high=mid-1。若Array[mid]<x,依据升序的原则可以判断出x在后半部分,令low=mid+1。之后在前半部分或后半部分继续用该思想查找,直到找到目标数。

以故事中的菜单为例,把菜单中各道菜的价格按序放到数组中,查找范围的上边界为low,下边界为high。每次查找的中间值下标为mid,查找的数x=17。

  1. 第一次查找
    在这里插入图片描述
  2. 第二次查找
    在这里插入图片描述
    这时我们发现Array[mid]=x=17,仅仅只是查找了两次就找到了这道菜,如果用从头到尾遍历的方法,需要找五次,而且随着元素数量的增加,二分查找的高效率会反映的更明显。

有人可能会问了,要是查找的数在第一个,那二分查找法的效率就比不上遍历法了。确实,查找的数在第一个的话,那么遍历只要找一次就够了,但是在实际应用时,绝大多数情况还是要查找位于中间的数,在首位的情况只是特例。

当然,这种算法也有不足之处。它只能对有序数列进行查找,对无序数列不能使用这种算法。

二.代码

二分查找有两种实现形式:递归形式和非递归形式。

用两种语言表示程序,递归程序使用C++,非递归程序使用java

递归形式

#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
int binarysearch(int Array[], int x, int low, int high)
{
	if (low > high)return -1;//Returns -1 if the element is not found
	int mid = (low + high)/2;
	if (Array[mid] == x)//Find the element
	{
		return mid;//return 
	}
	else if (Array[mid] > x)//The number found is greater than the target
	{
		return binarysearch(Array, x, low, mid - 1);//Look for the first half
	}
	else//The number found is less than the target
	{
		return binarysearch(Array, x, mid+1, high);//Look for the second half
	}
}
int main()
{
	int Array[1000];
	int n,x;
	scanf("%d", &n);
	for (int i = 0;i < n;i++)
		scanf("%d", &Array[i]);
	scanf("%d", &x);
	sort(Array,Array+n);
	int flag = binarysearch(Array, x, 0, n - 1);
	if (flag == -1)printf("此数不存在\n");
	else printf("此数排序后在第%d个位置", flag + 1);
	return 0;
}

非递归形式

import java.util.Arrays;
import java.util.Scanner;

public class Search {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int[] Array1=new int[n];
        for(int i=0;i<n;i++){
            Array1[i]=sc.nextInt();
        }
        Arrays.sort(Array1);
        int x=sc.nextInt();
        int flag=binarysearch(Array1,x,0,n-1);
        if(flag==-1){
            System.out.println("此数不存在");
        }else{
            System.out.printf("此数排序后在第%d个位置",flag+1);
        }
    }
    private static int binarysearch(int[] Array1,int x,int low,int high){
        while(low<=high){
            int mid=(low+high)/2;
            if(Array1[mid]==x){//Find the element
                return mid;//return
            }else if(Array1[mid]>x){//The number found is greater than the target
                high=mid-1;//Look for the first half
            }else{//The number found is less than the target
                low=mid+1;//Look for the second half
            }
        }
        return -1;//Returns -1 if the element is not found
    }
}

此号从这篇文章开始正式更名为【堆栈树图】(这个名字感觉更接近发布文章的主题),公众号也改成此名,如果发布的文章对您有所帮助,欢迎关注公众号–【堆栈树图】,阅读更多类似文章。如果文章中有不足之处,也欢迎批评指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值