【第2章】matlab程序设计基础

matlab语言的常量与变量

matlab语言的变量命名规则

  • 一个字母引导,后面可以为其他字符。
  • 区分大小写 如Abc ≠ ABc

matlab的保留常量

以下为系统保留常量,自己定义的变量不能与他们重名

eps   %表示机器的精度,其值通常在10^-16左右
i     %虚数单位,表示根号-1
j     %同i
pi    %表示常量π
NaN   %不定式,如∞/∞或者0/0的结果
Inf   %表示无穷大
lastwarn
lasterr

matlab语言的数据结构

数值型数据

matlab主要使用双精度的数据结构,满足IEEE标准,单个数值型数据大小8字节占64位。64位中有11个指数位,52个数据位,1个符号位。表示范围大概是±1.7x10^{308}。我们可以使用double()命令将变量转换为双精度数据结构。

扩展:其他数据类型

  • 单精度数据结构single()32位
  • uint8(),常用于图像表示和处理
  • int8(),int16(),int32(),uint16(),uint32()

符号型数据结构

  1. matlab同时还支持符号型的数据结构,我们可以使用sym(A)这个命令把数值型变量A转换为符号型数据

  2. 使用syms声明符号变量

  3. 显示符号变量的任何精度(前n位数值) vpa(A) vpa(A,n) 比如显示pi的前n位数值

    显示pi的前20位

  4. 显示符号变量的一些属性 assumptions()

  5. 设置符号变量类型 assume(),assumeAlso()

举个栗子:定义一个大于等于-1且小于5的实数

syms x real;
assume(x>=-1);
assumeAlso(x<5);

再以1/3的存储内容举个例子说明符号型数值与双精度数值的区别

符号型数值与双精度数值的区别

再来个例子:使用符号型数据结构表示数值12345678901234567890(20位,双精度无法表示,需要使用符号型)

错误的方法 实际上计算机还是先将参数转变成双精度的数据类型再转变成符号型的数据,转换有偏差

x

正确的方法 将参数用字符串表示,再转换为字符型

√

矩阵与向量的输入

matlab的基本语句结构

直接赋值语句:
variable=expression;

将表达式运算得到的结果赋值给变量,赋值语句的结尾加分号可以阻止运算结果的显示。如果未指定变量,则表达式的值被赋予保留变量ans

实数矩阵输入方法

实数矩阵输入方法

复数矩阵输入方法

复数矩阵输入方法
复数元素1+9i之间不能有空格,不然会引起歧义

函数调用语句
[returned_arguments] = function_name(input_arguments)
[U S V] = svd[X]  %函数调用举例

函数可以通过不同的方式被调用,比如:

  • 内核函数,*.m函数
  • 匿名函数,inline函数 (不建议使用)
  • 重载函数,私有函数等
冒号表达式

matlab下有个很重要的表达式 : 它是定义行向量的有效方法。例如,定义一个从s1到s3,间隔为s2的向量。默认间隔为1。

v = s1:s2:s3

但用这种方法时如果选择的步距不合适,那么生成的行向量可能就不会包含s3,像下面这种情况:

生成的变量中不包含pi

如果像同时包含s1和s3呢?可以使用下面这个命令linspace(0,pi,50),表示从0到pi生成一个行向量,中间有50个数据点。

linspace(0,pi,50)

另外,如果输入的布局s2为负数,显然是错误的,但matlab仍然会执行该语句,结果返回一个1x0的空向量

子矩阵提取

子矩阵提取

B = A(1:2:end,:)  %提取矩阵A的奇数行并赋值给B
C = A([1 1 1 1],:)   %将A的第一行提取4次并赋值给C

结果如下图所示

图 1

矩阵的代数运算

矩阵的转置

C = A.'  %一般转置
C = A'   %Hermite转置

矩阵的加减法

C = A + B
C = A - B

它可以直接将两个矩阵A、B相加减。如果其中一个是标量,那就会把这个标量遍加/减到另一个矩阵上。如果矩阵维数不匹配,系统会报错

矩阵的乘法

C = A*B

系统会自动检测维数是否匹配,不匹配会报错。

矩阵的除法

矩阵的除法 求解线性方程组 MATLAB解法 最小二乘解
矩阵左除 AX=B X=A\B(注意除号的方向!)
如果原方程不可解则得到最小二乘解
$X = A^{-1}B $
矩阵右除 XA=B X=B/A

