Matlab中数据结构总结.docx
《Matlab中数据结构总结.docx》由会员分享,可在线阅读,更多相关《Matlab中数据结构总结.docx(14页珍藏版)》请在冰豆网上搜索。
Matlab中数据结构总结
参考链接:
心心水滴论坛古木小永
主要数据结构包括数组,字符串,胞,结构体的用法,下面依次介绍
1数组
1.1数组的创建
创建数组的方法有很多,首先先讲一下如何手动去输入一个数组。
比如我现在有两组数据,分别对应的是5个被试的身高以及体重,我想身高数据放在第一列,数据位178,167,170,156,182,第二列数据为体重数据,其对应为65,50,63,70,67。
我们想把这两组数据存在一个变量Data上,这个时候我们只要在matlab命令框中输入
>>Data=[178,65;167,50;170,63;156,70;182,67]
→ Data=
178 65
167 50
170 63
156 70
182 67
这里可以发现对于一堆数据的输入,可以先用一个中括号把所有数据括起来,一行的每个数据用逗号隔开或者可以通过空格,比如下面例子,行与行之间用分号隔开。
Data2=[123;456]
→ Data2=
1 23
4 56
如果每个数据都需要这样输入,那么会很麻烦,这里就提供了一些简单的方法来输入比较规整的数据。
1. >>A=1:
5
→ A=
1 2 3 4 5
2. >>B=1:
2:
10
→ B=
1 3 5 7 9
可以看到如果我们想输入一列数据,并且这些数据是以等差数列的方式排布,我们就可以用a:
b:
c这样的形式来写,意思就是从a开始,每隔b有一个数据,然后写直到不大于c这样一组数。
当然其中b可以省略,省略默认b的值为1。
1.2数组的合并(这里要用到上面的A,B变量)
>>C=[A;B]
→ C=
1 2 3 4 5
1 3 5 7 9
>>D=[A,B]
→ D=
1 2 3 4 5 1 3 5 7 9
%其中A和B都是一个数组,如果其能保证对齐,那么这些数组是可以合并的,就好像上面的两条命令。
可以发现如果用分号,那么合并的情况是以列的方式合并,如果用逗号,那么是以行的方式合并,这个和手动输入数组是一致的,只不过把前面的数字当成数组来操作就可以了。
1.3数组内部数据的取得(这里要用到前面的Data变量)
输入的方法我们有了,但我们如何来取出一个数据呢?
先看看命令
>>Data(4,1) → ans=156
如何取出一行数据
>>Data(3,:
) → ans= 170 63
%和上面所说的一样,前面那个数代表行数,后面如果我们想取所有的数据,只需要在逗号后面写1:
end就可以了,也就是第三行的对应的第一列到最后一列的数据,可以简写为一个冒号。
同理比如取出第一列的数据可以写成
>>Data(1:
end,1) 或者 Data(:
1)
但我们有的时候不希望取出一整列的数据,而是想选出某列当中的几行数据,这个时候我们就可以发现其实数据取得前面是管行,后面是管列,并且看到1:
end这个就可以联想到我们前面所演示的如何输入规整的数组。
说白了这个1:
end其实就是一个数组,如果是这样,我们就可以以此类推,如果我想输出第二列的第一,三,五行数据,那么命令就是
>>Data([1,3,5],2)
%输出的结果我就不演示了,大家可以尝试一下。
1.4数组内部数据的修改以及增添
同样我们可以用上面的Data变量,比如我现在发现我在Data里面有个数据是错的,比如第4行的第二个数据觉得有问题,通过查看我们原始的数据发现第四个人的体重不是70而是50,那么我们就需要修改原始的数据。
如果重新输入一遍那就太蛋疼了,所以修改数据是非常关键的。
有了上面的一些经验,我们来看看如何修改这个数据
>>Data(4,2)=50
→ Data=
178 65
167 50
170 63
156 50
182 67
%在这里我们发现Data数据变了。
如果我们想改一行数据,比如第三行数据应该是180,61,命令是
>>Data(3,:
)=[180,61]
→ Data=
178 65
167 50
180 61
156 50
182 67
%这里要注意我们要改写一行,一列数组,那么后面的数据尺寸一定要和前面那行或者列的尺寸相同。
假如我们想改这个Data的第一列的第一,三行的数据,分别改为150,160 ,这个时候我们输入的方法就是
>>Data([1,3],1)=[150,160]
1.5数组的运算
>>A=1:
5;
>>B=A+5
→B= 6 7 8 9 10
2字符串
2.1字符串的创建
字符串的创建和数组的创建还是有一定的区别,使用单引号将所需要的字符括起来就可以(这里对比数组,数组是用中括号将数字括起来)
>>A=‘helloworld’
A= helloworld
%这里我们就建立了一个字符串变量,变量的内容就是helloworld,同时我们可以再workspace当中查看这个变量。
注意:
1. 这里的单引号必须是英文字符的单引号,如果在中文输入法的情况下输入这个单引号是会出现错误的,这个事初学者经常会犯的错误。
不能用双引号,会报错。
2. 字符串是用单引号括起来就可以,但我们想输入单引号这这个字符,那么就要在单引号的前面再加一个单引号,比如我想生成一个字符串是Tom’scat,这个时候的命令就是
>>A=‘Tom’’scat’
A= Tom’scat
2.2字符串的合并
数组可以实现合并,如果维数匹配,那么两个数组可以合并成一个数组,那么字符串也可以合并,其合并的方法和数组的合并一样,譬如
>>A=‘hello’; %这里在命令的后面使用了分号,这个分号的意思就是运行这行命令,但不将结果显示出来,所以这个命令的意思就是创建一个变量名为A的字符串,并且变量A的内容是hello
>>B=‘world’; %创建字符串B
>>C=[A,B] %将A,B这两个字符串以水平方式合并起来,结果见下面
C= helloworld
>>D=[A;B] %将A,B这两个字符串以垂直方式合并起来,结果见下面
D=
hello
world
最常用的还是水平合并
2.3字符串的使用
现在我们先创建一个字符串,比如是一个数据的文件名
>>filename=‘data.txt’;
这个时候我们只是想看看这个文件是什么类型的文件,也就是我们需要将后面三个字符取出来,而不去管其它的内容,获取的方法和数组的使用方法一致,可以使用括号来实现这个功能,譬如
>>filename(end-2:
end) %这个命令的意思是取出这个字符串倒数第三至最后一个字符
ans= txt
如果我们想取出前面文件名那部分,而不想关注后面的数据类型,这时候使用方法如下
>>filename(1:
end-4) %取出字符串的第一个至倒数第五的字符
ans= data
2.4字符串的修改
这个可以参照数组的用法,这里就不详细的解释了,如果有问题可以参考数组的用法
>>A=‘helloworld’; %创建字符串
>>A(6:
10)=‘China’ %将helloworld中的world改成China
A= helloChina
注意:
这里赋值号后面所跟的字符数量要和前面A中要修改的字符数量相同,如果不匹配的话是会出现错误的。
2.5字符串的其它用法
数组的其中一个用法就是在数组后面的括号中加入一个逻辑变量数组,这样就可以取出逻辑数组中那个对应是true的那个位置的值,这个用法在字符串中同样适用。
譬如
>>A=‘helloChina’;
>>index=A~=’h’ %取出helloChina 当中不是h这个字符的位置返回一个逻辑数组,这个数组的意思就是当helloChina当中不等于h的那个位置为true,否则为false
index= 0 1 1 1 1 1 0 1 1 1
>>B=A(index)
B= elloCina
这个用法经常会用来去除字符串当中的空格,在这里就先注意一下。
3胞
好比“数组”是个容器(这里我们将字符串也当成数组看待),它可以装很多相同类型的数据。
但后面经常会碰到我们希望找到一个更大的容器能装各式各样的“数组”,这个时候我们就用到了胞(cell)。
在我眼中胞就是一个能装各种各样数据类型的这么一个容器,可以装前面所讲的所有的数据类型,还可以装后面要讲的结构体,甚至胞还可以自己装自己,也就是一个胞中套一个胞。
3.1 胞的创建
数组的创建是用方括号,数组的调用要用到小括号,胞的创建是用花括号,胞的调用既可以用小括号,也可以用花括号,但效果不一样。
对于胞的调用会在后面详细的介绍,但前面所说的这些括号的使用是很多初学者经常弄混的,所以这个需要大家注意一下。
胞的创建要用花括号,譬如:
>>A={‘helloworld’,true,[1,2,3,4]}
A='helloworld' [1] [1x4double]
这里我们创建了一个胞,这个胞里面有三个元素,第一个元素是一个字符串,字符串的内容是helloworld,第二个元素是一个逻辑型变量,其值为true,第三个元素是一个数组,数组里面有4个整型变量。
创建的方法很简单,用花括号将要放在一起的东西括起来,然后用逗号或者分号隔开,分号和逗号的使用和在创建数组时是一样的。
看起来胞很难用,乱七八糟的一堆东西,但在后面用的过程中,胞里面的所存的东西一般都是同一种类型的,比如要么都是数组,要么都是字符串。
这里也只是显示一下胞的里面是可以装各种各样的数据类型。
当然胞里面也可以装变量,譬如
>>M=‘helloworld’;
>>N=‘Tom’’scat’;
>>A={M,N,[1,2,3,4]}
A= 'helloworld' 'Tom'scat' [1x4double]
3.2胞中元素的调用(重点与难点)
比如我们现在有一堆字符串组成了一个胞,这个时候我们如何来调用这个字符串是一个很重要的问题。
在前面我有说过胞的调用既可以使用小括号,也可以使用花括号,下面我们来看看其区别在什么地方。
>>A={'data1.txt','data2.txt','data3.txt'}; %创建一个胞,里面有三个字符串
>>M=A
(1) %将A
(1)这个东西存到M这个变量中
M= 'data1.txt'
>>N=A{1} %将A{1}这个东西存到N这个变量中
N= data1.txt
这个时候我们可以在workspace中看到,M这个变量的属性是1*1cell,而N这个变量的属性是字符串。
也就是说用小括号调用的时候,没有改变cell的属性,出来的东西还是cell,然而当用花括号调用的时候,出来的东西是原本我们存进去的东西,比如我们存一个字符串的时候,调用出来的就是一个字符串,如果存的是一个数组,那么调用出来的就是一个数组。
假如我们现在只需要A这个胞中的前两个字符串,而第三个字符串我们不需要,这个时候我们可以这样使用
>>B=A(1,1:
2) %这个用法和数组的用法一样,并且如果这个cell是一行或者一列,可简写为
>>B=A(1:
2)
也就是说大规模的调用胞中的元素的时候会用小括号,而胞中单一的元素调用用的是花括号。
同样我们还可以更进一步的调用胞中的元素。
比如
>>A={'data1.txt','data2.txt','data3.txt'}; %创建一个胞,里面有三个字符串
>>B=A{1}(end-2:
end) %取出胞的第一个元素(data1.txt)的后三个字符(txt)的使用方法
B= txt
同样如果胞里面存的是一个数组,我们希望取出数组中的某个元素或者某行数据,也可以使用类似的方法。
比如
>>A={[1,2;3,4],[5,6;7,8]} %创建一个胞,胞里面的两个元素都一个2*2数组
A= [2x2double] [2x2double]
>>B=A{2}(:
2) %取出第二个矩阵的第二列数
B=
6
8
也就是说这里我们只要将A{2}当成一个数组就可以了,里面的调用,修改都可以参照数组的用法
3.3胞中元素的添加
比如现在有个胞,里面只有2个矩阵,我现在想增加第三个矩阵,用法如下
>>A={[1,2;3,4],[5,6;7,8]} %创建一个胞,胞里面的两个元素都一个2*2数组
>>A{3}=[9,10;11,12]
A= [2x2double] [2x2double] [2x2double]
或者
>>A(3)={[9,10;11,12]}
A= [2x2double] [2x2double] [2x2double]
这里我们发现用圆括号和花括号都可以实现胞中元素的添加,使用花括号的时候,只要直接写内容就好,而使用圆括号的时候,需要先生成一个胞,然后将这个胞添加到原来那个胞的后面。
注意:
如果使用A{3}={[9,10;11,12]},在matlab当中是不会出错的,但可以发现结果是
[2x2double] [2x2double] {1x1cell}
如果仅仅用A{3}(:
2)是会出错的,所以尽量避免不要弄混了。
3.4胞的一个常用用法
比如现在我有3个txt文档,里面存储着3个被试的行为数据,我们想通过循环的方式来依次读这三个文档,这个时候就会碰到一个问题,如何去调用这三个txt文档的文件名?
由于现在还没有将如何使用循环,在这里就先简单说一下,我们现在写的命令,运行的时候是按照命令从上到下的顺序依次运行一遍。
但假如我们有在一堆代码中有其中一段需要重复运行几次,那么最简单的方法就是将这段代码复制粘贴几次,但如果这样做,那么程序就会变得很冗杂,于是就会用到循环这个东西,也就是我会告诉电脑,你运行到这里的时候给我重复运行其中的这几条命令。
但只是重复而没任何改变的话,那么这个循环就太死板了。
更多情况下重复的过程中会有些许的变化,但变化不会太大。
这个时候就需要一个能变得东西,比如我有一个变量i,我希望第一次循环的时候i等于1,第二次循环的时候i等于2,这样我就可以通过这个i来改变每次循环的内容。
对于怎么写这个循环以及循环的用法,后面会有专门的一节来介绍。
这里就记得在每次循环的过程中i就会增大1.
对于前面的这个问题,我们可以先生成一个胞,这个胞里面存着这些txt文档的文件名。
譬如
>>filename={‘data1.txt’,’data2.txt’,’data3.txt’}
当我们调用第一个文件的时候,我们需要告诉一个读txt文档函数需要读的文件名是什么,这个时候我们就可以告诉那个函数要读的文件名是filename{i},也就是说当第一次循环的时候,读的txt文档的文件名就是filename{1},也就是字符串data1.txt,后面也就可以处理这个文件的数据,当循环第二次的时候,调用的文件名就变成filename{2},就可以处理第二个文件,以此类推。
当然我们发现在创建这个filename的时候,每次都要在最后输入.txt很麻烦,我们能不能有一些简单的方法?
这个时候我们就可以先建一个cell,譬如
>>filename={‘data1’,’data2’,’data3’}
当我用第一个文件名的时候,应该是data1.txt,我如何将这个固定的.txt加到后面呢?
其实最简单的方法是用strcat函数,但对于函数是什么,还没有介绍。
但不用函数同样能达成目的,这个时候就要想想前面讲字符串的一些知识,由于字符串可以接起来,所以每次循环用文件名的时候,就可以使用[filename{i},’.txt’]来实现,这个方括号所得到的东西就是一个字符串,也就是data1.txt。
如果有心细的同学说,那么前面那个data是不是也可以不用写?
答案是肯定的,这个时候我们可以输入
>>filename={‘1’,’2’,’3’}
在循环的过程中,可以将’data’,filename{i}和’.txt’连接起来,连接的方法为[‘data’,filename{i},‘.txt’],如果有对连接方法不太清楚的同学,可以参见字符串的用法那节。
当然还有同学提出,那个i不就是1,2,3么?
干嘛还要再生成那个胞?
这里需要提醒的一点是,i所代表的是一个整型变量,而在字符串中那个1,2,3是一个字符类型的变量,如果直接使用[‘data’,i,’.txt’],matlab会自动将i所对应的那个ascii码转换成相应字符,而1,2,3所代表的ascii码都是空,所以直接使用[‘data’,i,’.txt’]出来的字符串都是data.txt。
当然解决办法就是将整型i变成字符1,2,3,这里就要使用到另外一个函数num2str,这个函数就是能将数字变成字符。
上面正确的写法应该是[‘data’,num2str(i),’.txt’]。
4结构体
首先介绍一下什么是结构体,按照我的理解,结构体就是将很多变量集中在一起的一个数据类型。
举个形象的例子来看,结构体就是一个很大的盒子,在盒子中可以装各种小盒子,而这些小盒子就结构体内装的变量,比如一个数,一个数组,一个胞,甚至是另外一个结构体,并且这个大盒子还有个好处就是可以给里面的每个小盒子起一个名字,类似装鞋子的盒子,装领带的盒子或者装首饰的盒子。
其实胞同样也可以这样理解,在上面的例子中,胞也可以看成是一个大盒子,里面能装各种小盒子,但和结构体不同的是在胞中这些小盒子是按照顺序放置的,我们只能通过其顺序获取小盒子内的东西,比如第一个盒子,第二个盒子,而不同通过形象的名字来获取。
所以在我理解当中凡是能用结构体完成的,胞同样也能完成,但可能在有些情况下使用胞会方便一些,有些情况使用结构体会更加方便一些。
具体使用什么方式来存储变量,可能要根据实际情况来分析。
4.1结构体创建
假如我们现在想存储一个被试的信息,包括这个被试的编号(整数),性别(字符串),年龄(整数)以及爱好(胞),我们可以使用四个变量来存储,但如何我们会经常用到这些信息,并且想将这些信息传递给其它函数,那么这个时候如果使用4个变量来存储就嫌的比较麻烦;如果是用cell去存储,那么如果我们取内容的时候就要严格按照其顺序获取单个内容(比如在存储的时候爱好排在第4个,那么在后面使用的时候就要从cell的第4个元素中取),这样同样不方便。
这个时候结构体就是一个比较好的选择。
subject=struct('ID',1,'gender','male','age',23,'hobby',{{'football','singing'}});
或者
subject.ID=1;
subject.gender='male';
subject.age=23;
subject.hobby={'football','singing'};
以上的两种创建的方式都是允许的,一般下面的这种方式可能会更加直观并且更加常用一些。
注意:
在第一种创建的方法中,cell是用两个大括号括起来的,也就是这里需要大家注意一下,如果我只用一个大括号会出现什么问题呢?
这个可以留给大家自己试试。
一般为了避免出现不必要的错误,我比较推荐第二种创建方式。
这里如果只用一个大括号的话,会变成1×2struct
在这个里面我们就可以理解subject就是那个所谓的大盒子,在这个大盒子中我们装了4个小盒子,分别取名叫ID,gender,age,hobby。
然后在这4个盒子中装了对应的内容。
当然如果我们有很多个被试如何去存储呢?
这个时候就会出来一个东东叫做结构体数组,你可以将这个东西想象成顺序排放的一堆大盒子。
创建的方式也很简单,比如:
subjects=[struct('ID',1,'gender','male','age',23,'hobby',{{'football','singing'}}),struct('ID',2,'gender','female','age',21,'hobby',{{'singing','dancing'}})];
或者
subjects
(1).ID=1;
subjects
(1).gender='male';
subjects
(1).age=23;
subjects
(1).hobby={'football','singing'};
subjects
(2).ID=2;
subjects
(2).gender='female';
subjects
(2).age=21;
subjects
(2).hobby={'singing','dancing'};
注意:
既然是结构体数组,那么也就是要保证结构体数组内每个成员的形式是一样的,比如上面的例子来说,结构体数组中每个元素都要有相同的"小盒子",但"小盒子"里面装的内容可以不同。
如果在某个成员中不设置这个小盒子,那么这个成员同样会被默认创建一个空的"盒子"
如果我们想获取所有成员的年龄怎么办?
[subjects.age]或者{subjects.age}