准备考研了,我们学校使用的教材不是这一本,大概整理一下。共勉
线性结构的特点:在数据元素的非空有限集合中
线性表是最常用 且最简单的一种数据结构,即一个线性表是n个数据元素的有限序列。例如26个英文字母表:
(a,b,c,…z)
在稍复杂的线性表中,一个数据元素可以由若干的数据项组成。此时,数据元素常常称为记录
,含有大量记录的线性表又称为文件
。
例如一个学校的学生健康情况登记表如下图
void union(List &La, List &Lb){
//将所有在线性表Lb但是不在La中的数据元素插入到La中
//求线性表的长度
La_len = ListLength(La);
Lb_len = ListLength(Lb);
for(i = 1; i <= Lb_len; i++){
GetElem(Lb, i, e);//取Lb中的第i个数据元素赋值给e
//La中不存在和e相同的数据元素,则插入
if(!LocateElem(La, e, equal))
ListInsert(La, ++La_len, e);
}
}
LA = (1,3,4,5)
LB = (2,7)
LC = (1,2,3,4,5,7)
void MergeList(List La, List Lb, List &Lc){
//已知线性表La和Lb中的数据元素按值非递减排列
//归并Lb和Lb得到新的线性表Lc,Lc的数据元素也按值费递减排序
InitList(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(La, 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(La, j++, bj);
ListInsert(Lc, ++k, bj);
}
}
线性表的顺序表示指的是用一组地址连续的存储单元依次存储线性表的数据单元。线性表的这种机内表示称为线性表的顺序存储结构或者顺序映像。称这种存储结构的线性表称为顺序表。只要确定了存储线性表的起始位置,线性表中的任意一个数据单元都可随机存取,所以线性表的顺序存储结构是一种随机存取的储存结构。
图中的l
代表每一个元素需要占用的l个存储单元。
//线性表的动态分配顺序存储结构
# define LIST_INIT_SIZE 100 //线性表存储空间的初始分配量
# define LISTINCREATEMENT 10 //线性表存储空间的分配增量
typedef struct{
ElemType * elem; // 存储空间基址
int length; //当前长度
int listsize; //当前分配的存储容量
}SqList;
初始化线性表
Status InitList_Sq(SqList &L){
//构造一个的线表L
L.elem = (ElemType *)malloc(LIST_INIT_SIZE*sizeof(ElemType));
if(!L.elem) exit(OVERFLOW); //存储分配失败
L.length = 0; //空表长度为0
L.listsize = LIST_INIT_SIZE; //初始化存储长度
return OK;
}//InitList_Sq
线性表的插入操作和删除操作
一般情况下,在第i(0<=i<=n)个元素之前插入一个元素时,需要将第n至第i(共n-i+1)个元素向后移动一个位置。算法实现如下。
Status ListInsert_Sq(SqList &L, int i, ElemType e){
//在顺序线性表L中的第i个位之前插入新的元素e
//判断1长度的合法性
if(i<1||i>L.length+1)
return ERROR;
//如果内存空已满,增加分配
if(L.length>=L.listsize){
newbase = (ElemType*)realloc(L.elem,(L.listsize+LISTINCREATEMENT)*sizeof(ElemType));
if(!newbase)
exit(OVERFLOW);
L.elem = newbase;
L.listsize += LISTINCREATEMENT;
}
//q为插入的位置
q = &(L.elem[i-1]);
//插入位置以及之后的元素右移
for(p = &(L.elem[L.length-1]);p>=q;--p){
*(p+1) = *p;
}
//插入以及表长加1
*q = e;
++L.length;
return OK;
}//ListInsert
一般情况下,删除第i(0<=i<=n)个元素需将第i+1至n(n-i)个元素依次向前移动一个位置。算法实现如下。
Status ListDelete_Sq(SqList &L, int i, ElemType &e){
//在顺序线性表L中删除第i个元素,并用e返回其值
if((i<1)||(i>L.length))
return ERROR;
//p为被删除元素的地址(位置)
p = &(L.elem[i-1]);
// e 为 删除的值
e = *p;
//表尾元素的位置
q = L.elem + L.length-1;
for(++p; p>=q; ++p)
*(p-1) = *p;
--L.length;
return OK;
}//ListDelete_Sq
由这两个算法得知,当在顺序储存结构的线性表中某个位置插入或者删除一个数据元素时,其时间主要消耗在移动元素上。平均需要移动一半的元素,时间复杂度为O(n)。
查找
int LocateElem_Sq(SqList L, ElemType e, Status (*compare)(ElemType, ElemType)){
//在顺序表中查找第一个值与e满足compare()的元素位序,否则返回0
i = 1;
p = L.elem;
while(i<L.length && !(*compare)(*p++, e))
++i;
if(i<L.length) return i;
else return 0;
}//LocateElem_Sq
归并
void MergeList_Sq(SqList La, SqList Lb, SqList &Lc){
//已知顺序线性表La 和Lb 的元素按值非递排列
// 归并La 和 Lb 得到一个新的顺序线性表Lc,Lc 的元素按值非递排列
pa = La.elem;
pb = Lb.elem;
Lc.listsize = Lc.length = La.length + Lb.length;
pc = Lc.elem = (ElemType*) malloc(Lc.listsize*sizeof(ElemType));
if(!Lc.elem)
exit(OVERFLOW);
pa_last = La.elem + La.length - 1;
pb_last = Lb.elem + Lb.length - 1;
while(pa<=pa_last&&pb<=pb_last){
if(*pa<=*pb){
*pc++ = *pa++;
}else{
*pc++ = *pb++;
}
}
while(pa<pa_last)
*pc++ = pa++;
while(pb<pb_last)
*pc++ = pb++;
}//MergeList_Sq