View
119
Download
0
Category
Preview:
DESCRIPTION
第 2 章 线 性 表. 2 . 1 线性表的类型定义 2.2 线性表的顺序表示和实现 2.3 线性表的链式表示和实现 2.4 一元多项式的表示及相加. 2.1 线性表的类型定义. 线性表: 是 n 个类型相同的数据元素的有限序列,数据元素之间是一对一的关系,即每个数据元素最多有一个直接前驱和一个直接后继 。. 例 1 英文字母表( A , B , C , … , Z) 是一个线性表 例 2. 数据元素. 线性表的定义. 线性表 是由 n (n≥0) 个类型相同的数据元素 a 1 ,a 2 , … , a n 组成的有限序列,记做 - PowerPoint PPT Presentation
Citation preview
2.1 线性表的类型定义
2.2 线性表的顺序表示和实现
2.3 线性表的链式表示和实现
2.4 一元多项式的表示及相加
第 2 章 线 性 表
学号 姓名 年龄001 张锦 18
002 李鹏 19
003 林立 19
…… …… ……
100 刘磊 20
2.1 线性表的类型定义
线性表:是 n个类型相同的数据元素的有限序列,数据元素之间是一对一的关系,即每个数据元素最多有一个直接前驱和一个直接后继 。
例 1 英文字母表( A, B, C,…, Z)是一个线性表
例 2
学号 姓名 年龄001 张锦 18
002 李鹏 19
…… …… ……
数据元素
线性表的定义
线性表是由 n (n≥0)个类型相同的数据元素 a1,a2,…, an组成的有限序列,记做( a1,a2,…, ai-1, ai, ai+1, …, an)。n为线性表的长度, n=0时称为空表.线性表的特点同一性:线性表由同类数据元素组成,每一个 ai必须属于同一数据对象。有穷性:线性表由有限个数据元素组成,表长度就是表中数据元素的个数。 n=0时称为空表。有序性:线性表中相邻数据元素之间存在着序偶关系 <ai,ai+1> 。
线性表的抽象数据类型定义ADT List {
数据元素: D={ai| ai D0, i=1,2,…∈ , n , n≥0 , D0为某一数据对象 }
关系: R1={ <ai-1,ai> | ai, ai-1 D∈ , i=2, …,n}基本操作:( 1) InitList( &L)操作前提: L为未初始化线性表。操作结果:将 L初始化为空表。( 2) DestroyList(&L)
操作前提:线性表 L已存在。操作结果:将 L销毁。
( 3) ClearList(&L)
操作前提:线性表 L已存在 。操作结果:将表 L置为空表。( 4) EmptyList( L)操作前提:线性表 L已存在。操作结果:如果 L为空表则返回真,否则返回假。( 5) ListLength( L)操作前提:线性表 L已存在。操作结果:如果 L为空表则返回 0,否则返回表中的元素个数。( 6) Locate(L,e)操作前提: 表 L已存在, e为合法元素值。操作结果: 如果 L中存在元素 e,则将“当前指针”指向元素 e所在位置并返回真,否则返回假。
( 7) GetData(L,i)
操作前提:表 L存在,且 i值合法,即 1≤i≤ListLength(L))
操作结果:返回线性表 L中第 i个元素的值。( 8) ListInsert (&L,i,e)
操作前提:表 L已存在, e为合法元素值且 1≤i≤ListLength(L)+1。操作结果:在 L中第 i个位置之前插入新的数据元素 e,L的长度加 1。( 9) ListDelete(&L,i,&e)
操作前提:表 L已存在且非空, 1≤i≤ListLength(L)。操作结果:删除 L的第 i个数据元素,并用 e返回其值,L的长度减 1。}ADT List
2.2 线性表的顺序表示和实现
2.2.1 线性表的顺序存储结构
线性表的顺序存储结构(顺序映像):用一组地址连续的存储单元依次存储线性表的数据元素。
顺序表 : 采用顺序存储结构的线性表通常称为顺序表
内存存储地址 元素序号
备用空间
a1
a2
an
LOC(a1)
LOC(a1) +L
LOC(a1) +(n-1)L
1
2
n
元素地址计算方法:LOC(ai)=LOC(a1)+(i-1)*LLOC(ai+1)=LOC(ai)+L其中:
L—一个元素占用的存储单元个数LOC(ai)—线性表第 i个元素的地址
特点:实现逻辑上相邻—物理地址相邻实现随机存取
顺序存储结构的实现
可以借助于高级程序设计语言中的数组来表示,一维数组的下标与元素在线性表中的序号相对应。
// 线性表的顺序存储结构#define LIST_INIT_SIZE 100 /*
存储空间的初始分配量 */ typedef struct { ElemType elem [LIST_INIT_SIZE];
// 存储空间基址 int length; // 当前长度 }SqList;
以 C语言为例 :
2.2.2 线性表顺序存储结构上的运算
• 查找• 插入• 删除• 合并
顺序表的查找运算线性表有两种基本的查找运算。按序号查找 GetData(L,i): 要求查找线性表 L中第 i个数据元素,其结果是 L.elem[i-1] 或 L->elem[i-1] 。按内容查找 Locate ( L,e ) : 要求查找线性表L中与给定值 e相等的数据元素,其结果是:若在表 L中找到与 e相等的元素,则返回该元素在表中的序号;若找不到,则返回一个“空序号”,如 -1。
顺序表的查找运算
算法分析:查找运算可采用顺序查找法实现,即从第一个元素开始,依次将表中元素与 e相比较,若相等,则查找成功,返回该元素在表中的序号;若 e与表中的所有元素都不相等,则查找失败,返回“ -1”。
算法实现:int Locate(SqList L, ElemType e) {i=0 ; //i 为计数器 , 从第一个元素开始比较 while ((i<=L.length-1)&&(L.elem[i]!=e) ) /* 顺序扫描表,直到找到值为 e 的元素 , 或扫描到表尾而没找到 */ i++; if (i<=L.length-1) return(i+1); /* 若找到值为 e 的元素,则返回其序号 */ else return(-1); /* 若没找到,则返回空序号 */ }
顺序表的插入运算
定义:在第 i( 1i n+1)个元素前插入一个新的数据元素 e,使长度为 n的线性表(a1, a2,……, ai-1, ai,……, an)
变成长度为 n+1的线性表(a1, a2,……, ai-1, e, ai,……, an)
算法分析:
e
内存
a1
a2
ai
ai+1
an
0
1
i-1
数组下标
n-1
i
n
1
2
i
元素序号
i+1
n
n+1
内存
a1
a2
ai
ai+1
an
0
1
i-1
数组下标
n-1
i
n
1
2
i
元素序号
i+1
n
n+1
an-1
插入 e
算法实现:
Status ListInsert_Sq(Sqlist &L,int i,ElemType e){if(i<1||i>L.length+1) return ERROR;if(L.length>=LIST_INIT_SIZE){ //当前存储已满
return ERROR ;} q=&(L.elem[i-1]); // q为插入位置for(p=&(L.elem[L.length-1]); p>=q; - -p) *(p+
1)=*p; //插入位置之后元素后移 *q=e; ++L.length; return OK;}
算法实现 2:
Status ListInsert_Sq(Sqlist &L,int i,ElemType e){if(i<1||i>L.length+1) return ERROR;if(L.length>=LIST_INIT_SIZE){ //当前存储已满
return ERROR ;}
for(k=L.length-1; k>=i-1; - -k)L.elem[k+1]=L. elem[k]; //插入位置之后元素后移
L.elem[i-1]=e; ++L.length; return OK;}
算法时间复杂度 T(n)
设 Pi是在第 i个元素之前插入一个元素的概率,则在长度为 n的线性表中插入一个元素时,所需移动的元素次数的期望值(平均次数)为:
1
1
)1(n
ii inPEis
nOnT
nin
nEis
nP
n
i
i
1
1 2)1(
1
11
1
则
若认为
顺序表的删除运算
–定义:线性表的删除是指将第 i( 1i n)个元素删除,使长度为 n的线性表(a1, a2,……, ai-1, ai, ai+1,……, an)
变成长度为 n-1的线性表(a1, a2,……, ai-1, ai+1, ……, an)
–算法分析:需将第 i+1至第 n共( n-i)个元素前移
内存数组下标 元素序号
0
1
i-1
n-1
i
n
1
2
i
i+1
n
n+1
a1
a2
ai
ai+1
an
ai-1i-2 i-1删除 ai
内存
a1
a2
ai+1
数组下标
0
1
i-1
n-2
i
n-1
1
2
i
元素序号
i+1
n-1
n
an
ai+2
ai-1i-2 i-1
算法实现:
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; // 被删除元素的值赋给 eq=&L.elem[L.length-1]; // 表尾元素的位置for(++p; p<=q; ++p) *(p-1)=*p; // 被删除元素之后的元素左移- -L.length; // 表长减 1 return OK;}
算法实现 2:
Status ListDelete_Sq(Sqlist &L,int i,ElemType &e){
if(i<1||i>L.length) return ERROR;
e= L.elem[i-1]; // 被删除元素的值赋给 efor(k=i; k<=L.length-1; ++k) L.elem[k-1]=L.elem[k]; // 被删除元素之后的元素左移- -L.length; // 表长减 1 return OK;}
算法时间复杂度
设 Qi是删除第 i个元素的概率,则在长度为 n的线性表中删除一个元素所需移动的元素次数的 (期望值)平均次数为:
n
iide inQE
1
)(
nOnT
nin
nE
nQ
n
ide
i
1 2
1)(
1
1
则
若认为
算法评价:
在顺序表中插入或删除一个元素时,平均移动表的一半元素,当 n很大时,效率很低。
例:顺序表的合并 .有两个顺序表 LA和 LB ,其元素均为非递减有序排列,编写一个算法,将它们合并成一个顺序表 LC,要求 LC 也是非递减有序排列。例如 LA=(2, 2, 3), LB=(1, 3, 3, 4), 则 LC=(1, 2, 2, 3, 3, 3, 4) 。
算法分析 :设表 LC是一个空表,为使 LC也是非递减有序排列,可设两个指针 i、 j分别指向表 LA和 LB 中的元素,若 LA.elem[i]>LB.elem[j] ,则当前先将 LB.elem[j] 插入到表 LC中,若 LA.elem[i]≤LB.elem[j] ,当前先将 LA.elem[i] 插入到表 LC中,如此进行下去,直到其中一个表被扫描完毕,然后再将未扫描完的表中剩余的所有元素放到表 LC中。
算法模拟
2
2
3
1
3
3
4
下标下标 下标LA
值 值值LB LC
0
2
1
0
1
2
0
1
2
3
4
5
6
i j k12
2
3
3
3
43
i
i
j
j
j
j
i
k
k
k
k
k
k
k
算法实现 :void merge(SqList LA, SqList LB, SqList &LC) { i=0;j=0;k=0; while(i<=LA.length-1&&j<=LB.length-1) if(LA.elem[i]<=LB.elem[j]) { LC.elem[k]= LA.elem[i]; i++; k++; } else { LC.elem[k]=LB.elem[j]; j++; k++; } while(i<=LA.length-1) /* 当表 LA有剩余元素时,则将
表 LA余下的元素赋给表 LC*/ { LC.elem[k]= LA.elem[i]; i++; k++; } while(j<=LB.length-1) /* 当表 LB 有剩余元素时,则将表
LB余下的元素赋给表 LC*/ { LC.elem[k]= LB.elem[j]; j++; k++; } LC.length=LA.length+LB.length; }
顺序存储结构的优缺点:
优点逻辑相邻,物理相邻可随机存取任一元素
缺点插入、删除操作需要移动大量的元素
特点:•用一组任意的存储单元存储线性表的数据元素•利用指针实现了用不相邻的存储单元存放逻辑上相邻的元素•每个数据元素 ai,除存储本身信息外,还需存储其直接后继的信息•结点–数据域:元素本身信息–指针域:指示直接后继的存储位置
数据域 指针域结点
2.3 线性表的链式存储结构
ZHAO QIAN SUN LI
ZHOU WU ZHENG WANG ^
H
例 线性表 (ZHAO,QIAN,SUN,LI,ZHOU,WU,ZHENG,WANG)
43
13
1
NULL3771925
数据域 指针域
LI
QIAN
SUN
WANGWU
ZHAOZHENG
ZHOU
存储地址
17
131925313743
31H
头指针
• 实现 typedef struct LNode { ElemType data; struct LNode *next;}LNode,*LinkList;
LinkList L,p;
data next
p 结点( *p)
(*p)表示 p所指向的结点(*p).datap->data表示 p指向结点的数据域(*p).nextp->next表示 p指向结点的指针域
生成一个 LNode型新结点: p=(LinkList)malloc(sizeof(LNode));系统回收 p结点: free(p)
2.3.1 线性链表• 定义:结点中只含一个指针域的链表叫 ~,也叫单链表
L a1 a2
头结点头结点an ^…...…...
L 空表^̂
头结点:在单链表第一个结点前附设一个结点叫头结点 .头结点指针域为空表示线性表为空
第一个数据元素的值 :L->next->data第二个数据元素的指针 :L->next->next
p
p->datap->nextp->next->datap->next->next
1. 头插法建立单链表2. 尾插法建立单链表3. 查找4. 插入5. 删除
单链表的基本运算
1. 头插法建立单链表算法描述 :逆位序输入 n个元素的值 ,建立带头结点的单链表算法演示 :如输入二个元素 a,b,头插法建立单链表
L ^ a
b
^
p
p
1. 头插法建立单链表算法实现 :void CreateList_L(LinkList &L,int n){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. 尾插法建立单链表算法描述 :正位序输入 n个元素的值 ,建立带头结点的单链表算法演示 :如输入二个元素 a,b, 尾插法建立单链表
L ^
p
a
r
b^
r
2. 尾插法建立单链表算法实现 :void CreateList_L2(LinkList &L,int n){L=(LinkList)malloc(sizeof(LNode));L->next=NULL;//先建立一个带头结点的单链表r=L;//r为表尾元素指针for(i=n;i>0;--i){p=(LinkList)malloc(sizeof(LNode));//生成新结点scanf(&p->data);//输入元素值p->next=NULL;r->next=p;r=p; // 插入到表尾}}
3. 查找
• 按序号查找• 按值查找
按序号查找
算法描述 : 设带头结点的单链表的头指针为 L,要查找表中第 i个结点 ,则需从单链表的头指针 L出发 , 从头结点开始 ,顺着链域扫描 .用指针 p指向当前扫描到的结点 ,初值指向第一个结点 (p=L->next). 用 j做计数器 ,累计当前扫描过的结点数 (初值为 1), 当 j=i 时 ,指针 p所指的结点就是要找的第 i个结点 .
算法演示
Status GetElem_L(LinkList L,int i,ElemType &e)
{p=L->next;j=1;
while(p&&j<i){
p=p->next;++j;}
if(!p||j>i)
return ERROR;
e=p->data;
return OK;}
L
a
b
m
n
……
……
i
p
^
按值查找
算法演示
LinkList Locate_L(LinkList L,ElemType e)}
p=L->next;
while(p){
if(p->data==e)
break;
else
p=p->next;}
return p;}
L
a
b
e
n
……
……
p
^
p a b
xs
插入:在线性表两个数据元素 a和 b间插入 x,已知 p指向 a
s->next=p->next;p->next=s;
1OnT
算法评价
4. 插入
算法实现
Status ListInsert_L(ListList &L,int I,ElemType e){// 在带头结点的单链表 L中第 i个位置之前插入元素 e
p=L;j=0;while(p&&j<i-1){p=p->next;++j;}// 寻找第 i-1个结点if(!p||j>i-1) return ERROR;s=(LinkList)malloc(sizeof(LNode));// 生成新结点s->data=e;s->next=p->next;p->next=s;return OK;}
p a b c
1OnT
算法评价
–删除:单链表中删除 b,设 p指向 a
p->next=q->next;
5. 删除
q
算法实现Status ListDelete_L(ListList &L,int I,ElemType
&e){// 在带头结点的单链表 L 中删除第 i 个元素,由 //e 返回其值
p=L;j=0;
while(p->next&&j<i-1){p=p->next;++j;}// 寻找第 i-1 个结点
if(!(p->next)||j>i-1) return ERROR;
q=p->next;p->next=q->next;
e=q->data;free(q);
return OK;
}
例 :将两个有序链表并为一个有序链表
算法描述 : 设头指针 La和 Lb的单链表分别为线性表 LA和 LB 的存储结构 ,现要归并 La和 Lb 得到单链表 Lc.需设立 3个指针 pa,pb和 pc, 其中 pa 和 pb分别指向 La 表和 Lb表中当前待比较插入的结点 ,而 pc 指向 Lc 表中当前最后一个结点 .若 pa->data<=pb->data, 则将 pa 所指结点链接到 pc 所指结点之后 ,否则将 pb所指结点链接到 pc 所指结点之后 ,直到 La或 Lb 链表为空,则将另一个链表的剩余段链接在 pc 所指结点之后即可。
算法演示
La
Lb
pa
pb
pcLc
2 2 3
4331
^
^
算法实现void MergeList_L(LinkList La, Lb,&Lc){
pa=La->next;pb=Lb->next;
Lc=pc=La;
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);}
• 单链表特点–它是一种动态结构,整个存储空间为多个链表共用
–不需预先分配空间–指针占用额外存储空间–不能随机存取,查找速度慢
循环链表是表中最后一个结点的指针指向头结点,使链表构成环状•特点:从表中任一结点出发均可找到表中其他结点,提高查找效率•操作与单链表基本一致 ,循环条件不同–单链表 p 或 p->next=NULL–循环链表 p=H 或 p->next=H
H
H 空表
2.3.2 循环链表
单链表具有单向性的缺点• 结点定义
typedef struct DuLNode { ElemType data; struct DuLNode *prior,*next;} DuLNode,*DuLinkList;
prior data next
L空双向循环链表:
非空双向循环链表:L A B
b ca
p
p->prior->next= p= p->next->proir
2.3.3 双向链表
查找操作
算法描述 : 在带头结点的双循环链表L中查找第 i个位置的元素 ,找到则返回该元素的指针 ,否则返回空指针
算法演示
DuLinkList GetElem_Du(DuLinkList L,int i)
{p=L->next;j=1;
while(p!=L&&j<i){
p=p->next;++j;}
if(p==L)
p=NULL;
return p;
}
L
a
b
m
n
……
……
i
p
b c
void del_dulist(DuLinkList p){p->prior->next=p->next; p->next->prior=p->prior; free(p);}
– 算法描述
– 算法评价: T(n)=O(1)
p->prior->next=p->next;
p->next->prior=p->prior;
删除操作
a
p
void ins_dulist(DuLinkList p,int x){ s=(DuLinkList)malloc(sizeof(DuLNode)); s->data=x; s->prior=p->prior; p->prior->next=s; s->next=p; p->prior=s;}
算法描述
算法评价:T(n)=O(1)
xS
ba
P插入操作
一元多项式的表示:
200001000 231)( xxxS 但对 S(x)这样的多项式浪费空间
其存储结构可以用顺序存储结构,也可以用单链表
2.4 一元多项式的表示及相加
nnn xPxPxPPxP 2
210)( ……
),,,,( 210 nPPPPP 可用线性表 P表示 ……
用数据域含两个数据项的线性表表示
emPePeP m,,,,, 21 21 …
一般 emmn xPxPxPxP ee 21
21)(
其中 为非零系数)( iPemee 210 …
……
单链表的结点定义
coef exp next
-1A 7 0 3 1 9 8 5 17 ^
-1B 8 1 22 7 -9 8 ^
-1C 7 0 11 1 22 7 5 17 ^
一元多项式相加
typedef struct node{int codf,exp;struct node *next}node,*linklist;
177
87
172
522117)()()(
9228)(
5937)(
xxxxBxAxC
xxxxB
xxxxA
8
设p,q 分别指向 A,B中某一结点,p,q 初值是第一结点
比较p->exp与 q->exp
p->exp < q->exp: p结点是和多项式中的一项 p后移 ,q不动p->exp > q->exp: q结点是和多项式中的一项 将 q插在 p之前 ,q后移 ,p不动p->exp = q->exp: 系数相加 0:从 A表中删去 p,
释放 p,q, p,q后移
0:修改 p系数域 , 释放 q, p,q后移
直到 p或 q为 NULL 若 q==NULL,结束 若 p==NULL,将 B中剩余部分连到 A上即可
运算规则
q
-1pa 7 0 3 1 9 8 5 17 ^
-1pb 8 1 22 7 -9 8 ^
ppre
q
-1pa 7 0 3 1 9 8 5 17 ^
-1pb 8 1 22 7 -9 8 ^
ppre
q
-1pa 7 0 11 1 9 8 5 17 ^
-1pb 8 1 22 7 -9 8 ^
p
preq
-1pa 7 0 11 1 9 8 5 17 ^
-1pb 8 1 22 7 -9 8 ^
ppre
q=NULL
-1pa 7 0 11 1 9 8 5 17 ^
-1pb 8 1 22 7 -9 8 ^
p
pre
q=NULL
-1pa 7 0 11 1 9 8 5 17 ^
-1pb 8 1 22 7 -9 8 ^
p
pre
-1pa 7 0 11 1 22 7 5 17 ^
–算法描述
Recommended