基本概念
线性表是零个或者多个数据元素的有序序列,第一个元素没有前驱,最后一个元素没有后继,其他数据元素有且仅有一个前驱一个后继,同时线性表元素的个数n定义为线性表长度。
线性表的抽象数据类型ADT
=>Data
{a1, a2, ..., an}, 且每个元素的类型均为DataType,从第二个数据元素到倒数第二个数据元素都有且仅有一个前驱元素,和一个后继元素。
=>Operation
InitList(*L)
ListEmpty(L)
ClearList(*L)
GetElem(L, i, *e)
LocateElem(L, e)
ListInsert(*L, i, e)
ListDelete(*L, i, *e)
ListLength(L)
endADT
void union(List *La, List Lb)
{
ing La_len, Lb_len, i ;
ElemType e;
La_len = ListLength(La);
Lb_len = ListLength(Lb);
for (i=1; i<=Lb_len; i++) {
GetElem(Lb, i, e);
if (!LocateElem(La, e, equal))
ListInsert(La, ++La_len, e); }
}
线性表的顺序存储结构
线性表的顺序存储结构,指的是用一段连续的物理地址存储单元一次存储线性表的数据元素,(a1, a2, ..., ai-1, ai, ..., an)
线性表的顺序存储结构就是通过占位的形式,把一定内存空间占据,然后让不同的数据元素一次放在空地中。线性表顺序存储的结构代码中需要三个属性
- 存储空间的起始位置
- 最大存储容量
- 线性表当前的长度
顺序存储结构的插入与删除
线性表的插入本质上是将元素i插入到表的某处,并将后续数据元素依次向后挪一位。插入算法的思路是,
- 插入位置不合理,抛出异常
- 线性表长度大于或者等于数组长度,抛出异常或者动态增加容量
- 最后一个元素开始向前遍历到i位置,分别后移
- 元素插入位置i
- 表长加1
删除操作则反向,将元素删除后,后续数据元素向前挪位。删除算法思路:
- 如果删除位置不合理,抛出异常
- 去除删除元素
- 删除元素位置遍历到最后,前移
- 表长-1
优缺点:
优点:无需因为逻辑关系增加存储空间,且可以快速存取表中元素
缺点:插入和删除操作需要移动大量元素,难以确定存储空间容量且会造成存储空间碎片
线性表的链式存储结构
链式存储结构的设计打破了物理存储地址必须连续的规定,这也是他和线性表区别最大的地方。一个数据元素包含了两个部分,即数据域和指针域。数据域负责存储所使用的具体数据,指针域则负责指向后继节点地址。由于节点之间使用链子式结构进行链接,因而称为线性表的链式存储结构,这两部分的组合称为一个节点Node。
同理,对于线性表来说,都是有头有尾的人物。因此链表也不例外,第一个节点存储位置称为头指针,最后一个节点的后继指针指向Null,就是空。第一个节点称为头节点。头指针式指向第一个节点的指针,头指针具有标识作用,且无论链表是否为空,头指针均不是空。头指针式链表的必要元素。
单链表的插入与删除
链表插入非常简单,将新节点和相邻节点的指针域重新链接即可。注意顺序不能反 不然会出现循环指针造成错误。
s->next = p->next;
p->next = s;
那么,单链表的第i个数据插入的思路是:
- 声明节点p指向链表第一个节点,初始化j从1开始
- j<i, 继续遍历链表让p指针后移,j累加1
- 若p为空链表,则第i元素不存在
- 否则查找成功,生成空节点s
- 将e赋值给s->data
- 单链表插入标准语句
- 返回OK
单链表的删除
q=p->next; p->next = p->next->next
本质上就是将q节点隔开了,同时重新接上了p节点和下下个节点q->next 或者p->next->next。
单链表的整表创建与删除
单链表的整表创建是:
- 声明节点p和i计数器变量i
- 初始化空链表i
- L的头结点指针指向NULL
- 循环
- 生成新结点给p
- 随机生成数字给p数据域
- p插入到头结点与新节点之间
单链表的整表删除:
声明节点P和Q
第一个节点的值赋值给P
循环
- 将下一节点赋值给Q
- 释放P
- Q赋值给P