Matlab提供了两种除法运算:左除(\)和右除(/)。

一般情况下,x=a\b是方程ax =b的解,而x=b/a是方程xa=b的解。

例:a=[1 2 3; 4 2 6; 7 4 9]

b=[4; 1; 2];

x=a\b

则显示:x=

     -1.5000

      2.0000

      0.5000

如果a为非奇异矩阵,则a\b和b/a可通过a的逆矩阵与b阵得到:

  a\b = inv(a)*b

  b/a = b*inv(a)

什么是奇异矩阵

首先,看这个矩阵是不是方阵(即行数和列数相等的矩阵。若行数和列数不相等,那就谈不上奇异矩阵和非奇异矩阵)。 然后,再看此方阵的行列式|A|是否等于0,若等于0,称矩阵A为奇异矩阵;若不等于0,称矩阵A为非奇异矩阵。 同时,由|A|≠0可知矩阵A可逆,这样可以得出另外一个重要结论:可逆矩阵就是非奇异矩阵,非奇异矩阵也是可逆矩阵。 如果A为奇异矩阵,则AX=0有无穷解,AX=b有无穷解或者无解。如果A为非奇异矩阵,则AX=0有且只有唯一零解,AX=b有唯一解。

矩阵的翻转

矩阵的翻转

矩阵的乘方

前提:矩阵为方阵

数学描述:

\[F = A^x \]

matlab描述

F = A^x

求矩阵A的全部三次方艮,并检验结果

