鱼C论坛

 找回密码
 立即注册
12
返回列表 发新帖
楼主: 万千只cnm

[已解决]分块矩阵转置

[复制链接]
发表于 2021-9-21 10:07:58 | 显示全部楼层
开卷有益,多多益善·····
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-9-21 10:34:32 | 显示全部楼层
3.png

这个你还是没有说对不对
不过你没有说错,而且从你说的内容来看,应该是对的,那我就认为是对的了

  1. #include <algorithm>
  2. #include <iostream>

  3. using namespace std;

  4. void TransposeMatri(int **array, int n) { //全部转置
  5.     for(int i = 0; i < n; i++)
  6.         for(int j = 0; j < n; j++) {
  7.             if(j > i) //主副三角
  8.                 swap(array[i][j], array[j][i]);
  9.         }
  10. }

  11. void Block_transpose(int **array, int n) { //分块转置
  12.     int k = 2;
  13.     for(int i = 0; i < n; i += k)
  14.         for(int j = 0; j < n; j += k)
  15.             TransposeMatri((int **)((int *)array + i * n + j), k);
  16. }

  17. int main() {
  18.     int **a = new int *[4];
  19.     for(int i = 0; i < 4; i++)
  20.         a[i] = new int[4];
  21.     for(int i = 0; i < 4; i++) {
  22.         for(int j = 0; j < 4; j++) {
  23.             a[i][j] = i * 4 + j;
  24.         }
  25.     }
  26.     for(int i = 0; i < 4; i++) {
  27.         for(int j = 0; j < 4; j++)
  28.             cout << a[i][j] << ' ';
  29.         cout << endl;
  30.     }
  31.     Block_transpose(a, 4);
  32.     cout << "---------------------" << endl;
  33.     /*
  34.     for(int i = 0; i < 4; i++)
  35.         for(int j = 0; j < 4; j++)
  36.             cout << a[i][j] << ' ';
  37.     cout << endl;
  38.     */
  39.     for(int i = 0; i < 4; i++) {
  40.         for(int j = 0; j < 4; j++)
  41.             cout << a[i][j] << ' ';
  42.         cout << endl;
  43.     }
  44.     // 释放一定要写,不写释放的代码在一些环境下会报错的
  45.     for(int i = 0; i < 4; i++)
  46.         delete[] a[i];
  47.     delete[] a;
  48.     return 0;
  49. }
复制代码

1.jpg

这个代码是错的,因为你进行了强制类型转换,可以通过编译了,但是类型不对
地址值是一样的,但是类型不对
应该转成下面这样

  1. #include <algorithm>
  2. #include <iostream>

  3. using namespace std;

  4. void TransposeMatri(int **array, int n) { //全部转置
  5.     for(int i = 0; i < n; i++)
  6.         for(int j = 0; j < n; j++) {
  7.             if(j > i) //主副三角
  8.                 //swap(array[i][j], array[j][i]);
  9.                 swap((*(int (*)[n][n])(array))[i][j], (*(int (*)[n][n])(array))[j][i]);
  10.         }
  11. }

  12. void Block_transpose(int **array, int n) { //分块转置
  13.     int k = 2;
  14.     for(int i = 0; i < n; i += k)
  15.         for(int j = 0; j < n; j += k)
  16.             TransposeMatri((int **)((int *)array + i * n + j), k);
  17. }

  18. int main() {
  19.     int **a = new int *[4];
  20.     for(int i = 0; i < 4; i++)
  21.         a[i] = new int[4];
  22.     for(int i = 0; i < 4; i++) {
  23.         for(int j = 0; j < 4; j++) {
  24.             a[i][j] = i * 4 + j;
  25.         }
  26.     }
  27.     for(int i = 0; i < 4; i++) {
  28.         for(int j = 0; j < 4; j++)
  29.             cout << a[i][j] << ' ';
  30.         cout << endl;
  31.     }
  32.     Block_transpose(a, 4);
  33.     cout << "---------------------" << endl;
  34.     /*
  35.     for(int i = 0; i < 4; i++)
  36.         for(int j = 0; j < 4; j++)
  37.             cout << a[i][j] << ' ';
  38.     cout << endl;
  39.     */
  40.     for(int i = 0; i < 4; i++) {
  41.         for(int j = 0; j < 4; j++)
  42.             cout << a[i][j] << ' ';
  43.         cout << endl;
  44.     }
  45.     // 释放一定要写,不写释放的代码在一些环境下会报错的
  46.     for(int i = 0; i < 4; i++)
  47.         delete[] a[i];
  48.     delete[] a;
  49.     return 0;
  50. }
