问题分析
输入:磁带中的 4000 x 4000 矩阵
输出:转置后的矩阵
约束:无
解答思路
常见的思路是遍历上/下三角矩阵,交换 a[i][j] 和 a[j][i] 进行转置。但由于 a[i][j] 和 a[j][i] 在磁带中不是存放在一起的,因此交换这两个元素会很容易引发磁盘IO中断。
因此,对于处理磁盘中的数据,最好是连续的进行处理。( 事实上对内存中的数据也是如此 这样可以充分利用内存预读技术 )
故可采用以下思路对磁盘中的矩阵进行转置:
1. 给矩阵文件中的每个元素附加上其行号和列号
2. 对矩阵以行为关键字进行排序 形成矩阵
3. 对矩阵以列为关键字进行排序 转置矩阵
为了测试方便,下面的测试矩阵是存放在内存的二维数组中的。对于存放在磁盘中的情况类似。
代码实现
1 #include <iostream> 2 3 using namespace std; 4 5 // 声明矩阵元素类型 6 class Elem { 7 public: 8 Elem() { 9 this->r = 0; 10 this->c = 0; 11 this->e = 0; 12 } 13 int getR() { 14 return r; 15 } 16 int getC() { 17 return c; 18 } 19 int getElem() { 20 return e; 21 } 22 void setElem(int r, int c, int e) { 23 this->r = r; 24 this->c = c; 25 this->e = e; 26 } 27 private: 28 int r; 29 int c; 30 int e; 31 }; 32 33 int main(void) { 34 // 创建二维矩阵并初始化 然后打印 然后输出 35 Elem A[10][10]; 36 37 int t=1; 38 for (int i=0; i<10; i++) { 39 for (int j=0; j<10; j++) { 40 A[i][j].setElem(i, j, t++); 41 } 42 } 43 44 cout << "矩阵转置前:" << endl; 45 for (int i=0; i<10; i++) { 46 for (int j=0; j<10; j++) { 47 cout << A[i][j].getElem() << " "; 48 } 49 cout << endl; 50 } 51 cout << endl; 52 53 // 将矩阵按列转置 54 Elem *p = &A[0][0]; 55 for (int i=1; i<100; i++) { 56 int temr = (p+i)->getR(); 57 int temc = (p+i)->getC(); 58 int teme = (p+i)->getElem(); 59 60 int j; 61 for (j=i-1; j>=0; j--) { 62 if((p+j)->getC() > temc) { 63 (p+j+1)->setElem((p+j)->getR(), (p+j)->getC(), (p+j)->getElem()); 64 } 65 else 66 break; 67 } 68 (p+j+1)->setElem(temr, temc, teme); 69 } 70 71 cout << "矩阵转置后:" << endl; 72 for (int i=0; i<10; i++) { 73 for (int j=0; j<10; j++) { 74 cout << A[i][j].getElem() << " "; 75 } 76 cout << endl; 77 } 78 cout << endl; 79 80 return 0; 81 }
运行测试
小结
也许读者会疑惑为何只进行了列排序而没进行行排序。这是因为测试是直接在二维数组中进行的,而二维数组本身自动进行过行排序了。