第2章 线 性 表
@(教材_数据结构【C】)[2023-11-6ev, C语言]
线性表是线性结构。线性结构的特点:在数据元素的非空有限集中:
1)存在唯一的一个被称做“第一个”的数据元素;
2)存在唯一的一个被称做“最后一个”的数据元素;
3)除第一个外,集合中的每个数据元素均只有一个前驱;
4)除最后一个之外,集合中的每个数据元素均只有一个后继。
2.1 线性表的类型定义
线性表(Linear_List
)是最常用且最简单的数据结构,一个线性表是n个数据元素的有限序列。
线性表中的数据元素可以是各种各样的,但同一线性表中的元素必定具有相同的特性,即属同一数据对象,相邻数据元素之间存在着序偶关系。
若将线性表记为:
(
a
1
,
.
.
.
,
a
i
−
1
,
a
i
,
a
i
+
1
,
.
.
.
,
a
n
)
.
.
.
.
.
.
.
.
.
.
.
.
(
2
−
1
)
(a_1, ..., a_{i-1}, a_i, a_{i+1}, ... , a_n) ............(2-1)
(a1,...,ai−1,ai,ai+1,...,an)............(2−1)
- a i − 1 领先于 a i , a i 领先于 a i + 1 ; a_{i-1}领先于a_i, a_i领先于a_{i+1}; ai−1领先于ai,ai领先于ai+1;
- a i − 1 是 a i 的直接前驱, a i + 1 是 a i 的直接后继; a_{i-1}是a_i的直接前驱,a_{i+1}是a_i的直接后继; ai−1是ai的直接前驱,ai+1是ai的直接后继;
- 当 i = 1 , 2 , . . . , n − 1 时, a i 有且仅有一个直接后继; 当 i = 1,2,...,n-1时,a_i有且仅有一个直接后继; 当i=1,2,...,n−1时,ai有且仅有一个直接后继;
- 当 i = 2 , 3 , . . . , n 时, a i 有且仅有一个直接前驱。 当 i = 2,3, ...,n时,a_i有且仅有一个直接前驱。 当i=2,3,...,n时,ai有且仅有一个直接前驱。
线性表中元素的个数n(n≧0)定义为线性表的长度,n=0时成为空表。
在非空表中的每个元素都有一个确定的位置,i
为数据元素
a
i
a_i
ai的位序。
抽象数据类型线性表的定义如下:
ADT List{
**数据对象:**D={ a i ∣ a i ∈ E l e m S e t , i = 1 , 2 , . . . , n , n ≧ 0 a_i | ai∈ElemSet, i = 1, 2,..., n, n≧0 ai∣ai∈ElemSet,i=1,2,...,n,n≧0}
**数据关系:**R1= { < a i − 1 , a i > ∣ a i − 1 , a i ∈ D , i = 2 , . . . , n <a_{i-1}, a_i>|a_{i-1}, a_i∈D, i = 2,...,n <ai−1,ai>∣ai−1,ai∈D,i=2,...,n}
基本操作:
InitList( &L )
操作结果:构造一个空的线性表L。
DestroyList( &L )
初始条件:线性表L已存在。
操作结果:销毁线性表L。
ClearList( &L )
初始条件:线性表L已存在。
操作结果:将L重置为空表。
ListEmpty( &L )
初始条件:线性表L已存在。
操作结果:若L为空表,则返回TRUE,否则返回FALSE。
ListLength( &L )
初始条件:线性表L已存在。
操作结果:返回L中数据元素个数。
GetElem( L, i, &e )
初始条件:线性表L已存在,1≦i≦ListLength(L)。
操作结果:用e返回L中第i个数据元素的值。
… …
}ADT List
2.2 线性表的顺序表示和实现
线性表的顺序表示是指:用一组地址连续的存储单元依次存储线性表的数据元素。
假设:线性表的每个元素需占用l
个存储单元,并以所占的第一个单元的存储地址作为数据元素的存储位置。则线性表中第i+1
个数据元素的存储位置
L
O
C
(
a
i
+
1
)
LOC(_{a_{i+1}})
LOC(ai+1)和第i
个数据元素的存储位置$ LOC(_{a_i})
之间满足下列关系:
之间满足下列关系:
之间满足下列关系:
L
O
C
(
a
i
+
1
)
=
L
O
C
(
a
i
)
+
l
LOC(_{a_{i+1}}) = LOC(_{a_i}) + l
LOC(ai+1)=LOC(ai)+l$
一般来说,线性表的第i
个数据元素
a
i
a_i
ai的存储位置为:
L
O
C
(
a
i
)
=
L
O
C
(
a
1
)
+
(
i
−
1
)
×
l
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
(
2
−
2
)
LOC(_{a_i}) = LOC(_{a_1}) +(i -1)× l ......................(2-2)
LOC(ai)=LOC(a1)+(i−1)×l......................(2−2)
式中:$LOC(_{a_1}) 是线性表中的第一个元素 是线性表中的第一个元素 是线性表中的第一个元素a_1$的存储位置,通常称为线性表的起始位置或基地址。
这种表示称做线性表的顺序存储结构
或顺序映像
。称这种存储结构的线性表为**顺序表
**。
线性表的顺序存储结构是一种随机存取的的存储结构 —— 线性表是逻辑关系上相邻的两个元素在物理位置上也相邻。
优点:是可以随机存取表中任一元素,它的存储位置可用一个简单、直观的公式来表示;
弱点:在作插入或删除操作时,需移动大量元素。
2.3 线性表的链式表示和实现
链式存储结构,它不要求逻辑上相邻的元素在物理位置上也相邻,因此它没有顺序存储结构所具有的弱点,但同时也失去了顺序表可随机存取
的优点。
2.3.1 线性链表
线性表的链式存储结构的特点:用一组任意的存储单元存储线性表的数据元素(可以是连续的,也可以是不连续的)。
a i → a i + 1 a_i →a_{i+1} ai→ai+1,对数据元素 a i a_i ai来说,除了存储本身的信息之外,还需存储一个指示后继信息的信息(即直接后继的存储位置)。
本身信息+后继信息,组成数据元素
a
i
a_i
ai的存储映像,称为结点(node)。包括两个域:
其中存储数据元素信息的域称为数据域;
存储直接后继存储位置的域称为指针域;
指针域中存储的信息称做指针或链。
n个结点( a i a_i ai(1≤i≤n)的存储映像)链结成一个链表,即为线性表 ( a 1 , a 2 , . . . . , a n ) (a_1, a_2, ...., a_n) (a1,a2,....,an)的链式存储结构。又由于此链表每个结点只包含一个指针域,故称为线性链表或单链表。
头指针:指示链表中的第一个结点(即第一个数据元素的存储映像)的存储位置。
同时,由于最后一个数据元素没有直接后继,则线性链表中最后一个结点的指针为“空”(NULL)。
*单链表可由头指针唯一确定。有时,我们在单链表的第一个结点之前附设一个结点,称之为头结点。头结点的数据域可以不存储任何信息,也可存储如线性表的长度等类的附加信息,头结点的指针域存储指向第一个结点的指针(即第一个匀速结点的存储位置)。若线性表为空表,则头结点的指针域为“空”
。
在单链表中,取得第i
个数据元素必须从头指针触发寻找,因此,单链表是非随机存取的存储结构
。
静态链表:用数组描述的链表。
2.3.2 循环链表
循环链表:表中最后一个结点的指针指向头结点,整个链表形成一个环。
2.3.3 双向链表
顾名思义:在双向链表的结点中有两个指针域,其一指向直接后继,另一个指向直接前驱。
2.4 一元多项式的表示及相加
一般地,一元n次多项式可写成:
P
n
(
x
)
=
p
1
x
e
1
+
p
2
x
e
2
+
.
.
.
+
P
m
x
e
m
.
.
.
.
.
.
(
2
−
7
)
P_n(x) = p_1x^{e_1} + p_2x^{e_2} + ... + P_mx^{e_m} ......(2-7)
Pn(x)=p1xe1+p2xe2+...+Pmxem......(2−7)
其中:
p
i
p_i
pi是指数为
e
i
e_i
ei的项的非零系数,且满足:
0
≤
e
1
≤
e
2
≤
.
.
.
≤
e
m
=
n
0 ≤ e_1 ≤ e_2 ≤ ... ≤ e_m = n
0≤e1≤e2≤...≤em=n
若用一个长度为m,且每个元素有两个数据项(系数项和指数项)的线性表
(
(
p
1
,
e
1
)
,
(
p
2
,
e
2
)
,
.
.
.
,
(
p
m
,
e
m
)
)
.
.
.
.
.
.
(
2
−
8
)
((p_1,e_1) , (p_2,e_2), ... , (p_m,e_m)) ......(2-8)
((p1,e1),(p2,e2),...,(pm,em)) ......(2−8)
便可唯一确定多项式
P
n
(
x
)
P_n(x)
Pn(x)。
一元多项式可以有两种存储结构:若只对多项式“求值”等不改变多项式系数和指数的运算,可以采用顺序存储结构;否则应采用链式存储结构。
抽象数据类型一元多项式的定义如下:
ADT Polynomial {
数据对象:D = { a i ∣ a i ∈ T e r m S e t a_i | a_i ∈ TermSet ai∣ai∈TermSet, i = 1, 2, …, m, m ≧ 0
TermSet 中的每个元素包含一个表示系数的实数和表示指数的整数}
数据关系:R1 = { < a i − 1 , a i > ∈ D ,且 a i − 1 中的指数值 < a i 中的指数值, i = 2 , . . . , n <a_{i-1}, a_i>∈D,且a_{i-1}中的指数值<a_i中的指数值, i = 2, ..., n <ai−1,ai>∈D,且ai−1中的指数值<ai中的指数值,i=2,...,n}
基本操作:
CreatPolyn( &P, m )
操作结果:输入m项的系数和指数,建立一元多项式P。
DestroyPolyn( &P )
初始条件:一元多项式P已存在。
操作结果:销毁一元多项式P。
PrintPolyn ( P )
初始条件:一元多项式P已存在。
操作结果:打印输出一元多项式P。
PolyLength( P )
初始条件:一元多项式P已存在。
操作结果:返回一元多项式P中的项数。
AddPolyn( &Pa, &Pb )
初始条件:一元多项式Pa和Pb已存在。
操作结果:完成多项式相加运算,即:Pa = Pa + Pb,并销毁一元多项式Pb。
SubtractPolyn( &Pa, &Pb )
初始条件:一元多项式Pa和Pb已存在。
操作结果:完成多项式相减运算,即:Pa = Pa - Pb,并销毁一元多项式Pb。
MultiplyPolyn( &Pa, &Pb )
初始条件:一元多项式Pa和Pb已存在。
操作结果:完成多项式相乘运算,即:Pa = Pa × Pb,并销毁一元多项式Pb。
}ADT Polynomial
实现上述定义的一元多项式,显然应采用链式存储结构。