100个python算法超详细讲解:矩阵转置

【100个python算法超详细讲解】@谷哥技术

1.问题描述
编写一个程序,将一个3行3列的矩阵进行转置。
2.问题分析
要解决该问题首先应该清楚什么是矩阵的转置。矩阵转置在数学
上的定义为:
设A为m×n阶矩阵(即m行n列的矩阵),其第i行第j列的元素是
a(i,j),即A=a(i,j) m×n
定义A的转置为这样一个n×m阶矩阵B,满足B=a(j,i) n×m ,即
b(i,j)=a(j,i)(B的第i行第j列元素是A的第j行第i列元素),记为A'=B。
假设有如下的矩阵A:

则经过转置过,即将矩阵的第i行变成了现在的第i列,则原来的矩
阵A变为如下的矩阵B:

 

3.算法设计
解决矩阵问题时通常都是先将矩阵存放在一个二维数组中,而当
矩阵发生变化时,二维数组中对应的元素也会发生变化。
以问题分析中提到的A矩阵为例,要实现A的转置,首先应将其存
放在一个二维数组n中,该二维数组中的元素及其内容如表8.1所示。

表8.1 二维数组n中的元素及其内容

 

将A转置后,二维数组n中的元素及其内容如表8.2所示。
表8.2 A转置后二维数组n中的元素及其内容

 

观察表8.2可知,转置后矩阵主对角线上的数组元素n[0][0]、n[1]
[1]、n[2][2]的值并没有发生变化,只是位于对角线右上方的三个元素
与位于对角线左下方的三个元素的值进行了交换。具体为n[0][1]与n[1]
[0]进行了交换,n[0][2]与n[2][0]进行了交换,n[1][2]与n[2][1]进行了交
换。
根据这个发现就可以来设计我们的算法,在对一个3×3阶矩阵转置
时,只需将主对角线右上方的数组元素n[0][1]、n[0][2]、n[1][2]分别与
主对角线左下方的数组元素n[1][0]、n[2][0]、n[2][1]的值通过一个临时
变量进行交换即可,总共只需要进行三次交换就可以实现矩阵的转
置。
4.确定程序框架
根据算法设计来确定程序的主体结构。矩阵问题和循环结构是分
不开的,要想访问二维数组中的每个元素,就需要使用一个双重循
环。这里我们可以使用一个双重的for循环在循环体中完成数组元素交
换,即矩阵转置的任务。
我们先来分析下面这段代码:

for i in range(3):
for j in range(3):
if i != j:
temp = n[i][j]
n[i][j] = n[j][i]
n[j][i] = temp

 在上面这段代码中利用双重循环遍历了二维数组中所有的数组元
素,在循环体中使用了临时变量temp,将数组中的元素n[i][j]和与之对
应的n[j][i]进行了交换。请读者思考这样做是否正确呢?
先考虑外层循环的次数,外层循环的变量为i,它的取值为0、1、
2,共循环三次。由于是双重循环,因此对于每一次外层循环,都嵌入
了一个循环变量为j的内层循环,j的取值也为0、1、2,内层循环也有
三次,这样,内层循环总共运行了3×3=9次。除去(i=0,j=0)、(i=1,j=1)和
(i=2,j=2)的三次外,代码中加粗的部分,即if语句中的布尔表达式i!=j在
其中的6次循环中都是成立的,所以在整个循环过程中一共进行了6次
形如n[i][j]与n[j][i]的数组元素之间值的交换,而我们已经分析过正确的
交换次数应该是3次。显然不符合矩阵转置的要求,因此上面的代码是
有问题的,但哪里有问题呢?
出问题的部分就是if语句中的布尔表达式。布尔表达式i!=j没有限
定只能将主对角线右上方的数组元素与主对角线左下方的数组元素进
行单方向交换,因此,主对角线右上方的数组元素与主对角线左下方
的数组元素发生了双方向交换,这样交换次数就变成了6次,而且矩阵
并没有被转置。
改正的方法很简单,只需将if语句的条件修改为j>i即可,代码如
下:

for i in range(3):
for j in range(3):
#将主对角线右上方的数组元素与主对角线左下方的数组元素进行单方向交换
if j > i:
temp = n[i][j]
n[i][j] = n[j][i]
n[j][i] = temp

按照上面的代码执行就可以正确地实现矩阵的转置。程序流程图
如图8.5所示。
5.完整的程序
根据上面的分析,编写程序如下:

#!/usr/bin/python3
# -*- coding: utf-8 -*-
# @author : liuhefei
# @desc: 矩阵转置
if __name__ == "__main__":
n = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
print("原始矩阵:")
for i in range(3):
for j in range(3):
print("%d " %(n[i][j]), end=" ") # 输出原始矩阵
print()
for i in range(3):
for j in range(3):
#将主对角线右上方的数组元素与主对角线左下方的数组元素进行单方向交换
if j > i:
temp = n[i][j]
n[i][j] = n[j][i]
n[j][i] = temp
print("转置矩阵:")
for i in range(3):
for j in range(3):
print("%d " %(n[i][j]), end=" ")
print()

6.运行结果
在PyCharm下运行程序,结果如图8.6所示。由图8.6可见,程序正
确地生成了原始矩阵的转置矩阵。

 

7.问题拓展
在解决与矩阵相关的问题时,常常需要使用到二维数组。而要想
遍历二维数组中的每个元素就需要使用双重循环,一般使用的是两个
for循环,例如我们在解决矩阵转置问题时就是这样处理的。
与矩阵相关的问题除了矩阵转置以外,还有编程实现矩阵的加、
减、乘,以及求矩阵元素的最大值、最小值和求对角线元素的和等运
算。此处,我们再介绍如何求矩阵元素的最大值和最小值,其他的矩
阵问题读者可作为练习自己编程实现。
已知有一个3×4的矩阵,要求编程求出其中值最大及最小的元素所
在的行号和列号,以及该元素的值。
显然,要解决这个问题必须要遍历矩阵中的每个元素,因此程序
的结构就是一个双重的for循环,在循环体中进行的就是矩阵元素的比
较,然后找出最大和最小元素。
该问题的程序流程图如图8.7所示。

完整的程序如下:

#!/usr/bin/python3
# -*- coding: utf-8 -*-
# @author : liuhefei
# @desc: 求矩阵的最值
if __name__ == "__main__":
row1, row2 = 0, 0 # 行下标
column1, column2 = 0, 0 # 列下标
a = [[12, 17, 13, 16], [18, 11, 19, 15], [10, 14, 12, 15]]
print("打印矩阵:")
for i in range(3):
for j in range(4):
print("%d " %(a[i][j]), end=" ")
print()
max = a[0][0] # 设置max的初值
min = a[0][0] # 设置min的初值
# 矩阵中每个元素逐一与max进行比较
for i in range(3):
for j in range(4):
if a[i][j] > max: # 如果某个矩阵元素大于max,则将其与max进行交换
max= a[i][j]
row1 = i
column1 = j
if a[i][j] < min: # 如果某个矩阵元素小于min,则将其与min进行交换
min = a[i][j]
row2 = i
column2 = j
print("矩阵的最大值为:%d,其所在行为第%d行,所在列为第%d列\n" %(max, row1, column1))
print("矩阵的最小值为:%d,其所在行为第%d行,所在列为第%d列\n" %(min, row2, column2))

 在PyChar下运行程序,结果如图8.8所示。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lee达森

创作不易,感谢打赏!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值