2.2 何时选用顺序表、何时选用链表作为线性表的存储结构解析
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
操作结果:构造一个空的线性表L。 …… }ADT List
2.2 基于抽象数据类型线性表的操作 1、建立一个空的线性表 3、判断线性表L是否为空 5、在线性表中插入某元素 2、求线性表中元素个数 4、取线性表L中第i个元素 6、在线性表中删除某元素
7、求线性表中某元素的前驱元素 8、求线性表中某元素的后继元素 9、在线性表中查找某元素 10、两个线性表进行合并
2.3 线性表的存储结构
1、两种存储结构:
顺序存储--数组
链式存储--链表
2、线性表的顺序存储结构
示意图:
存储地址 b b+l
…
内存状态
数据元素在线性表中的位序
1
2 … i … n
b+(i-1)l … b+(n-1)l
b+nl …
b+(maxlen-1)l 空闲
类型定义:
//---线性表的动态分配顺序存储结构--#define LIST_INIT_SIZE 100
2.7 双向链表的操作算法
* 什么是双向链表? 为了克服单链表单向性的缺点,可利用双向链表, 在它的结点中有两个指针域,其一指向直接后继,另 一指向直接前趋。在C语言中可描述如下:
//-------线性表的双向链表存储结构-------typedef struct DuLNode{ ElemType data; struct DuLNode *prior; struct DuLNode *next; }DuLNode, *DuLinkList;
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; //插入位置及之后的元素右移
数据结构
C语言版
内
• • • • • • • • •
容
2.1 线性表的定义 2.2 基于抽象数据类型线性表的操作 2.3 线性表的存储结构 2.4 基于顺序存储结构的线性表操作算法 2.5 基于链式存储的线性表操作算法 2.6 循环链表的操作算法 2.7 双向链表的操作算法 2.8 顺序存储线性表与链式存储线性表的比较 2.9 一元多项式的表示及相加
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
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, //i的合法值为1≤i≤Listlength_Sq(L)+1 if(i<1 || i>L.length+1) return ERROR; //i的值不合法 if(L.length>=L.listsize){ //当前存储空间已满,增加分配
· 直接后继元素--线性表中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)
p=L; j=0;
while (p && j<i-1) {p=p->next; ++j;} //寻找第i-1个结点 if (!p || j>i-1) return ERROR; //i小于1或者大于表长
s=(LinkList) malloc (sizeof (LNode)); //生成新结点
s->data=e; s->next=p->next; //插入L中 p->next=s;
3、线性表的链式存储结构L=(a1,a2,……,an)
示意图:
注:(a)为非空表,(b)为空表。
类型定义: //---线性表的单链表存储结构---
typedef struct LNode{ ElemType data; struct LNode *next;
}LNode,*LinkList;
2.4 基于顺序存储结构的线性表操作算法
第 2章
2.1 线性表的定义
线性表
1、名词术语
· 线性表--n个数据元素的有限序列. 记为(a1,a2,……,ai-1,ai,ai+1,……,an)。 例如:26英文字母表(A,B,C,……,X,Y,Z)、一个班级的学生成绩报表等 · 表长--线性表中元素的个数
· 直接前驱元素--线性表中ai-1领先于ai,则ai-1是ai的直接前驱元素
//线性表存储空间的初始分配量
#define LISTINCREMENT 10 //线性表存储空间的分配增量 typedef struct{ ElemType *elem; //存储空间基址
int length; //当前长度
int listsize; //当前分配的存储容量 (以sizeof(ElemType)为单位) }SqList;
*q=e; //插入e
++L.length; //表长增1 return OK; } //ListInsert_Sq
3、删除元素算法
Status ListDelete_Sq(SqList &L,int i,ElemType &e){ //在顺序线性表L中删除第i个元素,并用e返回其值 //i的合法值为1≤i≤Listlength_Sq(L) if((i<1)||(i>L.length)) return ERROR; //i的值不合法 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;
}//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
1.在双向链表中插入节点
Status ListInsert_Dul(DuLinkList &L,int i,ElemType e){ //在带头结点的双链循环线性表L中第i个位置之前插入元素 e,i的合法值为1≤i≤表长+1。 if (!(p=GetElemp_DuL(L,i))) //在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
return OK;
}//ListDelete_Sq
4、查找wk.baidu.com素算法
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
4、两个有序链表合并成一个有序链表 void MergeList_L(LinkList &La,LinkList &Lb,LinkList &Lc){ //已知单链线性表La和Lb的元素按值非递减排列 //归并La和Lb得到新的单链线性表Lc,Lc的元素也按值非递减排列。
pa=La->next; pb=Lb->next;
2.5 基于链式存储的线性表操作算法
* 带头结点的单链表(如右:a图为非空表,b图为空表)
1、创建一个带头结点的单链表 void CreateList_L(LinkList &L,int n){ //逆位序输入n个元素的值,建立带表头结点的单链线性表L。 L=(LinkList) malloc (sizeof (LNode)); L->next=NULL; //先建立一个带头结点的单链表
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
1、创建一个空的线性表
Status InitList_Sq(SqList &L){
// 构造一个空的线性表L。
L.elem=(ElemType *)malloc(LIST_INIT_SIZE * sizeof(ElemType));
if (!L.elem) exit(OVERFLOW); // 存储分配失败
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=pa?pa:pb; //插入剩余段 free(Lb); //释放Lb的头结点
}//MergeList_L
2.6 循环链表的操作算法
* 什么是循环链表?
循环链表是另一种形式的链式存储结构。它的特点是表中最后一个结
点的指针域指向头结点,整个链表形成一个环。由此,从表中任一结点
出发均可找到表中其他结点,如下图所示为单链的循环链表。
循环链表的操作与单链表的差别
循环链表的操作与单链表基本一致, 差别仅在于算法中的循环条件不是P或 P->netx 是否为空,而是它们是否等于 头指针。
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));
2.2 基于抽象数据类型线性表的操作 1、建立一个空的线性表 3、判断线性表L是否为空 5、在线性表中插入某元素 2、求线性表中元素个数 4、取线性表L中第i个元素 6、在线性表中删除某元素
7、求线性表中某元素的前驱元素 8、求线性表中某元素的后继元素 9、在线性表中查找某元素 10、两个线性表进行合并
2.3 线性表的存储结构
1、两种存储结构:
顺序存储--数组
链式存储--链表
2、线性表的顺序存储结构
示意图:
存储地址 b b+l
…
内存状态
数据元素在线性表中的位序
1
2 … i … n
b+(i-1)l … b+(n-1)l
b+nl …
b+(maxlen-1)l 空闲
类型定义:
//---线性表的动态分配顺序存储结构--#define LIST_INIT_SIZE 100
2.7 双向链表的操作算法
* 什么是双向链表? 为了克服单链表单向性的缺点,可利用双向链表, 在它的结点中有两个指针域,其一指向直接后继,另 一指向直接前趋。在C语言中可描述如下:
//-------线性表的双向链表存储结构-------typedef struct DuLNode{ ElemType data; struct DuLNode *prior; struct DuLNode *next; }DuLNode, *DuLinkList;
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; //插入位置及之后的元素右移
数据结构
C语言版
内
• • • • • • • • •
容
2.1 线性表的定义 2.2 基于抽象数据类型线性表的操作 2.3 线性表的存储结构 2.4 基于顺序存储结构的线性表操作算法 2.5 基于链式存储的线性表操作算法 2.6 循环链表的操作算法 2.7 双向链表的操作算法 2.8 顺序存储线性表与链式存储线性表的比较 2.9 一元多项式的表示及相加
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
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, //i的合法值为1≤i≤Listlength_Sq(L)+1 if(i<1 || i>L.length+1) return ERROR; //i的值不合法 if(L.length>=L.listsize){ //当前存储空间已满,增加分配
· 直接后继元素--线性表中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)
p=L; j=0;
while (p && j<i-1) {p=p->next; ++j;} //寻找第i-1个结点 if (!p || j>i-1) return ERROR; //i小于1或者大于表长
s=(LinkList) malloc (sizeof (LNode)); //生成新结点
s->data=e; s->next=p->next; //插入L中 p->next=s;
3、线性表的链式存储结构L=(a1,a2,……,an)
示意图:
注:(a)为非空表,(b)为空表。
类型定义: //---线性表的单链表存储结构---
typedef struct LNode{ ElemType data; struct LNode *next;
}LNode,*LinkList;
2.4 基于顺序存储结构的线性表操作算法
第 2章
2.1 线性表的定义
线性表
1、名词术语
· 线性表--n个数据元素的有限序列. 记为(a1,a2,……,ai-1,ai,ai+1,……,an)。 例如:26英文字母表(A,B,C,……,X,Y,Z)、一个班级的学生成绩报表等 · 表长--线性表中元素的个数
· 直接前驱元素--线性表中ai-1领先于ai,则ai-1是ai的直接前驱元素
//线性表存储空间的初始分配量
#define LISTINCREMENT 10 //线性表存储空间的分配增量 typedef struct{ ElemType *elem; //存储空间基址
int length; //当前长度
int listsize; //当前分配的存储容量 (以sizeof(ElemType)为单位) }SqList;
*q=e; //插入e
++L.length; //表长增1 return OK; } //ListInsert_Sq
3、删除元素算法
Status ListDelete_Sq(SqList &L,int i,ElemType &e){ //在顺序线性表L中删除第i个元素,并用e返回其值 //i的合法值为1≤i≤Listlength_Sq(L) if((i<1)||(i>L.length)) return ERROR; //i的值不合法 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;
}//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
1.在双向链表中插入节点
Status ListInsert_Dul(DuLinkList &L,int i,ElemType e){ //在带头结点的双链循环线性表L中第i个位置之前插入元素 e,i的合法值为1≤i≤表长+1。 if (!(p=GetElemp_DuL(L,i))) //在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
return OK;
}//ListDelete_Sq
4、查找wk.baidu.com素算法
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
4、两个有序链表合并成一个有序链表 void MergeList_L(LinkList &La,LinkList &Lb,LinkList &Lc){ //已知单链线性表La和Lb的元素按值非递减排列 //归并La和Lb得到新的单链线性表Lc,Lc的元素也按值非递减排列。
pa=La->next; pb=Lb->next;
2.5 基于链式存储的线性表操作算法
* 带头结点的单链表(如右:a图为非空表,b图为空表)
1、创建一个带头结点的单链表 void CreateList_L(LinkList &L,int n){ //逆位序输入n个元素的值,建立带表头结点的单链线性表L。 L=(LinkList) malloc (sizeof (LNode)); L->next=NULL; //先建立一个带头结点的单链表
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
1、创建一个空的线性表
Status InitList_Sq(SqList &L){
// 构造一个空的线性表L。
L.elem=(ElemType *)malloc(LIST_INIT_SIZE * sizeof(ElemType));
if (!L.elem) exit(OVERFLOW); // 存储分配失败
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=pa?pa:pb; //插入剩余段 free(Lb); //释放Lb的头结点
}//MergeList_L
2.6 循环链表的操作算法
* 什么是循环链表?
循环链表是另一种形式的链式存储结构。它的特点是表中最后一个结
点的指针域指向头结点,整个链表形成一个环。由此,从表中任一结点
出发均可找到表中其他结点,如下图所示为单链的循环链表。
循环链表的操作与单链表的差别
循环链表的操作与单链表基本一致, 差别仅在于算法中的循环条件不是P或 P->netx 是否为空,而是它们是否等于 头指针。
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));