代码改变世界

第二章上机实践报告

2018-10-20 21:37  秤字逃  阅读(191)  评论(0)    收藏  举报

一、实践题目

  改写二分搜索算法

二、问题描述

  设a[0:n-1]是已排好序的数组,请改写二分搜索算法,使得当x不在数组中时,返回小于x的最大元素位置i和大于x的最小元素位置j。当搜索元素在数组中时,i和j相同,均为x在数组中的位置。

  输入格式:输入有两行,第一行是n值和x值; 第二行是n个不相同的整数组成的非降序序列,每个整数之间以空格分隔。

  输出格式:输出小于x的最大元素的最大下标i和大于x的最小元素的最小下标j。当搜索元素在数组中时,i和j相同。 提示:若x小于全部数值,则输出:-1 0 若x大于全部数值,则输出:n-1的值 n的值。

三、算法描述

  本题的要求事实上是要求我们把一个数插入到一个有序序列中,如果这个数本来就在序列中,则不需要插入。

  使用二分查找法进行稍微改写即可。我们原来的二分查找算法BiSearch(int length,int* array, int targe)寻找的是在序列(array)中存在的某个数(target),为了达到这一目的,我们需要定义左右两个指针(pright & pleft),如果找不到,最后的指针将会是 pleft > pright ,这时候这两个指针所夹着的位置即我们要把数字查进入的数字,而 pleft 和 pright 就是我们题目中要求的最小大于数和最大小于数了。而当所求的数字比序列中的数字都小或者都大时,这两个指针也能符合题目的要求。

  综上,如果在序列中找到了我们想要的那个数,我们便返回那个数在序列中的下标,如果不存在,我们则返回 pleft 或者 pright 任意一个指针,返回之后做一个简单的判断即可。

四、算法部分代码

 1 int BiSearch(int n, int *a, int x) {
 2     int left = 0;
 3     int right = n-1;
 4     while (left <= right) {
 5         int mid = (left + right)/2;
 6         if (x == a[mid]){
 7 
 8             return mid;
 9         }
10         if (x > a[mid]){
11             left = mid + 1;
12 
13         }
14         else {
15             right = mid - 1;
16         }        
17     }
18     return left;
19 }

五、算法分析

  时间复杂度:二分查找是将数组 array 从中间切成大致相等的两部分,取 array[n/2] 与target做比较,如果 target=a[n/2] ,则找到 target 。因为每次规模都小一半,我们可以假设查找了 k 次,则 2^k = n,所以 k = log n,所以时间复杂度为O(log n)。

  空间复杂度:本题采用的是非递归的做法,而且变量不会随着 n 而变化,所以空间复杂度为O(1)。

六、心得体会

  事实上打出这道题花费的时间并不长,我们只是在第一题的代码上进行了细微的修改。但是前提是我们对二分查找有一个比较好的了解,还要进行一定的分析,正是我们对二分查找查找不到数字的情况进行更深入的思考才让我们这道题目解决的比较顺利。这启示我们今后对于算法要有一个比较全面的理解,包括每一步要做什么,为什么这样,某个变量会如何改变,这都对我们灵活运用某个算法有很好的帮助。