0
点赞
收藏
分享

微信扫一扫

数据结构与算法 二分查找

                                                              数据结构与算法 二分查找

一、简述

记--二分查找的C语言简单实现。

例子打包:外链:https://wwi.lanzouq.com/b0ca7a38b 密码:ckk5

二、二分查找

释义

假设有一个有序表A,元素个数为n,要查找元素为K

1)将A表分成左右两个子表A1,A2,让中间元素A[n/2]跟K比较,

2)如果A[n/2] == K说明已经找到K,

3)如果A[n/2] > K说明K在左子表A1,继续将表A1分为两个子表进行查找(即将A1当做A表继续按步骤1开始)

4)如果A[n/2] < K说明K在右子表A2,继续将表A2分为两个子表进行查找(即将A2当做A表继续按步骤1开始)

二分到最后只剩下一个元素,如果A[n/2] != K 说明找不到元素。

时间复杂度O(log2 n)
空间复杂度O(1)
优点查找速度较快,不需要全部遍历元素
缺点待查表需要有序

三、二分查找实现

3.1 实现框架

/******************************************
* 函数: BinarySearch
* 功能: 二分查找
* 参数: int nums[]:待查找数据数组
*       int nums_size:数据数组元素个数
*       int target:查找目标
* 输入:
* 输出:
* 返回: int 成功返回:;其它返回:
* 说明: @Liang 2022.03.05 周六
******************************************/

int BinarySearch(int nums[], int nums_size, int target) {
	int left = 0;
	int right = ...;
	int mid = 0;

	while (...) {
		mid = (left + right) / 2; //防止(left+right)溢出写法:mid = left + (right - left) / 2;
		if (nums[mid] == target) {
			//TODO 找到目标
		} else if (nums[mid] < target) {
			left = ...;	//目标在右半部分,进行收缩左边界
		} else if (nums[mid] > target) {
			right = ...; //目标在右半部分,进行收缩右边界
		}
	}
	return ...;
}

3.2 测试代码

#include <stdio.h>

/******************************************
* 函数: BinarySearch
* 功能: 二分查找
* 参数: int nums[]:待查找数据数组
*       int nums_size:数据数组元素个数
*       int target:查找目标
* 输入:
* 输出:
* 返回: int 成功返回:;其它返回:
* 说明: @Liang 2022.03.05 周六
******************************************/

int BinarySearch(int nums[], int nums_size, int target) {
	int left = 0;
	int right = nums_size - 1;
	int mid = 0;

	while (left <= right) {
		mid = left + (right - left) / 2;	//防止(left+right)溢出写法
		if (nums[mid] == target) {
			return mid;//找到目标
		} else if (nums[mid] < target) {
			left = mid + 1;	//目标在右半部分,进行收缩左边界
		} else if (nums[mid] > target) {
			right = mid - 1; //目标在右半部分,进行收缩右边界
		}
	}
	return -1;
}

/* 获取数据元素个数 */
#define GET_ARR_NUM(arr)	(sizeof(arr)/sizeof(arr[0]))

int main(int argc, char *argv[])
{
	int ret;
	int target;
	int nums[] = {2, 15, 26, 37, 41, 68, 93};
	target = 93;
	ret = BinarySearch(nums, GET_ARR_NUM(nums), target);
	if (0 <= ret) {
		printf("target:%d, nums[%d]=%d\r\n", target, ret, nums[ret]);
	} else {
		printf("not found target:%d, ret:%d\r\n", target,ret);
	}

	target = 100;
	ret = BinarySearch(nums, GET_ARR_NUM(nums), target);
	if (0 <= ret) {
		printf("target:%d, nums[%d]=%d\r\n", target,ret, nums[ret]);
	}
	else {
		printf("not found target:%d, ret:%d\r\n", target, ret);
	}

	getchar();
    return 0;
}

运行结果

四、找左侧边界、右侧边界

      待查找表中存在相同的元素,找到最左边的元素,比如: {1, 2, 3, 3, 3, 3, 3, 5, 7}中查找第一个3 或最后一个3。

测试代码

#include <stdio.h>

