数据结构与算法—二分查找

目录

二分查找

时间复杂度

程序设计要点

局限性

二分查找的变形

实例分析

二叉搜索实现(不考虑重复条件)


二分查找

        针对的是一个有序的数据集合,查找思想类似于分治思想。

每次通过跟区间中的元素对比,将待查找的区间缩小为原来的一半,直到找到数据为止,或区间缩小到0

时间复杂度

        查找速度O(logn),非常高效

N, n/2 , n/4 , … n/2^k

经过K次区间缩小操作,时间复杂度O(K)

n/2^k = 1 -> k = log2n 时间复杂度O(logn)

42亿个数据用二分查找,最多32次找到

程序设计要点

1,循环退出条件 low<=high

2、mid取值 mid=(low+high)/2 不佳,如果low,high比较大,之和可能溢出。

        low+(high-low)/2  或者 low+((high-low)>>1)

3、low,high值更新

        low=mid+1,high=mid-1

可以使用递归实现

局限性

1、依赖的顺序结构,数组。

        链表是不可以的

2、有序的数据

        动态的插入,删除,使用二叉树

3、数据量太小,不适合二分查找

4、数据量太大,不适合。数据连续存储困难。1GB数据太大

实例:如何在1000万个整数快速查找某个整数,内存限制100MB

        每个数据大小是8字节,将1000万数据存在数组中,内存占用80MB。

        8*10000000/1024/1024 = 76.2939MB

先排序,再用二分查找。

散列表和二叉树好像能解?实际上不行的,内存空间不够,节点指针占用空间。

二分查找的变形

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

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

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

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

实例分析

查找IP地址归属地,IP区间

假设有12万条这样的IP区间与归属地对应关系,如何快速定位出一个IP地址的归属地?

因为IP地址区间不经常更新,先将12万条数据,按照起始地址IP 从小到大排列(IP地址转化为32位的整型数)

在有序数组中,查找最后一个小于等于某个给定值的元素。

通过二分查找,找到最后一个起始IP小于等于这个IP地址区间,然后,检查这个IP是否在这个IP区间内,如果在,就取出对应的归属地显示,如果不在则返回没找到。

二分查找能解决的问题,大部分倾向于用散列表或者二叉查找树。即使二分查找在内存使用上更节省,但毕竟内存如此紧缺的情况并不多。

二分查找更适合在“近似”查找问题,如二分查找的变体边界查找的处理。如果用散列表、二叉树、比较难实现。

二叉搜索实现(不考虑重复条件)

#include<stdio.h>
#include<stdlib.h>

typedef int(*binarch_search)(int *arr,int size,int val);

//使用递归实现
int binary_search_rec(int *arr,int size,int val)
{
	int mid = size / 2;
	int idx;

	if(arr[mid] == val)
		return mid;

	if(!mid)
		return -1;
	if(arr[mid]<val)
	{
		idx = binary_search_rec(arr+mid+1,size - mid -1,val);
		if(idx !=-1)
			idx +=mid+1;
	}
	else
	{
		idx = binary_search_rec(arr,mid,val);
	}

	return idx;
}
//使用迭代
int binary_search_iter(int *arr,int size,int val)
{
	int low,mid;
	int high = size - 1;

	while(low < high)
	{
		mid = (low + high)/2;
		if(arr[mid] == val)
			return mid;

		if(arr[mid] < val)
			low = mid + 1;
		else
			high = mid -1;
	}

}

void iter_test(binarch_search binary_search_fun)
{
	int arr[10] = {1, 4, 5, 9, 12, 19, 21, 28, 31, 36};
	int idx ; 
	idx = binary_search_fun(arr,10,12);
	if(idx != -1)
	{
		printf("find 12 at %d\n",idx);
	}
	else
	{
		printf("12 not find in arr\n");
	}

}

//实现方法不同,参数相同
//回调函数使用

void main()
{

	iter_test(binary_search_iter);
	iter_test(binary_search_rec);

}

猜你喜欢

转载自blog.csdn.net/WANGYONGZIXUE/article/details/129212141
今日推荐