算法导论 6-3 Young氏矩阵

一、题目

二、思考

最小Young氏矩阵和最小堆的思想差不多,可以通过比较两者的同异来理解Young氏矩阵

不同点:

  min-Heap min-Young
堆顶(最小值) H[1] Y[i][j]
最后一个元素的位置 H[N] Y[N][N]
最后一个元素 不一定是最大值 一定是最大值
parent H[i]的parent是H[i/2] Y[i][j]的parent是Y[i-1][j]和Y[i][j-1]
child H[i]的child是H[i*2]和H[i*2+1] Y[i][j]的child是Y[i+1][j]和Y[i][j+1]
find(x) 从H[1]开始遍历 从西南角开始,或当前值小于key,则向东走,否则向北走

相同点:

1.堆顶是最小值所在的位置

2.parent的值<=child的值

3.空条件:堆顶元素值为INIT

4.满条件:最后一个元素的值不为INIT

5.delete:插入到最后一个元素的位置,然后向parent调整

6.extract:提取堆顶元素,将堆顶元素置为INIT,然后child调整

三、练习

a)不唯一
2    3    4    5
8    9    12    
14    16    
c)
提取Y[1][1],并用ox7FFFFFFF填充。然后向右下调整
YOUNG-EXTRACR-MIN(Y)
1    if  Y[1][1] == 0X7FFFFFFF
2        then error "heap underflow"
3    min <- Y[1][1]
4    A[1][1] <- 0X7FFFFFFF
5    MAX-HEAPIFY(Y, 1, 1)
6    return min
//递归
MIN-YOUNGIFY(Y, i, j)
 1    min <- Y[i][j]
 2    mini <- i
 3    minj <- j
 4    if i < m and Y[i+1][j] < min
 5        mini <- i+1
 6        minj <- j
 7        min <- Y[i+1][j]
 8    if j < n and Y[i+1][j+1] < min
 9        mini <- i
10        minj <- j+1
11        min <- Y[i][j+1]
12    if i != mini or j != minj
13        exchange Y[i][j] <-> Y[mini][minj]
14        MIN-YOUNGIFY(Y, mini, minj)
d)
//若表未满,插入到右下角,然后向左上调整
MIN-YOUNG-INSERT(Y, key)
 1    if Y[m][n] < 0x7fffffff
 2        then error "young overflow"
 3    Y[m][n] <- key
 4    flag <-  true
 5    i <- m
 6    j <- n
 7    max <- key
 8    maxi <- i
 9    maxj <- j
10    while true
11        if i > 1 and max < Y[i-1][j]
12            maxi <- i - 1
13            maxj <- j
14            max <- Y[i-1][j]
15        if j > 1 and max < Y[i][j-1]
16            maxi <- i
17            maxj <- j-1
18            max <- Y[i][j-1]
19        if max == Y[i][j]
20            break
21        exchange Y[maxi][maxj] <-> Y[i][j]
22        i <- maxi
23        j <- maxj
24        max <- Y[i][j]
e)排序过程为:
取下矩阵Y[1][1]元素,O(1)
将Y[1][1]置为0x7FFFFFFF,O(1)
调整矩阵,O(n)
对n^2个结点各执行一次,因此时间为O(n^3)
f)
从左下角开找,若比它小,则向上,则比它大,则向右找
FIND-YOUNG-KEY(Y, key)
 1    i <- m
 2   j <- 0
 3   while i >= 1 and j <= n
 4       if Y[i][j] = key
 5       then return true
 6       else if Y[i][j] < key
 7       then j++
 8       else if Y[i][j] > key
 9       then i--
10   return false

四、代码(旧版)

(1)Young.h

//头文件
#include <iostream>
#include <stdio.h>
using namespace std;

//宏定义
#define N 100

class Young
{
    public:
    //成员变量
    int Y[N+1][N+1];
    int m, n;
    //构造与析构
    Young(){}
    Young(int a, int b);
    //Heap(int size):length(size),heap_size(size){}
    ~Young(){}
    //功能函数
    void Min_Youngify(int i, int j);
    void Build_Min_Young();
    void YoungSort();
    bool Find_Young_key(int key);
    //优先队列函数
    void Young_Decrease_Key(int i, int j, int key);
    void Min_Young_Insert(int key);
    int Young_Minimum();
    int Young_Extract_Min();
    void Young_Delete(int i, int j);
    //辅助函数
    void Print();
};

