参考:http://xudacheng06.blog.163.com/blog/static/4894143320127891610158/

杨氏矩阵(Young Tableau)是一个很奇妙的数据结构,他类似于堆的结构,又类似于BST的结构,对于查找某些元素,它优于堆;对于插入、删除它比BST更方便。

首先介绍一下这个数据结构的定义,Young Tableau有一个m*n的矩阵,让后有一数组 a[k], 其中k<=m*n ,然后把a[k]中的数填入 m*n 的矩阵中,填充规则为(如图1-1):

1.  每一行每一列都严格单调递增(有其他的版本是递减,其原理相同)。

2.  如果将a[k]中的数填完后,矩阵中仍有空间,则填入 

1

2

3

4

5

6

1

3

5

7

8

11

a

4

6

9

14

15

19

b

10

21

23

33

56

57

c

34

37

45

55

d

e

图1-1

则现在讨论,这个数据结构的几种操作,而在这些操作中,我们会发现堆排序的影子,并且这些操作具有很好的时间复杂度。

条件:一个已经建好的杨氏矩阵(Young Tableau

操作:

【1】  在杨氏矩阵中插入元素x ---- Insert(x)

【2】  在杨氏矩阵中删除位于 (x, y) 位置的元素---- Delete(x, y)

【3】  返回x是否在矩阵中----Find(x)

【4】  第k大数

其中1-2操作类似于堆的操作,而3操作类似于BST的操作。下面我就用我

自己的理解把这几个操作加以解释。

【1】 插入操作

本操作的时间复杂度为O( n + m ),其操作类似于堆排序的SIFT-UP算法(具体算法见《算法设计技巧与分析》 M.H,Alsuwaiyel 著)。它的堆的结构在这里表现为某个元素Y[x, y] 下面和右面的两个元素Y[x, y+1] ,Y[x+1, y]均比Y[x, y]要大。于是其插入算法可以描述为,首先把待插入元素以行为主序置于所有有效数字(除了无穷以外的数)最后面,如将x=2,放入 图1-1 的d5的位置,然后执行类似于SIFT-UP的操作,将x与它左边(记为x-l)及上面(记为x-u)的数进行比较,根据比较结果有三种可能的操作:

1:x-u > x 且x-u >= x-l  则将x 与 x-u进行交换

2:x-l > x 且x-l > x-u  则将x 与 x-l进行交换

3: x >= x-l 且 x > x-u  则x 不动,此时已经插入成功

(可以有其他合理的约定)

对例子插入2进行操作如图1-2箭头的操作方向。

1

2

3

4

5

6

1

3

5

7

8

11

a

2

6

9

14

15

19

b

4

10

21

23

33

57

c

34

37

45

55

56

d

e

图1-2

由上述的操作知其时间复杂度最大为行列之和,即O(m+n)

【2】 删除操作

操作类似于插入操作,其时间复杂度也为O(m+n)。其操作类似于堆排序的SIFT-DOWN算法。删除算法可以描述为,首先将删除的位置(x, y)的数字删除,然后调整,把杨氏矩阵中的最大值k(可以行为主序进行搜索到最后)填入到被删除位置,然后让此数与其下面的数(k-d)和右面的数进行(k-r)比较,此时比较结果为两种,因为此时元素一定会下移:

1:k-d > k-r 将k-r 和 k进行交换

2:k-d < k-r 将k-d 和 k进行交换

举例 删除图1-1的a3位置的元素5图1-3

1

2

3

4

5

6

1

3

7

8

11

19

a

4

6

9

14

15

57

b

10

21

23

33

56

c

34

37

45

55

d

e

图1-3

由操作知,删除算法时间复杂同样最多为行列之和,即O(m + n)。

【3】查找算法

查找算法类似于BST二叉排序树,不过需要在其思想上稍微进行修改,才能满足杨氏矩阵的查找操作,同样利用杨氏矩阵的性质,不过此时应该换一个角度思考问题,因为与BST二叉排序树类比,所以应该从左下角开始看起(如 图1-1d1位置),该元素的上面的元素比本身小和右面的元素比本身大,这样就与BST二叉排序树具有相同的性质。所以在查找时从左下角不断的比较,从而最终确定所查找元素位置。

如查找19,比较顺序如图1-4

1

2

3

4

5

6

1

3

5

7

8

11

a

4

6

9

14

15

19

b

10

21

23

33

56

57

c

34

37

45

55

d

e

图1-4

此算法的时间复杂度同前两个算法,复杂度也是O(m + n)。

【4】杨氏矩阵第K大数

1)小顶堆法

