【算法】有序数组 二分查找,有序数组循环移动后的 二分查找

0.有序数组的二分查找

 

/* 在升序数组arr[]中查找key,如果key存在,则返回其在数组中的位置index,否则返回 -1。*/
int BinarySearch(int arr[],int arr_size, int key)
{
	if (arr == NULL)
	{
		return -1;
	}

	int low = 0;
	int high = arr_size - 1;
	int mid;
	while (low <= high)
	{
		mid = (low + high) / 2;
		if (arr[mid] == key)
		{
			return mid;
		}
		else if (arr[mid] > key)
		{
			high = mid - 1;
		}
		else
		{
			low = mid + 1;
		}
	}
	return -1;
}

测试用例:

//test1
int arr[] = { 1, 2, 3, 5, 6, 7 };
int key = 3;

//test2
int arr[] = { 1, 2, 3, 5, 6, 7 };
int key = 4;

//test3
int arr[] = { 1 };
int key = 3;

//test4
int *arr = NULL;
int key = 3;

 

 

1、二分查找变体:有序数组循环移动后,查找最小值

 

【题目】一个有序数组的元素经过循环移动,元素的顺序可能变为“3、4、5、6、7、1、2”。
找出数组中最小的那个元素,假设数组中元素各不相同。

 

这是一个有序数组,只是部分元素循环移动过,因此元素的排序肯定是从小到大,在某一个位置突然变小,接着又开始从小到大排列,那个从突然变小的“转折点”,就是最小元素。

 

比较最小元素与末尾元素(6>2), 说明 在 6 到 2 直接有从大变小再变大的转折点,需要继续在6和2的区间继续查找。

如果mid < j ,则说明mid 到 j 之间是正常排序的,不存在转折点,说明转折点要么在前半部分,要么不存在,因此,继续在[i,m]之间继续查找。

 

思路:

3、4、5、6、7、1、2

i                m              j          :    arr[m] > arr[j]  :  最小元素在[m,j] 之间,i=m

                  i   m         j          :    arr[m] > arr[j]  :  最小元素在[m,j] 之间,i=m

                       i    m   j          :     arr[m] < arr[j]  :  最小元素在[i,m] 之间,  j=m

                       im  j               :    arr[m] > arr[j]  :  最小元素在[m,j] 之间,i=m

什么时候停止呢?算是找到了最小值?

当j - i == 1 的时候(假设数组元素个数>=2),谁是最小元素呢?比较一下 arr[i] 和 arr[j] 即可知道!

然后再处理下特殊情况:数组元素个数=1,

非法情况:arr == NULL

/*
二分查找 变体:

【题目】一个有序数组的元素经过循环移动,元素的顺序可能变为“3、4、5、6、7、1、2”。
找出数组中最小的那个元素,假设数组中元素各不相同。

*/
// 返回有序数组循环移动后的最小值,index 带回其下标
int BinarySearch_Rotate_loop(int arr[], int arr_size, int *index)
{
	if (arr == NULL)
	{
		*index = -1;
		return 0;
	}

	if (arr_size == 1)
	{
		*index = 0;
		return arr[0];
	}

	int low = 0;
	int high = arr_size - 1;
	int mid = -1;

	while ( high - low != 1 )
	{
		mid = (low + high) / 2;
		if (arr[mid] < arr[high])
		{
			high = mid;
		}
		else if (arr[mid] > arr[high])
		{
			low = mid ;
		}
	}

    // 退出循环的时候 j - i == 1
	if (arr[low] < arr[high])
	{
		*index = low;
		return arr[low];
	}
	else
	{
		*index = high;
		return arr[high];
	}
}
	/* 测试用例 */

	int arr1[] = { 3, 5, 6, 7, 1, 2 };

	int arr2[] = { 6, 7, 1, 2, 3, 5 };

	int arr3[] = { 1, 2, 3, 5, 6, 7 };

	int arr4[] = { 1 };

	// int arr50[] = {  };   // 无法实现空数组

	int arr5[] = { NULL };  // 这个不是空数组,C中的NULL = 0 ; #define NULL 0

	int * arr6 = NULL;	    // 空指针

 

2、思考

1)有序数组经过循环移动后,还能使用二分查找法,查找特定元素吗?

2)写代码循环移动一个数组。

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值