Young::Young(int a, int b):m(a),n(b)
{
    int i, j;
    for(i = 1; i <= m; i++)
    {
        for(j = 1; j <= n; j++)
            Y[i][j] = 0x7fffffff;
    }
}

void Young::Build_Min_Young()
{
    int i, j, s;
    for(s = m + n; s >= 2; s--)
    {
        for(i = 1; i <= m; i++)
        {
            j = s - i;
            if(j > n)continue;
            if(j < 1)break;
            Min_Youngify(i, j);
        }
    }
}

int Young::Young_Extract_Min()
{
    int Min = Y[1][1];
    Y[1][1] = 0x7fffffff;
    Min_Youngify(1, 1);
    return Min;
}

void Young::Min_Youngify(int i, int j)
{
    int Min = Y[i][j], mini = i, minj = j;
    if(i+1 < m && Y[i+1][j] < Min)
    {
        mini = i + 1;
        minj = j;
        Min = Y[i+1][j];
    }
    if(j+1 < n && Y[i][j+1] < Min)
    {
        mini = i;
        minj = j + 1;
        Min = Y[i][j+1];
    }
    if(i != mini || j != minj)
    {
        swap(Y[i][j], Y[mini][minj]);
        Min_Youngify(mini, minj);
    }
}

void Young::Min_Young_Insert(int key)
{
    if(Y[m][n] < 0x7fffffff)
    {
        cout<<"error:young overflow"<<endl;
        return ;
    }
    Y[m][n] = key;
    int i = m, j = n, Max = key, maxi = i, maxj = j;
    while(true)
    {
        if(i > 1 && Max < Y[i-1][j])
        {
            maxi = i - 1;
            maxj = j;
            Max = Y[i-1][j];
        }
        if(j > 1 && Max < Y[i][j-1])
        {
            maxi = i;
            maxj = j - 1;
            Max = Y[i][j-1];
        }
        if(Max == Y[i][j])
            break;
        swap(Y[maxi][maxj], Y[i][j]);
        i = maxi;
        j = maxj;
        Max = Y[i][j];
    }
}

bool Young::Find_Young_key(int key)
{
    int i = m, j = 0;
    while(i >= 1 && j <= n)
    {
        if(Y[i][j] == key)
            return true;
        else if(Y[i][j] < key)
            j++;
        else if(Y[i][j] > key)
            i--;
    }
    return false;
}

void Young::Print()
{
    int i, j;
    for(i = 1; i <= m; i++)
    {
        for(j = 1; j <= n; j++)
            cout<<Y[i][j]<<' ';
        cout<<endl;
    }
}

void Young::Young_Delete(int i, int j)
{
    Y[i][j] = 0x7fffffff;
    Min_Youngify(i, j);
}

void Young::Young_Decrease_Key(int i, int j, int key)
{
    if(key > Y[i][j])
    {
        cout<<"error:new key is larger than current key"<<endl;
        return ;
    }
    Y[i][j] = key;
    int Max = key, maxi, maxj;
    while(true)
    {
        if(i > 1 && Max < Y[i-1][j])
        {
            maxi = i - 1;
            maxj = j;
            Max = Y[i-1][j];
        }
        if(j > 1 && Max < Y[i][j-1])
        {
            maxi = i;
            maxj = j - 1;
            Max = Y[i][j-1];
        }
        if(Max == key)
            break;
        swap(Y[maxi][maxj], Y[i][j]);
        i = maxi;
        j = maxj;
    }
}

int Young::Young_Minimum()
{
    return Y[1][1];
}

void Young::YoungSort()
{
    while(Y[1][1] != 0x7fffffff)
    {
        cout<<Young_Extract_Min()<<' ';
    }
    cout<<endl;
}
(2)main.cpp
#include <iostream>
#include "Young.h"
using namespace std;

