1 线性表的定义
2 基于抽象数据类型线性表的操作
3 线性表的存储结构
4 基于顺序存储结构的线性表操作算法
5 基于链式存储的线性表操作算法
6 循环链表的操作算法
7 双向链表的操作算法
8 顺序存储线性表与链式存储线性表的比较
9 一元多项式的表示及相加
-----------------------------------------------------------------------
1、名词术语
·线性表--n个数据元素的有限序列。记为(a1,a2,……,ai-1,ai,ai+1,……,an)。
例如:26英文字母表(A,B,C,……,X,Y,Z)、一个班级的学生成绩报表等
·表长--线性表中元素的个数
·直接前驱元素--线性表中ai-1领先于ai,则ai-1是ai的直接前驱元素
·直接后继元素--线性表中ai领先于ai+1,则ai+1是ai的直接后继元素
2、线性表的抽象数据类型定义
ADT List{
数据对象:D={ai|ai∈ElemSet,i=1,2,……,n,n≥0}
数据关系:R1={<ai-1,ai>|ai-1,ai∈D,i=2,……,n}
基本操作:InitList(&L)
操作结果:构造一个空的线性表L。
……
}ADT List
·基于抽象数据类型线性表的操作
1、建立一个空的线性表
2、求线性表中元素个数
3、判断线性表L是否为空
4、取线性表L中第i个元素
5、在线性表中插入某元素
6、在线性表中删除某元素
7、求线性表中某元素的前驱元素
8、求线性表中某元素的后继元素
9、在线性表中查找某元素
10、两个线性表进行合并
·线性表的存储结构
1、两种存储结构:顺序存储--数组,链式存储--链表
-----------------------------------------------------------------------
类型定义:
//---线性表的动态分配顺序存储结构---
#define LIST_INIT_SIZE 100 //线性表存储空间的初始分配量
#define LISTINCREMENT 10 //线性表存储空间的分配增量
typedef struct{
ElemType *elem; //存储空间基址
int length; //当前长度
int listsize; //当前分配的存储容量(以sizeof(ElemType)为单位)
}SqList;
1、创建一个空的线性表
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
2、插入元素算法
Status ListInsert_Sq(SqList &L,int i,ElemType e){ //在顺序线性表L中第i个位置之前插入新的元素e
if(i<1 || i>L.length+1) return ERROR; //i的值不合法,i的合法值为1≤i≤Listlength_Sq(L)+1
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;
} //ListInsert_Sq
3、删除元素算法
Status ListDelete_Sq(SqList &L,int i,ElemType &e){ //在顺序线性表L中删除第i个元素,并用e返回其值
if((i<1)||(i>L.length)) return ERROR; //i的值不合法,i的合法值为1≤i≤Listlength_Sq(L)
p=&(L.elem[i-1]); //p为被删除元素的位置
e=*p; //被删除元素的值赋给e
q=L.elem+L.length-1; //表尾元素的位置
for(++p; p<=q; ++p) *(p-1)=*p; //被删除元素之后的元素左移
--L.length; //表长减1
return OK;
}//ListDelete_Sq
4、查找元素算法
int LocateElem_Sq(Sqlist L,ElemType e,Status(*compare)(ElemType,ElemType)){ //在顺序线性表L中查找第1个值与e满足compare()的元素的位序
//若找到,则返回其在L中的位序,否则返回0。
i=1; //i的初值为第1个元素的位序
p=L.elem; //p的初值为第1个元素的存储位置
while(i<=L.length &&! (*compare)(*p++,e)) ++i;
if(i<=L.length) return i;
else return 0;
}//LocateElem_Sq
5、两表合并算法
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++; //插入La的剩余元素
while(pb<=pb_last) *pc++=*pb++; //插入Lb的剩余元素
} //MergeList_Sq
-----------------------------------------------------------------------
类型定义:
//---线性表的单链表存储结构---
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
1、创建一个带头结点的单链表
void CreateList_L(LinkList &L,int n){ //逆位序输入n个元素的值,建立带表头结点的单链线性表L。
L=(LinkList) malloc (sizeof (LNode));
L->next=NULL; //先建立一个带头结点的单链表
for (i=n; i>0; --i){
p=(LinkList) malloc (sizeof (LNode)); //生成新结点
scanf(&p->data); //输入元素值
p->next=L->next;
L->next=p; //插入到表头
}
2、链表中插入结点算法
Status ListInsert_L(LinkList &L, int i, ElemType e){ //在带头结点的单链线性表L中第i个位置之前插入元素e
p=L;
j=0;
while (p && j<i-1) {p=p->next; ++j;} //寻找第i-1个结点
s=(LinkList) malloc (sizeof (LNode)); //生成新结点
s->data=e;
s->next=p->next; //插入L中
p->next=s;
return OK;
}//ListInsert_L
3、链表中删除结点算法
Status ListDelete_L(LinkList &L, int i, ElemType &e){ //在带头结点的单链线性表L中,删除第i个元素,并由e返回其值
p=L;
j=0;
while (p->next && j<i-1){ //寻找第i个结点,并令p指向其前趋
p=p->next;
++j;
}
if (!(p->next) || j>i-1) return ERROR; //删除位置不合理
q=p->next;
p->next=q->next; //删除并释放结点
e=q->data;
free(q);
return OK;
}//ListDelete_L
4、两个有序链表合并成一个有序链表
void MergeList_L(LinkList &La,LinkList &Lb,LinkList &Lc){ //已知单链线性表La和Lb的元素按值非递减排列
//归并La和Lb得到新的单链线性表Lc,Lc的元素也按值非递减排列。
pa=La->next;
pb=Lb->next;
Lc=pc=La; //用La的头结点作为Lc的头结点
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=papa:pb; //插入剩余段
free(Lb); //释放Lb的头结点
}//MergeList_L
-----------------------------------------------------------------------
循环链表
是另一种形式的链式存储结构。它的特点是表中最后一个结点的指针域指向头结点,整个链表形成一个环。
由此,从表中任一结点出发均可找到表中其他结点。
循环链表的操作与单链表基本一致,差别仅在于算法中的循环条件不是P或P->next是否为空,而是它们是否等于头指针。
-----------------------------------------------------------------------
双向链表
为了克服单链表单向性的缺点,可利用双向链表,在它的结点中有两个指针域,其一指向直接后继,另一指向直接前趋。
//-------线性表的双向链表存储结构---------
typedef struct DuLNode{
ElemType data;
struct DuLNode *prior;
struct DuLNode *next;
}DuLNode, *DuLinkList;
1.在双向链表中插入节点
Status ListInsert_Dul(DuLinkList &L,int i,ElemTypee){ //在带头结点的双链循环线性表L中第i个位置之前插入元素e
if (!(p=GetElemp_DuL(L,i))) //i的合法值为1≤i≤表长+1。在L中确定第i个元素的位置指针p
return ERROR; //p=NULL,即第i个元素不存在
if(!(s=(DuLinkList) malloc (sizeof (DuLNode)))) return ERROR;
s->data=e;
s->prior=p->prior;
p->prior->next=s;
s->next=p;
p->prior=s;
return OK;
}//ListInsert_DuL
2.在双向链表中删除节点
Status ListDelete_Dul(DuLinkList &L,int i,ElemType &e){ //删除带头结点的双链循环线性表L中第i个元素,i的合法值为1≤i≤表长。
if (!(p=GetElemp_DuL(L,i))) //在L中确定第i个元素的位置指针p
return ERROR;
e=p->data;
p->prior->next=p->next;
p->next->prior=p->prior;
free(p);
return OK;
}//ListDelete_DuL
-----------------------------------------------------------------------
顺序存储线性表与链式存储线性表的比较
顺序表的优缺点:存取数据速度快、占用的存储空间小;但需占用连续存储空间、插入操作需移动元素
链表的优缺点:不需占用连续存储空间、插入操作不需移动元素;但存储数据麻烦、速度慢、占用的存储空间大