007's Studio.

算法导论思考题6-3Young氏矩阵

字数统计: 2.3k阅读时长: 11 min
2019/08/21 Share

思考题6-3(Young氏矩阵)在一个$m\times n$的Young氏矩阵(Young tableau)中,每一行的数据都是从左到右排序的,每一列的数据都是从上到下排列的。Young氏矩阵中也会存在一些为 $\infty$ 的数据项,表示那些不存在的数据。因此,Young氏矩阵可以用来村出$r \leq mn$个有限的数。

a. 画出一个包含元素$\{9,16,3,2,4,8,5,14,12\}$的$4 \times 4$Young氏矩阵。

第一题比较简单,只要满足插入和每行每列都是非递减就行。
下面示例:

采用不同规则最终效果不同,只要满足其定义即可。

在后面的实现中我们为了简化边界检查,我们实际的矩阵实现行数和列数要比实际大2,Y的存储位置为$[1,1]$到$[M,N]$。
$4 \times 4$的Young氏矩阵的实际存储空间。

采取这种方案,当达到边界时,不会越界。

b. 对于一个$m \times n$的Young氏矩阵来说,请证明:如果$Y[1,1]=\infty$,则$Y$为空;如果$Y[m,n]< \infty$,则$Y$为满(即包含$mn$个元素)。

这道题比较简单,根据定义就可以快速得出。
证明:根据Young氏矩阵的定义,$Y[i,j] \leq Y[i+k1,j+k2],\forall i,i+k1 \leq m$ 且 $j,j+k2 \leq n$。即$Y[1,1]$为矩阵的最小值,$Y[m,n]$为最大值。

如果$Y[1,1]=\infty$,则矩阵其他元素均为$\infty$,即为空。若$Y[m,n]< \infty$,则其他元素均小于$\infty$,故$Y$为满。

c. 请给出一个在$m \times n$ Young氏矩阵上时间复杂度为$O(m+n)$的EXTRACT-MIN的算法实现。你的算法可以考虑使用一个递归过程,它把一个规模为$m \times n$的问题分解为规模为$(m-1) \times n$或$m \times (n-1)$的子问题(提示:考虑使用MAX-HEAPFY)。这里,定义T(p)用来表示在任意$m \times n$的Young氏矩阵上的时间复杂度,其中$p = m+n$。给出并求解$T(p)$的递归表达式,其结果为$O(m+n)$。

这个实现上也比较简单。如下:

  • 在$Y$非空时,将$Y[1,1]$用$\infty$替换

然后重新调整$\infty$的位置,记当前位置在$Y[i,j]$,让其满足定义。

  • 取其下面元素$Y[i+1,j]$和右边元素$Y[i,j+1]$的最小值$mix$,若$min \neq \infty$交换它和$\infty$的位置。
  • 当达到矩阵边界,或$min = \infty$,此时结束。

下面是伪代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
extractMin(Y)
if(!Y.empty())//非空
Y[1][1] = INF;//第一个元素置为INF
MinFixup(Y,Loc{1,1});//调整

MinFixup(Young,loc)
t = Y[loc.x][loc.y]
do
if(Y[loc.x][loc.y+1] < Y[loc.x+1][loc.y])//获取下方和右边小的数的位置
small = {loc.x,loc.y+1}
else
small = {loc.x+1,loc.y}
if(Y[small.x][small.y] < t)
Y[loc.x][loc.y] = Y[small.x][small.y]
loc = small
else
break
while(true)
Y[loc.x][loc.y] = t

该过程相当于一个棋子从左上角向右下方行走,每次交换后$i=i+1$或$j=j+1$,最多交换$m+n$次,总是时间复杂度为$O(m+m)$。

d. 是说明如何在$O(m+n)$的时间内,将一个元素插入到一个未满的$m \times n$的Young氏矩阵中。

类似二叉堆的插入过程,我们将新的元素放置在矩阵的最后一个位置$Y[m,n]$,类似题目c相反,让它与上面的元素$Y[m-1,n]$或左边的元素$Y[m,n-1]$比较,取它们的最大值$max$,若$max\leq Y[m,n]$,那么此时满足,否则,取用$max$与它交换。直到达到达到边界或满足Young氏矩阵的定义。

下面是伪代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
insert(Y,x)
if(!Y.full())
Y[M][N] = x
MaxFixup(Loc{M,N});