int main()
{
    int m, n, x;
    char c;
    cin>>m>>n;
    //输入随机测试数据
    Young *Y = new Young(m, n);
    int i, j;
    for(i = 1; i <= m; i++)
    {
        for(j = 1; j <= n; j++)
            Y->Y[i][j] = rand() % 100;
    }
    Y->Print();
    //建堆
    Y->Build_Min_Young();
    Y->Print();
    //测试成员函数
    while(cin>>c)
    {
        switch(c)
        {
        case 'E':
            cout<<Y->Young_Extract_Min()<<endl;
            break;
        case 'P':
            Y->Print();
            break;
        case 'I':
            x = rand() % 100;
            cout<<x<<endl;
            Y->Min_Young_Insert(x);
            break;
        case 'F':
            cin>>x;
            cout<<Y->Find_Young_key(x)<<endl;
            break;
        }
    }
    return 0;
}

五、代码(新版)

按照clean code的方式重构了代码,并使用gtest做测试

(1)Young.h

#include <vector>
using namespace std;

#define SIZE_OF_YOUNG 100
#define INIT_DATA 0x7fffffff

enum errorType
{
    SUCCESS = 0,
    SIZE_OVERFLOW,
    OUT_OF_SIZE,
    PARAM_ERROR,
};

struct structCoordinate
{
    int h_index;
    int w_index;
    structCoordinate(int h, int w):h_index(h),w_index(w){}
};

class Young
{    
    int Y[SIZE_OF_YOUNG+1][SIZE_OF_YOUNG+1];
    int height, width;

    bool isInRange(structCoordinate position);
    void build();
    void YoungifyWithSon(structCoordinate position);
    void YoungifyWithParent(structCoordinate position);
    void setDataInPosition(structCoordinate position, int data);
    int getDataFromPosition(structCoordinate position);
    void swapDatainPosition(structCoordinate c1, structCoordinate c2);
    void Print();
public:
    Young(int h = SIZE_OF_YOUNG, int w = SIZE_OF_YOUNG);
    void fillData(int *data, int size);
    int extractMin();
    bool findKey(int key);
    errorType insert(int key);
    errorType decreaseKey(structCoordinate position, int key);
    int getMinimum();
    vector<int> sort();
    errorType deleteData(structCoordinate position);
};
(2)Young.cpp
#include "Young.h"
#include <iostream>
using namespace std;

enum directionType
{
    EAST = 0,
    SOUTH,
    WEST,
    NORTH
};

structCoordinate directionStep[4] = {structCoordinate(0, 1),
                                    structCoordinate(1, 0),
                                    structCoordinate(0, -1),
                                    structCoordinate(-1, 0)};

structCoordinate getNeibourCoordinate(directionType direction, structCoordinate currentPosition)
{
    currentPosition.h_index += directionStep[direction].h_index;
    currentPosition.w_index += directionStep[direction].w_index;
    return currentPosition;
}

Young::Young(int h, int w):height(h),width(w)
{
    if(height < 1 || height > SIZE_OF_YOUNG)
        height = SIZE_OF_YOUNG;
    if(width < 1 || width > SIZE_OF_YOUNG)
        width = SIZE_OF_YOUNG;
    for(int i = 1; i <= height; i++)
        for(int j = 1; j <= width; j++)
            Y[i][j] = INIT_DATA;
}

void Young::fillData(int *data, int size)
{
    int i, j, cnt = 0;
    for(i = 1; i <= height; i++)
    {
        if(cnt >= size)
            break;
        for(j = 1; j <= width; j++)
        {
            if(cnt >= size)
                break;
            Y[i][j] = data[cnt];
            cnt++;
        }
    }
    build();
}

int Young::extractMin()
{
    structCoordinate minDataPosition(1, 1);
    int minData = getDataFromPosition(minDataPosition);
    setDataInPosition(minDataPosition, INIT_DATA);
    YoungifyWithSon(minDataPosition);
    return minData;
}

bool Young::findKey(int key)
{
    structCoordinate currentPosition(height, 1);
    while(isInRange(currentPosition) == true)
    {
        if(getDataFromPosition(currentPosition) == key)
            return true;
        else if(getDataFromPosition(currentPosition) < key)
            currentPosition = getNeibourCoordinate(EAST, currentPosition);
        else if(getDataFromPosition(currentPosition) > key)
            currentPosition = getNeibourCoordinate(NORTH, currentPosition);
    }
    return false;
}

errorType Young::insert(int key)
{
    structCoordinate currentPosition(height, width);
    if(getDataFromPosition(currentPosition) < INIT_DATA)
        return SIZE_OVERFLOW;

    setDataInPosition(currentPosition, key);
    YoungifyWithParent(currentPosition);
    return SUCCESS;
}