复制代码

2.jpg

  1. TransposeMatri((int **)((int *)array + i * n + j), k);
复制代码

我一开始确实是在这里改的,但是我发现这里修改对 int a[4][4];,这样的数组无效,所以修改了
  1. swap((*(int (*)[n][n])(array))[i][j], (*(int (*)[n][n])(array))[j][i]);
复制代码



但是这样依然不对,因为这样的转换要求数组中的值是连续存放的,通过 new 这样的形式创建出来的数组,数组中存储的值不是连续的

  1. #include <algorithm>
  2. #include <iostream>

  3. using namespace std;

  4. void TransposeMatri(int **array, int n) { //全部转置
  5.     for(int i = 0; i < n; i++)
  6.         for(int j = 0; j < n; j++) {
  7.             if(j > i) //主副三角
  8.                 //swap(array[i][j], array[j][i]);
  9.                 swap((*(int (*)[n][n])(array))[i][j], (*(int (*)[n][n])(array))[j][i]);
  10.         }
  11. }

  12. void Block_transpose(int **array, int n) { //分块转置
  13.     int k = 2;
  14.     for(int i = 0; i < n; i += k)
  15.         for(int j = 0; j < n; j += k)
  16.             TransposeMatri((int **)((int *)array + i * n + j), k);
  17. }

  18. int main() {
  19.     /*
  20.     int **a = new int *[4];
  21.     for(int i = 0; i < 4; i++)
  22.         a[i] = new int[4];
  23.     */
  24.     int a[4][4];
  25.     for(int i = 0; i < 4; i++) {
  26.         for(int j = 0; j < 4; j++) {
  27.             a[i][j] = i * 4 + j;
  28.         }
  29.     }
  30.     for(int i = 0; i < 4; i++) {
  31.         for(int j = 0; j < 4; j++)
  32.             cout << a[i][j] << ' ';
  33.         cout << endl;
  34.     }
  35.     //Block_transpose(a, 4);
  36.     Block_transpose((int **)a, 4);
  37.     cout << "---------------------" << endl;
  38.     /*
  39.     for(int i = 0; i < 4; i++)
  40.         for(int j = 0; j < 4; j++)
  41.             cout << a[i][j] << ' ';
  42.     cout << endl;
  43.     */
  44.     for(int i = 0; i < 4; i++) {
  45.         for(int j = 0; j < 4; j++)
  46.             cout << a[i][j] << ' ';
  47.         cout << endl;
  48.     }
  49.     /*
  50.     // 释放一定要写,不写释放的代码在一些环境下会报错的
  51.     for(int i = 0; i < 4; i++)
  52.         delete[] a[i];
  53.     delete[] a;
  54.     */
  55.     return 0;
  56. }
复制代码
  1. $ ./main
  2. 0 1 2 3
  3. 4 5 6 7
  4. 8 9 10 11
  5. 12 13 14 15
  6. ---------------------
  7. 0 2 1 4
  8. 3 5 6 7
  9. 8 10 9 12
  10. 11 13 14 15
  11. $
复制代码


