算法 --- 二分查找

目录

一、二分法

二、二分法变形

1、变形一:查找第一个值等于给定值的元素

2、变形二:查找最后一个值等于给定值的元素

3、变形三:查找第一个大于等于给定值的元素

4、变形四:查找最后一个小于等于给定值的元素


一、二分法

1、概念:一种针对有序数据集合的查找算法,查找思想有点类似分治思想。每次都通过跟区间的中间元素对比,将待查找的区间缩小为之前的一半,直到找到要查找的元素,或者区间被缩小为 0。

2、时间复杂度分析:假设数据大小是 n,每次查找后数据都会缩小为原来的一半,也就是会除以 2。最坏情况下,直到查找区间被缩小为空,才停止。

可以看出来,这是一个等比数列。其中 n/2k=1 时,k 的值就是总共缩小的次数。而每一次缩小操作只涉及两个数据的大小比较,所以,经过了 k 次区间缩小操作,时间复杂度就是 O(k)。通过 n/2k=1,我们可以求得 k=log2n,所以时间复杂度就是 O(logn)

3、局限

首先,二分查找依赖的是顺序表结构,简单点说就是数组。

其次,二分查找针对的是有序数据:二分查找只能用在插入、删除操作不频繁,一次排序多次查找的场景中。针对动态变化的数据集合,二分查找将不再适用

再次,数据量太小不适合二分查找。

最后,数据量太大也不适合二分查找:二分查找的底层需要依赖数组这种数据结构,而数组为了支持随机访问的特性,要求内存空间连续,对内存的要求比较苛刻

/**
 * binary search.
 * 
 * @param array: search array
 * @param size: array size
 * @param search_value: search value
 * @return 1
 */
int binary_search(int array[], int size, int search_value)
{
	int low = 0;
	int high = size - 1;
	int mid = 0;
	
	/* 注意结束条件,不是low<high */
	while(low <= high)
	{
		/* 注意size太大导致溢出,所以不为(high+low)/2 */
		mid = low + (high - low) / 2; 
		if (array[mid] == search_value)
		{
			return mid;
		}
		else if (array[mid] < search_value)
		{
			low = mid + 1;
		}
		else
		{
			high = mid - 1;
		}
	}
	
	return -1;
}

二、二分法变形

1、变形一:查找第一个值等于给定值的元素

如下图如果给定要查找的数为8,变形一要解决的就是找到a[5]位置上的8

/**
 * 查找第一个等于给定数值的元素.
 * 
 * @param array: search array
 * @param size: array size
 * @param search_value: search value
 * @return 1
 */
int binary_search_variant1(int array[], int size, int search_value)
{
	int low = 0;
	int high = size - 1;
	int mid = 0;
	
	/* 注意结束条件,不是low<high */
	while(low <= high)
	{
		/* 注意size太大导致溢出,所以不为(high+low)/2 */
		mid = low + (high - low) / 2; 

		if (array[mid] < search_value)
		{
			low = mid + 1;
		}
		else if (array[mid] > search_value)
		{
			high = mid - 1;
		}
		else
		{
			if (mid == 0 || (array[mid - 1] != search_value))
			{
				return mid;
			}
			else
			{
				high = mid - 1;
			}
		}
	}
	
	return -1;
}

2、变形二:查找最后一个值等于给定值的元素

/**
 * 查找最后一个等于给定数值的元素.
 * 
 * @param array: search array
 * @param size: array size
 * @param search_value: search value
 * @return 1
 */
int binary_search_variant2(int array[], int size, int search_value)
{
	int low = 0;
	int high = size - 1;
	int mid = 0;
	
	/* 注意结束条件,不是low<high */
	while(low <= high)
	{
		/* 注意size太大导致溢出,所以不为(high+low)/2 */
		mid = low + (high - low) / 2; 

		if (array[mid] < search_value)
		{
			low = mid + 1;
		}
		else if (array[mid] > search_value)
		{
			high = mid - 1;
		}
		else
		{
			if (mid == (size - 1) || (array[mid + 1] != search_value))
			{
				return mid;
			}
			else
			{
				low = mid + 1;
			}
		}
	}
	
	return -1;
}

3、变形三:查找第一个大于等于给定值的元素

比如,数组中存储的这样一个序列:3,4,6,7,10。如果查找第一个大于等于 5 的元素,那就是 6。

/**
 * 查找第一个大于等于给定数值的元素.
 * 
 * @param array: search array
 * @param size: array size
 * @param search_value: search value
 * @return 1
 */
int binary_search_variant3(int array[], int size, int search_value)
{
	int low = 0;
	int high = size - 1;
	int mid = 0;
	
	/* 注意结束条件,不是low<high */
	while(low <= high)
	{
		/* 注意size太大导致溢出,所以不为(high+low)/2 */
		mid = low + (high - low) / 2; 

		if (array[mid] < search_value)
		{
			low = mid + 1;
		}
		else
		{
			if (mid == 0 || (array[mid - 1] < search_value))
			{
				return mid;
			}
			else
			{
				high = mid - 1;
			}
		}
	}
	
	return -1;
}

4、变形四:查找最后一个小于等于给定值的元素

比如,数组中存储了这样一组数据:3,5,6,8,9,10。最后一个小于等于 7 的元素就是 6

/**
 * 查找最后一个小于等于给定数值的元素.
 * 
 * @param array: search array
 * @param size: array size
 * @param search_value: search value
 * @return 1
 */
int binary_search_variant4(int array[], int size, int search_value)
{
	int low = 0;
	int high = size - 1;
	int mid = 0;
	
	/* 注意结束条件,不是low<high */
	while(low <= high)
	{
		/* 注意size太大导致溢出,所以不为(high+low)/2 */
		mid = low + (high - low) / 2; 

		if (array[mid] > search_value)
		{
			high = mid - 1;
		}
		else
		{
			if (mid == (size - 1) || (array[mid + 1] > search_value))
			{
				return mid;
			}
			else
			{
				low = mid + 1;
			}
		}
	}
	
	return -1;
}
发布了35 篇原创文章 · 获赞 22 · 访问量 1139

猜你喜欢

转载自blog.csdn.net/m0_37845735/article/details/103675190