数据结构和算法————二分查找
二分查找
这些天深刻的体会到了巩固知识的重要性。对数据结构和算法的学习有一年的时间,然后搁置了一年,最后发现都忘记了。
不过还好不是失忆,看了之前做过的笔记,还是能回想起来的。
现在想在写一遍,算是对本子上的笔记做一个备份,更重要的是加深我的印象。
首先说一下二分查找的思想:假设数据是按升序排序的,对于给定值val,从序列的中间位置开始比较。
如果当前位置值等于val,则查找成功;
若val小于当前位置值,则在数列的前半段中查找
若val大于当前位置值,则在数列的后半段中继续查找。
重复以上步骤,直到找到为止。
这里我实现两种查找方式:
1 二分查找的非递归实现
2 二分查找的递归实现
第一种 :二分查找的非递归实现
/* author:Embarce param: int arr 待查找的数组,该数组要求是有序的,该段程序针对的是升序的数组 param: int n 数组的长度 param: int val 要查找的值 return:int index 该值在数组中的下标 ,如果没有找到相应的值,返回-1 */ int search(int arr[],int n,int val){ int left = 0; int right = n-1; int index = -1; int i;
for( i = 0; i < n; i++ ){ int mid = (left + right) / 2; if( arr[mid] == val ){ index = mid; }else if( arr[mid] > val){ right = mid -1; }else{ left = mid + 1; } } return index; }
第二种 :二分查找的递归实现
/* author:Embarce param: int left 查找区间的左下标 param: int right 查找区间的右下标 param: int arr 待查找的数组,该数组要求是有序的,该段程序针对的是升序数组 param: int n 数组的长度 param: int val 要查找的值 return:int index 该值在数组中的下标 ,如果没有相应的值,返回-1 */ int search(int left,int right,int arr[],int val){ int mid; int index = -1; if(left > right) return index; else{ mid= (left + right) / 2; if( arr[mid] == val ){ index = mid; return index; }else if( arr[mid] > val){ right = mid -1; return search(left,right,arr,val); }else{ left = mid + 1; return search(left,right,arr,val); } } }
二分查找的两种实现方式已经写完了。我只写了数组的,链式的二分查找和数组思想一样,有兴趣的可以自己去实现。
然后在补充刚刚在书上看到的一个题:一个二维数组,每一行从左到右按照递增的方式排序,每一列从上往下递增按照得方式排序。输入一个数,判断这个数是否存在于二维数组。
我这里就直接说一下解决方案,当然你也可以自己先思考有哪些解决方案,然后在看我下面写的是否和你想的一样。
例如:二维数组arr
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
输入的要查找的数为7
我们选取右上角的数5为基准,因为5比7小,且5是第一行最大且索引位置最靠后的数,因此判断5所在的这一行从5的位置往左肯定不包含7,所以可以剔除5所在的这一整行。
之后数组如下:
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
接着,我们在选取右上角的数10为基准,因为10比7大,且10是最后一列索引位置最靠前且最小的数,因此判断10这一列往下肯定不包含7,所以可以剔除10所在的这一整列。
之后数组如下:
6 7 8 9
11 12 13 14
16 17 18 19
接着,我们在选取右上角的数9为基准,因为9比7大,且9是最后一列索引位置最靠前且最小的数,因此判断9这一列往下肯定不包含7,所以可以剔除9所在的这一整列。
之后数组如下:
6 7 8
11 12 13
16 17 18
接着,我们在选取右上角的数8为基准,因为8比7大,且8是最后一列索引位置最靠前且最小的数,因此判断8这一列往下肯定不包含7,所以可以剔除8这一列。
之后数组如下:
6 7
11 12
16 17
最后选取 7为基准,也就是说找到了对应的值。
问题到此解决完毕。
其实我们也可以选择左下角的数为基准然后去分析,最终也可以找到相对应的值,这里我就不做分析了。
然后现在的疑问就是为什么不选择左上角和右下角。
我们现在就尝试一下选取左下脚为基准,即选取1为基准,1比7小,1也是它所在行的最小值,1也是它所在列的最小值。因此没办法判断到底该剔除那一列或者哪一行。
同样在尝试右下脚,即以20为基准,20比7大,20同样是它所在行和所在列的最大值,同样我们也没有办法判断到底该剔除那一列或者哪一行。
那么什么时候选取左下右上,什么时候选取左上右下呢。我想大家应该有了自己的答案。
就是当二维数组行列都是升序的情况选择左下右上,行列都是降序的情况选择左上右下。
现在附上具体的代码实现。
/* author:Embarce param:int arr 待查找的数组,该数组要求是有序的 param:int row_length 数组的行数 param:int col_length 数组的列数 param:int val 要查找的值 return:int rs 找到了返回1,没找到返回0 */ int search(int arr[4][6],int row_length,int col_length,int val){ int rs = 0; int tmp = 0; int row_index = 0; int col_index = col_length-1; while(row_index < row_length && col_index < col_length){ tmp = arr[row_index][col_index];
if(tmp == val){ rs = 1; break; }else if(tmp< val){ row_index = row_index+1; }else{ col_index = col_index-1; } } return rs; }
到此二分查找结束。
后面还补充了一个非二分但是属于查找类型题。
想看的人可以看看 ^_^