python行列式值计算程序_解行列式程序 python代码实现

解行列式程序 python代码实现

制作背景

大二上学期结束要放假时,线性代数有一个小作业:做一个阶行列式的程序。由于我此时最熟悉的语言是Python,所以就用python做的。我猜到网上应该有很多答案,但是为了锻炼,我没查资料,我尽可能自己造轮子。也没引用到任何库,就按上课老师讲的思路来的。

现功能

理论上能计算任意阶的行列式,但由于性能和算法原因,只能计算1~10阶。

主要思路

n阶行列式用二维数组表示

用户逐行输入行列式

实现计算行列式的方法

获取行列式的每一条路径,(路径的每个数的每行每列都不重复)

例如:

1 2 3

4 5 6

7 8 9

1->5->9

1->6->8

2->4->9

2->6->7

3->4->8

3->5->7

如果把每个路径上的数字改为对应的x坐标,就是:

0 1 2 3

.--------> x

1 | 1 2 3

2 | 4 5 6

3 | 7 8 9

y

1->2->3

1->3->2

2->1->3

2->3->1

3->1->2

3->2->1

这样,获取路径的数字可以通过获取二维数组的下标获得,二维数组的下标相当于上面转换后的路径。观察发现,获取n阶行列式的所有路径问题转化成了求n的全排列问题。

若获取n的全排列,可以先画(构建)个树结构

n=3:

start

/ | \

/ | \

1 2 3

/| /\ |\

2 3 1 3 1 2

| | | | | |

3 2 3 1 2 1

构建这样一棵树,从上到下的每条路径都为要获取的路径。

创建节点类

节点 {

data: 存放此节点数据

child: 存放子节点们的集合

father: 存放父节点

}

用递归法添加节点

当前节点为空节点

// 对应 add() 函数

递归函数 (当前节点 当前路径上已有的节点集合) {

遍历 n {

如果n 不在 当前路径上已有的节点集合 中 {

创建 新节点

新节点的 父 为当前节点

新节点的 子 添加n

添加 新节点 到当前路径上已有的节点集合

如果 当前路径上已有的节点集合长度 <= n {

递归函数 (新节点 当前路径上已有的节点集合)

}

}

}

}

获取每条路径

具体代码对应 getAllPath() 函数

递归的进入每个分支

归到了最深,则把当前节点一直到最祖先节点的路径反添加到记录

把当前节点一直到最祖先节点的路径反添加到记录的方法具体见 getPath() 递归函数

获取每条路径的所有x坐标位数字的逆序数

把每条路径的所有实际数据相乘,得到结果

如果逆序数为偶数,则该路径的结果为正,奇数则负

将所有结果先加,得到最终结果。

源代码

# -*- encoding: utf-8 -*-

"""

计算行列式的程序

2021年1月15日

by littlefean

"""

def main():

while True:

n = eval(input("请输入行列式的阶数:"))

if n > 0:

temp = []

array = []

for y in range(n):

line = input(f"请输入第{y + 1}行的所有数据,中间用空格隔开:").split()

temp.append(line)

for y in range(n):

numLine = []

for x in range(n):

numLine.append(int(temp[y][x]))

array.append(numLine)

detCalc(array)

else:

print("输入阶数不符合规范")

continue

def detCalc(det: list):

"""

计算行列式

det: 表示行列式的二维数组

注意:请保证二维数组的形状为正方形

return: 行列式的计算结果

"""

level = len(det) # 获得行列式的阶数

paths = fullPermutation(level)

d = 0 # 最终结果

pathsResults = []

printDet(det)

print("=", end=" ")

for path in paths:

y = 0

num = 1 # 每条路径的结果

if tao(path) % 2 == 0:

print("+(", end="")

else:

print("-(", end="")

for x in range(len(path)):

if x == len(path) - 1:

print(det[y][path[x]], end="")

else:

print(det[y][path[x]], end="x")

num *= det[y][path[x]]

