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

                二分查找

      这些天深刻的体会到了巩固知识的重要性。对数据结构和算法的学习有一年的时间,然后搁置了一年,最后发现都忘记了

      不过还好不是失忆,看了之前做过的笔记,还是能回想起来的。

      现在想在写一遍,算是对本子上的笔记做一个备份,更重要的是加深我的印象。 

      首先说一下二分查找的思想:假设数据是按升序排序的,对于给定值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; }

    到此二分查找结束。

    后面还补充了一个非二分但是属于查找类型题。

    想看的人可以看看 ^_^ 

 

      

      

posted @ 2016-06-06 15:24  小土豆biubiubiu  阅读(707)  评论(0编辑  收藏  举报