MaxFixup(Y,loc)
t = Y[loc.x][loc.y]
do
if(Y[loc.x][loc.y-1] < Y[loc.x-1][loc.y])
lager = {loc.x,loc.y-1}
else
small = {loc.x-1,loc.y}
if(Y[lager.x][lager.y] > t)
Y[loc.x][loc.y] = Y[lager.x][lager.y]
loc = lager
else
break
while(true)
Y[loc.x][loc.y] = t

e. 在不用其他排序算法的情况下,是说明如何利用一个$n \times n$的Young氏矩阵在$O(n^3)$时间内将$n^2$个数进行排列。

将$n \times n$个元素插入Young氏矩阵中,花费$O(n^3)$,然后将他们意义取出即可,也是花费$O(n^3)$。故总的时间复杂度为$O(n^3)$。

f. 设计一个时间复杂度为$O(m+n)$的算法,它可以用来判断一个给定的数是否存储在$m \times n$的Young氏矩阵内。

查找一个数$x$,我们可以从左下角或右上角开始搜索。不能从左上角或右下角进行,例如左上角来说,当我们查找点元素大于$Y[1,1]$时,若往右或下均是大于$x$时,我们不知道往那个方向,有可能选择方向错误后,后面需要回过头来找尝试另一方向,花费额外时间。

但是如果我们从左下角开始查找,如果$x < Y[m,1]$,那么我们往上继续查找,若$X > T[m,1]$,那么我们往右边查找。这样可以在$O(m+n)$时间内完成。当然,从右上角开始也是一样的效果。

下面从左下角查找的伪代码:

1
2
3
4
5
6
7
8
9
10
search(Y,t)//查找t
x = M,y=1
while(Y[x][y] != INF && Y[x][y] != -INF)//未到达边界
if(Y[x][y] == t)
return true
else if(t < Y[x][y])
x = x + 1
else
y = y - 1
return false

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#include<iostream>
#include<cassert>
#include<array>
#include<ctime>
#include<random>
using namespace std;
const int INF=0x3f3f3f3f;
struct Loc//位置定义
{
unsigned x,y;
};
template<typename T,unsigned M,unsigned N=M>
class Youngtableau{
public:
Youngtableau();//构造函数
void insert(const T&x);//插入
void extractMin();//删除
bool empty() {return matrix[1][1]==INF;}//判空
bool full() {return matrix[M][N]!=INF;}//判满
T top() {return matrix[1][1];}//返回首元素
bool search(const T&t);//查找
void print();//输出
private:
void MinFixup(Loc loc);//调整函数
void MaxFixup(Loc loc);
private:
//底层存储
//为了方便边界处理,行列多开2个空间,方便处理边界
array<array<T,N+2>,M+2> matrix;
Loc ins;//插入位置[M,N]
};
/*
Functions Definition
*/
template<typename T,unsigned M,unsigned N>
Youngtableau<T,M,N>::Youngtableau():ins({M,N})
{
matrix[0].fill(-INF);
matrix[M+1].fill(INF);
for(int i=1;i<matrix.size();++i)
{
matrix[i][0]=-INF;
for(int j=1;j<matrix[i].size();++j)
matrix[i][j]=INF;
}
}
template<typename T,unsigned M,unsigned N>
void Youngtableau<T,M,N>::print(){
for(int i=1;i<=M;++i)
{
for(int j=1;j<=N;++j)
{
if(matrix[i][j]!=INF)
cout << matrix[i][j] << " ";
else
cout << "INF ";
}
cout << endl;
}
}
template<typename T,unsigned M,unsigned N>
void Youngtableau<T,M,N>::insert(const T&x)
{
if(!full())
{
matrix[ins.x][ins.y]=x;
MaxFixup(ins);
}
}
template<typename T,unsigned M,unsigned N>
void Youngtableau<T,M,N>::extractMin()
{
if(!empty())
{
matrix[1][1]=INF;
MinFixup(Loc{1,1});
}
}
template<typename T,unsigned M,unsigned N>
bool Youngtableau<T,M,N>::search(const T&t)
{
int x=M,y=1;
while(matrix[x][y]!=INF&&matrix[x][y]!=-INF)//边界检查
{
if(t==matrix[x][y])
return true;
else if(t<matrix[x][y])
--x;
else
++y;
}
return false;
}
template<typename T,unsigned M,unsigned N>
void Youngtableau<T,M,N>::MaxFixup(Loc loc){
T t=matrix[loc.x][loc.y];
Loc lager;
do{
if(matrix[loc.x][loc.y-1]>matrix[loc.x-1][loc.y])
lager={loc.x,loc.y-1};
else
lager={loc.x-1,loc.y};
if(matrix[lager.x][lager.y]>t){
matrix[loc.x][loc.y]=matrix[lager.x][lager.y];
loc=lager;
}
else
break;
}while(true);
matrix[loc.x][loc.y]=t;
}
template<typename T,unsigned M,unsigned N>
void Youngtableau<T,M,N>::MinFixup(Loc loc){
T t=matrix[loc.x][loc.y];
Loc small;
do{
if(matrix[loc.x][loc.y+1]<matrix[loc.x+1][loc.y])
small={loc.x,loc.y+1};
else
small={loc.x+1,loc.y};
if(matrix[small.x][small.y]<t){
matrix[loc.x][loc.y]=matrix[small.x][small.y];
loc=small;
}
else
break;
}while(true);
matrix[loc.x][loc.y]=t;
}
template<unsigned M,unsigned N=M>
void Youngtableau_test(Youngtableau<int,M,N>&matrix)
{
static default_random_engine e(time(nullptr));
static uniform_int_distribution<int> d(100,999);//等概率生成3位的随机整数
cout << "Before insert" << endl;
matrix.print();
int i=0;
while(i<M*N)
{
matrix.insert(d(e));
i++;
}
cout << "After insert" << endl;
matrix.print();
cout << "\nInput the number to check it if in the Young tableau,(-1 to stop):\n";
while(cin >> i && i!=-1)
{
cout << boolalpha << matrix.search(i) << endl;
}
int pre=-INF;
while(!matrix.empty())
{
int t=matrix.top();
assert(pre<=t);//不满足非递减终止
pre=t;
matrix.extractMin();
}
cout << "After delete" << endl;
matrix.print();
}
int main()
{
Youngtableau<int,5,10> matrix;
Youngtableau_test(matrix);
return 0;
}

