数据结构_线性表及其基本算法
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
int LocateElem_Sq(Sqlist L, ElemType e){ i=0; while (i<L.length && L.elem[i]!=e) ++i; if (i<L.length) return i+1; else return 0; }//ListDelete_Sq
注 : 设L.length=n,则T(n)=O(n)
H 160
存储地址 110 150 160 190 200 210 240 260
数据域 a5 a2 a1 a3 a6 a4 a8 a7
指针域 200 190 150 210 260 110 NULL 240
示意图:
H
a1
a2
a3
H NULL
L
a1
a2
L
∧
an ∧ an ∧
2.3 线性表的链式存储结构
算法2.1(线性表的首尾合并)
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); if (!LocateElem(La,e,equal)) ListInsert(La,++La_len,e); }
掌握链表如何表示线性表中元素之间的逻辑关系;单链 表、双链表、循环链表链接方式上的区别;单链表上实 现的建表、查找、插入和删除等基本算法及其时间复杂 度。循环链表上尾指针取代头指针的作用,以及单循环 链表上的算法与单链表上相应算法的异同点。双链表的 定义和相关算法。利用链表设计算法解决简单应用问题。
基本操作: InitList(&L) ListLength(L) GetElem(L,i,&e) PriorElem(L,cur_e,&pre_e) NextElem(L,cur_e,&next_e) LocateElem(L,e,compare()) ListInsert(&L,i,e) ListDelete(&L,i,&e) }ADT List
}
顺序存储结构的优缺点
优点
▪ 逻辑相邻,物理相邻 ▪ 可随机存取任一元素 ▪ 存储空间使用紧凑
缺点
▪ 插入、删除操作需要移动大量的元素; ▪ 预先分配空间需按最大空间分配,空间利
用不充分。
2.3 线性表的链式存储结构
先看一个例子: 线性表 (a1,a2,a3,a4,a5,a6,a7,a8)
头指针
ffoorr((pj==&L(.Lle.enlegmth[L-1.le;jn>g=thi--11];);jp-->)=q;- -p)) *(p+1)=*p; *q=Le.;elem[j+1]=L.elem[j]
++L.length; return OK; }//ListInsert_Sq
L.elem a1 a2
有且仅有一个终端结点(表尾结点tail)an,它没有直接 后继,只有一个直接前驱;
其它结点都有一个直接前驱和直接后继; 元素之间为一对一的线性关系。
线性表的抽象数据类型定义(P18 )
ADT List{
数据对象:D={ai|ai∈ElemSet;1≤i≤n,n≥0;} 数据关系:R={<ai,ai+1>| ai, ai+1∈D,i=1,2,……,n-1}
平均移动元素的次数为:
▪
n1
n1 1
n
i 1
pi ci
[ (n i 1)] i1 n 1
2
▪故时间复杂度为O(n)。
算法2.5 顺序表中删除元素
Status ListDelete_Sq(Sqlist &L,int i,ElemType & e){ if ((i<1)||(i>L.length)) return ERROR; p=&(L.elem[i-1]); ee==*Lp.;elem[i-1];
删除算法花费的时间,主要在于循环中元素的前移上,而元 素的移动次数与删除的位置i有关: (设L.length=n)
当i=1时,其后的全部元素都得移动,需n-1次移动,
当i=n时,不需移动元素,
一般地:在i位置删除元素时的移动次数ci为n-i 假设在每个位置删除的概率为pi (不妨设为等概率) ,则
if (!L.elem) exit (OVERFLOW);
L.length=0; L.listsize=LIST_INIT_SIZE; return OK; }//InitList_Sq
算法2.4 :顺序表中插入一个元素
Status ListInsert_Sq(SqList &L,int i,ElemType e){ 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+=LISTINCREMET; } q=&(L.elem[i-1]);
}//MergeList
2.2 线性表的顺序存储结构
一、特点
1. 用一组地址连续的存储单元依次存放线性 LOC(a1) 表中的元素;
a1
2. 以元素在机内的“物理位置相邻”来表示
a2
数据之间的逻辑关系:
……
LOC(ai+1)= LOC(ai)+L 3. 是一种随机存取的存储结构;
LOC(ai)=LOC(a1)+(i-1)*L 4. 插入/删除时需移动大量元素;
领会顺序表和链表的比较,以及如何选择其一作为其存 储结构才能取得较优的时空性能。
教学重点与难点
本章的重点是掌握顺序表和单链表上实现的各种 基本算法及相关的时间性能分析;
难点是使用本章所学的基本知识设计有效算法解 决与线性表相关的应用问题。
教学方法
课堂讲授 提问互动 实验
2.1 线性表的类型定义
}//union 算法分析:
设LocateElem的执行时间与表长成正比, 即:算法的时间复杂度为:O(ListLength(La) * ListLength(Lb))
算法2.2(有序线性表的合并)
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) { 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);}
CH2 线性表
2.1 线性表的逻辑结构 2.2 线性表的顺序存储及运算实现 2.3 线性表的链式存储和运算实现 2.4 线性表的两种存储结构的比较 2.5 线性表的应用举例
教学目标
线性表的逻辑结构特征;线性表上定义的基本运算,并 利用基本运算构造出较复杂的运算。
掌握顺序表的含义及特点,顺序表上的插入、删除操作 是及其平均时间性能分析,解决简单应用问题。
定义:
线性表(linear list) ( a1,a2,… , an )
其中:
n :数据元素的个数或线性表的长度; ai : 是一个抽象的符号,它的数据类型设定为ElemType,
表示某一种具体的已知数据类型(1≤i≤n) 。
非空线性表的特征(P18)
有ຫໍສະໝຸດ Baidu仅有一个开始结点(表头结点 head)a1,它没有直 接前驱,只有一个直接后继;
平均移动元素的次数为:
n
i 1
pi
ci
n [ 1 (n i)] i1 n
n 1 2
故时间复杂度为O(n)。
算法2.6 顺序表中元素的查找
int LocateElem_Sq(Sqlist L, ElemType e, status (*compare))(ElemType ,ElemType)){
2.2 线性表的顺序存储结构
三、基本操作的算法描述
初始化顺序表 (算法 2.3)
插入元素
(算法 2.4)
删除元素
(算法 2.5)
元素的查找
(算法 2.6)
顺序表的合并 (算法 2.7)
算法2.3 (初始化顺序表)
Status InitList_Sq(SqList &L){ L.elem=(ElemType*) malloc(LIST_INIT_SIZE*sizeof(ElemType))
算法2.7 顺序表的合并
Status MergeList_Sq(Sqlist La, Sqlist Lb, Sqlist &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 (!pc) return OVERFLOW; pa_last=pa+La.length-1; pb_last=pb+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++;
ai ai+1
an
下标
a1 0 a2 1
e i-1
ai i
an-1 an
插入算法的时间复杂度分析
插入算法花费的时间,主要在于循环中元素的向后移动上面,
而元素的移动次数与插入的位置i有关: (设L.length=n)
当i=1时,全部元素都得移动,需n次移动,
当i=n+1时,不需移动元素,
一般地:在i位置插入时移动次数ci为n-i+1, 假设在每个位置插入的概率为pi (不妨设为等概率) ,则
LOC(ai) LOC(ai+1)
ai ai+1 ……
an
2.2 线性表的顺序存储结构
二、描述方式
#define LIST_INIT_SIZE 100 #define LISTINCREMENT 10 typedef struct{
ElemType *elem; int length; int listsize; } SqList
i=1; p=L.elem; while (i<L.length && !(*compare)(*p++,e) ++i; if (i<=L.length) return i; else return 0; }//ListDelete_Sq
注 : 设L.length=n,则T(n)=O(n)
算法2.6-1 顺序表中元素的查找
线性表的链式存贮结构及特点
用一组任意的存储单元存放线性表中的各元素; 数据之间的逻辑关系由结点中的指针指示; 是一种非随机存取(顺序存取)的存储结构; 插入/删除时无需移动大量元素。
常用的链表有:
单链表 循环链表 双向链表 多重链表
2.3.1 线性链表(单链表)
在定义的链表中,若只含有一个指针域来存放下
一个元素地址,称这样的链表为单链表或线性链
表。
typedef struct LNode{
结点结构与定义:
ElemType data;
data next
struct LNode *next;
▪ 线性链表示意图
qF=oLLr..e(ejll=eemim;j+[<jL-=1.Ll]e=.nleLgn.teghlt-eh1m-;1[j;]j;++)
for (++p;p<=q;++p) *(p-1)=*p; - -L.length; return OK; }//ListDelete_Sq
删除算法的时间复杂度分析
注 : 设L.length=n,则T(n)=O(n)
H 160
存储地址 110 150 160 190 200 210 240 260
数据域 a5 a2 a1 a3 a6 a4 a8 a7
指针域 200 190 150 210 260 110 NULL 240
示意图:
H
a1
a2
a3
H NULL
L
a1
a2
L
∧
an ∧ an ∧
2.3 线性表的链式存储结构
算法2.1(线性表的首尾合并)
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); if (!LocateElem(La,e,equal)) ListInsert(La,++La_len,e); }
掌握链表如何表示线性表中元素之间的逻辑关系;单链 表、双链表、循环链表链接方式上的区别;单链表上实 现的建表、查找、插入和删除等基本算法及其时间复杂 度。循环链表上尾指针取代头指针的作用,以及单循环 链表上的算法与单链表上相应算法的异同点。双链表的 定义和相关算法。利用链表设计算法解决简单应用问题。
基本操作: InitList(&L) ListLength(L) GetElem(L,i,&e) PriorElem(L,cur_e,&pre_e) NextElem(L,cur_e,&next_e) LocateElem(L,e,compare()) ListInsert(&L,i,e) ListDelete(&L,i,&e) }ADT List
}
顺序存储结构的优缺点
优点
▪ 逻辑相邻,物理相邻 ▪ 可随机存取任一元素 ▪ 存储空间使用紧凑
缺点
▪ 插入、删除操作需要移动大量的元素; ▪ 预先分配空间需按最大空间分配,空间利
用不充分。
2.3 线性表的链式存储结构
先看一个例子: 线性表 (a1,a2,a3,a4,a5,a6,a7,a8)
头指针
ffoorr((pj==&L(.Lle.enlegmth[L-1.le;jn>g=thi--11];);jp-->)=q;- -p)) *(p+1)=*p; *q=Le.;elem[j+1]=L.elem[j]
++L.length; return OK; }//ListInsert_Sq
L.elem a1 a2
有且仅有一个终端结点(表尾结点tail)an,它没有直接 后继,只有一个直接前驱;
其它结点都有一个直接前驱和直接后继; 元素之间为一对一的线性关系。
线性表的抽象数据类型定义(P18 )
ADT List{
数据对象:D={ai|ai∈ElemSet;1≤i≤n,n≥0;} 数据关系:R={<ai,ai+1>| ai, ai+1∈D,i=1,2,……,n-1}
平均移动元素的次数为:
▪
n1
n1 1
n
i 1
pi ci
[ (n i 1)] i1 n 1
2
▪故时间复杂度为O(n)。
算法2.5 顺序表中删除元素
Status ListDelete_Sq(Sqlist &L,int i,ElemType & e){ if ((i<1)||(i>L.length)) return ERROR; p=&(L.elem[i-1]); ee==*Lp.;elem[i-1];
删除算法花费的时间,主要在于循环中元素的前移上,而元 素的移动次数与删除的位置i有关: (设L.length=n)
当i=1时,其后的全部元素都得移动,需n-1次移动,
当i=n时,不需移动元素,
一般地:在i位置删除元素时的移动次数ci为n-i 假设在每个位置删除的概率为pi (不妨设为等概率) ,则
if (!L.elem) exit (OVERFLOW);
L.length=0; L.listsize=LIST_INIT_SIZE; return OK; }//InitList_Sq
算法2.4 :顺序表中插入一个元素
Status ListInsert_Sq(SqList &L,int i,ElemType e){ 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+=LISTINCREMET; } q=&(L.elem[i-1]);
}//MergeList
2.2 线性表的顺序存储结构
一、特点
1. 用一组地址连续的存储单元依次存放线性 LOC(a1) 表中的元素;
a1
2. 以元素在机内的“物理位置相邻”来表示
a2
数据之间的逻辑关系:
……
LOC(ai+1)= LOC(ai)+L 3. 是一种随机存取的存储结构;
LOC(ai)=LOC(a1)+(i-1)*L 4. 插入/删除时需移动大量元素;
领会顺序表和链表的比较,以及如何选择其一作为其存 储结构才能取得较优的时空性能。
教学重点与难点
本章的重点是掌握顺序表和单链表上实现的各种 基本算法及相关的时间性能分析;
难点是使用本章所学的基本知识设计有效算法解 决与线性表相关的应用问题。
教学方法
课堂讲授 提问互动 实验
2.1 线性表的类型定义
}//union 算法分析:
设LocateElem的执行时间与表长成正比, 即:算法的时间复杂度为:O(ListLength(La) * ListLength(Lb))
算法2.2(有序线性表的合并)
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) { 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);}
CH2 线性表
2.1 线性表的逻辑结构 2.2 线性表的顺序存储及运算实现 2.3 线性表的链式存储和运算实现 2.4 线性表的两种存储结构的比较 2.5 线性表的应用举例
教学目标
线性表的逻辑结构特征;线性表上定义的基本运算,并 利用基本运算构造出较复杂的运算。
掌握顺序表的含义及特点,顺序表上的插入、删除操作 是及其平均时间性能分析,解决简单应用问题。
定义:
线性表(linear list) ( a1,a2,… , an )
其中:
n :数据元素的个数或线性表的长度; ai : 是一个抽象的符号,它的数据类型设定为ElemType,
表示某一种具体的已知数据类型(1≤i≤n) 。
非空线性表的特征(P18)
有ຫໍສະໝຸດ Baidu仅有一个开始结点(表头结点 head)a1,它没有直 接前驱,只有一个直接后继;
平均移动元素的次数为:
n
i 1
pi
ci
n [ 1 (n i)] i1 n
n 1 2
故时间复杂度为O(n)。
算法2.6 顺序表中元素的查找
int LocateElem_Sq(Sqlist L, ElemType e, status (*compare))(ElemType ,ElemType)){
2.2 线性表的顺序存储结构
三、基本操作的算法描述
初始化顺序表 (算法 2.3)
插入元素
(算法 2.4)
删除元素
(算法 2.5)
元素的查找
(算法 2.6)
顺序表的合并 (算法 2.7)
算法2.3 (初始化顺序表)
Status InitList_Sq(SqList &L){ L.elem=(ElemType*) malloc(LIST_INIT_SIZE*sizeof(ElemType))
算法2.7 顺序表的合并
Status MergeList_Sq(Sqlist La, Sqlist Lb, Sqlist &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 (!pc) return OVERFLOW; pa_last=pa+La.length-1; pb_last=pb+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++;
ai ai+1
an
下标
a1 0 a2 1
e i-1
ai i
an-1 an
插入算法的时间复杂度分析
插入算法花费的时间,主要在于循环中元素的向后移动上面,
而元素的移动次数与插入的位置i有关: (设L.length=n)
当i=1时,全部元素都得移动,需n次移动,
当i=n+1时,不需移动元素,
一般地:在i位置插入时移动次数ci为n-i+1, 假设在每个位置插入的概率为pi (不妨设为等概率) ,则
LOC(ai) LOC(ai+1)
ai ai+1 ……
an
2.2 线性表的顺序存储结构
二、描述方式
#define LIST_INIT_SIZE 100 #define LISTINCREMENT 10 typedef struct{
ElemType *elem; int length; int listsize; } SqList
i=1; p=L.elem; while (i<L.length && !(*compare)(*p++,e) ++i; if (i<=L.length) return i; else return 0; }//ListDelete_Sq
注 : 设L.length=n,则T(n)=O(n)
算法2.6-1 顺序表中元素的查找
线性表的链式存贮结构及特点
用一组任意的存储单元存放线性表中的各元素; 数据之间的逻辑关系由结点中的指针指示; 是一种非随机存取(顺序存取)的存储结构; 插入/删除时无需移动大量元素。
常用的链表有:
单链表 循环链表 双向链表 多重链表
2.3.1 线性链表(单链表)
在定义的链表中,若只含有一个指针域来存放下
一个元素地址,称这样的链表为单链表或线性链
表。
typedef struct LNode{
结点结构与定义:
ElemType data;
data next
struct LNode *next;
▪ 线性链表示意图
qF=oLLr..e(ejll=eemim;j+[<jL-=1.Ll]e=.nleLgn.teghlt-eh1m-;1[j;]j;++)
for (++p;p<=q;++p) *(p-1)=*p; - -L.length; return OK; }//ListDelete_Sq
删除算法的时间复杂度分析