y += 1

if tao(path) % 2 == 0:

d += num

pathsResults.append(num)

else:

d -= num

pathsResults.append(-num)

print(")", end="")

print()

print("=", end=" ")

for r in range(len(pathsResults)):

if r == 0 and pathsResults[r] >= 0:

print(f"{pathsResults[r]}", end=" ")

if pathsResults[r] >= 0:

print(f"+{pathsResults[r]}", end=" ")

else:

print(f"{pathsResults[r]}", end=" ")

print()

print(f"= {d}")

return d

def printDet(arr):

"""

传入二维数组,打印行列式

:param arr:

:return:

"""

maxStrLen = 1

for line in arr:

for x in line:

if len(str(x)) > maxStrLen:

maxStrLen = len(str(x))

for line in arr:

print("|", end=" ")

for x in line:

print(" " * (maxStrLen - len(str(x))) + str(x), end=" ")

print("|")

def tao(arr: list):

"""

传入数组,返回该数组的逆序数

arr: 所有元素都为int类型数据的数组

return: 正整数

"""

n = 0

for i in range(len(arr) - 1):

for j in range(i + 1, len(arr)):

if arr[i] > arr[j]:

n += 1

return n

def fullPermutation(n: int):

"""

输入一个正整数 n,返回 [0, n-1]组成的所有排列情况组成的二维列表

例如:

传入 n = 3

返回 [[0, 1, 2],[0, 2, 1],[1, 0, 2],[1, 2, 0],[2, 0, 1],[2, 1, 0]]

"""

class Joint:

"""节点类,用于构建树结构"""

def __init__(self, data, father):

"""

data: 表示本节点自身存储的数据

child: 表示存储子节点的列表,请自觉保证其类型均为 Joint

father: 表示节点的父节点,请自觉保证其类型同样为 Joint,如果没有父节点请写 None

"""

self.data = data

self.child = []

self.father = father

def show(self):

"""

在终端打印此节点以及它的所有子节点所组成的树结构

return: 无返回值

"""

def printSelf(jnt, deep):

tabStr = "\t" * deep

print(tabStr + str(jnt.data))

deep += 1

if len(jnt.child) != 0:

for jt in jnt.child:

printSelf(jt, deep)

printSelf(self, 1)

def getAllPath(self):

"""

获取此节点对象与所有子节点所组成的树结构 的所有路径 并将所有路径以数组的形式返回

return: 二维数组,该二维数组由很多 “路径数组”组成,路径数组 由该路径上所有节点的 item 属性值组成

"""

array = []

def getPath(jnt: Joint):

"""

传入节点 jnt

返回 祖先节点到当前节点 jnt 所组成的路径数组,路径数组由每个节点的 item 属性值组成

"""

arr = [jnt.data]

def goOut(jt):

"""递归的向父节点走"""

if jt.father.data is not None:

arr.append(jt.father.data)

goOut(jt.father)

else:

return

goOut(jnt)

return arr[::-1]

def goIn(jnt):

"""递归的深入每一个分支"""

for son in jnt.child:

if len(son.child) == 0:

arr = getPath(son)

array.append(arr)

else:

goIn(son)

goIn(self)

return array

root = Joint(None, None)

def add(r, arr):

"""

递归地添加节点,用于构造全排列的树结构

r: 用于表示递归中的当前节点

arr: 表示该节点到祖先节点的路径上已经存在的所有节点的 item 属性

"""

for x in range(n):

if x not in arr:

jSon = Joint(x, r)

r.child.append(jSon)

arrNew = arr + [x]

if len(arrNew) <= n:

add(jSon, arrNew)

add(root, [None])

# 把树的每一个路径都抽取出来

return root.getAllPath()

if __name__ == '__main__':

main()

不足之处

获取每条路径的方式很消耗时间和空间

此算法为一般方法,还可以更新有技巧的方法。

你可能感兴趣的:(python行列式值计算程序)