/******************************************
* 函数: BinarySearch
* 功能: 二分查找
* 参数: int nums[]:待查找数据数组
*       int nums_size:数据数组元素个数
*       int target:查找目标
* 输入:
* 输出:
* 返回: int 成功返回:;其它返回:
* 说明: @Liang 2022.03.05 周六
******************************************/

int BinarySearch(int nums[], int nums_size, int target) {
	int left = 0;
	int right = nums_size - 1;
	int mid = 0;

	while (left <= right) {
		mid = left + (right - left) / 2;	//防止(left+right)溢出写法
		if (nums[mid] == target) {
			return mid;//找到目标
		} else if (nums[mid] < target) {
			left = mid + 1;	//目标在右半部分,进行收缩左边界
		} else if (nums[mid] > target) {
			right = mid - 1; //目标在右半部分,进行收缩右边界
		}
	}
	return -1;
}

//找左边界
int BinarySearchLeft(int nums[], int nums_size, int target) {
	int left = 0;
	int right = nums_size; //因为[left, right)右开区间right取不到,所以不减一,否则漏了right
	int mid = 0;

	while (left < right) {	//[left, right) 存在最后一个元素未查找的情况,故在return之前需要检查
		mid = left + (right - left) / 2;	//防止(left+right)溢出写法
		if (nums[mid] == target) {
			right = mid;//找到目标,但可能不是最左的,进行收缩右边界,逐步向左逼近
		} else if (nums[mid] < target) {
			left = mid + 1;	//目标在右半部分,进行收缩左边界
		} else if (nums[mid] > target) {
			right = mid; //目标在右半部分,进行收缩右边界, 因为[left, right)右开区间right取不到,所以不减一,否则漏了right
		}
	}

	if (left == nums_size) {//因为[left, right)
		return -1;//遍历结束都找不到target
	}

	return (nums[left] == target) ? left : -1;
}

//找右边界
int BinarySearchRight(int nums[], int nums_size, int target) {
	int left = 0;
	int right = nums_size;//因为[left, right)右开区间right取不到,所以不减一,否则漏了right
	int mid = 0;

	while (left < right) {	//存在最后一个元素未查找的情况,故在return之前需要检查
		mid = left + (right - left) / 2;	//防止(left+right)溢出写法
		if (nums[mid] == target) {
			left = mid + 1;//找到目标,但可能不是最右的,进行收缩左边界,逐步向右逼近, 由于mid是取整的,所以+1才能保证收缩。
		} else if (nums[mid] < target) {
			left = mid + 1;	//目标在右半部分,进行收缩左边界
		} else if (nums[mid] > target) {
			right = mid; //目标在右半部分,进行收缩右边界
		}
	}

	if (0 < left) {
		--left;//因为在nums[mid] == target时为了收缩左边界进行了left = mid + 1;
	}

	return (nums[left] == target) ? left : -1;
}

/* 获取数据元素个数 */
#define GET_ARR_NUM(arr)	(sizeof(arr)/sizeof(arr[0]))

int main(int argc, char *argv[])
{
	int ret;
	int target;
	int nums[] = { 1, 2, 3, 3, 3, 3, 3, 5, 7 };
	target = 3;
	ret = BinarySearch(nums, GET_ARR_NUM(nums), target);
	if (0 <= ret) {
		printf("BinarySearch target:%d, nums[%d]=%d\r\n", target, ret, nums[ret]);
	} else {
		printf("BinarySearch not found target:%d, ret:%d\r\n", target, ret);
	}

	ret = BinarySearchLeft(nums, GET_ARR_NUM(nums), target);
	if (0 <= ret) {
		printf("BinarySearchLeft target:%d, nums[%d]=%d\r\n", target, ret, nums[ret]);
	} else {
		printf("BinarySearchLeft not found target:%d, ret:%d\r\n", target, ret);
	}

	ret = BinarySearchRight(nums, GET_ARR_NUM(nums), target);
	if (0 <= ret) {
		printf("BinarySearchRight target:%d, nums[%d]=%d\r\n", target, ret, nums[ret]);
	} else {
		printf("BinarySearchRight not found target:%d, ret:%d\r\n", target, ret);
	}

	getchar();
    return 0;
}

运行结果

举报

相关推荐

0 条评论