杨氏矩阵YOUNG Tableau,作为一个既类似于二叉排序树(BST),又类似于堆结构的一种简单数据结构。乍看一下,其实就是一个二维数组,但是该数据结构有着明显的特点,即数组的每一行元素严格单调递增(当然也可以递减),同时每一列的元素也是严格单调递增(同前面)。有了这种特点,使得它对于查找某些元素,比堆的性能要好;而对于插入或者删除元素,比BST更方便。
杨氏矩阵数据结构的特点有(如图1):
1.是一个M*N矩阵,并且对于同一行左边的元素要小于(或大于)右边的元素,同一列上面的元素要小于(或大于)下面的元素;
2.如过元素不够组成一个M*N矩阵,即矩阵有一定的空余空间,那么可以采用+∞(递减的情况为-∞)填充。
图1 杨氏矩阵
1 6 7 10
3 8 11 14
12 15 16 + ∞
13 18 +∞ + ∞
杨氏矩阵常用的操作:
1.对有空余控件的矩阵插入元素k,记为INSERT(Y,k);
2.矩阵删除位置为(m,n)处的元素,记为DELETE(Y,(m,n));
3.从矩阵中查找元素k,记为FIND(Y,k);
4.对杨氏矩阵所有元素进行排序输出;
5.其他相关的操作,类似于返回最大值MAX(Y),或者MIN(Y),以及除去最大最小值EXTRACT_MAX(Y),EXTRACT_MIN(Y)等等。
下面对这些操作进行详细分析:
1.矩阵插入元素k,首先将元素k置于矩阵的空余位置上。注意放置位置为先最左边的最上面(或者是最上面的最左边),因此可以将元素k放置在第四行第二列的位置上(或者是第三行第三列),假设k为2,那么图1变为:
图2 杨氏矩阵
1 6 7 10
3 8 11 14
12 15 16 + ∞
13 18 2 + ∞
2作为新插入的元素,可以看到它打破了杨氏矩阵的特性,需要进行处理,保持杨氏矩阵的特点。从图中看到2所在列的上面一个元素为A[3][2]=15,所在行的前面元素为A[4][1]=20,并且A[4][1]>A[3][2]>2,所以2最好跟元素A[4][1]进行位置交换,如果跟所在列的位置A[3][2]进行交换的话,因为A[4][1]>A[3][2],列虽然保持了递增的特点,但是又破坏了行递增的特点,即还需要交换A[4][1]和A[3][2]的位置,所以应该让2与本行的元素A[4][1]进行交换;反之,如果该行的前一个元素要小于该列的上一个元素那么新插入的元素应该与该列的元素前一个交换位置。这里我们可以总结出插入元素步骤:
插入元素的初始位置为A[m][n],
如果A[m-1][n]>=A[m][n-1],并且A[m-1][n]>A[m][n],将A[m-1][n]与A[m][n]进行交换,对A[m-1][n]进行插入操作;
如果A[m-1][n]<=A[m][n-1],并且A[m][n-1]>A[m][n],将A[m][n-1]与A[m][n]进行交换,对A[m][n-1]进行插入操作;
如果A[m][n-1]<A[m][n]并且A[m-1][n]<A[m][n],此时A[m][n]位置正确,插入完成。
根据上面的操作具体的步骤:
图3 因为18>16,所以2和18交换位置
1 6 7 10
3 8 11 14
12 15 16 + ∞
13 2 18 + ∞
图4 因为15>13,所以2和15交换位置
1 6 7 10
3 8 11 14
12 2 16 + ∞
13 15 18 + ∞
图5 因为12>8,所以2和12交换位置
1 6 7 10
3 8 11 14
2 12 16 + ∞
13 15 18 + ∞
图6 因为3已经到了最左边,所以2与上面的元素对比,3>2,交换位置,此时交换结束
1 6 7 10
2 8 11 14
3 12 16 + ∞
13 15 18 + ∞
小结:根据上面的操作可以看出,存在一个递归过程,即不断将插入元素网上或者往左移动,时间复杂度最差为o(M+N)。
2. 对于矩阵删除位置为(m,n)处的元素,可以借鉴上面的插入操作,但是比较的方法签好与上面相反。删除元素是跟该元素下面的元素以及后面的元素进行比较,如果后面的元素小于下面的元素,那么后面的元素与该元素交换,反之依然。具体的操作如下。
删除元素的初始位置为A[m][n],
如果A[m+1][n]<A[m][n+1]],将A[m+1][n]与A[m][n]进行交换,对A[m+1][n]进行删除操作;
如果A[m+1][n]>A[m][n+1],将A[m][n+1]与A[m][n]进行交换,对A[m][n+1]进行插入操作;
如果A[m][n+1]、A[m+1][n]元素存在,并且都为+∞,此时A[m][n]位置调整结束,将A[m][n]=+∞,删除完成。
例如删除(2,2)的元素8,如图7:
图7 杨氏矩阵删除元素(2,2)
1 6 7 10
3 8 11 14
12 15 16 + ∞
13 18 +∞
- ∞
现在要删除元素8的位置为A[2][3],可以看到其下面和后面的元素分别为15和11,而15>11,所以应该用11与8交换:
图8 8和15交换位置
1 6 7 10
3 11 8 14
12 15 16 + ∞
13 18 +∞ - ∞
现在要删除元素8的位置为A[2][4],可以看到其下面和后面的元素分别为16和14,而16>14,所以应该用14与8交换:
图9 8和14交换
1 6 7 10
3 11 14 8
12 15 16 + ∞
13 18 +∞ - ∞
8和14交换完后,可以看到8的下面为+∞,而后面没有元素,因此8交换结束,把8置为+∞即可。
小结:根据上面的操作可以看出,存在一个递归过程,即不断将删除元素往下或者往后移动,时间复杂度最差为o(M+N)。
3. 对于矩阵查找元素k,由于杨氏矩阵并不是完全排序的,而只是局部排好顺序,即对每一行、每一列单独来说是排好顺序的,而对于不同的行,谁大谁小谁也摸不准。因此不能直接使用2叉排序树的查找算法,而需要对2叉排序树的查找算法进行修改。具体的操作如下。
查看矩阵的左下角,如果左下角元素比k大,那么就可以跳过左下角元素所在的行,往上继续查找;而如果左下角元素比k小,就可以跳过左下角元素所在列,往后面继续查找;(或者查看矩阵的右上角,如果右上角元素比k大,那么就可以跳过右上角元素所在的列,往前继续查找;而如果右上角元素比k小,就可以跳过右上角元素所在行,往下面继续查找;或者两种步骤间歇性进行)
如果根据上面的两步,以及搜索完这个矩阵,还是没有找到元素k,则返回布尔值false,如果找到k值对应的元素,则返回true,并且保存其对应的坐标。
例如搜索的元素8,如图10:
图10 杨氏矩阵删除元素(2,2)
1 6 7 10
3 8 11 14
12 15 16 + ∞
13 18 +∞
- ∞
现在要搜索元素8,首先查找最左下角的元素13,13>8,所以可以抛弃13对应的行,如图11:
图11 删除13对应的行
1 6 7 10
3 8 11 14
12 15 16 + ∞
继续搜索元素8,可以继续查看左下角元素为12,12>8,可以抛弃12对应的行,如图12:
图12 删除12对应的行
1 6 7 10
3 8 11 14
继续搜索元素8,可以继续查看左下角元素为3,3<8,可以抛弃3对应的列,如图13:
图12 删除3对应的列
6 7 10
8 11 14
继续搜索元素8,继续查看左下角元素为8,搜索完毕,返回对应的坐标值。
小结:根据上面的操作可以看出,存在一个循环(递归)过程,即不断往上或者往前移动,时间复杂度最差为o(M+N)。
4.对杨氏矩阵所有元素进行排序输出,可以借鉴删除元素操作来完成排序。我们根据杨氏矩阵元素的特征可以看出:A[1][1]是矩阵中值最小的。所以依次删除A[1][1],并输出A[1][1],直到矩阵都为+∞,排序输出结束。
5.返回最大值MAX(Y),或者MIN(Y),以及除去最大最小值EXTRACT_MAX(Y),EXTRACT_MIN(Y)这些操作都是前面三种基本操作的不同形式或者不同的组合,这里不再赘述了。
作者:dqjyong
来源:CSDN
原文:https://blog.csdn.net/dqjyong/article/details/7648698
版权声明:本文为博主原创文章,转载请附上博文链接!