这样就能运行了,不会在运行的时候报错,然后停止运行了
但是结果依然不对
因为这个数组在内存中是这样存储的
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
是线性的,0 后面存储 1,1 后面存储 2,2 后面存储 3,。。。
第一个子矩阵中,你要互换的是 1 和 4,但是 1 和 4 并不挨着
要么进行计算,算出 4 的地址,要么创建一个临时数组,让 1 和 4 挨着
我选择了后者
  1. #include <algorithm>
  2. #include <iostream>

  3. using namespace std;

  4. void TransposeMatri(int **array, int n) { //全部转置
  5.     for(int i = 0; i < n; i++)
  6.         for(int j = 0; j < n; j++) {
  7.             if(j > i) //主副三角
  8.                 //swap(array[i][j], array[j][i]);
  9.                 swap((*(int (*)[n][n])(array))[i][j], (*(int (*)[n][n])(array))[j][i]);
  10.         }
  11. }

  12. void Block_transpose(int **array, int n) { //分块转置
  13.     /*
  14.     int k = 2;
  15.     for(int i = 0; i < n; i += k)
  16.         for(int j = 0; j < n; j += k)
  17.             TransposeMatri((int **)((int *)array + i * n + j), k);
  18.     */
  19.     int k = 2;
  20.     for(int i = 0; i < n; i += k)
  21.         for(int j = 0; j < n; j += k) {
  22.             int a[k][k];
  23.             for(int y = 0; y < k; ++y) {
  24.                 for(int x = 0; x < k; ++x) {
  25.                     a[y][x] = (*(int (*)[n][n])array)[i + y][j + x];
  26.                 }
  27.             }
  28.             //TransposeMatri((int **)((int *)array + i * n + j), k);
  29.             TransposeMatri((int **)a, k);
  30.             for(int y = 0; y < k; ++y) {
  31.                 for(int x = 0; x < k; ++x) {
  32.                     (*(int (*)[n][n])array)[i + y][j + x] = a[y][x];
  33.                 }
  34.             }
  35.         }
  36. }

  37. int main() {
  38.     /*
  39.     int **a = new int *[4];
  40.     for(int i = 0; i < 4; i++)
  41.         a[i] = new int[4];
  42.     */
  43.     int a[4][4];
  44.     for(int i = 0; i < 4; i++) {
  45.         for(int j = 0; j < 4; j++) {
  46.             a[i][j] = i * 4 + j;
  47.         }
  48.     }
  49.     for(int i = 0; i < 4; i++) {
  50.         for(int j = 0; j < 4; j++)
  51.             cout << a[i][j] << ' ';
  52.         cout << endl;
  53.     }
  54.     //Block_transpose(a, 4);
  55.     Block_transpose((int **)a, 4);
  56.     cout << "---------------------" << endl;
  57.     /*
  58.     for(int i = 0; i < 4; i++)
  59.         for(int j = 0; j < 4; j++)
  60.             cout << a[i][j] << ' ';
  61.     cout << endl;
  62.     */
  63.     for(int i = 0; i < 4; i++) {
  64.         for(int j = 0; j < 4; j++)
  65.             cout << a[i][j] << ' ';
  66.         cout << endl;
  67.     }
  68.     /*
  69.     // 释放一定要写,不写释放的代码在一些环境下会报错的
  70.     for(int i = 0; i < 4; i++)
  71.         delete[] a[i];
  72.     delete[] a;
  73.     */
  74.     return 0;
  75. }
复制代码
  1. $ ./main
  2. 0 1 2 3
  3. 4 5 6 7
  4. 8 9 10 11
  5. 12 13 14 15
  6. ---------------------
  7. 0 4 2 6
  8. 1 5 3 7
  9. 8 12 10 14
  10. 9 13 11 15
  11. $
复制代码

  1. a[y][x] = (*(int (*)[n][n])array)[i + y][j + x];
复制代码

其实这样也需要计算 4 的地址,然后读取 4 的值到 临时数组
我认为创建临时数组比较好,所以选择了创建临时数组

小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-9-21 10:43:44 | 显示全部楼层    本楼为最佳答案   
其实对于调试程序,输入和输出是很重要的,不知道输出就不知道努力的方向,不知道应该把程序调试成什么样子,不知道应该通过调试让程序输出什么
而输出依赖于输入
正确的输出依赖于正确的输入,知道了输入和输出问题就简单了,因为你知道正确的输出,就知道了要把程序调试成什么样子
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-9-21 12:49:14 | 显示全部楼层
人造人 发表于 2021-9-21 10:34
这个你还是没有说对不对
不过你没有说错,而且从你说的内容来看,应该是对的,那我就认为是对的了

”通过 new 这样的形式创建出来的数组,数组中存储的值不是连续的“
请问这句话啥意思 跟c的malloc不一样吗 不都是申请的一整块空间嘛

  1. swap((*(int (*)[n][n])(array))[i][j], (*(int (*)[n][n])(array))[j][i]);
复制代码

这是先array转换为一个指向二维数组的指针然后解引用吗

“这个代码是错的,因为你进行了强制类型转换,可以通过编译了,但是类型不对
地址值是一样的,但是类型不对”
如果说array本来是个指针数组名  我强制转换为int** 为啥会不对

小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-9-21 12:52:21 | 显示全部楼层
jhq999 发表于 2021-9-21 06:58
这个流程,而且成员越多,小矩阵互换越多

