2.1 线性表的类型定义 2.2 线性表的顺序表示和实现 2.3 ...

74

Click here to load reader

Upload: steffi

Post on 13-Jan-2016

120 views

Category:

Documents


9 download

DESCRIPTION

第 2 章 线性表. 2.1 线性表的类型定义 2.2 线性表的顺序表示和实现 2.3 线性表的链式表示和实现 2.4 一元多项式的表示. 本章重点难点. 重点 : (1) 线性表 ADT 顺序存储实现中的基本操作及相关算法; (2)ADT 链式存储实现中基本操作及相关算法; (3) 双向链表的基本操作及相关算法; (4) 循环链表的特点、基本操作及相关算法。 难点 : 线性表 ATD 的设计和实现,线性表 ADT 链式存储实现,包括双向链表、循环链表的基本操作和有关算法。. 第 2 章 线性表. 2.1 线性表的类型定义 - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

1

2.1 线性表的类型定义

2.2 线性表的顺序表示和实现

2.3 线性表的链式表示和实现

2.4 一元多项式的表示

Page 2: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

2

第 2 章 线性表

重点 : (1) 线性表 ADT 顺序存储实现中的基本操作及相关算法; (2)ADT 链式存储实现中基本操作及相关算法; (3) 双向链表的基本操作及相关算法; (4) 循环链表的特点、基本操作及相关算法。 难点 : 线性表 ATD 的设计和实现,线性表 ADT 链式存储实现,包括双向链表、循环链表的基本操作和有关算法。

本章重点难点

Page 3: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

3

2.1 线性表的类型定义

2.2 线性表的顺序表示和实现

2.3 线性表的链式表示和实现

2.4 一元多项式的表示

Page 4: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

4

第 2 章 线性表

线性结构的基本特征为 :

(1) 集合中必存在唯一的一个“第一元素”; (2) 集合中必存在唯一的一个“最后元

素” ;

(3) 除最后元素在外,均有唯一的后继; (4) 除第一元素之外,均有唯一的前驱。

线性表是 n 个类型相同数据元素的有限序列,通常记作( a1, a2, a3, …, an )。

2.1 线性表的类型定义

线性表的定义

Page 5: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

5

第 2 章 线性表

ADT List {

数据对象:D = { ai | ai ∈ElemSet, i=1,2,...,n,

n≥0 } { 称 n 为线性表的表长 ; 称 n=0 时的线性表为空表。 }数据关系:R1= { <ai-1 ,ai >|ai-1 ,ai∈D, i=2,...,n }

线性结构的基本特征为 :

2.1 线性表的类型定义

基本操作:

}ADT List

见下页

Page 6: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

6

第 2 章 线性表

基本操作

2.1 线性表的类型定义

InitList( &L ) // 构造一个空的线性表L 。DestroyList( &L ) // 销毁 L

ListEmpty( L ) // 判断 L 是否空ListLength( L ) //求 L 的长度PriorElem( L, cur_e, &pre_e ) // 求前驱的值

NextElem( L, cur_e, &next_e ) // 求后继的值

Page 7: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

7

第 2 章 线性表

基本操作

2.1 线性表的类型定义

GetElem( L, i, &e ) //取 i 位置的值 LocateElem( L, e, compare( ) ) // 在线性表中查找 eListTraverse(L, visit( )) // 遍历线性表ClearList( &L ) // 清空线性表ListInsert( &L, i, e ) //在 i 位置插入 eListDelete(&L, i, &e) // 删除 i 位置的元素

Page 8: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

8

第 2 章 线性表

基本操作的应用

2.1 线性表的类型定义

假设 : 有两个集合 A 和 B 分别用两个线性表 LA 和 LB 表示,即:线性表中的数据元素即为集合中的成员。 现要求一个新的集合 A = A∪B 。

例 2-1

用定义过的基本操作实现例 2-1 ,例 2-

2

Page 9: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

9

第 2 章 线性表

(1) 从线性表 LB 中依次察看每个数据元素 ;

(2) 依值在线性表 LA 中进行查访 ;

(3) 若不存在,则插入之。

