引言
之前我们讲过猜数字游戏,那么假若有一个数字,位于0~100之间,我们该怎么找到他呢?我想这里有两个办法:遍历法、二分法。接下来我们,我们来探讨以下这二者的优缺点。
遍历法
顾名思义,遍历法就是从这组数据的第一位开始找起,遇到我们所需要的数停止。那么很明显,这样带来的最大问题就是慢!固然,计算机的运算速度很快很快,那么假若我们要查找的这个数目很大呢?是不是还是要从第一个数字开始找起呢?
二分法
在讲述二分法的利弊之前,我们先了解以下什么是二分法!
我们小学或是中学学过,所有的实数都是在是实数坐标系上的,那么我们该如何确定一个数的位置呢?是不是可以用谁和谁之间来说明!
例如:2在1和3的中间,50在49和51的中间!
我们继续来想,假设有一个数位于0~100中间,假设这个数字是70,那么我们该如何用上面的思想来找到他呢?
第一次,我猜是50,那么答案很明显不是50,但是,50是不是把这个0-100分成了0-50和50-100两部分。那么70是不是位于50-100这个部分呢?
第二次,我猜是75,这一次,是不是这个部分就变成了50-75呢?
…
以此类推,我是不是用这种方法确定了70的位置。
像这种,通过逐次的把数据段二等分的方法就叫做二分法!
!!!是不是茅塞顿开了!!!
okok那怎么实现这个过程呢?
我们继续看上面这段话:
第一次,我猜是50,那么答案很明显不是50,但是,50是不是把这个0-100分成了0-50和50-100两部分。那么70是不是位于50-100这个部分呢?
第二次,我猜是75,这一次,是不是这个部分就变成了50-75呢?
第一次的时候,我们是不是取了0和100的中间数50,我们是不是经过了一次比较!比较的是中间数和我们预想的数!,我们是不是因为中间数比我们所想的那个数要小,因此把新线段(这里仅供方便理解)的左端变成了中间数,那么同样的道理,假若中间数要比我们所想的数大,是不是可以把线段的右端的数变成中间数,逐次循环,直到左边的数比右边的数大了!!!
经过了上述的分析,我相信你已经可以写出这段代码了!下面是我的代码,仅供参考:
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int k = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
scanf("%d", &k);
//查找-二分查找
int left = 0;
int right = sz - 1;
int find = 0;//假设找不到
while (left<=right)
{
int mid = left + (right-left)/2;
if (arr[mid] < k)
{
left = mid + 1;
}
else if (arr[mid] > k)
{
right = mid - 1;
}
else
{
printf("找到了,下标是%d\n", mid);
find = 1;
break;
}
}
if (find == 0)
{
printf("找不到了\n");
}
return 0;
}
到了这里,其实我们也可以很明显的感受到一个问题,那就是二分法只能适用于有序数组,假设是一个无序数组,那么这种方法就没办法使用了。
那么如何把一个无序数组变成一个有序数组呢?我们冒泡算法见!