杨氏矩阵查找

1. 简述

杨氏矩阵中,每行元素是递增的,每列元素也是递增的。即a[i][j]<a[i+1][j]且a[i][j]<a[i][j+1]。要在这样的矩阵中查找某个数值元素的位置,复杂度可以达到o(m+n),其中n为矩阵行长度,m为矩阵列长度。
2. 原理
从矩阵的左下角或者矩阵的右上角处开始递归运行,以左下角为例,key为要查找的值,(i,j)为当前矩阵中的位置,初始为(N-1, 0)。
如果超过了矩阵范围则说明不存在这样的元素。
下面, 每行元素从左到右递增,每列元素从上到下递增。
例如:
5 5
2 3 4 5 6
3 4 5 6 7
4 5 6 7 8
5 6 7 8 9
6 7 8 9 10
话说杨氏矩阵不存在相同元素,不过这不是重点,有相同元素一样可以查找。。。。

普通的代码如下,复杂度 O(M+N) .

  1. #include<iostream>  
  2. #include<string>  
  3. using namespace std;  
  4. const int MM=1005;  
  5. int map[MM][MM],N,M;  
  6. int search(int x,int y,int key,int &px,int &py){//从矩阵的左下角开始查找  
  7.     if(x<0 || y>=M)  
  8.         return 0;  
  9.     if(map[x][y]<key)  
  10.         return search(x,y+1,key,px,py);  
  11.     else if(map[x][y]>key)  
  12.         return search(x-1,y,key,px,py);  
  13.     else{  
  14.         px=x, py=y;  
  15.         return 1;  
  16.     }  
  17. }  
  18. int main(){  
  19.     while(scanf("%d%d",&N,&M)==2){  
  20.         for(int i=0;i<N;++i) //输入矩阵,N行,M列,下标从0开始  
  21.             for(int j=0;j<M;++j)  
  22.                 scanf("%d",&map[i][j]);  
  23.         int key;  
  24.         while(scanf("%d",&key)==1){  // 查找key  
  25.             int px,py;  
  26.             if(search(N-1,0,key,px,py)){ //返回的(px,py)是key在矩阵中的最后一个位置  
  27.                 puts("have find");  
  28.                 printf("px == %d , py == %d \n",px,py);  
  29.             }  
  30.             else  
  31.                 puts("not find");  
  32.         }  
  33.     }  
  34.     return 0;  
  35. }  

二分这个矩阵是可以的,效率还高很多,复杂度 O(log(N*M) )。显然这个效率远比上面那个代码高。
第一次选中间那个数,设为x,那么x的左上角子矩阵的每个数是小于x的,其他部分可化为3个子矩阵。这样就可以转换为子问题了。
代码如下:

  1. #include<iostream>  
  2. #include<string>  
  3. using namespace std;  
  4. const int MM=1005;  
  5. int map[MM][MM],N,M;  
  6. int search(int lx,int ly,int rx,int ry,int key,int &px,int &py){ //从矩阵(左上角为(lx,ly),右下角为(rx,ry))中查找key  
  7.     int midx=lx+(rx-lx)/2,midy=ly+(ry-ly)/2;  
  8.     if(lx>rx || ly>ry)  
  9.         return 0;  
  10.     if(midx<0 || midx>=N || midy<0 || midy>=M)  
  11.         return 0;  
  12.     if(key==map[midx][midy]){  
  13.         px=midx, py=midy;  
  14.         return 1;  
  15.     }  
  16.     if(midx==0 && midy==0) //  
  17.         return 0;  
  18.     if(key<map[midx][midy])  
  19.         return search(lx,ly,midx,midy,key,px,py);  
  20.     else{  
  21.         if(search(lx,midy+1,midx,ry,key,px,py))  
  22.             return 1;  
  23.         if(search(midx+1,ly,rx,midy,key,px,py))  
  24.             return 1;  
  25.         if(search(midx+1,midy+1,rx,ry,key,px,py))  
  26.             return 1;  
  27.     }  
  28.     return 0;  
  29. }  
  30. int main(){  
  31.     while(scanf("%d%d",&N,&M)==2){  
  32.          for(int i=0;i<N;++i) //输入矩阵,N行,M列,下标从0开始  
  33.              for(int j=0;j<M;++j)  
  34.                  scanf("%d",&map[i][j]);  
  35.          int key;  
  36.          while(scanf("%d",&key)==1){  // 查找key  
  37.              int px,py;  
  38.              if(search(0,0,N-1,M-1,key,px,py)){ //返回的(px,py)是key在矩阵中的最后一个位置  
  39.                  puts("have find");  
  40.                  printf("px == %d , py == %d \n",px,py);  
  41.              }  
  42.              else  
  43.                  puts("not find");  
  44.          }  
  45.     }  
  46.     return 0;  
  47. }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值