GetElem(LB, i,&e)

LocateElem(LA, e, equal( ))

ListInsert(LA, n+1, e)

例 2-1 操作步骤:

2.1 线性表的类型定义

Page 10: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

10

第 2 章 线性表

void union(List &La, List Lb) { La_len = ListLength(La); // 求线性表的长度 Lb_len = ListLength(Lb);

for (i = 1; i <= Lb_len; i++) {

}

}

例 2-1 算法2.1 线性表的类型定义

…………………………….

Page 11: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

11

第 2 章 线性表

GetElem(Lb, i, e); // 取 Lb 中第 i 个数据元素赋给 e if (!LocateElem(La, e, equal( )) ) ListInsert(La, ++La_len, e); // La 中不存在和 e 相同的数据元素,则插入之

例 2-1 算法时间复杂性O(ListLength(La)*ListLength(Lb))

例 2-1 算法

2.1 线性表的类型定义

Page 12: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

12

第 2 章 线性表

将两个“数据元素按值递增有序排列”的线性表La和 Lb 归并到线性表 Lc ,且 Lc 具有同样的性质。

设 La=(a1,…ai,….an)

Lb=(b1,…bj,….bm)

Lc=(c1,…ck,…cm+n)

2.1 线性表的类型定义基本操作的应用

用定义过的基本操作实现例 2-2

例 2-2

Page 13: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

13

第 2 章 线性表

void MergeList(List La, List Lb, List &Lc) {

} // merge_list

