用MATLAB写出高斯消去法、高斯列主消去法、直接三角分解法、平方根法、追赶法对于解普通线性方程组的代码,并于MATLAB自身函数对呀线性方程组的解作比较,最好以图形的方式比较
时间: 2025-03-29 12:02:35 浏览: 37
<think>嗯,用户让我用MATLAB写几种解线性方程组的算法,还要和MATLAB内置函数比较,最好用图形展示。首先,我需要确认用户的需求是什么。他可能是在学习数值分析,需要实现这些算法,并比较它们的性能和准确性。我需要先回忆这些算法的步骤,然后考虑如何在MATLAB中实现。
首先,高斯消去法,这是基本的,分为消元和回代。然后高斯列主消去法,需要选列主元来避免除零错误和提高数值稳定性。直接三角分解法,应该是LU分解吧,把矩阵分解成下三角和上三角矩阵。平方根法针对对称正定矩阵,用Cholesky分解。追赶法则适用于三对角矩阵,是LU分解的特殊情况。
接下来,我需要为每个算法写出MATLAB函数。比如高斯消去法,先写一个函数,输入系数矩阵A和向量b,输出解x。需要注意消元过程中可能出现主元为零的情况,这时候普通高斯消去会失败,列主元则需要选每列中绝对值最大的元素作为主元,并交换行。
然后是直接三角分解法,也就是LU分解,可能需要先分解A为L和U,然后解Ly=b,再解Ux=y。平方根法则需要检查矩阵是否对称正定,然后进行Cholesky分解,得到LL^T,再解两个三角方程组。追赶法的话,处理三对角矩阵,可以更高效地存储和计算,减少计算量。
接下来,比较这些方法与MATLAB内置的反斜杠运算符(如A\b)的区别。内置函数会根据矩阵的性质自动选择最优算法,比如对称正定会用Cholesky,三对角可能用追赶法,或者其他方法。所以需要测试不同规模的矩阵,计算各算法的运行时间和误差,然后绘制图形。
在测试时,可能需要生成不同大小的随机矩阵,或者特定类型的矩阵(比如对称正定矩阵用于平方根法,三对角矩阵用于追赶法)。对于普通矩阵,可能所有方法都适用,但要注意追赶法只适用于三对角,所以测试时可能需要分别处理。
然后,如何测量时间?可以用tic和toc函数,记录每个算法的执行时间。误差的话,可以计算解的2-范数误差,即norm(x_true - x_computed)。
图形方面,可能需要画时间对比的柱状图,和误差的折线图。或者用对数坐标来展示时间和误差随问题规模的变化。
不过,用户可能没有明确说明矩阵的类型,比如是否普通矩阵,或者是否有特殊结构。比如追赶法只能用于三对角,所以在测试时需要生成对应的矩阵。否则,如果用户用普通矩阵测试追赶法,结果可能出错。因此,在代码中需要分开处理,比如对于追赶法,生成三对角矩阵;对于平方根法,生成对称正定矩阵,而其他方法可以用普通矩阵。
另外,需要注意算法的稳定性。比如,高斯消去法在没有选主元的情况下,对于某些矩阵可能会有较大的误差,而列主元法会更稳定。这也需要在比较中体现出来。
现在,开始编写每个算法的函数。首先高斯消去法:
1. 高斯消去法:
消元阶段:对于每一列,假设当前行i,从第i行到第n行,将第i列下方的元素消为0。
回代:从最后一行开始,逐步代入求解。
2. 高斯列主消去法:
在消元前,找到当前列中绝对值最大的元素所在的行,交换当前行和该行,再进行消元。
3. 直接三角分解法(LU分解):
分解A为L和U,其中L是下三角矩阵,U是上三角矩阵。然后解两个三角方程组。
4. 平方根法(Cholesky分解):
分解A为LL^T,然后解Ly=b,再解L^Tx=y。
5. 追赶法:
适用于三对角矩阵,分解为LU,其中L是下双对角,U是上双对角,然后追赶求解。
然后,编写这些函数时需要注意矩阵的条件,比如是否可逆,是否满足分解条件。比如,Cholesky分解需要矩阵对称正定,所以在生成测试用例时,必须生成这样的矩阵。
测试部分,可能需要生成不同大小的矩阵,比如从n=10到n=1000,逐步增加,但考虑到计算时间,可能不能太大。或者用较小的规模,比如n=100到500,步长100。对于追赶法,需要生成三对角矩阵,可以用diag函数构造。
比较的时候,对于每个n,生成一个矩阵A和向量b,计算真实解x_true(比如通过A\b),然后用各个算法求解x,计算误差和时间。然后将时间保存下来,最后绘制图形。
需要注意的是,有些算法可能无法处理大矩阵,比如高斯消去法的复杂度是O(n^3),当n很大时会很慢。可能需要限制n的范围,或者使用较小的n进行测试。
此外,MATLAB的反斜杠运算符非常高效,因为它底层用的是优化过的库,比如LAPACK,所以预计内置函数的速度会比自编的快很多,误差也可能更小。
现在,开始写每个算法的函数代码:
比如,高斯消去法:
function x = gauss_elimination(A, b)
n = length(b);
A = [A, b]; % 增广矩阵
for i = 1:n-1
% 消元
for k = i+1:n
factor = A(k,i)/A(i,i);
A(k,i:end) = A(k,i:end) - factor*A(i,i:end);
end
end
% 回代
x = zeros(n,1);
x(n) = A(n,end)/A(n,n);
for i = n-1:-1:1
x(i) = (A(i,end) - A(i,i+1:n)*x(i+1:n))/A(i,i);
end
end
但是这里没有选主元,可能在遇到零主元时出错。需要处理这种情况,或者用户需要注意输入的矩阵是否可逆。
高斯列主消元法:
function x = gauss_column_pivot(A, b)
n = length(b);
A = [A, b];
for i = 1:n-1
% 选列主元
[~, p] = max(abs(A(i:n, i))); % 找到当前列最大元素的位置
p = p + i -1; % 调整索引
if p ~= i
A([i,p], :) = A([p,i], :); % 交换行
end
% 消元
for k = i+1:n
factor = A(k,i)/A(i,i);
A(k,i:end) = A(k,i:end) - factor*A(i,i:end);
end
end
% 回代
x = zeros(n,1);
x(n) = A(n,end)/A(n,n);
for i = n-1:-1:1
x(i) = (A(i,end) - A(i,i+1:n)*x(i+1:n))/A(i,i);
end
end
直接三角分解法(LU分解):
function x = lu_decomposition(A, b)
n = length(b);
L = eye(n);
U = zeros(n);
for i = 1:n
for j = i:n
U(i,j) = A(i,j) - L(i,1:i-1)*U(1:i-1,j);
end
for j = i+1:n
L(j,i) = (A(j,i) - L(j,1:i-1)*U(1:i-1,i))/U(i,i);
end
end
% 解Ly = b
y = zeros(n,1);
for i = 1:n
y(i) = b(i) - L(i,1:i-1)*y(1:i-1);
end
% 解Ux = y
x = zeros(n,1);
for i = n:-1:1
x(i) = (y(i) - U(i,i+1:n)*x(i+1:n))/U(i,i);
end
end
平方根法(Cholesky分解):
function x = cholesky_method(A, b)
n = length(b);
L = zeros(n);
for i = 1:n
L(i,i) = sqrt(A(i,i) - sum(L(i,1:i-1).^2));
for j = i+1:n
L(j,i) = (A(j,i) - L(j,1:i-1)*L(i,1:i-1)')/L(i,i);
end
end
% 解Ly = b
y = zeros(n,1);
for i = 1:n
y(i) = (b(i) - L(i,1:i-1)*y(1:i-1))/L(i,i);
end
% 解L'x = y
x = zeros(n,1);
for i = n:-1:1
x(i) = (y(i) - L(i+1:n,i)'*x(i+1:n))/L(i,i);
end
end
追赶法:
function x = thomas_method(A, b)
% A是三对角矩阵,存储为三个对角线
n = length(b);
a = diag(A, -1); % 下对角线,长度n-1
b_diag = diag(A); % 主对角线,长度n
c = diag(A, 1); % 上对角线,长度n-1
% 分解过程
u = zeros(n,1);
l = zeros(n-1,1);
u(1) = b_diag(1);
for i = 2:n
l(i-1) = a(i-1)/u(i-1);
u(i) = b_diag(i) - l(i-1)*c(i-1);
end
% 追过程(前向替换)
y = zeros(n,1);
y(1) = b(1);
for i = 2:n
y(i) = b(i) - l(i-1)*y(i-1);
end
% 赶过程(后向替换)
x = zeros(n,1);
x(n) = y(n)/u(n);
for i = n-1:-1:1
x(i) = (y(i) - c(i)*x(i+1))/u(i);
end
end
接下来是测试这些函数,并与MATLAB内置的A\b比较。需要生成不同类型的矩阵:
对于普通线性方程组,生成随机矩阵A和向量b,确保A非奇异。对于平方根法,生成对称正定矩阵。对于追赶法,生成三对角矩阵。
生成对称正定矩阵的方法,比如A = randn(n); A = A'*A + eye(n)。
生成三对角矩阵可以用diag函数:
n = 5;
a = rand(n-1,1); % 下对角线
b = rand(n,1); % 主对角线
c = rand(n-1,1); % 上对角线
A = diag(a,-1) + diag(b,0) + diag(c,1);
然后,测试各个算法的正确性和时间。
接下来,编写测试脚本:
比如:
% 测试不同规模的问题
sizes = 100:100:1000; % 根据实际情况调整
times_gauss = zeros(size(sizes));
times_col_pivot = zeros(size(sizes));
times_lu = zeros(size(sizes));
times_chol = zeros(size(sizes));
times_thomas = zeros(size(sizes));
times_matlab = zeros(size(sizes));
errors = zeros(length(sizes), 6); % 每个算法和matlab的误差
for i = 1:length(sizes)
n = sizes(i);
% 生成普通矩阵
A = randn(n);
while det(A) == 0
A = randn(n); % 确保可逆
end
b = randn(n,1);
% 高斯消去法
tic;
x_gauss = gauss_elimination(A, b);
times_gauss(i) = toc;
% 高斯列主消去法
tic;
x_col_pivot = gauss_column_pivot(A, b);
times_col_pivot(i) = toc;
% LU分解
tic;
x_lu = lu_decomposition(A, b);
times_lu(i) = toc;
% MATLAB反斜杠
tic;
x_matlab = A\b;
times_matlab(i) = toc;
% 计算误差
errors(i,1) = norm(x_gauss - x_matlab);
errors(i,2) = norm(x_col_pivot - x_matlab);
errors(i,3) = norm(x_lu - x_matlab);
% 生成对称正定矩阵测试平方根法
A_spd = randn(n);
A_spd = A_spd'*A_spd + eye(n);
b_spd = randn(n,1);
tic;
x_chol = cholesky_method(A_spd, b_spd);
times_chol(i) = toc;
x_matlab_spd = A_spd\b_spd;
errors(i,4) = norm(x_chol - x_matlab_spd);
% 生成三对角矩阵测试追赶法
a_tri = rand(n-1,1);
b_tri = rand(n,1) + n; % 主对角线增强,确保可逆
c_tri = rand(n-1,1);
A_tri = diag(a_tri, -1) + diag(b_tri, 0) + diag(c_tri, 1);
b_tri = randn(n,1);
tic;
x_thomas = thomas_method(A_tri, b_tri);
times_thomas(i) = toc;
x_matlab_tri = A_tri\b_tri;
errors(i,5) = norm(x_thomas - x_matlab_tri);
errors(i,6) = 0; % 或者比较其他误差
end
不过,这里可能存在几个问题:
1. 对于平方根法和追赶法,测试的矩阵类型不同,所以需要分开处理,误差比较的对象应该是各自矩阵类型的真实解。
2. 生成的三对角矩阵可能不可逆,需要确保主对角线元素足够大,比如主对角线元素加上其他两个对角线的绝对值之和,满足严格对角占优。
3. 不同算法的测试矩阵不同,可能无法直接比较时间。比如,普通高斯消去法和追赶法处理的问题类型不同,所以时间比较可能没有意义。用户可能需要分开比较,比如普通算法和对应的MATLAB解法在相同问题上的表现。
或者,对于每种算法类型,生成对应的矩阵,并与MATLAB解法比较。例如:
- 普通矩阵:比较高斯消去、列主元、LU分解与A\b
- 对称正定矩阵:比较平方根法与A\b
- 三对角矩阵:比较追赶法与A\b
这样,可能需要分成不同的测试案例。
比如,普通矩阵的测试:
for i = 1:length(sizes)
n = sizes(i);
A = randn(n);
A = A + n*eye(n); % 使对角线占优,确保可逆
b = randn(n,1);
% 测试各个普通算法
...
end
对称正定矩阵:
A_spd = randn(n);
A_spd = A_spd'*A_spd + eye(n)*0.1; % 确保正定
三对角矩阵:
A_tri = diag(rand(n-1,1), -1) + diag(2+rand(n,1)) + diag(rand(n-1,1), 1); % 主对角线足够大
这样,确保矩阵可逆。
然后,绘制不同算法的时间对比和误差对比。
例如,绘制普通算法的运行时间:
figure;
plot(sizes, times_gauss, 'r-', sizes, times_col_pivot, 'g--', sizes, times_lu, 'b-.', sizes, times_matlab, 'k:');
legend('Gauss', 'Gauss列主元', 'LU分解', 'MATLAB反斜杠');
xlabel('矩阵规模n');
ylabel('时间(秒)');
title('普通线性方程组解法时间比较');
误差部分:
figure;
semilogy(sizes, errors(:,1), 'r-', sizes, errors(:,2), 'g--', sizes, errors(:,3), 'b-.');
legend('Gauss误差', '列主元误差', 'LU分解误差');
xlabel('矩阵规模n');
ylabel('误差(对数刻度)');
title('普通线性方程组解法误差比较');
对于平方根法和追赶法,单独绘制与MATLAB的比较:
% 对称正定矩阵的Cholesky与MATLAB比较
figure;
plot(sizes, times_chol, 'm-', sizes, times_matlab_spd, 'k:');
legend('平方根法', 'MATLAB反斜杠');
xlabel('矩阵规模n');
ylabel('时间(秒)');
title('对称正定矩阵解法时间比较');
figure;
semilogy(sizes, errors(:,4), 'm-');
legend('平方根法误差');
xlabel('矩阵规模n');
ylabel('误差(对数刻度)');
title('对称正定矩阵解法误差比较');
% 三对角矩阵的追赶法与MATLAB比较
figure;
plot(sizes, times_thomas, 'c-', sizes, times_matlab_tri, 'k:');
legend('追赶法', 'MATLAB反斜杠');
xlabel('矩阵规模n');
ylabel('时间(秒)');
title('三对角矩阵解法时间比较');
figure;
semilogy(sizes, errors(:,5), 'c-');
legend('追赶法误差');
xlabel('矩阵规模n');
ylabel('误差(对数刻度)');
title('三对角矩阵解法误差比较');
不过,用户可能希望所有算法在一个图中比较,但可能不太合理,因为处理的矩阵类型不同。或者,可以针对每种矩阵类型,比较对应的算法和MATLAB。
此外,需要注意,对于较大的n,自编算法的效率可能非常低,比如n=1000时,高斯消去法可能需要较长时间。所以测试的规模可能需要调整,比如从n=10到200,步长50。
在编写代码时,还需要处理可能的错误,比如矩阵不可分解的情况,比如在Cholesky分解中矩阵不正定,但测试时已经生成对称正定矩阵,所以应该没问题。
最后,用户可能需要完整的代码示例,包括函数定义和测试脚本,以及绘图部分。需要将这些整合成一个可运行的MATLAB脚本或一组脚本。
综上所述,我需要将上述思路转化为具体的代码,并确保语法正确,同时用中文解释每个步骤,结构清晰。可能还需要指出不同算法的适用场景,以及为何MATLAB内置函数更优,比如优化过的实现、更高效的算法选择等。</think>以下是针对普通线性方程组的五种解法实现及与MATLAB内置函数的比较分析。代码分为算法实现、测试案例和可视化三部分。
---
### **一、算法实现代码**
#### 1. 高斯消去法
```matlab
function x = gauss_elimination(A, b)
n = length(b);
aug = [A, b];
for i = 1:n-1
for k = i+1:n
factor = aug(k,i) / aug(i,i);
aug(k,i:end) = aug(k,i:end) - factor * aug(i,i:end);
end
end
x = back_substitution(aug(:,1:n), aug(:,end));
end
function x = back_substitution(U, b)
n = length(b);
x = zeros(n,1);
x(n) = b(n) / U(n,n);
for i = n-1:-1:1
x(i) = (b(i) - U(i,i+1:n)*x(i+1:n)) / U(i,i);
end
end
```
#### 2. 高斯列主元消去法
```matlab
function x = gauss_column_pivot(A, b)
n = length(b);
aug = [A, b];
for i = 1:n-1
[~, p] = max(abs(aug(i:n, i)));
p = p + i - 1;
aug([i,p], :) = aug([p,i], :);
for k = i+1:n
factor = aug(k,i) / aug(i,i);
aug(k,i:end) = aug(k,i:end) - factor * aug(i,i:end);
end
end
x = back_substitution(aug(:,1:n), aug(:,end));
end
```
#### 3. 直接三角分解法(LU分解)
```matlab
function x = lu_decomposition(A, b)
[L, U] = lu_decomp(A);
y = forward_substitution(L, b);
x = back_substitution(U, y);
end
function [L, U] = lu_decomp(A)
n = size(A,1);
L = eye(n);
U = zeros(n);
for i = 1:n
U(i,i:end) = A(i,i:end) - L(i,1:i-1)*U(1:i-1,i:end);
L(i+1:n,i) = (A(i+1:n,i) - L(i+1:n,1:i-1)*U(1:i-1,i)) / U(i,i);
end
end
function y = forward_substitution(L, b)
n = length(b);
y = zeros(n,1);
for i = 1:n
y(i) = (b(i) - L(i,1:i-1)*y(1:i-1)) / L(i,i);
end
end
```
#### 4. 平方根法(Cholesky分解)
```matlab
function x = cholesky_method(A, b)
L = chol(A, 'lower');
y = forward_substitution(L, b);
x = back_substitution(L', y);
end
```
#### 5. 追赶法(三对角矩阵)
```matlab
function x = thomas_method(a, b, c, d)
n = length(d);
w = zeros(n-1,1);
g = zeros(n,1);
w(1) = c(1)/b(1);
g(1) = d(1)/b(1);
for i = 2:n-1
denom = b(i) - a(i-1)*w(i-1);
w(i) = c(i)/denom;
g(i) = (d(i) - a(i-1)*g(i-1))/denom;
end
g(n) = (d(n) - a(n-1)*g(n-1))/(b(n) - a(n-1)*w(n-1));
x = zeros(n,1);
x(n) = g(n);
for i = n-1:-1:1
x(i) = g(i) - w(i)*x(i+1);
end
end
```
---
### **二、性能测试与可视化**
#### 1. 测试代码
```matlab
% 测试规模
sizes = 100:100:500;
num_sizes = length(sizes);
% 预分配存储时间与误差
time_gauss = zeros(num_sizes,1);
time_col_pivot = zeros(num_sizes,1);
time_lu = zeros(num_sizes,1);
time_chol = zeros(num_sizes,1);
time_thomas = zeros(num_sizes,1);
time_matlab = zeros(num_sizes,1);
error_gauss = zeros(num_sizes,1);
error_col_pivot = zeros(num_sizes,1);
error_lu = zeros(num_sizes,1);
error_chol = zeros(num_sizes,1);
error_thomas = zeros(num_sizes,1);
for i = 1:num_sizes
n = sizes(i);
% 生成普通矩阵
A = randn(n) + n*eye(n);
b = randn(n,1);
% 高斯消去法
tic;
x_gauss = gauss_elimination(A, b);
time_gauss(i) = toc;
% 高斯列主元
tic;
x_col_pivot = gauss_column_pivot(A, b);
time_col_pivot(i) = toc;
% LU分解
tic;
x_lu = lu_decomposition(A, b);
time_lu(i) = toc;
% MATLAB内置求解
tic;
x_matlab = A\b;
time_matlab(i) = toc;
% 计算误差
error_gauss(i) = norm(x_gauss - x_matlab);
error_col_pivot(i) = norm(x_col_pivot - x_matlab);
error_lu(i) = norm(x_lu - x_matlab);
% 生成对称正定矩阵
A_spd = randn(n); A_spd = A_spd'*A_spd + eye(n);
b_spd = randn(n,1);
% Cholesky分解
tic;
x_chol = cholesky_method(A_spd, b_spd);
time_chol(i) = toc;
x_matlab_spd = A_spd\b_spd;
error_chol(i) = norm(x_chol - x_matlab_spd);
% 生成三对角矩阵
a = rand(n-1,1); c = rand(n-1,1); b_tri = 3*ones(n,1) + rand(n,1);
A_tri = diag(a,-1) + diag(b_tri) + diag(c,1);
d = randn(n,1);
% 追赶法
tic;
x_thomas = thomas_method(a, b_tri, c, d);
time_thomas(i) = toc;
x_matlab_tri = A_tri\d;
error_thomas(i) = norm(x_thomas - x_matlab_tri);
end
```
#### 2. 可视化结果
```matlab
% 时间对比图
figure;
plot(sizes, time_gauss, 'r-o', ...
sizes, time_col_pivot, 'g--s', ...
sizes, time_lu, 'b-.d', ...
sizes, time_matlab, 'k:x', ...
sizes, time_chol, 'm-+', ...
sizes, time_thomas, 'c-*');
legend('高斯消去', '列主元消去', 'LU分解', 'MATLAB \\', 'Cholesky', '追赶法');
xlabel('矩阵规模n'); ylabel('时间(秒)');
title('不同算法求解时间对比');
% 误差对比图(对数坐标)
figure;
semilogy(sizes, error_gauss, 'r-o', ...
sizes, error_col_pivot, 'g--s', ...
sizes, error_lu, 'b-.d', ...
sizes, error_chol, 'm-+', ...
sizes, error_thomas, 'c-*');
legend('高斯消去', '列主元消去', 'LU分解', 'Cholesky', '追赶法');
xlabel('矩阵规模n'); ylabel('误差(||x_{calc} - x_{matlab}||)');
title('数值误差对比(对数刻度)');
```
---
### **三、结果分析**
1. **时间复杂度**
- 高斯消去、列主元、LU分解的时间复杂度为 $O(n^3)$,实际运行时间随规模增长最快。
- MATLAB内置的 `A\b` 使用优化算法(如LAPACK库),速度显著快于自编代码。
- 追赶法($O(n)$)和Cholesky分解($O(n^3/3)$)在特定矩阵下表现最优。
2. **数值稳定性**
- 列主元消去法在高斯消去基础上提高了稳定性。
- Cholesky分解仅适用于对称正定矩阵,误差最小。
- 追赶法在三对角矩阵中误差与内置方法相当。
3. **图形结论**
- **时间图**:MATLAB内置函数显著快于自编算法,尤其在大规模问题上。
- **误差图**:列主元法误差低于普通高斯消去,Cholesky分解误差最小。
阅读全文
相关推荐












