一个 m x n 的Young氏矩阵是指,每一行数据都是从左到右排好序,每一列的数据也都是从上到下排好序。其中也可能存在一些INF的数据,表示不存在的元素,一个mxn的Young氏矩阵最多用来存放 r <= mn个元素。
详细见《算导》P.83
Young氏矩阵类似于堆的结构,主要实现的API包括以下:
1. void insert(int x)
功能:将一个元素x插入到矩阵中,复杂度O(m+n)
算法过程:
1) 判断矩阵是否为Full
2) 如果不为Full,插入元素到矩阵的右下角(row, col)位置,然后进行swim(row, col)将元素移动到合适位置。
2. int getMin()
功能:返回矩阵中的最小值,复杂度O(1)
算法过程:
1) 判断矩阵是否为Empty
2) 直接返回mat[0][0].左上角元素,依据矩阵的性质
3. int delMin()
功能:返回矩阵中的最小值,并把它从矩阵中删除,复杂度O(m+n)
算法过程:
1) 判断矩阵是否为Empty
2) 暂存mat[0][0]元素用于返回,把矩阵最右下角的元素放到mat[0][0],使用sink(0, 0)进行下沉调整元素到合适位置
4. bool seach(int x)
功能:判断矩阵是否存在元素x,复杂度O(m+n)
算法过程:
版本1:通过递归的方式,比较当前mat[x][y] 和 key的关系,将划分到是否需要在(m-1)x(n)子矩阵和mx(n-1)子矩阵进行递归查找
版本2:初始位置为矩阵右上角,如果当前元素大于key,向左移动,如果当前元素小于key向下移动。
5. void sort()
功能:对矩阵元素进行排序,对矩阵执行元素个数次的delMin()操作就可以得到排序结果。复杂度O(n*m*(n+m))
辅助函数:
==两个函数的实现与实现堆的swim和sink操作思想完全一样==
void swim(int i, int j)
功能:对(i, j)位置元素进行上浮操作,与(i-1, j) 和 (i, j-1)位置的元素进行比较,与他们之间的最大值进行交换
void sink(int i, int j)
功能:对(i, j)位置元素进行下沉操作,与(i+1, j) 和 (i, j+1)位置的元素进行比较, 与他们之间的最小值进行交换
完整代码如下:
const int INF = 0x3fffffff; class YoungMatrix { public: YoungMatrix(int row, int col); // constructor ~YoungMatrix(); // destructor void insert(int x); // insert a element int delMin(); // delete and return the minimal element bool search(int x, int version = 1); // search a element int getMin(); // return the minimal element // sort(); // 调用 n*n delMin()得到结果n*n*(n+n) O(n^3) // print the matrix void printMatrix() { for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) cout << mat[i][j] << "\t"; cout << endl; } cout << endl; } /*** auxiliary function ***/ private: void swim(int i, int j); // swim the element at (i, j), 从右下角上升到左上角 void sink(int i, int j); // sink the element at (i, j), 从左上角下沉到右下角 bool searchHelp1(int x, int y, int key); // recursive function to search the element, divide the problem into sub-matrix (m, n-1) and (m-1, n) bool searchHelp2(int key); // init the position in (0, col-1). like go down the stairs from right to left private: int **mat; int row, col; int num; }; YoungMatrix::YoungMatrix(int row, int col) { this->num = 0; this->row = row; this->col = col; mat = new int*[row]; for (int i = 0; i < row; i++) mat[i] = new int[col]; for (int i = 0; i < row; i++) for (int j = 0; j < col; j++) mat[i][j] = INF; } YoungMatrix::~YoungMatrix() { for (int i = 0; i < row; i++) delete[] mat[i]; delete[] mat; } void YoungMatrix::swim(int i, int j) { while (true) { int v = mat[i][j], p = -1; if (i - 1 >= 0 && v < mat[i - 1][j]) { v = mat[i - 1][j], p = 0; } if (j - 1 >= 0 && v < mat[i][j - 1]) { v = mat[i][j - 1]; p = 1; } if (p == -1) break; if (p == 0) { swap(mat[i - 1][j], mat[i][j]); i -= 1; } else { swap(mat[i][j - 1], mat[i][j]); j -= 1; } } } void YoungMatrix::sink(int i, int j) { while (true) { int v = mat[i][j], p = -1; if (i + 1 < row && v > mat[i + 1][j]) { v = mat[i + 1][j], p = 0; } if (j + 1 < col && v > mat[i][j + 1]) { v = mat[i][j + 1]; p = 1; } if (p == -1) break; if (p == 0) { swap(mat[i + 1][j], mat[i][j]); i += 1; } else { swap(mat[i][j + 1], mat[i][j]); j += 1; } } } void YoungMatrix::insert(int x) { // is full? if (num == col * row) { cerr << "Error: the matrix is full" << endl; return; } // put at the last position this->num++; int i = row - 1, j = col - 1; mat[i][j] = x; swim(i, j); } int YoungMatrix::getMin() { if (this->num > 0) return mat[0][0]; else { cerr << "Error: The matrix is empty" << endl; return -1; } } int YoungMatrix::delMin() { if (this->num <= 0) { cerr << "Error: The matrix is empty" << endl; return -1; } else { int ret = mat[0][0]; mat[0][0] = mat[row - 1][col - 1]; this->num--; sink(0, 0); return ret; } } bool YoungMatrix::search(int x, int version) { if (this->num <= 0) return false; if (version == 1) { return searchHelp1(0, 0, x); } else { return searchHelp2(x); } } bool YoungMatrix::searchHelp1(int x, int y, int key) { if (x >= row || y >= col) return false; if (mat[x][y] < key) return searchHelp1(x + 1, y, key) || searchHelp1(x, y + 1, key); else if (mat[x][y] > key) return false; else return true; } bool YoungMatrix::searchHelp2(int key) { int i = 0, j = col - 1; while (true) { if (i >= row || j >= col) return false; if (mat[i][j] == key) return true; else if (mat[i][j] < key) i++; else if (mat[i][j] > key) j--; } }
测试代码:
#include "YoungMatrix.h" using namespace std; int a[] = { 9, 16, 3, 2, 4, 8, 5, 14, 12 }; int main(int argc, char** argv) { YoungMatrix ym(4,4); int e; for (int i = 0; i < 9; i++) { ym.insert(a[i]); } ym.printMatrix(); cout << "search result: " << ym.search(2, 2) << endl; cout << ym.delMin() << endl; cout << "search result: " << ym.search(2, 2) << endl; ym.printMatrix(); return 0; }