while ((i <= La_len) && (j <= Lb_len)) { // La 和 Lb 均不空 }while (i<=La_len) // 若 La 不空while (j<=Lb_len) // 若 Lb 不空

InitList(Lc); // 构造空的线性表 Lci = j = 1; k = 0;La_len = ListLength(La);Lb_len = ListLength(Lb);

2.1 线性表的类型定义例 2-2 算法

见下页

Page 14: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

14

第 2 章 线性表

GetElem(La, i, ai);

GetElem(Lb, j, bj);

if (ai <= bj) { // 将 ai 插入到 Lc 中 ListInsert(Lc, ++k, ai); ++i;

}

else { // 将 bj 插入到 Lc 中 ListInsert(Lc, ++k, bj); ++j;

}

2.1 线性表的类型定义例 2-2 算法

Page 15: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

15

第 2 章 线性表

while (i <= La_len) { // 当 La 不空时 GetElem(La, i++, ai);

ListInsert(Lc, ++k, ai);

} // 插入 La 表中剩余元素

while (j <= Lb_len) { // 当 Lb 不空时 GetElem(Lb, j++, bj);

ListInsert(Lc, ++k, bj);

} // 插入 Lb 表中剩余元素

2.1 线性表的类型定义例 2-2 算法

Page 16: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

16

2.1 线性表的类型定义

2.2 线性表的顺序表示和实现

2.3 线性表的链式表示和实现

2.4 一元多项式的表示

Page 17: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

17

存储线性表,就是要保存至少两类信息:(1) 线性表中的数据元素;(2) 线性表中数据元素的顺序关系;

如何在计算机中存储线性表?如何在计算机中实现线性表的基本操作?

2.2 线性表的顺序表示和实现

Page 18: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

18

第 2 章 线性表2.2 线性表的顺序表示和实现

线性表的顺序表示最简单的一种顺序映象方法是:令 x 的存储位置和 y 的存储位置相邻。

以数据元素 x 的存储位置和数据元素 y 的存储位置之间的某种关系表示逻辑关系 <x,y> 。

线性表的顺序表示的定义

Page 19: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

19

第 2 章 线性表

用一组地址连续的存储单元依次存放线性表中的数据元素

a1 a2 … ai-1 ai … an

线性表的起始地址称作线性表的基地址

线性表的顺序表示图示

2.2 线性表的顺序表示和实现

Page 20: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

20

第 2 章 线性表

以“存储位置相邻”表示有序对 <ai-1, ai>

时, ai-1和 ai 的地址关系如下:

LOC(ai) = LOC(ai-1) + C

C 为一个数据元素所占存储量 所有数据元素的存储位置均取决于第一个数据元素的存储位置。 LOC(ai) = LOC(a1) + (i-1)×C

↑ 基地址

数据元素地址之间的关系

2.2 线性表的顺序表示和实现

Page 21: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

21

第 2 章 线性表

顺序表示的实现

typedef struct {

} SqList; // 俗称 顺序表

#define LIST_INIT_SIZE 80 // 线性表存储空间的初始分配量#define LISTINCREMENT 10 // 线性表存储空间的分配增量

ElemType *elem; // 存储空间基址int length; // 当前长度

int listsize; // 当前分配的存储容量 // (以 sizeof(ElemType) 为单位 )

2.2 线性表的顺序表示和实现

Page 22: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

22

第 2 章 线性表

Status InitList_Sq( SqList &L ) { // 构造一个空的线性表

} // InitList_Sq

L.elem = (ElemType*) malloc (LIST_ INIT_SIZEsizeof (ElemType));if (!L.elem) exit(OVERFLOW);

L.length = 0;L.listsize = LIST_INIT_SIZE;return OK;

2.2 线性表的顺序表示和实现基本操作的实现

Page 23: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

23

第 2 章 线性表

线性表操作 ListInsert(&L, i, e) 的实现:

首先分析 :

插入元素时,线性表的逻辑结构发生什么变化?

2.2 线性表的顺序表示和实现

基本操作的实现

Page 24: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

24

第 2 章 线性表2.2 线性表的顺序表示和实现插入操作过程示意图

a1

a2

ai-1

ai

ai+1

an

a1

a2

ai-1

ai

ai+1

an

a1

a2

ai-1

e

ai+1

an

Page 25: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

25

第 2 章 线性表

Status ListInsert_Sq(SqList &L, int i, ElemType e) { // 在顺序表 L 的第 i 个元素之前插入新的元素e

} // ListInsert_Sq

q = &(L.elem[i-1]); // q 指示插入位置for (p = &(L.elem[L.length-1]); p >= q; --p) *(p+1) = *p; // 插入位置及之后的元素右移 *q = e; // 插入 e ++L.length; // 表长增 1return OK;

……

2.2 线性表的顺序表示和实现插入操作算法

Page 26: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

26

第 2 章 线性表

if (L.length >= L.listsize) { // 当前存储空间已满,增加分配 newbase = (ElemType *)realloc(L.elem, (L.listsize+LISTINCREMENT)*sizeof (ElemType));

if (!newbase) exit(OVERFLOW); L.elem = newbase; // 新基址 L.listsize += LISTINCREMENT;}

if (i < 1 || i > L.length+1) return ERROR; // 插入位置不合法

2.2 线性表的顺序表示和实现插入操作算法

Page 27: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

27

第 2 章 线性表

设在第 i 个元素之前插入的概率为 pi ,则在长度为n 的线性表中插入一个元素时所需平均移动元素次数为:

若假定在任何一个位置上插入元素的概率相同,则平均移动次数为:

1

1

)1()(n

iiIS inpnE

21

)1()(

1

1

n

n

innE

n

iIS

O(n)

2.2 线性表的顺序表示和实现

插入算法时间复杂性分析

Page 28: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

28

第 2 章 线性表

线性表删除操作 ListDelete(&L, i, &e) 的实现:

首先分析:删除元素时,线性表的逻辑结构发生什么变化?

基本操作的实现

2.2 线性表的顺序表示和实现

Page 29: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

29

第 2 章 线性表2.2 线性表的顺序表示和实现删除操作过程示意图

a1

a2

ai-1

ai

ai+1

an

a1

a2

ai-1

ai+1

an

Page 30: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

30

第 2 章 线性表

Status ListDelete_Sq (SqList &L, int i, ElemType &e) {

} // ListDelete_Sq

for (++p; p <= q; ++p) *(p-1) = *p; --L.length; // 表长减 1return OK;

p = &(L.elem[i-1]); // p 为被删除元素的位置e = *p; // 被删除元素的值赋给 eq = L.elem+L.length-1; // 表尾元素的位置

if ((i < 1) || (i > L.length)) return ERROR;

删除操作过程示意图2.2 线性表的顺序表示和实现

Page 31: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

31

第 2 章 线性表

设删除第 i 个元素的概率为 pi ,则在长度为 n的线性表中删除一个元素时所需平均移动次数为:

若假定在任何一个位置上删除元素的概率相同,则平均移动次数为:

n

iiIS inpnE

1

)()(

2

1)()(

1

n

n

innE

n

iIS O(n)

删除操作时间复杂性分析

2.2 线性表的顺序表示和实现

Page 32: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

32

第 2 章 线性表

(1) 优点 a. 节省存储空间 ;

b. 对线性表中第 i 个结点的操作易于实现 ;

c. 容易查找一个结点的前驱和后继。 (2) 缺点 a. 插入和删除操作比较困难 ;

b. 建立空表时,较难确定所需的存储空间。

顺序表的优缺点

2.2 线性表的顺序表示和实现

Page 33: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

33

2.1 线性表的类型定义

2.2 线性表的顺序表示和实现

2.3 线性表的链式表示和实现

2.4 一元多项式的表示

Page 34: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

34

第 2 章 线性表

2.3 线性表的链式表示和实现

2.3.1 单链表

2.3.2 静态链表

2.3.3 循环链表

2.3.4 双向链表

Page 35: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

35

第 2 章 线性表

一个线性表由若干个结点组成,每个结点至少含有两个域:数据域 ( 信息域 ) 和指针域 ( 链域 ) ,由这样的结点形成存储的线性表称作链表。

链表的定义

2.3.1 单链表

单链表结构示意图

a1 a2… an ^

Page 36: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

36

第 2 章 线性表

逻辑次序和物理次序 相同; 元素之间的逻辑关系用 表示;需要额外空间存储元素之间的关系 ; 是不是随机存储结构?

不一定 指针

不是

结构特点

单链表结构示意图

a1 a2… an ^

2.3.1 单链表

Page 37: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

37

第 2 章 线性表

在链式存储结构中以第一个结点的存储地址作为线性表的基地址,通常称它为头指针。

头指针的概念

线性表的最后一个数据元素没有后继,因此最后一个结点中的 "指针 "是一个特殊的值 "NULL" ,通常称它为 "空指针 "。

a1 a2… an ^

2.3.1 单链表

Page 38: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

38

第 2 章 线性表

在单链表上设置一个结点,它本身不存放数据,它的指针域指向第一个元素的地址。

头结点的概念

使对第一个元素的操作与对其它元素的操作保持一致。

头结点的作用

a1 a2… an ^

2.3.1 单链表

Page 39: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

39

第 2 章 线性表

Typedef struct LNode {

ElemType data; // 数据域 struct Lnode *next; // 指针域 } LNode, *LinkList;

单链表的 C 语言实现

LinkList L ; // L 为单链表的头指针

2.3.1 单链表

Page 40: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

40

第 2 章 线性表

单链表操作的实现

GetElem_L(LinkList L, int i, ElemType &e)

// 查找第 i 个结点,将第 i 个结点的值存入 e

查找过程

(1) 从第一个结点 p 开始, j=1开始记数;

(2)当 p->next 不为空时,转向下一个继续记数 ;

(3)直到 j=i或 p->next 为空。

2.3.1 单链表

Page 41: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

41

第 2 章 线性表

Status GetElem_L(LinkList L, int i, ElemType &e) {

}

p = L->next; j = 1; // p 指向第一个结点, j 为计数器while (p && j<i) { p = p->next; ++j; }

if ( !p) return ERROR; // 第 i 个元素不存在e = p->data; // 取得第 i 个元素return OK;

GetElem_L 算法

2.3.1 单链表

Page 42: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

42

第 2 章 线性表

单链表操作的实现

Status ListInsert_L(LinkList L, int i, ElemType e) // L 为带头结点的单链表的头指针,本算法// 在链表中第 i 个结点之前插入新的元素 e

插入过程

(1) 查找第 i-1 个结点 p ;

(2) 生成结点 s, 存入 e;

(3)s->netx=p->next, p->next=s;

2.3.1 单链表

Page 43: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

43

第 2 章 线性表

Status ListInsert_L(LinkList L, int i, ElemType e) { // L 为带头结点的单链表的头指针,本算法 // 在链表中第 i 个结点之前插入新的元素 e

} // LinstInsert_L

p = L; j = 0;while (p && j < i-1) { p = p->next; ++j; } // 寻找第 i-1 个结点if (!p ) return ERROR; // i 大于表长或者小于 1

……

ListInsert_L 算法

2.3.1 单链表

Page 44: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

44

第 2 章 线性表

s = (LinkList) malloc ( sizeof (LNode)); // 生成新结点s->data = e; s->next = p->next; p->next = s; // 插入return OK;

O(ListLength(L))

ListInsert_L 算法

ListInsert_L 算法的时间杂性

2.3.1 单链表

Page 45: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

45

第 2 章 线性表

单链表操作的实现

ListDelete_L(LinkList L, int i, ElemType &e)// L 为带头结点的单链表的头指针,本算法// 删除链表中第 i 个结点,值储入 e删除过程

(1) 查找第 i-1 个结点 p ;

(2) q=p->netx,p->next=q->next

(3) free(q)

2.3.1 单链表

Page 46: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

46

第 2 章 线性表

ListDelete_L 算法

Status ListDelete_L(LinkList L, int i, ElemType &e) {

} // ListDelete_L

p = L; j = 0;while (p->next && j < i-1) { p = p->next; ++j; } if (!(p->next) ) return ERROR; // 删除位置不合理q = p->next; p->next = q->next; e = q->data; free(q);return OK;

2.3.1 单链表

Page 47: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

47

第 2 章 线性表

单链表应用举例

将两个“数据元素按值递增有序排列”的线性表La和 Lb 归并到线性表 Lc ,且 Lc 具有同样的性质。

设 La=(a1,…ai,….an)

Lb=(b1,…bj,….bm)

Lc=(c1,…ck,…cm+n)

例 2-3

2.3.1 单链表

Page 48: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

48

第 2 章 线性表

Status MergeList_L(LinkList &La,LinkList &Lb,LinkList &Lc)

{ LinkList pa=La->next,pb=Lb->next,pc=Lc=La;

while(pa&&pb)

{ if(pa->data<=pb->data)

{pc->next=pa;pc=pa;pa=pa->next;}

else {pc->next=pb;pc=pb;pb=pb->next;}

}

pc->next=pa?pa:pb;

free(Lb);

} // MergeList_L

例 2-3 算法

2.3.1 单链表

Page 49: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

49

第 2 章 线性表

(1) 优点 a. 插入和删除时间复杂性低 ;

b. 不需预先分配空间。 (2) 缺点 a. 指针占用存储空间,增加了内存负担。

链表的优缺点

2.3.1 单链表

Page 50: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

50

第 2 章 线性表

2.3 线性表的链式表示和实现

2.3.1 单链表

2.3.2 静态链表

2.3.3 循环链表

2.3.4 双向链表

Page 51: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

51

第 2 章 线性表

静态链表的引入2.3.2 静态链表

链表具有不需事先分配存储空间,插入和删除操作时间复杂性低等优点,但实现链表必须能够对内存地址进行操作,但直接对内存地址进行操作是很多高级语言不具备的功能,为了在不具备地址操作的高级语言上实现链表的功能,引入了静态链表。

静态链表的概念

定义一个较大的结构数组作为备用结点空间 ( 即存储池 ) ,当申请结点时,从存储池中取出一个结点,当释放结点时,将结点归还存储池内。

Page 52: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

52

第 2 章 线性表

静态链表示意图2.3.2 静态链表

9

zhao 3

qian 4

sun 5

li 7

zhou 6

wu 0

zheng 8

wang 0

10

0

0

1

2

3

4

5

6

7

8

9

10

存储池 space

data 域 cur 域

静态链表的第一个结点位置是一个下标:左图中有两个静态链表

第一个以 1 开头。space[1],space[3],space[5], space[6].

第二个以 2 开头space[2],space[4],space[7], space[8].

Page 53: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

53

第 2 章 线性表

//---- 线性表的静态单链表存储结构 ----//#define MAXSIZE 1000 // 链表的最大长度typedef struct { ElemType data; int cur; //游标} component, SLinkList[MAXSIZE];

SLinkList space;

2.3.2 静态链表

静态链表的 C 语言实现

Page 54: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

54

第 2 章 线性表

//---- 初始化 ----//void InitSpace_SL(SLinkList &space){ for (i=0;i<MAXSIZE-1;++i) space[i].cur=i+1; space[MAXSIZE-1].cur=0;}

2.3.2 静态链表静态链表模拟可用空间初始化

Page 55: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

55

第 2 章 线性表

//----申请空间 ----//int Malloc_SL(SLinkList &space){ i = space[0].cur; if (space[0].cur) space[0].cur = space[i].cur; return i;}

2.3.2 静态链表静态链表模拟申请空间的实现

Page 56: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

56

第 2 章 线性表

//----回收结点 ----//void Free_SL(SLinkList &space,int K){ space[k].cur=space[0].cur; space[0].cur=k;}

2.3.2 静态链表静态链表模拟释放空间的实现

Page 57: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

57

第 2 章 线性表

Status ListInsert_L(int L, int i, ElemType e) {

// L 为静态链表的第一个结点位置,本算法 // 在链表中第 i 个结点之前插入新的元素 e

}

p =L; j = 0;

while (p && j < i-1)

{ p =space[p].cur; ++j; }

if (!p)

return ERROR; ……

2.3.2 静态链表静态链表插入算法

Page 58: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

58

第 2 章 线性表

s = Malloc_SL(space) // 生成新结点space[s].data = e;

space[s].cur =space[p].cur;

space[p].cur = s; // 插入新结点return OK;

O(ListLength(L))

静态链表插入算法

静态链表插入算法时间复杂性

2.3.2 静态链表

Page 59: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

59

第 2 章 线性表

2.3 线性表的链式表示和实现

2.3.1 单链表

2.3.2 静态链表

2.3.3 循环链表

2.3.4 双向链表

Page 60: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

60

第 2 章 线性表

单链表最后一个结点的指针域没有利用,如果使其指向指向头指针(头结点),则首尾构成一个循环,称作循环链表。

2.3.3 循环链表循环链表的概念

循环链表示意图

a1 a2… an

head

Page 61: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

61

第 2 章 线性表

从表中任一结点出发均可找到表中其它结点。

讨论:在循环链表中多采用尾指针?为什么?

结论:如果采用尾指针,则查找第一个结点和最后一个结点都容易。

循环链表的优点

a1 a2… an

head

2.3.3 循环链表

Page 62: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

62

第 2 章 线性表

设两个链表 La=(a1,a2,...,an) 和Lb=(b1,b2,...bm) ,讨论如下问题: (1) La、 Lb都是带头结点的单链表,如何实现将 Lb接在 La 之后?时间复杂度是多少?

(2) La、 Lb都是带头结点头指针的单循环链表,如何实现将 Lb接在 La 之后还形成一个循环链表?时间复杂度是多少?

(3) La、 Lb都是带头结点尾指针的单循环链表,如何实现将 Lb接在 La 之后还形成一个循环链表?时间复杂度是多少?

单链表和循环链表操作比较2.3.3 循环链表

Page 63: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

63

第 2 章 线性表

结论:

(1) La、 Lb都是带头结点的单链表, Lb接在La 之后,时间复杂度是 O(length(La)) 。

(2) La、 Lb都是带头结点头指针的单循环链表,实现将 Lb接在 La 之后还形成一个循环链表,时间复杂度是多少 O(length(La)+length(Lb)) 。

(3) La、 Lb都是带头结点尾指针的单循环链表,实现将 Lb接在 La 之后还形成一个循环链表,时间复杂度是 O(1) 。

单链表和循环链表操作比较2.3.3 循环链表

Page 64: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

64

第 2 章 线性表2.3.3 双向链表 双向链表的概念

一个链表的每一个结点含有两个指针域:一个指针指向其前驱结点,另一个指针指向其后继结点,这样的链表称为双向链表。

双向链表结构示意图

^ a1

a2

^

head

Page 65: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

65

第 2 章 线性表

// 类型定义typedef struct DuLNode{

ElemType data;

struct DuLNode *prior;

struct DuLNode *next;

} DuLNode,*DuLinkList;

2.3.3 双向链表 双向链表的 C 语言实现

Page 66: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

66

第 2 章 线性表

在双向链表中:p->prior 指向 p 的前驱, p->next 指向 p 的后继以下都是 p 结点的地址:p->next->prior 和 p->prior->next

2.3.3 双向链表 双向链表中地址关系

双向链表的操作特点: “ 查询” 和单链表相同。 “ 插入” 和“删除”时需要同时修改两个方向上的指针。

Page 67: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

67

第 2 章 线性表

Status ListInsert_Dul(DuLinkList &L, int i ,ElemType e){ if(!(p=GetElemP_DuL(L,i))) return error; if(!(s=(DuLinkList)malloc(sizeof(DuLNode)))) return error; s->data=e; s->prior=p->prior; s->next=p; p->prior->next=s; p->prior=s; return OK;}

2.3.3 双向链表 双向链表的插入算法

Page 68: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

68

第 2 章 线性表

Status ListDelete_Dul(DuLinkList &L,int i ,ElemType &e){ if(!(p=GetElemP_DuL(L,i))) return error; e=p->data; p->prior->next=p->next; p->next->prior=p->prior; free(p); return OK;}

2.3.3 双向链表

双向链表的删除算法

Page 69: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

69

第 2 章 线性表

2.1 线性表的类型定义

2.2 线性表的顺序表示和实现

2.3 线性表的链式表示和实现

2.4 一元多项式的表示

Page 70: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

70

第 2 章 线性表2.4 一元多项式的表示

nnn xpxpxppxp ...)( 2

210

讨论一元多项式用什么方式存储比较合适?

结论:一元多项式既可以用顺序表存储,也可以用链表存储,在用顺序表存储时,如果是稀疏多项式则浪费空间严重,用链式存储比较好。

一元多项式的讨论

Page 71: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

71

第 2 章 线性表

ADT Polynomial {

数据对象:

数据关系:

} ADT Polynomial

R1= { <ai-1 ,ai >|ai-1 ,ai∈D, i=2,...,n

且 ai-1 中的指数值< ai 中的指数值 }

D = { ai | ai ∈TermSet, i=1,2,...,m, m≥0

TermSet 中的每个元素包含一个 表示系数的实数和表示指数的整数 }

2.4 一元多项式的表示 一元多项式的抽象数据类型

基本操作: 见下页

Page 72: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

72

第 2 章 线性表

CreatPolyn ( &P, m ) // 存储多项式 DestroyPolyn ( &P ) // 销毁多项式 PrintPolyn ( &P ) // 打印输出多项式

PolynLength( P ) // 求多项式的项数 AddPolyn ( &Pa, &Pb ) // 两个多项式相加 SubtractPolyn ( &Pa, &Pb )// 两个多项式相减 ……

2.4 一元多项式的表示一元多项式的基本操作

Page 73: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

73

第 2 章 线性表

typedef struct { // 项的表示 float coef; // 系数 int expn; // 指数} term, ElemType;

typedef LinkList polynomial;

// 用带表头结点的有序链表表示多项式

2.4 一元多项式的表示一元多项式类型的 C 语言实现

Page 74: 2.1   线性表的类型定义 2.2   线性表的顺序表示和实现 2.3   线性表的链式表示和实现 2.4   一元多项式的表示

74

第 2 章 线性表本章小结 熟练掌握:

(1) 线性表的逻辑结构特性和线性表的 (ADT) 设计;

(2) 线性表的顺序存储结构和链式存储结构两种实现方式和基本操作;

(3) 双向链表的插入和删除等基本操作及相关算法 ;

(4) 循环链表的特点及相关操作 ;

(5)理解一元多项式的表示方法及相加算法,提高自己用线性表解决实际问题的应用水平。