二分查找/排序 C语言实现算法解析

一、二分查找算法介绍

 1、二分查找简介

        二分查找(Binary search)也称折半查找,当我们需要在一个有序序列中寻找一个元素,我们很快就能想到按序查找的方法--顺序查找法(即从前往后寻找),但使用顺序查找法时,当有序序列中的元素较多,需要查找的元素处于序列的后端,这样查找起来就会费时费力, 这时二分查找就是一种简单且效率高的查找元素的方法

2、 二分查找的本质

        很多人认为二分查找的本质是单调性,但其实不是,二分查找与单调性的关系:单调性的序列一定可以使用二分查找,而能使用二分查找的序列不一定满足单调性

        二分查找的本质其实是边界性,即判断所要寻找的元素在哪个满足条件的区域,直到区域内的元素 = 所要寻找的元素

 确定所要查找的元素k,寻找这个序列的中间值mid

       

 区分元素k所在的区域

3、 二分查找的基本思路

        确定序列的中间值mid,将 mid 与将要寻找的元素 k 进行比较,如果 mid<k ,说明 k 处于序列中间值 mid 的右侧。反之,如果 mid>k ,则元素 k 处于 mid 的左侧,这时我们就能缩小寻找的范围。当寻找的范围改变时,重新计算新范围的中间值 mid,再与元素 k 进行比较,找到 k 处于新的区域,以此类推下去,直到找到元素k在序列中所处的位置。

        在进行二分查找时,假如我们需要查找的序列元素为2^32个,那我们所需要查找的次数最多为32次(即每次对于区域范围进行/2缩小处理),使用顺序查找时,我们需要查找的次数最多为4,294,967,296次!

        当只需要查找一次时,时间复杂度为O(1),当需要查找的次数为32次时(假设查找的元素为2^32个),时间复杂度为O(\log n)。

以下为二分查找的演示:

                                                                  ↓ 要查找的元素k

0         1         2         3         4         5         6         7         8         9

                                                                                                           确定mid


                                            mid             ↓k 

0         1         2         3                 5         6         7         8         9     

                                                                                                  mid<k  区域更新为mid的右侧


                                k         mid                                                           

                 5             6            7             8              9                   mid>k   区域更新为mid的左侧


                                 ↓ mid           ↓k 

                                 5                  6                                           mid<k  区域更新为mid的右侧


                                ↓ mid 

                                                                                               mid=k  找到所要寻找的元素

                                ↑k

二、二分查找算法代码解析 

1,建立一个单调性的序列或数组

int main()
{
	//创建一个存放int类型数据的数组
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[20] = { -3,-1,0,2,5,7,8,9,10,15,15 };
	int arr3[20] = { 10,9,8,7,6,5,4,3,2,1 };
	return 0;
}

创建的数组/序列只要满足单调性即可,即不必按照+1的顺序进行排序。

2,计算数组/序列的长度

int main()
{
	//创建一个存放int类型数据的数组
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int sz = sizeof(arr1) / sizeof(arr1[0]); 
                //数组字节大小/数组单个元素的字节大小  
                // 40/4
	return 0;
}

         这里用arr1[ ] 数组进行举例说明。 

        一个int类型的数据为4个字节,arr1[ ] 数组存放了10个int类型的数据,整个数组大小为40,创建一个int类型的sz来接受计算之后得出的数组长度大小。

3,确定区域的左右边界

int main()
{
	//创建一个存放int类型数据的数组
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int sz = sizeof(arr1) / sizeof(arr1[0]); //数组字节大小/数组单个元素的字节大小  40/4
	int left = 0;
	int right = sz - 1;
	return 0;
}

数组的第一个元素下标为0,第十个元素下标为 10-1 ,因此可以确定数组的左右边界:

left=0, right = sz - 1 

4,计算中间值并开始进行比较 

int main()
{
	//创建一个存放int类型数据的数组
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int sz = sizeof(arr1) / sizeof(arr1[0]); //数组字节大小/数组单个元素的字节大小  40/4
	int left = 0;
	int right = sz - 1;
	int k = 7;  //要查找的元素k
	int mid = (left + right) / 2;
	if (k > arr1[mid])
	{

	}
	else if(k < arr1[mid])
	{

	}
	else
	{

	}
	return 0;
}

 将要查找的元素与数组中间值的元素进行比较

当k为7时,k<mid 即k处于mid的右侧,这时候区域的边界就开始发生改变 ,因为k是大于mid的,因此mid元素所在的位置及左边的区域都已经不需要再排查了。

 所以left 左边边界值就改变为mid的后一个区域位置,即 mid + 1,而right的值不需要改变,并计算新的mid值。

 

当right的边界要改变时,与left边界的改变是同理的,改变为mid的前一个区域位置,即 mid - 1 

int main()
{
	//创建一个存放int类型数据的数组
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int sz = sizeof(arr1) / sizeof(arr1[0]); //数组字节大小/数组单个元素的字节大小  40/4
	int left = 0;
	int right = sz - 1;
	int k = 7;  //要查找的元素k
	int mid = (left + right) / 2;
	if (k > arr1[mid])
	{
		left = mid + 1;
	}
	else if(k < arr1[mid])
	{
		right = mid - 1;
	}
	else
	{
		
	}
	return 0;
}

5 ,多次循环直到找到元素k

        上述的比较为一次比较的步骤,当然,我们有时候要查找的时候需要进行多次查找,这时候就需要判断什么时候查找出来或者查找结束。

        按照上述的描述我们可以知道,使用二分查找时是运用区间边界来进行比较判断,当我们的左右边界重合时,是不是意味着我们找到了元素k,或者没有找到即将要退出程序。

        那我们的判断语句可以将 left < right 作为条件,而我们的比较又不止一次,应该比较到条件不满足为止,因此可以使用while循环进行不断地判断,直到不满足 left < right 的条件。当我们找到了元素k,就意味着mid值就是我们所要寻找的元素k,返回mid的值,当找不到时就会返回0。

完整代码:

int main()
{
	//创建一个存放int类型数据的数组
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int sz = sizeof(arr1) / sizeof(arr1[0]); //数组字节大小/数组单个元素的字节大小  40/4
	int left = 0;
	int right = sz - 1;
	int k = 7;  //要查找的元素k
	while (left < right)
	{
		int mid = (left + right) / 2;
		if (k > arr1[mid])
		{
			left = mid + 1;
		}
		else if(k < arr1[mid])
		{
			right = mid - 1;
		}
		else
		{
			printf("找到了,下标为:%d", mid);
			return mid;
		}
	}
	return 0;
}

 由于mid因为数组区域的改变是不断变化的,所以应该将mid放入到while循环中,将mid进行不断的更新数据,直到找到所需要的元素k。

 

  • 22
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值