数据结构第2章
抽象数据类型定义 :
ADT LinearList{
数据元素:D={ai| ai∈D0, i=1,2,…,n n≥0 ,D0为某一数据对象} 关系:S={<ai,ai+1> | ai, ai+1∈D0,i=1,2, …,n-1} 基本操作:
(1)InitList(L) (2)DestroyList(L) (3)ClearList(L)
{ LC->elem[k]= LB->elem[j]; j++; k++; }
LC->last=LA->last+LB->last;
21
}
2019/8/31
顺序存储结构的优点和缺点
优点:
1.无需为表示结点间的逻辑关系而增加额外的存储空间;
2.可方便地随机存取表中的任一元素。
缺点:
1.插入或删除运算不方便,除表尾的位置外,在表的其 它位置上进行插入或删除操作都必须移动大量的结 点,其效率较低;
if(L->last>=maxsize-1)
{ printf(“表已满无法插入”); return(ERROR); } for(k=L->last;k>=i-1;k--) /*为插入元素而移动位置*/
L->elem[k+1]=L->elem[k];
L->elem[i-1]=e; /*在C语言中数组第i个元素的下标为i-1*/
1. 按序号查找GetData(L,i):要求查找线性表L中第i 个数据元素,其结果是L.elem[i-1]或L->elem[i-1]。
2. 按内容查找Locate(L,e): 要求查找线性表L中与 给定值e相等的数据元素,其结果是:若在表L中找 到与e相等的元素,则返回该元素在表中的序号;若 找不到,则返回一个“空序号”,如-1。
else
{
LC->elem[k]=LB->elem[j]; j++; k++; }
while(i<=LA->last) /*当表LA长则将表LA余下的元素赋给表LC*/
{ LC->elem[k]= LA->elem[i]; i++; k++; }
while(j<=LB->last) /*当表LB长则将表LB余下的元素赋给表LC*/
loc(ai) =loc(a1)+(i-1)×k
8
2019/8/31
顺序存储结构示意图
存储地址
Loc(a1) Loc(a1)+(2-1)k
…
loc(a1)+(i-1)k
…
loc(a1)+(n-1)k
...
loc(a1)+(maxlen-1)k
内存空间状态
a1 a2
…
ai
…
an
9
逻辑地址
1 2
…
i
…
n
空闲
2019/8/31
顺序存储结构的C语言定义
#define maxsize=线性表可能达到的最大长度; typedef struct {
ElemType elem[maxsize]; /* 线性表占用的数组空间*/ int last; /*记录线性表中最后一个元素在数组elem[ ]
中的位置(下标值),空表置为-1*/ } SeqList;
D B C H F A G E
指针域
43 13
1 NULL 37
7 19 25
26
2019/8/31
带头结点的单链表示意图
有时为了操作的方便,还可以在单链表的第一个 结点之前附设一个头结点。
带头结点的空单链表
H
∧
带头结点的单链表
H
a1
a2
…
an ∧
27
2019/8/31
单链表的存储结构描述
循环链表和双链表。
23
2019/8/31
链表
2.3.1 单链表 2.3.2 单链表上的基本运算 2.3.3 循环链表 2.3.4 双向链表 *2.3.5 静态链表 2.3.6 顺序表和链表的比较
24
2019/8/31
2.3.1 单链表
结点(Node)为了正确地表示结点间的逻辑关系,必 须在存储线性表的每个数据元素值的同时,存储指示 其后继结点的地址(或位置)信息,这两部分信息组 成的存储映象叫做结点(Node)。
线性表的定义
线性表(Linear List)是由n (n≥0)个类型相同的 数据元 素 a1,a2,…,an组成 的有限 序 列 ,记做 (a1,a2,…,ai-1,ai,ai+1, …,an)。 数据元素之间是一对一的关系,即每个数据 元素最多有一个直接前驱和一个直接后继。 线性表的逻辑结构图为:
L->last++;
return(OK);
}
16
2019/8/31
删除操作
线性表的删除运算是指将表的第i(1≤i≤n)个 元素删去,使长度为n的线性表 (e1,…,ei-1,ei, ei+1,…,en),变成长度为n-1的线性表 (e1,…,ei-1, ei+1,…,en)。 算法思路示意 算法实现
c1 ∧
7
2019/8/31
顺序存储结构的定义
线性表的顺序存储是指用一组地址连续的存 储单元依次存储线性表中的各个元素,使得线性 表中在逻辑结构上相邻的数据元素存储在相邻的 物理存储单元中,即通过数据元素物理存储的相 邻关系来反映数据元素之间逻辑上的相邻关系。 采用顺序存储结构的线性表通常称为顺序表。
假设线性表中每个元素占k个单元,第一个元素 的地址为loc(a1),则第k个元素的地址为:
2.由于顺序表要求占用连续的存储空间,存储分配只能 预先进行静态分配。因此当表长变化较大时,难以 确定合适的存储规模。
22
2019/8/31
2.3 线性表的链式存储
链表定义: 采用链式存储结构的线性表称为链表 。
现在我们从两个角度来讨论链表: 1.从实现角度看,链表可分为动态链表和静态
链表; 2.从链接方式的角度看,链表可分为单链表、
4 9 15 28 30 30 42 51 62
移动元素 4 9 15
28 30 30 42 51 62
插入元素 4 9 15 21 28 30 30 42 51 62
15
2019/8/31
插入运算
int InsList(SeqList *L,int i,ElemType e)
{ int k;
if( (i<1) || (i>L->last+2) ) /*首先判断插入位置是否合法*/ { printf(“插入位置i值不合法”);return(ERROR); }
if (i<=st) return(i); /*若找到值为e的元素,则返回其序号*/
else return(-1); /*若没找到,则返回空序号*/
}
13
2019/8/31
插入操作
线性表的插入运算是指在表的第i (1≤i≤n+1) 个位置,插入一个新元素e,使长度为n的线性表 (e1,…,ei-1,ei,…,en) 变成长度为n+1的线 性表(e1,…,ei-1,e,ei,…,en)。
线性表的查找运算算法描述为:
12
2019/8/31
线性表的查找运算
int Locate(SeqList L,ElemType e) { i=0 ; /*i为扫描计数器,初值为0,即从第一个元素开始比较*/
while ((i<=st)&&(L.elem[i]!=e) ) i++; /*顺序扫描表,直到找到值为key的元素,或扫描到表尾而没找到*/
for(k=i;i<=L->last;k++)
L->elem[k-1]= L->elem[k]; /*将后面的元素依次前移*/
L->last--;
return(OK);
}
19
2019/8/31
合并算法
已知 :有两个顺序表LA和LB,其元素均为非递减有序排列,编写 一个算法,将它们合并成一个顺序表LC,要求LC也是非递减有序 排列。
注意区分元素的序号和数组的下标,如a1的序号为1,而 其对应的数组下标为0。
10
2019/8/31
2.2.2 线性表顺序存储结构的基本运算
线性表的基本运算:
1. 查找操作 2. 插入操作 3. 删除操作 4. 顺序表合并算法
线性表顺序存储结构的优缺点分析
11
2019/8/31
查找操作
线性表的两种基本查找运算
线性表的插入运算算法。
14
2019/8/31
插入算法示意图
已知:线性表 (4,9,15,28,30,30,42,51,62),需在第4个元素之前插 入一个元素“21”。则需要将第9个位置到第4个位置的元素依次后 移一个位置,然后将“21”插入到第4个位置,
序号 1 2 3 4 5 6 7 8 9 10
算法思想 :设表LC是一个空表,为使LC也是非递减有序排列,可 设两个指针i、j分别指向表LA和LB中的元素,若 LA.elem[i]>LB.elem[j],则当前先将LB.elem[j]插入到表LC中,若 LA.elem[i]≤LB.elem[j] ,当前先将LA.elem[i]插入到表LC中,如此 进行下去,直到其中一个表被扫描完毕,然后再将未扫描完的表中 剩余的所有元素放到表LC中。
算法应用示例:
1. 求单链表的长度 2. 求两个集合的差