原文作者:007havegone

原文链接:http://007havegone.github.io/2019/08/21/算法导论思考题6-3Young氏矩阵/

发表日期:August 21st 2019, 4:32:55 pm

更新日期:August 22nd 2019, 12:41:20 am

版权声明:‘原创内容,转载时请附上出处’

CATALOG
  1. 1. 思考题6-3(Young氏矩阵)在一个$m\times n$的Young氏矩阵(Young tableau)中,每一行的数据都是从左到右排序的,每一列的数据都是从上到下排列的。Young氏矩阵中也会存在一些为 $\infty$ 的数据项,表示那些不存在的数据。因此,Young氏矩阵可以用来村出$r \leq mn$个有限的数。
    1. 1.1. a. 画出一个包含元素$\{9,16,3,2,4,8,5,14,12\}$的$4 \times 4$Young氏矩阵。
    2. 1.2. b. 对于一个$m \times n$的Young氏矩阵来说,请证明:如果$Y[1,1]=\infty$,则$Y$为空;如果$Y[m,n]< \infty$,则$Y$为满(即包含$mn$个元素)。
    3. 1.3. c. 请给出一个在$m \times n$ Young氏矩阵上时间复杂度为$O(m+n)$的EXTRACT-MIN的算法实现。你的算法可以考虑使用一个递归过程,它把一个规模为$m \times n$的问题分解为规模为$(m-1) \times n$或$m \times (n-1)$的子问题(提示:考虑使用MAX-HEAPFY)。这里,定义T(p)用来表示在任意$m \times n$的Young氏矩阵上的时间复杂度,其中$p = m+n$。给出并求解$T(p)$的递归表达式,其结果为$O(m+n)$。
    4. 1.4. d. 是说明如何在$O(m+n)$的时间内,将一个元素插入到一个未满的$m \times n$的Young氏矩阵中。
    5. 1.5. e. 在不用其他排序算法的情况下,是说明如何利用一个$n \times n$的Young氏矩阵在$O(n^3)$时间内将$n^2$个数进行排列。
    6. 1.6. f. 设计一个时间复杂度为$O(m+n)$的算法,它可以用来判断一个给定的数是否存储在$m \times n$的Young氏矩阵内。
  2. 2. 代码实现