\[ A = \begin{bmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 0 \\ \end{bmatrix} \]

matlab代码:

A = [1 2 3;4 5 6;7 8 0];
C = A^(1/3);   %结果可以得到一个复数型的三次方根
e = norm(A-C^3);  %所求值e为根C的误差,通常用一个范数表示

运行结果 从图中可以看出,误差是很小的

运行结果

但实际上A还有另外两个根,如何得到呢?另外两个根可以通过这个已知根旋转得到,我们先求出旋转常数j1,然后把它乘到得到的这个个根C上就能得到另外的两个根A1 A2

j1=exp(sqrt(-1)*2*pi/3)
A1 = C*j1
A2 = C*j1^2
norm(A-A1^3),norm(A-A2^3)

点运算

点运算是矩阵对应元素直接进行的运算

矩阵的点乘法

\[C=A.*B \]

\[c_{ij}=a_{ij}b_{ij} \]

矩阵的点乘方

\[B=A.^A \]

\[b_{ij}=a_{ij}^{a_{ij}} \]

比如求矩阵A的点乘方

\[ A = \begin{bmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 0 \\ \end{bmatrix} \]

\[ A.^A = \begin{bmatrix} 1^1 & 2^2 & 3^3 \\ 4^4 & 5^5 & 6^6 \\ 7^7 & 8^8 & 0^0 \\ \end{bmatrix} = \begin{bmatrix} 1 & 4 & 27 \\ 256 & 3125 & 46656 \\ 823543 & 16777216 & 1 \\ \end{bmatrix} \]

那么点运算的用处在哪呢?答案是可以用来绘制函数曲线图.比方说我们想要做一条y=x^2的曲线,那么我们需要先生成一个x向量,然后对x向量的每一个值单独做平方运算.这不正是点乘方运算吗?由此我们可以用以下代码实现

\[y=f(x)=x^2,y_i=x_i^2 \]

x=--5:5
y=x.^2

运行结果

矩阵的其他运算

矩阵的逻辑运算

  • 与运算 A&B
  • 或运算 A|B
  • 非运算 B = ~A
  • 异或运算 xor(A,B)

比较运算

各种允许的比较关系有:>,>=,<,<=,==,~=,find(),all(),any()

解析结果的化简变换

函数simplify()用于数学公式的化简

s1 = simplify(s);

其他常用化简函数

  • numden() 提取表达式分子分母
  • collect() 合并同类项
  • expand() 多项式展开
  • factor() 因式分解

例:化简多项式

\[P(s) = (s+3)^2(s^2+3s+2)(s^3+12s^2+48s+64) \]

syms s;
P = (s+3)^2*(s^2+3*s+2)*(s^3+12*s^2+48*s+64);      %输入多项式
P1 = simplify(P)        %得到最简形式
P3 = factor(P),P4 = prod(P3)    %用factor得到所有的公因式,再用prod将所有的公因数相乘

运行结果:

运行结果

变量替换及转成Latex表示

将函数表达式f中的x1全部替换为x1*

\[f_1 = subs(f,x_1,x_1^*) \]

\[f_1 = subs(f,\{x_1,x_2,\cdots,x_n\},\{x_1^*,x_2^*,\cdots,x_n^*\}) \]

图 1

应用举例:试用s=(z-1)/(z+1)对P(s)进行双线性变换

\[P(s) = (s+3)^2(s^2+3s+2)(s^3+12s^2+48s+64) \]

syms s z;
P = (s+3)^2*(s^2+3*s+2)*(s^3+12*s^2+48*s+64);      %输入多项式
P1 = simplify(subs(P,s,(z-1)/(z+1)))        %得到变换后的最简形式
P3 = latex(P1)  %转为latex形式

运行结果

运行结果

latex显示如下:

\[\frac{8\, z\, {\left(2\, z + 1\right)}^2\, \left(3\, z + 1\right)\, {\left(5\, z + 3\right)}^3}{{\left(z + 1\right)}^7} \]

matlab基本数论运算

函数 调用格式 功能
floor() n=floor(x) 向下(负无穷大)取整
ceil() n=ceil(x) 向上取整
round() n=round(x) 四舍五入取整
fix() n=fix(x) 向0方向取整
rat() [n,d]=rat(x) 将有理数转化为分式
rem() B=rem(A,C) 求余数
gcd() k=gcd(n,m) 求最大公约数
lcm() k=lcm(n,m) 求最小公倍数
factor() factor(n) 因数分解
isprime() v1=isprime(v) 判断是否是素数(质数)
perms() perms(1:5)或
perms('abcde')
求全排列

流程结构

利用matlab的流程结构,我们可以编写出复杂程序,实现更高级的功能。目前matlab支持的流程结构有:

  • 循环结构
  • 转移结构
  • 开关结构
  • 试探结构

matlab的循环结构

for循环结构
for i=v , 循环体 , end

其执行机制为:v为一个向量,循环变量i每次从v向量中取一个数值,执行一次循环体的内容,如此下去直到执行完v向量中的所有分量。v的内容可以任意排列

while循环结构
whlie(判断条件) %满足条件则进入循环
        循环体,
end

用循环求解最小的m,使下式成立

\[\sum_{i=1}^{m} {i>10000} \]

s=0;m=0;
while(s<=10000),m=m+1;
s=s+m; end,s,m

运行结果

运行结果

条件转移结构

if(condition)
        statement group
end
%或者
if(conditon1)
        statement group 1
elseif(conditon2)
        statement group 2
else
        statement group 3
end

用法与c语言中的if else基本差不多

开关结构

switch switch expression
case expression 1 ,statement 1
case {expression 2,expression 3 ,··· expression m},statement 2
otherwise statement n
end

与c语言也有些相似,不同之处在于执行完statement之后程序会自动结束,而在c语言中要使用break才能实现这样的功能。如果开关表达式witch expression满足{expression 2,expression 3 ,··· expression m}其中之一,那么程序就会执行这个段落,执行完后跳出此开关结构。

试探结构

try,
        statement group 1,
catch,
        statement group 2,
end

程序会先尝试执行语句段1,如果不出现错误,那么这个结构就执行结束了。如果出现错误,程序就转到语句段2去执行,执行完后结束此结构

函数编写

matlab编程有脚本程序M-函数,但更推荐使用M-函数的形式,这是因为函数更灵活,可以应用到各种场合而不需要反复修改源程序,只需要改变参数就好。

matlab语言函数的基本结构

函数可以看作是一个信息处理单元,它接受输入变量,然后经过处理计算,再返回相应的变量到上一级

1

函数的程序结构
function [return vars] = funname(input vars)
comments led by %
input and output variables check
main body of the function

通常,函数名funname要起一个有意义的名字,最后这个函数将存为一个.m文件(通常以函数名命名

例编写一个函数生成nxm的Hilbert矩阵

\[h_{i,j}=\frac {1} {i+j-1} \]

要求

  • 输入变量n,m,输出变量H
  • 若只给出一个输入参数,则自动生成方阵
  • 在函数中给出合适的帮助信息
  • 检测输入和返回变量的个数nargin,nargout
function H=myhilb(n,m)    %定义函数myhilb
if nargin == 1 ,m=n; end  %如果输入变量只有一个,那么强制将m=n
for i=1:n,for j=1:m       %使用循环生成Hilbert矩阵
H(i,j)=1/(i+j-1);
end,end
函数的递归调用

例题:利用函数的递归调用计算阶乘

原理 n! = n(n-1)!

递归调用函数编写如下

function k = my_fact(n)
if nargin ~= 1,
        error('error:只允许输入一个变量');
end
if(abs(n-floor(n))>eps | n<0),
        error('error:n不能为非负整数');
end     %前半部分用于检测n是否为非负整数
if n>1 k=n*my_fact(n-1);        %如果n>1,则使用递归调用求阶乘
elseif any([0 1]==n),k=1;end    %如果n为0或1,则设置一个出口,让k=1

除了我们自己编写函数外,matlab自带也有计算阶乘的函数:factorial(n),prod(1:n),gamma(1+n),gamma(1+sym(n)),factotial(sym(n))

可变输入输出参数个数

如何再matlab中编写可变输入输出参数个数的函数呢?首先我们需要先了解一下输入变量是怎么传递到函数里去的。

2

由图可知,输入输出变量是存储在varargin,varargout两个数组中的,我们可以使用花括号{}来提取某一个变量

例:任意多输入变量
conv()可以计算两个多项式的积,试使用varargin实现任意个多项式的积

matlab编程

%思路 每次从varargin中提取出一个做累积
function a=convs(varargin),a=1;
for i=1:nargin, a=conv(a,varargin{i});end

下面我们来具体试一下自己编写的函数

P=[1 2 4 0 5];
Q=[1 2];
F=[1 2 3]; %P Q F为三个多项式的系数
%传统求法
E=conv(conv(P,Q),F)
%自编写函数求解
D=convs(P,Q,F)
%我还能求更多 ^_+ 
G=convs(P,Q,F,[1,1],[1,3],[1,1])

运行结果

图 2

inline函数与匿名函数

inline函数会造成功能重叠,目前不建议大家使用。下面介绍一下匿名函数的使用
匿名函数的形式为:f=@(list of variables)function_contents。它的好处是不用单独编写一个.m文件,但只适合处理简单的函数。

二维曲线的绘制

二维图形绘制基本语句

假设有两个序列t=t1,t2,···,tn y=y1,y2,···,yn。构成向量t=[t1,t2,···,tn],y=[y1,y2,···,yn]。想要利用这两组数据绘图,只需要输入plot(t,y)即可

例:绘制函数曲线
绘制函数

\[y=sin(tan(x))-tan(sin(x)),x\in[-\pi,\pi] \]

matlab代码

x=[-pi:0.005:pi];
y=sin(tan(x))-tan(sin(x));
plot(x,y)

运行结果

4

例:绘制分段函数

绘制饱和函数方程

\[y= \begin{cases} 1.1sign(x),|x|>1.1 \\ x, \qquad\qquad |x|\leq1.1 \end{cases} \]

matlab绘图语句(互斥条件才能这么写)

x=[-2:0.02:2];
%互斥条件下将两段表达式分别与其条件做点乘运算再相加即可得函数图像
y=1.1*sign(x).*(abs(x)>1.1)+x.*(abs(x)<=1.1);
plot(x,y)

其他调用格式

情况1中y有m行,最终以t为x轴生成m条曲线。情况2、3也会得出多条曲线

5

更一般的调用格式

6

也可以重新设置曲线样式

7

多纵轴曲线绘制方法

8

特殊二维图形

其他二维图形绘制语句

不同的绘制函数

常用函数 意义 常用函数 意义
bar(x,y) 二维条形图 comet(x,y) 彗星状轨迹图
compass(x,y) 罗盘图 comet(x,y,ym,yM) 误差限图形
feather(x,y) 羽毛状图 fill(x,y,c) 二维填充函数
hist(y,n) 直方图 loglog(x,y) 对数图
polar(x,y) 极坐标图 quiver(x,y) 磁力线图
stairs(x,y) 阶梯图形 stem(x,y) 火柴杆图
semilogx(x,y) x-半对数图 semilogy(x,y) y-半对数图

例 用不同的函数绘制正弦函数图形

t=0:.2:2*pi; y=sin(t); 
subplot(2,2,1), stairs(t,y), 
subplot(2,2,2), stem(t,y), 
subplot(2,2,3), bar(t,y), 
subplot(2,2,4), semilogx(t,y)

其中subplot(x,y,n)函数用于在窗口的不同位置绘制图形,x表示行,y表示列,n表示第几幅图

运行结果

8

隐函数绘制及应用

隐函数即满足f(x,y)=0方程的x,y之间的关系式。由于很多隐函数无法求出x,y之间的显式关系,所以无法定义x向量再求出y向量从而进行绘制。matlab提供的ezplot(隐函数表达式,[xm,xM,ym,yM])可以直接绘制隐函数曲线

例:绘制出下列隐函数的曲线

\[f(x,y)=x^2sin(x+y^2)+y^2e^{x+y}+5cos(x^2+y)=0 \]

实现代码

h=ezplot('x^2 *sin(x+y^2) +y^2*exp(x+y)+5*cos(x^2+y)',[-10 10]); %设置定义域为-10到10
set(h,'Color','b')

运行结果截图

9

数据文件的存储和读取

matlab提供saveload命令来对外部文件读写数据

save mydat A B C  %以二进制形式存储ABC的数据
save /ascii mydat.dat A B C %以可读形式存储
X = load(filename)      %读取文件中的数据到x
X = xlsread(filename,range)   %从excel文件中读取数据 range可以为 'B6:C67'
xlswrite(filename,range)      %向excel文件中写入数据

例:已知excel文件census.xls给出某省人口数,第5-67行存储数据,B列存储年份,C列存储人口。试用matlab对两列数据绘图

> X=xlsread('census.xls','B5:C67'); %读入数据后X为一个两列的矩阵
t=X(:,1); %第一列所有行数据给t
p=X(:,2); %第二列所有行数据给p
plot(t,p) %绘图

三维图形表示

三维曲线绘制

二维曲线绘制函数plot()可以扩展到三维曲线的绘制中。这时可以使用plot3()函数来绘制三维曲线,其调用格式如下,其中选项和二维曲线绘制的完全一致。当然也有其它三维曲线绘制函数,大部分是由二维曲线绘制函数扩展而来。

plot3(x,y,z)
plot3(x1,y1,z1,选项1,x2,y2,z2,选项2,x3,y3,z3,选项3)

例:试绘制如下参数方程的三维曲线

\[\begin{cases} x(t)=t^3sin(3t)e^{-t} \\ y(t)=t^3cos(3t)e^{-t} \\ z=t^2 \end{cases} \]

matlab代码

t=0:0.01:2*pi; %先构造t向量,注意下面的点运算
x=t.^3.*sin(3*t).*exp(-t); 
y=t.^3.*cos(3*t).*exp(-t); 
z=t.^2; 
plot3(x,y,z), grid     %绘制三维曲线

运行结果截图

10

三维曲面绘制

如果已知二元函数z=f(x,y),则可以绘制出该函数的三维曲面图。在绘制三维曲面图之前,应该先调用meshgrid()函数生成网格矩阵数据x和y,这样就可以按函数公式用点运算的方式计算出z矩阵,之后就可以用mesh()surf()函数进行三维图形绘制。具体的函数调用格式为

[x,y]=meshgrid(v1,v2)   %生成网格数据,v1,v2为x、y轴的定义域及步距
z = ··· ,如z=x.*y       %计算二元函数的z矩阵
surf(x,y,z)或mesh(x,y,z)%surf绘制表面图,mesh绘制网格图
例绘制出下列函数的三位表面图形,定义域自取 $$ z=f(x,y)=(x^2-2x)e^{-x^2-y^2-xy} $$
[x,y]=meshgrid(-3:0.1:3,-2:0.1:2); 
z=(x.^2-2*x).*exp(-x.^2-y.^2-x.*y);
surf(x,y,z)  

运行结果截图

11

参数方程的表面图

\[对于三维函数参数方程 \begin{cases} x=f_x(u,v) \\ y=f_y(u,v) \\ z=f_z(u,v) \end{cases} \qquad 其中 \begin{cases} u_x \leq u \leq u_m \\ v_x \leq v \leq v_m \end{cases} \]

使用matlab绘制的方法如下

ezsurf(fx,fy,fz,[um,uM,vm,vM]) %如果不指定,默认区间为[-2pi,2pi]
例:绘制传说中的莫比乌斯带 $$ \begin{cases} x=cosu + v cosu cos\frac{u}{2} \\ y=sinu + v sinu cos\frac{u}{2} \\ z=vsin\frac{u}{2} \end{cases} $$ matlab代码
syms u v; 
x=cos(u)+v*cos(u)*cos(u/2); 
y=sin(u)+v*sin(u)*cos(u/2); 
z=v*sin(u/2); 
ezsurf(x,y,z,[0,2*pi,-0.5,0.5])

运行结果截图

12

球面的绘制

绘制球面的话首先使用matlab函数生成数据

[x,y,z] = sphere(n)

函数会生成3个(n+1)x(n+1)的矩阵,根据这三个矩阵,我们就能画出它的图形了

例:绘制两个球,一个圆心在原点,半径为1,另一个圆心(0.9,-0.8,0.6),半径为0.3

matlab代码

[x,y,z]=sphere(50);
surf(x,y,z), hold on, %绘制默认球体,并不让其消失
x1=0.3*x+0.9; 
y1=0.3*y-0.8; 
z1=0.3*z+0.6; 
surf(x1,y1,z1) %绘制第二个球体

运行结果:

13

柱面的绘制

曲线r沿z轴旋转一周可以得到广泛意义下的柱面,在matlab中,我们可以使用[x,y,z]=cylinder(r,n)生成柱面

例:试绘制如下柱面

\[r(z)=e^{-0.5Z^2}sinz,\quad z \in (-1,3) \]

matlab代码:

z0=-1:0.1:3; 
r=exp(-z0.^2/2).*sin(z0); 
[x,y,z]=cylinder(r); 
z=-1+4*z; 
surf(x,y,z)

运行结果截图

14

特殊三维图形

等高线绘制

  • 直接绘制
contour(x,y,z,n) %n为等高线条数
  • 带有标志的等高线
[C,h]=cotour(x,y,z,n)  %返回等高线的句柄及要标注的值
clabel(C,h)     %叠加到等高线图上
  • 绘制三维等高线
contour3(x,y,z,n)
contourf(x,y,z,n)

三维隐函数的绘制

matlab本身并没有提供三维隐函数绘制函数,我们需要到math work网站上下载ezimplot3()函数。

ezimplot3(fun,[xm,xM,ym,yM,zm,zM])

默认的范围是[-2pi,2pi]

三维图形的视角设置

除了使用工具栏中的三维旋转按钮,matlab还提供了视角设置函数view(α,β),也可以使用[α,β]=view(3)读出当前三维视角数据。视角的定义如下图所示:

13

例:试绘制函数 $ z=f(x,y)=(x2-2x)e{-x2-y2-xy} $ 的三视图

matlab代码

[x,y] = meshgrid(-3:0.1:3,-2:0.1:2); 
z=(x.^2-2*x).*exp(-x.^2-y.^2-x.*y); 
subplot(224), surf(x,y,z), 
subplot(221), surf(x,y,z), view(0,90); %俯视图
subplot(222), surf(x,y,z), view(90,0); %侧视图,右视图
subplot(223), surf(x,y,z), view(0,0); %正视图

运行结果截图

14

三维曲面的旋转

三维曲面旋转函数,其中h为三维曲面的句柄,v为旋转基轴,α为旋转角度。如果绘图时h=surf(x,y,z,那么h就是该三维图像的句柄。v是一个三维向量,如v=[1 1 1],那么转轴就是向量(1,1,1)所在的轴线。

rotate(h,v,α)
rotate(1,0,0) %绕x轴正方向旋转

例:把上例的图形绕x轴正方向旋转360度的动画,每0.01s旋转一度,使用循环结构旋转

matlab代码

fingure;
h=surf(x,y,z); 
r_ax=[1 0 0]; 
axis tight, 
for i=0:360, 
    rotate(h,r_ax,1); 
    pause(0.01), 
end
posted @ 2021-02-19 20:51  因为风的缘故~  阅读(907)  评论(0编辑  收藏  举报