数据结构与算法--线性表系列(顺序存储结构的线性表)
hello,everybody!又与大家见面了,因为线性表这章内容比较多一些,还有一些代码需要practice,所有好多天没有写博客。今天让我们一起来学习数据结构---线性表吧。
线性表的定义:
顾名思义,线性表,就是具有线性质的一种数据结构。书中的例子是这样说的:本书作者去幼儿园接孩子,发现了一个very interesting 的现象。孩子们每次都是排着队放学,每个孩子前面有个唯一的小朋友,后面也有一个唯一的小朋友。他们之间的关系是一对一的关系。好像是一条线把他们栓在了一起似的,这个例子很形象的向线性表做了诠释。
线性表(List):零个或多个数据元素的有限序列。
首先,数据元素要有限,不能是无限多个数据元素。其次,他们之间是有秩序的,是按顺序来存储https://signup.wordpress.com/activate/9e822d27ba11e157 的。就像,幼儿园的小朋友排队似的,是按顺序来。
线性表是数据结构中,用的最多的,也是最简单的一种数据结构。学好线性表很重要,她重要,必须学好。她简单,更要学好,把简单的学好了,我们才有信心学习之后较复杂的数据结构。
线性表的抽象数据类型:
通过前面的线性表的定义,我们知道了,线性表结构是相同数据元素之间的有限序列。所以,我们可以用数组来表示线性表。创建固定大小的数组,就相当于在内存中找个了一段地址连续的存储空间,我们可以把线性表存入到数组中。我们把线性表的元素个数,称为线性表的长度。这里我们要区分两个概念“线性表长度”,”数组长度”。
线性表的长度:是指表中所存元素的多少,她会随着元素的改变而改变。
数组的长度:它是来存放线性表的,相当于在内存总的开辟的空间。它一般是不会改变的。
一般情况下,线性表的大小小于等于数组的大小。
现在我们来看一下线性表的抽象数据类型:
我们来分析一下,线性表都会有哪些操作?
Firstly,创建线性表。InitList(*L)
Secondly,判断线性表是否为空.ListEmpty(L)
Thirdly,清空线性表。ClearList(*L)
Fourthly,读取线性表中某个位置的元素。GetElem(L,I,*e)
Fifthly,匹配元素。LocateList(L,e)
sixthly,插入元素。ListInsert(*L,I,e)
seventhly,删除元素。ListDelete(*L,I,*e)
eighthly,计算线性表的长度.
以上是些基本的线性表操作,对于一些复杂的操作,我们可以组合这些基础操作来完成。例如,两个线性表的并集操作。
线性表的存储结构
在第一章,讲解数据结构的概叙时,我们提到了,数据结构分为逻辑结构,物理结构。逻辑结构,是描述数据之间的存在关系。物理结构又称为存储结构,是将逻辑关系在内存中表现出来。存储结构分为两种,一种为顺序存储,一种为线性存储。
我们先来学习一下线性表的顺序存储。
线性表的顺序存储结构:指的是用一组地址连续的存储单元依次存储线性表的数据元素。
线性表的顺序存储的结构代码:
这里,我们发现描述线性表的顺序存储的结构需要三个属性:
Firstly,存储空间的起始位置:数组data,它的起始位置就是存储空间的起始位置。
Secondly,线性表的最大存储容量:数组的长度。
Thirdly,线性表的当前长度:length.
线性表顺序存储结构的操作
获得元素操作:
获得元素的算法思路:
Firstly:线性表L必须存在,不为空.
Secondly:位置i必须在线性表的合理位置。
#define ok 1
#define Error 0
#define TRUE 1
#define False 0
typedef int Status; /*Status是函数的类型,其值是函数结果状态码,如OK等*/
/*初始条件:顺序线性表L已存在,1《=i《=ListLength(L)*/
/*操作结果:用e返回L中第i个数据元素的值*/
Status GetElem(SqlList L,int I,ElemType *e)
{
if(i<1||i>L.length||L.length==0)
return Error;
else
*e=L.data[i-1];
return Ok;
}
线性表的插入操作:
插入的算法思路:
Firstly,插入位置i要合理,否则抛出异常。
Secondly,线性表的长度大于或等于数组长度,抛出异常或动态增加容量。
Thirdly,从表中最后一位开始,一直遍历到位置i.依次向后移动一个位置。
Fourthly, 将要插入的元素插入i位置。
Fifthly,线性表的长度增加1.
Status ListInsert(SqlList *L,int I,EnlemType e)
{
int k;
if(L->length==MAXSIZE)/*线性表的容量等于数组容量,线性表已满*/
return ERROR;
if(i<1||i>L->length+1)/*i位置不合理*/
return ERROR;
if(i<=L->length)/*判断不是向表尾插入数据*/
{
for(k=L->length-1;k>=i-1;k—)
L->data[k+1]=L->data[k]; /*将要插入位置元素以及之后的所有元素向后移动一位*/
}
L->data[i-1]=*e; /*将要插入的数据插入i位置*/
L->length++;/*线性表的长度加1*/
return OK;
}
线性表的删除操作:
删除操作的算法思路:
Firstly,删除位置i合理,否则抛出异常。
Secondly,将i位置的元素赋值给e。
Thirdly,,从i位置开始,直到最后一位元素,依次向前移动一个位置。
Fourthly,线性表的长度减1.
Status ListDelete(SqlList *L,int I,EnlemType *e)
{
int k;
if(L->length==0)/*线性表为空*/
return ERROR;
*e=L->data[i-1];
if(i<1||i>L.length)
return ERROR;
if(i<L.length)
{
for(k=1;k<length;k++)
L->data[k-1]=L->data[k];
}
L->length—;
return OK;
}
我们仔细观察,发现了如果是存取数据,线性表的顺序存储结构的时间复杂度为O【1】.如果是插入、删除,时间复杂度为O【n】.那么我们就得出了一个结论,对于线性表中元素移动变化不大,更多的是存储数据的应用,那么我们顺序存储结构是不错的选择。
线性表顺序存储结构的优缺点
优点:
Firstly,可以快速存取线性表中任一位置的元素。
Secondly,无需为了表示表中的数据之间的逻辑关系而增加额外的存储空间
缺点:
Firstly,插入、删除元素会影响其他元素,需要移动大量的数据。
Secondly,当线性表的容量变化较大时,难以确定存储空间的容量。
Thirdly,造成存储空间的“碎片”。
因为线性表内容比较多,我会分多篇文章介绍。