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

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

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

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

[ 2 5 8 ∞ 3 9 14 ∞ 4 12 16 ∞ ∞ ∞ ∞ ∞ ] \begin{bmatrix} 2 & 5 & 8 & \infin \\ 3 & 9 & 14 & \infin \\ 4 & 12 & 16 & \infin \\ \infin & \infin & \infin & \infin \\ \end{bmatrix} 234591281416
采用不同规则最终效果不同,只要满足其定义即可。

在后面的实现中我们为了简化边界检查,我们实际的矩阵实现行数和列数要比实际大2,Y的存储位置为 [ 1 , 1 ] [1,1] [1,1] [ M , N ] [M,N] [M,N]
4 × 4 4 \times 4 4×4的Young氏矩阵的实际存储空间。
[ − ∞ − ∞ − ∞ − ∞ − ∞ − ∞ − ∞ 2 5 8 ∞ ∞ − ∞ 3 9 14 ∞ ∞ − ∞ 4 12 16 ∞ ∞ − ∞ ∞ ∞ ∞ ∞ ∞ ] \begin{bmatrix} -\infin& -\infin & -\infin & -\infin & -\infin &-\infin \\ -\infin& 2 & 5 & 8 & \infin & \infin\\ -\infin & 3 & 9 & 14 & \infin & \infin \\ -\infin & 4 & 12 & 16 & \infin & \infin \\ -\infin & \infin & \infin & \infin & \infin & \infin\\ \end{bmatrix} 234591281416
采取这种方案,当达到边界时,不会越界。

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

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

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

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

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

  • Y Y Y非空时,将 Y [ 1 , 1 ] Y[1,1] Y[1,1] ∞ \infin 替换

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

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

下面是伪代码:

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 i=i+1 i=i+1 j = j + 1 j=j+1 j=j+1,最多交换 m + n m+n m+n次,总是时间复杂度为 O ( m + m ) O(m+m) O(m+m)

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

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

下面是伪代码

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 × n n \times n n×n的Young氏矩阵在 O ( n 3 ) O(n^3) O(n3)时间内将 n 2 n^2 n2个数进行排列。

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

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

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

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

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

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

代码实现

#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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值