errorType Young::decreaseKey(structCoordinate position, int key)
{
    if(false == isInRange(position))
        return OUT_OF_SIZE;
    if(getDataFromPosition(position) < key)
        return PARAM_ERROR;

    setDataInPosition(position, key);
    YoungifyWithParent(position);
    return SUCCESS;
}

int Young::getMinimum()
{
    return Y[1][1];
}

vector<int> Young::sort()
{
    vector<int> ret;
    while(getMinimum() != INIT_DATA)
    {
        ret.push_back(extractMin());
    }
    return ret;
}

errorType Young::deleteData(structCoordinate position)
{
    if(false == isInRange(position))
        return OUT_OF_SIZE;
    if(getDataFromPosition(position) == INIT_DATA)
        return PARAM_ERROR;

    setDataInPosition(position, INIT_DATA);
    YoungifyWithSon(position);
}

bool Young::isInRange(structCoordinate position)
{
    if(position.h_index < 1 || position.w_index < 1)
        return false;
    if(position.h_index > height || position.w_index > width)
        return false;
    return true;
}

void Young::build()
{
    int h, w, step;

    int maxHeight = height, minHeight = 1;
    int maxWidth = width, minWidth = 1;
    int maxStep = maxHeight + maxWidth;
    int minStep = minHeight + minWidth;

    for(step = maxStep; step >= minStep; step--)
    {
        for(h = minHeight; h <= maxHeight; h++)
        {
            w = step - h;
            if(w > maxWidth)continue;
            if(w < minWidth)break;
            YoungifyWithSon(structCoordinate(h, w));
        }
    }
}

void Young::YoungifyWithSon(structCoordinate position)
{
    int Min = getDataFromPosition(position);
    int i = position.h_index, j = position.w_index;
    structCoordinate minDataPosition = position;

    structCoordinate southNeibour = getNeibourCoordinate(SOUTH, position);
    if(isInRange(southNeibour) &&
        getDataFromPosition(southNeibour) < getDataFromPosition(minDataPosition))
    {
        minDataPosition = southNeibour;
    }

    structCoordinate eastNeibour = getNeibourCoordinate(EAST, position);
    if(isInRange(eastNeibour) &&
        getDataFromPosition(eastNeibour) < getDataFromPosition(minDataPosition))
    {
        minDataPosition = eastNeibour;
    }

    if(getDataFromPosition(position) != getDataFromPosition(minDataPosition))
    {
        swapDatainPosition(position, minDataPosition);
        YoungifyWithSon(minDataPosition);
    }
}

void Young::YoungifyWithParent(structCoordinate position)
{
    structCoordinate maxDataPosition = position;
    while(true)
    {
        structCoordinate northNeibour = getNeibourCoordinate(NORTH, position);
        if(isInRange(northNeibour) && 
            getDataFromPosition(maxDataPosition) < getDataFromPosition(northNeibour))
        {
            maxDataPosition = northNeibour;
        }

        structCoordinate westNeibour = getNeibourCoordinate(WEST, position);
        if(isInRange(westNeibour) && 
            getDataFromPosition(maxDataPosition) < getDataFromPosition(westNeibour))
        {
            maxDataPosition = westNeibour;
        }

        if(getDataFromPosition(maxDataPosition) == getDataFromPosition(position))
            break;
        swapDatainPosition(maxDataPosition, position);
        position = maxDataPosition;
    }
}

void Young::setDataInPosition(structCoordinate position, int data)
{
    Y[position.h_index][position.w_index] = data;
}

int Young::getDataFromPosition(structCoordinate position)
{
    return Y[position.h_index][position.w_index];
}

void Young::swapDatainPosition(structCoordinate c1, structCoordinate c2)
{
    int data1 = getDataFromPosition(c1);
    int data2 = getDataFromPosition(c2);
    setDataInPosition(c1, data2);
    setDataInPosition(c2, data1);
}

void Young::Print()
{
    for(int i = 1; i <= height; i++)
    {
        for(int j = 1; j <= width; j++)
            cout<<Y[i][j]<<' ';
        cout<<endl;
    }
}

原文地址:https://www.cnblogs.com/windmissing/p/4032047.html