线性表
线性结构的特点
在数据元素的有限集合中:
存在唯一的一个被称作“第一个”的数据元素
存在唯一的一个被称作“最后一个”的数据元素
除第一个外,集合中的每个数据元素均只有一个前驱
除最后一个外,集合中的每个数据元素均只有一个后继
线性表的类型定义
一、定义
一个线性表是n个数据元素的有限序列
二、抽象数据类型的定义
(一)、具体操作
1、初始化操作Initlist(&L)
2、结构销毁操作DestroyList( &L )
3、引用型操作
ListEmpty( L )线性表判空
ListLength( L )求线性表长度
PriorElem( L, cur_e, &pre_e )(求数据元素的前驱)
NextElem( L, cur_e, &next_e )(求数据元素的后继)
GetElem( L, i, &e )(求线性表中某个数据元素)
LocateElem( L, e, compare( ) )(定位函数)
ListTraverse(L, visit( ))(遍历线性表)
4、加工型操作
ClearList( &L )(将存在的线性表置空)
ListInsert( &L, i, e )(在i之前插入数据元素e)
ListDelete(&L, i, &e)(删除L的第i个数据元素,并用e返回其值)
(二)
1、线性表中元素的个数n(n>=0)定义为线性表的长度,n=0时称为空表。ai是第i个数据元素,称i为ai在线性表中的位序。
2、有序表
若线性表中的数据元素相互之间可以比较,并且数据元素在线性表中依值非递减或非递增有序排列,即
ai≥ai-1 或 ai≤ai-1(i = 2,3,…, n),
则称该线性表为有序表(Ordered List)。
3、例题:设 La = (a1, …, ai, …, an), Lb = (b1, …, bj, …, bm)
Lc = (c1, …, ck, …, cm+n)
且已由(a1, …, ai-1)和(b1, …,bj-1)归并得 (c1, …, ck-1)
取ai与bi中的最小值复值给Ck
void MergeList(List La, List Lb, List &Lc) {
// 本算法将非递减的有序表 La 和 Lb 归并为 Lc
InitList(Lc); // 构造空的线性表 Lc
i = j = 1; k = 0;
La_len = ListLength(La);
Lb_len = ListLength(Lb);
while ((i <= La_len) && (j <= Lb_len)){
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; }
}// La 和 Lb 均不空
while (i<=La_len) {
GetElem(La, i++, ai);
ListInsert(Lc, ++k, ai);
} // 若 La 不空
while (j<=Lb_len) {
GetElem(Lb, j++, bj);
ListInsert(Lc, ++k, bj);
} // 若 Lb 不空
线性表的类型实现
一、顺序映像
(一)基本内容
1、用一组地址连续的存储单元依次存放线性表中的数据元素。
2、一般来说,线性表的第i个数据元素ai的存储位置为
LOC(ai) = LOC(a1) + (i-1)×C
LOC(a1)为↑基地址
3、是一种随机存取的存储结构
4、时间复杂度为O(n)
(二)线性表的基本操作在顺序表中的实现
1、InitList(&L) // 结构初始化
Status InitList_Sq( SqList& L, int maxsize ) {
// 构造一个最大容量为 maxsize 的顺序表
L.elem = new ElemType[maxsize];// 为顺序表分配大小为 maxsize 的数组空间
if (!L.elem) exit(OVERFLOW);//存储分配失败
L.length = 0;//空表长度为0
L.listsize = maxsize;//初始存储量
return OK;
}
2、LocateElem(L, e, compare()) // 查找
2、ListInsert(&L, i, e) // 插入元素
(1)查找的基本操作是:
将顺序表中的 元素逐个和给定值e相比较。
(2)一般情况下,在第i(1<=i<=n)个元素之前插入一个元素时,需要将第n至第i(共n-i+1)个元素向后移动一个位置。
(3)代码:
Status ListInsert_Sq(SqList &L, int i, ElemType e) {
// 在顺序表L的第 i 个元素之前插入新的元素e,
// i 的合法范围为 1≤i≤L.length+1
if (i < 1 || i > L.length+1) return ERROR; // 插入位置不合法
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; // 增加存储容量
}
**q = &(L.elem[i-1]);** *// q 指示插入位置*
for (p = &(L.elem[L.length-1]); p >= q; --p)
*(p+1) = *p; *// 插入位置及之后的元素右移*
*q = e; // **插入e**
++L.length; // 表长增1
return OK;
(4)
若假定在线性表中任何一个位置上进行插入的概率都是相等的,则移动元素的期望值为 n/2
3、ListDelete(&L, i) // 删除元素
(1)一般情况下,删除第i(1<=i<=n)个元素时,需要将从第(i+1)至第n个元素(共n-i个)依次向前移动一个位置。
(2)代码:
Status ListDelete_Sq(SqList &L, int i, ElemType &e) {
if ((i < 1) || (i > L.length)) return ERROR; // 删除位置不合法
p = &(L.elem[i-1]); // p 为被删除元素的位置
e = *p; // 被删除元素的值赋给
q = L.elem+L.length-1; // 表尾元素的位置
for (++p; p <= q; ++p) *(p-1) = *p;// 被删除元素之后的元素左移
--L.length; // 表长减1
return OK;
}
(3)若假定在线性表中任何一个位置上进行删除的概率都是相等的,则移动元素的期望值为:(n-1)/2
4、LocateElem(L, e, compare()) // 查找
(三)、总结
1、特点:以数据元素物理位置的相邻表示逻辑关系的相邻。
2、优点:随机存取
3、缺点:插入删除操作需移动较多数据元素。
4、若以线性表表示集合的各种运算,应先对表中的元素进行排序。