构建一个小顶堆,首先将a[0][0]加入小顶堆,然后每次从小顶堆中取出最小元素,并加入比该元素大且与之相邻的两个元素(对于a[0][0],则需要加入 a[0][1]和a[1][0]),直到取出第k个元素,需要注意的是,需要采用额外空间记录某个元素是否已经加入到小顶堆以防止重复加入。

2)二分枚举+类堆查找

首先,二分枚举找到一个数x,它比杨氏矩阵中k个数大;然后,利用类堆查找法找到刚好小于x的元素。该算法的时间复杂度为O((m+n)lg(mn)),但不需要额外存储空间。代码如下:

int find_kth_in_YoungTableau(int** a, int m, int n, int k)
{
int low = a[][];
int high = a[m-][n-];
int order = ;
int mid = ;
do {
mid = (low + high) >> ;
order = get_order(a, m, n, mid);
if(order == k)
break;
else if(order > k)
high = mid - ;
else
low = mid + ;
} while(); //二分枚举整,找出正好大于k的一个整数 mid
int row = ;
int col = n - ;
int ret = mid;
while(row <= m- && col >= )
{ //找出比mid小的最大数
if(a[row][col] < mid) {
ret = (a[row][col] > ret) ? a[row][col] : ret;
row++;
} else {
col--;
}
}
return ret;
} //整数k在矩阵中的排名
int get_order(int** a, int m, int n, int k)
{
int row, col, order;
row = ; col = n-; order = ;
while(row <= m- && col >= ) {
if(a[row][col] < k) {
order += col + ;
row++;
}else {
col--;
}
}
return order;
}

方法2举例:要在下列杨氏矩阵中找第k大数,k=6.

1 3 5
2 4 8
6 9 10

首先会对mid进行枚举,重点是对枚举的mid计算其在该矩阵中小于它的有几个数。

下面以mid=7为例,说明order=6.

首先与a[0][2]比较,a[0][2]=5<7,则order = 0+2+1=3, row = 1;

再与a[1][2]比较,a[1][2]=8>7,则col = col-1 = 1;

再与a[1][1]比较,a[1][1]=4<7,则order = 3+1+1 = 5,row = 2;

再与a[2][1]比较,a[2][1]=9>7,则col = col-1 = 0;

在于a[2][0]比较,a[2][0]=6<7,则order = 5+0+1 = 6,row = 3;

row >(m-1)=2,所以退出循环,返回order值等于6,即在该杨氏矩阵中比mid=7小的数一共有6个。

PS:发现如果数组中有相同的值的话,可能无法通过枚举找到恰好比杨氏矩阵中k个数大的数。所以这种方法有其局限性。

最新文章

  1. MSSQL数据库表加锁
  2. EasyUI中Treegrid节点的删除
  3. Base64编码保存到文件服务器
  4. Android九宫图(draw9patch)
  5. 循序渐进Python3(五) -- 初识模块
  6. BZOJ 1015: [JSOI2008]星球大战starwar 并查集
  7. sql注入在线检測(sqlmapapi)
  8. postfix日志分析pflogsumm
  9. 如何给对话框中的控件发送消息呢?Windows消息分类
  10. 跟着刚哥梳理java知识点——反射和代理(十七)
  11. 多个code.csdn.net账号切换
  12. 2016广东工业大学新生杯决赛网络同步赛暨全国新生邀请赛 题解&amp;源码
  13. [Luogu 3389]【模板】高斯消元法
  14. hdu 5314 动态树
  15. Android 性能优化(一)内存篇
  16. 解决用友U8删除用户时提示“用户已启用”不能删除的问题
  17. python基础语法二
  18. Go语言下的线程模型
  19. 论文笔记:Concept Mask: Large-Scale Segmentation from Semantic Concepts
  20. ionic3+angular5页面间传递参数

热门文章

  1. 20145212&amp;20145204信息安全系统实验四报告
  2. CentOS 7.0安装配置Vsftp服务器
  3. SCI英文论文写作- Latex 进阶
  4. Android SDK升级后报错error when loading the sdk 发现了元素 d:skin 开头无效内容
  5. CSS3多列/多卷
  6. JAVA语法基础作业——动手动脑以及课后实验性问题 (八)
  7. [Bash Shell] Shell学习笔记
  8. Bestcoder#5 1002
  9. Android如何一进入一个activity就唤醒键盘
  10. calendar的一些操作