是不不止要分成4个子矩阵换吗
我感觉正中间的子矩阵也要互换才能
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-9-21 13:21:47 | 显示全部楼层
万千只cnm 发表于 2021-9-21 12:49
”通过 new 这样的形式创建出来的数组,数组中存储的值不是连续的“
请问这句话啥意思 跟c的malloc不一 ...
  1. #include <iostream>

  2. int main() {
  3.     int a[4][4];
  4.     for(int i = 0; i < 4; i++) {
  5.         for(int j = 0; j < 4; j++) {
  6.             a[i][j] = i * 4 + j;
  7.         }
  8.     }
  9.     for(int i = 0; i < 4; i++) {
  10.         for(int j = 0; j < 4; j++) {
  11.             std::cout << &a[i][j] << ": " << a[i][j] << std::endl;
  12.         }
  13.     }
  14.     return 0;
  15. }
  16. /*
  17. 0xffffcbd0: 0
  18. 0xffffcbd4: 1
  19. 0xffffcbd8: 2
  20. 0xffffcbdc: 3
  21. 0xffffcbe0: 4
  22. 0xffffcbe4: 5
  23. 0xffffcbe8: 6
  24. 0xffffcbec: 7
  25. 0xffffcbf0: 8
  26. 0xffffcbf4: 9
  27. 0xffffcbf8: 10
  28. 0xffffcbfc: 11
  29. 0xffffcc00: 12
  30. 0xffffcc04: 13
  31. 0xffffcc08: 14
  32. 0xffffcc0c: 15
  33. */
复制代码

  1. #include <iostream>

  2. int main() {
  3.     int **a = new int *[4];
  4.     for(int i = 0; i < 4; i++) {
  5.         a[i] = new int[4];
  6.         for(int j = 0; j < 4; j++) {
  7.             a[i][j] = i * 4 + j;
  8.         }
  9.     }
  10.     for(int i = 0; i < 4; i++) {
  11.         for(int j = 0; j < 4; j++) {
  12.             std::cout << &a[i][j] << ": " << a[i][j] << std::endl;
  13.         }
  14.     }
  15.     for(int i = 0; i < 4; i++) delete[] a[i];
  16.     delete[] a;
  17.     return 0;
  18. }
  19. /*
  20. 0x800038ca0: 0
  21. 0x800038ca4: 1
  22. 0x800038ca8: 2
  23. 0x800038cac: 3
  24. 0x800038cc0: 4      // 这里应该是 0x800038cb0 才是连续的
  25. 0x800038cc4: 5
  26. 0x800038cc8: 6
  27. 0x800038ccc: 7
  28. 0x80004b140: 8      // 0x800038cd0,如果从数组开始,这个地址是 0x800038cc0
  29. 0x80004b144: 9
  30. 0x80004b148: 10
  31. 0x80004b14c: 11
  32. 0x80004b160: 12     // 0x80004b150, 0x800038cd0
  33. 0x80004b164: 13
  34. 0x80004b168: 14
  35. 0x80004b16c: 15
  36. */
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-9-21 13:34:20 | 显示全部楼层
万千只cnm 发表于 2021-9-21 12:49
”通过 new 这样的形式创建出来的数组,数组中存储的值不是连续的“
请问这句话啥意思 跟c的malloc不一 ...

地址一样,类型不对
  1. #include <iostream>

  2. void func(int **a) {
  3.     for(int i = 0; i < 4; i++) {
  4.         std::cout << a[i] << std::endl;
  5.     }
  6.     /*
  7.     for(int i = 0; i < 4; i++) {
  8.         for(int j = 0; j < 4; j++) {
  9.             std::cout << a[i][j] << std::endl;
  10.         }
  11.     }
  12.     */
  13. }

  14. int main() {
  15.     int a[4][4];
  16.     for(int i = 0; i < 4; i++) {
  17.         for(int j = 0; j < 4; j++) {
  18.             a[i][j] = i * 4 + j;
  19.         }
  20.     }
  21.     func((int **)a);
  22.     return 0;
  23. }
  24. /*
  25. 0x100000000
  26. 0x300000002
  27. 0x500000004
  28. 0x700000006
  29. */
复制代码


这个输出结果你可能已经明白了,但是看了下面这个输出结果,你肯定明白了
  1. #include <iostream>

  2. void func(long long **a) {
  3.     for(int i = 0; i < 4; i++) {
  4.         std::cout << a[i] << std::endl;
  5.     }
  6.     /*
  7.     for(int i = 0; i < 4; i++) {
  8.         for(int j = 0; j < 4; j++) {
  9.             std::cout << a[i][j] << std::endl;
  10.         }
  11.     }
  12.     */
  13. }

  14. int main() {
  15.     long long a[4][4];
  16.     for(int i = 0; i < 4; i++) {
  17.         for(int j = 0; j < 4; j++) {
  18.             a[i][j] = i * 4 + j;
  19.         }
  20.     }
  21.     func((long long **)a);
  22.     return 0;
  23. }
  24. /*
  25. 0
  26. 0x1
  27. 0x2
  28. 0x3
  29. */
