目录
3.2线性表的顺序存储结构---顺序表 (定义-特点-优缺点)
11.前面讲了线性表的两种存储结构,顺序表和链表,它们分别有什么特点呢?
3.1线性表的逻辑结构 (定义-基本运算)
1.什么是线性表?
答:线性表是n(n大于等于0)个具有相同特性的数据元素的有限序列。
除了第一个元素,每个元素都有唯一的前驱;除了最后一个元素,每个元素都有唯一的后继。
数据元素在线性表中的位置取决于它自身的序号,即数据元素在位置上是有序的,元素之间存在一对一的关系。
所以线性表的逻辑结构是线性结构。
2.线性表有哪些基本运算?
- 初始化线性表
- 判断表是否为空
- 求线性表的长度
- 读取线性表中第i个元素
- 查找满足给定条件的数据元素
- 在线性表的第i个位置插入一个新的元素
- 删除线性表中的第i个元素
- 表置空
- 按一个或多个数据项值的递增或递减顺序重新排列线性表中的数据元素
利用以上基本运算可以实现线性表的复杂运算,如将两个线性表合并成一个线性表等等。
3.2线性表的顺序存储结构---顺序表 (定义-特点-优缺点)
1.什么是线性表的顺序存储结构?
在内存中开辟一段连续的存储空间,依次存放线性表的数据元素。这种方式叫做线性表的顺序存储结构。
2.顺序存储结构有什么特点?
顺序存储结构的特点是:在逻辑上相邻的数据元素,它们的物理位置也是邻接的。
由于线性表中数据元素具有相同的特性,所以很容易确定表中第i个元素的存储地址。
只要确定了线性表的基地址和一个元素占用的存储空间的大小,任意一个元素的存储地址都可以计算出来(location(ai)=location(a1)+(i-1)*m)。
所以可以随机存取顺序表中的任意一个元素,因此线性表的顺序存储结构是一种随机存取的存储结构。
3.顺序存储结构有哪些优点?
- 随机存取元素很容易实现,根据定位公式很容易确定每个元素的存储位置
- 简单、直观
4.顺序存储结构有哪些缺点?
- 1、插入和删除结点困难。
由于表中的结点在内存中是依次连续存放的,所以插入或者删除一个结点时,必须将插入点之后的结点依次向后移动,或将删除点之后的结点依次向前移动
- 2、扩展不灵活
建立表时,若估计不到表的最大长度,就难以确定分配的空间,影响扩展
- 3、容易造成浪费
分配的空间过大时,会造成预留空间浪费
5.顺序表上的基本运算
- 1.求线性表的长度
- 2.插入算法
定义:线性表的插入是指在表的第i个元素之前插入一个新的元素,使长度为n的线性表变成长度为n+1的线性表
思路:
判断线性表的存储空间是否已满,若已满,进行溢出处理;
检查i是否超出所允许的范围,若超出,进行超出处理;
将线性表的第i个元素和他后面的所有元素后移一个位置;
将新的元素写入到下标为i-1的位置上;
线性表的长度加1.
分析:最坏情况下时间复杂度为O(n),最好情况下复杂度为O(1)。
在顺序表中插入一个元素,平均约移动表中一半的数据,当n较大时,算法的效率很低。
- 3.删除算法
定义:指将线性表的第i个数据元素删去,使长度为n的线性表变成长度为n-1的线性表
思路:
分析:
- 4.查找算法
定义:找出数据元素x在表中的位序号
3.3线性表的链式存储结构---链表
1.为什么要有链式存储结构?
因为顺序表虽然简单,便于随机访问表中的任意元素,但顺序存储结构不利于插入和删除,不利于扩充,也容易造成空间浪费。为了弥补这些缺点,引入了链式存储结构。
2.常见的链表有哪些?
常见的链表有单链表、循环链表和双向链表。
链式存储是最常用的存储方法之一,它不仅可以表示线性表,还可以表示各种复杂的非线性数据结构
3.什么是链表?
用一组任意的存储单元存储线性表的数据元素(这组存储单元可以是连续的,也可以是不连续的),数据元素之间的逻辑关系借助指示元素存储位置的指针来表示,这种存储方式叫做线性表的链式存储结构,简称链表。
为了表示数据元素间的逻辑关系,除了存储数据元素本身的信息之外,还需要存放其直接后继的存储位置(存储地址),这两部分组成一个结点,用于表示线性表中的一个数据元素。
也就是说,存放数据元素的结点包括两个域:一个是数据域,用于存储数据元素的信息;另一个是指针域,用于存放直接后继元素的存储地址。
这种用指针链接的结点序列称为链表。
若链表中的结点只包含一个指针域,则称此链表为线性链表或单链表。
4.顺序表和线性链表有什么区别?
- 顺序表中,所有数据元素依次存放在一组连续的存储单元中,逻辑上相邻的两个数据元素其物理存储位置也相邻
- 线性链表中,结点在存储器中的位置是任意的,结点之间的逻辑关系由结点中的指针来指示
5.单链表的基本运算
对单链表的操作都必须从头结点开始,单链表是非随机存取的存储结构。
- 1.建立带头结点的单链表
//头插法建立带头结点的单链表
typedef char elemtype;
typedef struct node
{
elemtype data; //结点的数据域
struct node * next; //结点的指针域
}Lnode,*linklist; //Lnode为结点类型,linklist为指向结点的指针类型
//表头插入法,建立带头结点的单链表,通过函数返回头指针
Lnode *create()
{
FILE *fp;
elemtype ch;
Lnode *h,*p;
h=(Lnode*)malloc(sizeof(Lnode)); //建立头结点
h->next=NULL; //头结点的指针域置空
if(fp=fopen("input.txt","r")==NULL) //从文件输入元素的值
{
printf("can't open the file\n");
exit(0);
}
while(!feof(fp))
{
fscanf(fp,"%c",&ch);
p=(Lnode*)malloc(sizeof(Lnode)); //建立一个新结点p
p->data=ch; //将ch赋给p的数据域
p->next=h->next; //p的后继是头结点的后继
h->next=p; //头结点的直接后继是p
}
fclose(fp);
return h;
}
- 2.求带头结点单链表的长度
//h是带头结点单链表的头指针,函数返回单链表的长度
int length(Lnode *h)
{
Lnode *p;
int i=0;
p=h->next; //p指向第一个结点
while(p) //循环访问单链表的每个结点,p=NULL时结束
{
i++;
p=p->next; //p指针后移
}
return i;
}
- 3.插入算法
略
- 4.删除算法
略
- 5.按值查找
略
- 6.取元素
略
6.什么是循环链表?
循环链表是一种首尾相接的链表,在单链表中,如果最后一个结点的指针域不是NULL,而是指向头结点,则整个链表形成一个环,它是另一种形式的链式存储结构,称为单循环链表。
在建立单循环链表时,建立头结点后,应有“h->next=h;”语句。
循环链表的特点是从表中任意结点出发均可找到表中其他的结点,这样使得某些运算在循环链表上易于实现。
7.什么是双向链表?
在单链表中,每个结点只有一个指针域指向其直接后继,这样方便找到其后继。如果要便于找前驱,可以再加上一个指向其前驱的指针域。
这样链表中的每一个结点中有两个指针域:一个指向直接后继,一个指向直接前驱。这种链表称为双向链表。
8.什么是双向循环链表?
和单循环链表一样,双向链表也有循环链表。
将双向链表中的头结点和尾结点链接起来,就形成了双向循环链表。
即:头结点的前驱指针指向了尾结点,尾结点的后继指针指向了头结点
在空的双向循环链表中,头结点的前驱和后继指针均指向了自己,这也是判断双循环链表是否为空的条件。
9.双向循环链表的插入算法?
在结点p之前插入结点s:
s->prior=p->prior;
p->prior->next=s;
s->next=p;
p->prior=s;
10.双向循环链表的删除算法?
删除p结点:
p->prior->next=p->next;
p->next->prior=p->prior;
11.前面讲了线性表的两种存储结构,顺序表和链表,它们分别有什么特点呢?
- 顺序表的特点是逻辑关系上相邻的数据元素在物理位置上也相邻,数据元素在表中的位置可以通过序号或数组下标直接表示。因此,在表中方便随机存取任意元素,也方便求表的长度。但在进行插入或删除操作时,需要移动大量元素,尤其是当线性表的数据元素是很复杂的信息时,移动的工作量非常大。
- 链表的数据元素之间的逻辑关系用指针来表示,因此,在进行插入或删除操作时不需要移动元素,只需要修改指针。但是链表是非随机存取的存储结构,要访问表中的元素,必须从第一个元素开始查找。
可见,线性表的顺序存储和链式存储各有优缺点,应用中应该根据实际问题的需要来进行选择。
注:本文中空或者略的部分以后再补充