线性表的类型定义
线性结构是一个数据元素的有序(次序)集
线性结构的基本特征:
- 集合中必存在唯一的一个“第一元素”
- 集合中必存在唯一的一个“最后元素”
- 出最后元素之外,均有唯一的后继
- 除第一元素之外,均有唯一的前驱
抽象数据类型线性表的定义
抽象数据类型三要素:数据对象,数据关系,基本操作
数据对象和数据关系表示的是线性表的特征(一个数据元素的有序集,数据元素之间存在的是一个次序的关系)
线性表的定义:
ADT List{
数据对象:
D = { a i ∣ a i ∈ E l e m S e t , i = 1 , 2 , … , n , n ≥ 0 a_i\lvert a_i\in{ElemSet,i=1,2,\ldots,n, n\geq0} ai∣ai∈ElemSet,i=1,2,…,n,n≥0}
{称n为线性表的表长;
称n = 0时的线性表为空表 }
数据关系:
R 1 = { < a i − 1 , a i > ∣ a i − 1 , a i ∈ D , i = 2 , … n } R_1=\lbrace<a_{i-1},a_i>|a_{i-1},a_i\in D,i=2,\ldots n\rbrace R1={<ai−1,ai>∣ai−1,ai∈D,i=2,…n}
{设线性表为( a 1 , a 2 , … a i , … , a n a_1,a_2,\ldots a_i,\ldots,a_n a1,a2,…ai,…,an),称 i i i为 a i a_i ai在线性表中的位序}
}
基本操作:
-
结构初始化(构造一个空的线性表L,线性表长度为0)
InitList(&L) //结构初始化操作,构造一个空的线性表L
-
销毁结构
DestroyList(&L)
初始条件:线性表L已经存在
操作结果:销毁线性表L -
引用型操作(操作不改变线性表结构)
ListEmpty(L) //判空
ListLength(L) //判断线性表的长度
PriorElem(L, cur_e, &pre_e) //求一个元素的前驱
NextElem(L, cur_e, &next_e) //求一个元素的后继
GetElem(L, i, &e) //取第i个位置上的元素
LocateElem(L,e, compare()) //返回L中第一个与e满足关系的元素的位序,不存在则返回0
ListTraverse(L, visit()) //依次对L的每个元素调用visit()
-
加工型操作(改变线性表结构)
ClearList(&L) //将L重置位空表,和初始化操作的区别是有初始条件
PutElem(L, i, &e) //L中的第i个元素赋值同e的值
ListInsert(&L, i, e) //在L的第i的元素之前插入新的元素,L的长度增加1
ListDelete(&L, i, &e) //删除L第i个元素,并用e返回其值,L的长度减1
利用上述定义的线性表,可以完成其他更复杂的操作
例2-1
假设:有两个集合A和B分别用两个线性表LA和LB表示(即:线性表中的数据元素几位集合中的成员,现要求一个新的集合 A = A ∪ B A=A\cup B A=A∪B)
上述问题可演绎为:
扩大线性表LA,将存在于线性表LB中而不存在与线性表LA中的数据元素插入到线性表LA中去
- 从线性表LB中依次去除每个数据元素:GetElem(LB, i) ——>e
- 依值在线性表LA中进行查访:LocateElem(LA, e, equal())
- 若不存在, 则插入之:ListInsert(LA, n+1, e)
void union(List &La, List Lb){
La_len = ListLength(La);
lb_len = ListLength(Lb); //求线性表的长度
for (i = 1; i<=Lb_len; i++){
GetElem(Lb, i , e); //取Lb中的第i个元素赋给e
if(!LocateElem(La, e, equal()))
ListInsert(La, ++La_len, e); //La中不存在和e相同的元素,则插入之(先加一,后插入)
}
}//union
例2-2
已知一个非纯集合B(集合中有相同的元素),试构造一个纯集合A,使A中只包含B中所有值各不相同的数据元素。
有两个策略:
- 类似问题一的解题思路,先初始化A,依次从表B中取出元素和A中的元素进行比较,然后插入
- 先将表B进行排序,则只需要与A中的最后一个元素进行比较即可
void purge(List&La, List Lb){
//策略一
//时间复杂度为O(n2)
InitList(La); //设置空的线性表La
La_len = ListLength(La);
Lb_len = ListLength(Lb); //求线性表的长度
for(i=1; i<=Lb_len; i++){
GetElem(Lb, i ,e); //从线性表Lb中取第i个元素
if(!LocateElem(La, e, equal())){
++La_len;
ListInsert(La, La_len, e); //元素e插入线性表La
}//if
}//for
}//purge
void purge(List &La, List Lb){
// 策略二
// 时间复杂度为O(n),排序的时间复杂度为可以做到O(nlogn)
InitList(La);
La_len = ListLength(La);
Lb_len = ListLength(Lb);
for(i=1; i<=Lb_len; i++){
GetElem(Lb, i, e) //取Lb中的第i个元素赋值e
if(ListEmpty(LA)||!equal(en, e)){ //如果为空,则插入,不为空则比较最后一个值
ListInsert(La, ++La_len, e);
en = e; //插入后让最后一个元素值为新插入的元素
}
}
}
例2-3
归并两个“其数据元素按值非递减有序排列(关键字递增序排列,但并非是单调递增)的”线性表LA和LB,求得线性表LC也具有同样特性
设 L a = ( a 1 , … , a i , … , a n ) La=(a_1,\ldots,a_i,\ldots,a_n) La=(a1,…,ai,…,an) L b = ( b 1 , … , b i , … , b n ) Lb=(b_1,\ldots,b_i,\ldots,b_n) Lb=(b1,…,bi,…,bn)
L c = ( c 1 , … , c i , … , c n + m ) Lc=(c_1,\ldots,c_i,\ldots,c_{n+m}) Lc=(c1,…,ci,…,cn+m)
则 C k = k = 1 , 2 , … , m + n C_k= k=1,2,\ldots,m+n Ck=k=1,2,…,m+n
- 分别从LA 和LB中取得当前元素 a i a_i ai和 b j b_j bj
- 若 a i ≤ b j a_i\leq b_j ai≤bj,则将 a i a_i ai插入到LC中,否则将 b j b_j bj插入到LC中
void MergeList(List La, List Lb, List &Lc){
// 时间复杂度为线性
InitList(Lc);
i = j = 1; k = 0;
La_len = ListLength(La);
Lb_len = ListLength(Lb);
while((i<=La_len)&&(j<=Lb_len)){
//La和Lb均非空
GetElem(La,i,ai);
GetElem(Lb,j,bj);
if(ai<bj){
ListInsert(Lc,++k,ai); ++i}
else {ListInsert(Lc, ++k, bj); ++j}
}
while(i<=La_len){
GetElem(La,i++,ai);
ListInsert(Lc,++k,ai);
}
while(j<=Lb_len){
GetElem(Lb,j++,bj);
ListInsert(Lc,++k,bj);
}
}//merge_list