复制代码


一次解引用得到的就已经是数组中存储的值了,然后再对这个值解引用?
如果这个值是 0,那就是对 0 解引用
对于第二个代码,a[i][j] 就是对 0x00000000、0x00000001、0x00000002、0x00000003
这 4 个地址解引用

  1. #include <iostream>

  2. void func(long long **a) {
  3.     for(int i = 0; i < 4; i++) {
  4.         std::cout << a[i] << std::endl;
  5.     }
  6.     for(int i = 0; i < 4; i++) {
  7.         for(int j = 0; j < 4; j++) {
  8.             std::cout << a[i][j] << std::endl;
  9.         }
  10.     }
  11. }

  12. int main() {
  13.     long long a[4][4];
  14.     for(int i = 0; i < 4; i++) {
  15.         for(int j = 0; j < 4; j++) {
  16.             a[i][j] = i * 4 + j;
  17.         }
  18.     }
  19.     func((long long **)a);
  20.     return 0;
  21. }
  22. /*
  23. 0
  24. 0x1
  25. 0x2
  26. 0x3
  27. Segmentation fault (core dumped)
  28. */
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-9-21 13:37:11 | 显示全部楼层
1.png
2.png
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-9-21 13:51:34 | 显示全部楼层
地址一样,但是类型不对
  1. #include <iostream>

  2. int main() {
  3.     long long a[4][4] = {
  4.         {123, 456, 789, -1},
  5.         {223, 556, 889, -2},
  6.         {323, 656, 989, -3},
  7.         {423, 756, 189, -4}
  8.     };
  9.     long long **x = (long long **)a;
  10.     std::cout << a[0] << std::endl;
  11.     std::cout << x[0] << std::endl;
  12.     std::cout << (long long)a[0] << std::endl;
  13.     std::cout << (long long)x[0] << std::endl;
  14.     return 0;
  15. }
  16. /*
  17. 0xffffcb90
  18. 0x7b
  19. 4294953872
  20. 123
  21. */
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-9-21 21:44:11 | 显示全部楼层
人造人 发表于 2021-9-21 13:51
地址一样,但是类型不对

道理我是懂呀。
但我是new申请的数组不算严格的数组吧 new申请的二维数组不就是指针形式吗
为什么swap还要换呢
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-9-21 22:22:30 | 显示全部楼层
万千只cnm 发表于 2021-9-21 21:44
道理我是懂呀。
但我是new申请的数组不算严格的数组吧 new申请的二维数组不就是指针形式吗
为什么swap ...

没明白你的问题
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-9-22 18:14:54 | 显示全部楼层
  1. swap(array[i][j], array[j][i]);
复制代码

array本来就是一个int ** 指针呀  指向new申请的空间
不是二维数组名 ,不存在强制转换类型吧?
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-9-22 18:29:35 | 显示全部楼层
万千只cnm 发表于 2021-9-22 18:14
array本来就是一个int ** 指针呀  指向new申请的空间
不是二维数组名 ,不存在强制转换类型吧?
  1. TransposeMatri((int **)((int *)array + i * n + j), k);
复制代码


你在这里进行了强制类型转换
还有,你可以写一个示例代码说明你的问题吗?我还是不理解你的问题
示例代码越短小越好,能够说明你的问题就好了

你这样描述,我也没有什么概念,还是尽量用代码说话比较好
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-9-22 18:43:43 | 显示全部楼层
人造人 发表于 2021-9-22 18:29
你在这里进行了强制类型转换
还有,你可以写一个示例代码说明你的问题吗?我还是不理解你的问题
示 ...

array本身就是一个指针
  1. int **a = new int *[4];
复制代码

用这种方式来形成二维数组
我为了定位到 下一个子矩阵  i*n就是一行的总地址,j就列的地址
array+行+列 就是子矩阵的首地址,然后转换为 int**  就跟原形式一样了  
但你说了new申请的空间不一定连续 我就知道我错了
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-9-22 19:25:40 | 显示全部楼层
万千只cnm 发表于 2021-9-22 18:43
array本身就是一个指针

用这种方式来形成二维数组

嗯,也就是说这个问题你明白了?
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-9-22 19:29:04 | 显示全部楼层
人造人 发表于 2021-9-22 19:25
嗯,也就是说这个问题你明白了?

小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-4-26 10:58

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表