MATLAB系列07:稀疏矩阵、单元阵列和结构
- 7. 稀疏矩阵、单元阵列和结构
- 7.1 稀疏矩阵
- 7.1.1 sparse数据类型
- 7.1.1.1 产生稀疏矩阵
- 7.1.1.2 稀疏矩阵的运算
- 7.2 单元阵列(cell array)
- 7.2.1 创建单元阵列
- 7.2.1.1 用赋值语句创建单元阵列
- 7.2.1.2 用cell函数创建单元阵列
- 7.2.2 单元创建者——大括号({})的应用
- 7.2.3 查看单元阵列的内容
- 7.2.4 对单元阵列进行拓展
- 7.2.5 删除阵列中的元素
- 7.2.6 单元阵列数据的应用
- 7.2.7 字符串单元阵列
- 7.2.8 单元阵列的重要性
- 7.2.9 单元阵列函数总结
- 7.3 结构数组
- 7.3.1.1 用赋值语句创建函数
- 7.3.1.2 用struct函数创建结构
- 7.3.2 增加域到结构
- 7.3.3 删除结构中的域
- 7.3.4 函数getfield和函数setfield
- 7.3.5 对结构体应用size函数
- 7.3.6 结构的嵌套
- 7.3.7 struct函数总结
- 7.4 总结
7. 稀疏矩阵、单元阵列和结构
稀疏矩阵是矩阵的一种特殊形式,在这个矩阵中只对非零元素分配内存。单元阵列也是一种矩阵,它的每一个元素可以是 MATLAB 任何一种数据类型。它们广泛应用于 MATLAB 用户图象界面(GUI)函数。最后,结构提供了一种在单个变量中存储了不同类型的数据的方法,在这个变量中的每一个数据项目都有一个独立的名字。
7.1 稀疏矩阵
对大规模稀疏矩阵进行存储和运算(其中大部分为 0)是对内存空间和 cpu资源的极大浪费。不巧的是,在现实中的许多问题都需要稀疏矩阵,我们需要一些有效的方示来解决这个问题。
7.1.1 sparse数据类型
在 MATLAB 中有一个专门的数据类型,用来对稀疏进行运算。 sparse 数据类型不同于doulbe 数据,它在内存中只存储非零元素。实际上, sparse 数据类型只存储每一个非零元素的三个值:元素值,元素的行号和列号。尽管非零元素这三个值必须存储在这内存,但相对于存储稀疏矩阵的所有元素来说要简单高效得多。示例:
>> a=eye(10)a =1 0 0 0 0 0 0 0 0 00 1 0 0 0 0 0 0 0 00 0 1 0 0 0 0 0 0 00 0 0 1 0 0 0 0 0 00 0 0 0 1 0 0 0 0 00 0 0 0 0 1 0 0 0 00 0 0 0 0 0 1 0 0 00 0 0 0 0 0 0 1 0 00 0 0 0 0 0 0 0 1 00 0 0 0 0 0 0 0 0 1>> as=sparse(a)as =(1,1) 1(2,2) 1(3,3) 1(4,4) 1(5,5) 1(6,6) 1(7,7) 1(8,8) 1(9,9) 1(10,10) 1
7.1.1.1 产生稀疏矩阵
MATLAB 可以通过 sparse 函数把一个全矩阵转化为一个稀疏矩阵,也可以用 MATLAB 函数 speye, sprand 和 sprandn 直接产生稀疏矩阵,它们对应的全矩阵为 eye, rand, 和 randn。例如,表达式 a = speye(4)将产生一个 4×4 的稀疏矩阵。
>> a=speye(4)a =(1,1) 1(2,2) 1(3,3) 1(4,4) 1
表达式 b = full(a)把稀疏矩阵转化相应的全矩阵。
>> b=full(a)b =1 0 0 00 1 0 00 0 1 00 0 0 1
7.1.1.2 稀疏矩阵的运算
如果一个矩阵是稀疏的,那么单个元素可以通过简单的赋值语句添加或删除,例如下面的语句产生一个 4×4 的稀疏矩阵,然后把其他的非零元素加入其中。
>> a(2,1)=-2a =(1,1) 1(2,1) -2(2,2) 1(3,3) 1(4,4) 1
MATLAB 允许全矩阵与稀疏的混合运算。它们产生的结果可以是全矩阵也可以是稀疏矩阵,这取决于那种结果更高效。更重要的是,任何的适用全矩阵算法同样地也适合稀疏矩阵。一些普通的稀疏矩阵函数如下:
7.2 单元阵列(cell array)
单元阵列是 MATLAB 中特殊一种数组,它的元素被称为单元(cells),它可以存储其它类型的 MATLAB 数组。一个单元阵列的每一个元素都是一个指针,指向其他的数据结构,而这些数据结构可以是不同的数据类型。单元阵列为选择问题信息提供极好的方示,因为所有信息都聚集在一起,并可以通边一单个名字访问。单元阵列用大括号{}替代小括号来选择和显示单元的内容。这个不同是由于单元的内容用数据结构代替了内容。假设一单元阵列如图 7.2 所示。元素 a(1, 1)是数据结构 3×3 的数字数组。 a(1, 1)的含义为显示这个单元的内容,它是一个数据结构。
>> a(1,1)
ans =
[3x3 double]
相对地, a{1, 1}的含义为显示这个数据结构的内容。
>> a{1,1}
ans =1 3 -72 0 60 5 1
7.2.1 创建单元阵列
7.2.1.1 用赋值语句创建单元阵列
>> a{1,1} = [1 3 -7; 2 0 6; 0 5 1];
a{1,2} = 'This is a text string.';
a{2,1} = [3+4*i -5; -10*i 3-4*i];
a{2,2} = [];
>> a(1,1) ={[1 3 -7; 2 0 6;0 5 1]};
a(1,2) = {'This is a text string.'};
a(2,1) = {[3+4*i -5; -10*i 3-4*i]};
a(2,2) = {[]};
编程隐患:
不要创建一个与已存在的数字数组重名的元阵列。如果得名了, MATLAB 会认为你把单元阵列的内容赋值给一个普通的数组,这将会产生一个错误信息。在创建单元阵列之前,确保同名的数字数字数组已经被删除。
7.2.1.2 用cell函数创建单元阵列
函数 cell 允许用户创建空单元阵列,并指定阵列的大小。例如,下面的语句创建一个 2 ×2 的空单元阵列。
a=cell(2,2)
7.2.2 单元创建者——大括号({})的应用
如果在单个大括号中列出所有单元的内容,那么就定义了许多的单元,在一行中的独立单元用逗号分开,行与行之间用分号隔开。例如下面的语句创建一个 2×3 单元阵列。
>> b = {[1 2], 17, [2;4]; 3-4*i, 'Hello', eye(3)}b =2×3 cell 数组{[ 1 2]} {[ 17]} {2×1 double}{[3.0000 - 4.0000i]} {'Hello'} {3×3 double}
7.2.3 查看单元阵列的内容
如果想知道单元阵列的所有内容,要用到celldisp函数
>> celldisp(b)b{1,1} =1 2b{2,1} =3.0000 - 4.0000ib{1,2} =17b{2,2} =Hellob{1,3} =24b{2,3} =1 0 00 1 00 0 1
如果要用高质量图像显示数据结构内容,要用到cellplot函数
>> cellplot(b)
7.2.4 对单元阵列进行拓展
一个值赋值于一个单元阵列中的元素,如果这个元素现在不存在,那么这个元素就会被自动的建立,其他所需的元素也会被自动建立。
7.2.5 删除阵列中的元素
如果要删除单元阵列中的部分元素,我们把空值赋值于这一部分元素。
>> a(2,:)=[]a =1×2 cell 数组{3×3 double} {'This is a text string.'}
7.2.6 单元阵列数据的应用
在一个单元阵列中,数据结构中数据可以随时用内容索引或单元索引调用。
>> c = {[1 2; 3 4],'dogs';'cats',i}c =2×2 cell 数组{2×2 double} {'dogs' }{'cats' } {[0.0000 + 1.0000i]}>> c{1,1}ans =1 23 4>> c{1,1}(1,2)ans =2
7.2.7 字符串单元阵列
在一个单元阵列中存储一批字符串与在标准的字符数组中存储相比是非常方便的,因为在单元阵列中每一个字符串的长度可以是不相同的,而在标准字符数组的每一行的长度都必须相等。这就意味着在单元阵列中的字符串没的必要增加多余的空格。
字符串单元阵列可以由两种方法创建。我们可以用方括号把独立的字符串插入到单元阵列,我们也可以函数 cellstr 把一个二维字符数组转化为相应的字符串单元阵列。
>> cellstring{1}='abc';
>> cellstring{2}='agb fag';
>> cellstringcellstring =1×2 cell 数组{'abc'} {'agb fag'}
>> data=['Line ';'6666999']data =2×7 char 数组'Line ''6666999'>> c=cellstr(data)c =2×1 cell 数组{'Line' }{'6666999'}
可以使用char函数进行逆转换
>> newdata=char(c)newdata =2×7 char 数组'Line ''6666999'
7.2.8 单元阵列的重要性
单元阵列是非常灵活的,因为各种类型的大量数据可以存储在每一个单元中。所以,它经常当作中间 MATLAB 数据结构来用。单元阵列的灵活性可能使它们具有函数普通特性,这个函数是指带有输入参数和输出参数的变量个数的函数。一种特别的输入参数 varargin 可以在自定义函数中得到,这种函数支持输入参数的变量的个数。这个参数显在输入参数列表的最后一项,它返回一个单元阵列,所以一个输入实参可以包括任意数目的实参。每一个实参都变成了由 varagin 返回的单元阵列元素。如果它被应用, varagin 必须是函数中的最后一个输入参数。例如,假设我们要编写一个函数,它可能需要任意个数的输入参数。
function my_fun2(varargin)disp(['There are ' int2str(nargin) ' arguments.']);disp('The input arguments are:');disp(varargin)
end
>> my_fun2
There are 0 arguments.
The input arguments are:
>> my_fun2(6)
There are 1 arguments.
The input arguments are:{[6]}>> my_fun2(6,'test','hello')
There are 3 arguments.
The input arguments are:{[6]} {'test'} {'hello'}
7.2.9 单元阵列函数总结
7.3 结构数组
一个结构也是一种数据类型,它的每一个元素都有一个名字。我们称结构中的元素为域。单个的域可以通过结构名和域名来访问,用句号隔开。
7.3.1.1 用赋值语句创建函数
>> student.name='Tom';
>> student.age='18';
>> student.city='Anytown';
>> studentstudent = 包含以下字段的 struct:name: 'Tom'age: '18'city: 'Anytown'
第二个 student 可以通过在结构名前加上一个下标的方式加入到这个结构中。
>> student(2).name='Lida'student = 包含以下字段的 1×2 struct 数组:nameagecity
>> student(1)ans = 包含以下字段的 struct:name: 'Tom'age: '18'city: 'Anytown'>> student(2)ans = 包含以下字段的 struct:name: 'Lida'age: []city: []
7.3.1.2 用struct函数创建结构
>> str_array=struct('key1',1,'key2','hello')str_array = 包含以下字段的 struct:key1: 1key2: 'hello'
7.3.2 增加域到结构
如果一个新的域名在结构数组中的任意一个元素中被创建,那么这个域将会增加到数组的所有元素中去。
7.3.3 删除结构中的域
>> str_array2=rmfield(str_array,'key1')str_array2 = 包含以下字段的 struct:key2: 'hello'
7.3.4 函数getfield和函数setfield
MATLAB 中有两个函数用来创建结构,这比用自定义函数创建要简单的多。函数 getfield得到当前存储在域中的值,函数 setfield
在域中插入一新值。getfield 函数的结构是
f = getfield(array,{array_index},'field',{field_index})
当编写程序时,尽管程序不知道结构数组中的域名,这个语句也可以应用。例如,假设我们需要编写一个程序,读取一未知数组并对它进行操作。函数可以通过调用 fieldnames 命令来确定一个结构数据的域名,然后通过函数 getfield 读取数据。为了读取第二个学生的name,函数为
>> student.name='Tom';
>> student.age='18';
>> student.city='Anytown';
>> student(2).name='Lida'student = 包含以下字段的 1×2 struct 数组:nameagecity>> name2=getfield(student,{2},'name')name2 ='Lida'
相似地,我们可以用 setfield 函数修改结构的值。
>> student=setfield(student,{2},'name','Jone')student = 包含以下字段的 1×2 struct 数组:nameagecity>> student(2)ans = 包含以下字段的 struct:name: 'Jone'age: []city: []
等价于:
>> student(2).name='Amy'student = 包含以下字段的 1×2 struct 数组:nameagecity>> student(2)ans = 包含以下字段的 struct:name: 'Amy'age: []city: []
7.3.5 对结构体应用size函数
当 size 函数应用于结构数组时,它将返回这个结构数组的大小。当 size 函数应用于结构数组中的一个元素的域时它将返回这个域的大小。例如
>> size(student)ans =1 2>> size(student(1).name)ans =1 3
7.3.6 结构的嵌套
结构数组的每一个域可是任意数据类型,包括单元阵列或结构数组。例如,下面的语句定义了一个新结构数组。它作为 student 的一个域,用来存储每一个学生所在班级的信息。
>> student(1).class(1).name='COSC 2021';
>> student(1).class(2).name='PHYS 1001';
>> student(1).class(1).instructor='Mr. Jones';
>> student(1).class(1).instructor='Mrs. Smith';
>> student(1)ans = 包含以下字段的 struct:name: 'Tom'age: '18'city: 'Anytown'class: [1×2 struct]>> student(1).classans = 包含以下字段的 1×2 struct 数组:nameinstructor>> student(1).class(1)ans = 包含以下字段的 struct:name: 'COSC 2021'instructor: 'Mrs. Smith'>> student(1).class(2).nameans ='PHYS 1001'