数据结构学位考 复习课 (1)
description
Transcript of 数据结构学位考 复习课 (1)
数据结构学位考数据结构学位考复习课复习课 (1)(1)
主要内容:主要内容:1.1.第一部分 概述第一部分 概述2.2.第二部分 线性表、栈、队列第二部分 线性表、栈、队列
第一部分:第一部分:数据结构与算法的基本概念数据结构与算法的基本概念考核内容及要求:考核内容及要求: 理解算法、算法正确性、复杂性的概念;理解算法、算法正确性、复杂性的概念; 了解算法的时间与空间复杂性级别;了解算法的时间与空间复杂性级别; 重点掌握数据类型、数据结构和表示、实现的重点掌握数据类型、数据结构和表示、实现的概念;概念;
掌握抽象数据类型的说明、高级语言对抽象数掌握抽象数据类型的说明、高级语言对抽象数据类型的支持。据类型的支持。
基本概念和术语 数据数据 (Data)(Data) :: 数据元素数据元素 (Data Element)(Data Element) ::
数据的基本单位,计算机中通常作为一个整体来考虑,如一棵树数据的基本单位,计算机中通常作为一个整体来考虑,如一棵树中的一个结点、一个图中的一个结点。中的一个结点、一个图中的一个结点。
一个数据元素可以有若干个一个数据元素可以有若干个数据项数据项 (Data Item)(Data Item) 组成。组成。 数据对象数据对象 (Data Object)(Data Object) ::性质相同的数据元素的集合性质相同的数据元素的集合 数据结构:数据结构:数据元素之间的关系——结构数据元素之间的关系——结构
四种基本结构四种基本结构 集合 线性结构 树形结构 集合 线性结构 树形结构
图状结构图状结构 // 网状结构网状结构 数据结构的形式定义:数据结构的形式定义:
一个二元组:一个二元组:Data_Structure=(D,S)Data_Structure=(D,S)
其中:其中: DD 是数据元素的集合,是数据元素的集合, SS 是是 DD 上的关系集合上的关系集合
数据的逻辑、物理(存储)结构数据的逻辑、物理(存储)结构 逻辑结构:数据元素之间的逻辑关系逻辑结构:数据元素之间的逻辑关系 物理结构:数据元素在计算机中的存储方法(表物理结构:数据元素在计算机中的存储方法(表
现和实现) 现和实现) 数据结构的分类:数据结构的分类:
按照按照逻辑结构逻辑结构的不同分为:集合、线性结构、树的不同分为:集合、线性结构、树状结构、网状结构状结构、网状结构
按照按照物理结构物理结构的不同分为:的不同分为: 顺序结构:利用在存储器中的物理关系来表示逻辑关系。顺序结构:利用在存储器中的物理关系来表示逻辑关系。 链式结构:用在存储器中附加指针的方式来表示逻辑关链式结构:用在存储器中附加指针的方式来表示逻辑关
系。系。
算法:对特定问题求解步骤的一种描述,是指算法:对特定问题求解步骤的一种描述,是指令的有序序列令的有序序列
算法的五个特性:有穷性、确定性、可行性、算法的五个特性:有穷性、确定性、可行性、输入、输出输入、输出
算法设计的要求:时间复杂度,空间复杂度算法设计的要求:时间复杂度,空间复杂度
时间复杂度:算法执行时间随规模增长而增时间复杂度:算法执行时间随规模增长而增长的趋势长的趋势
T(n)=O(f(n)) T(n)=O(f(n)) f(n)f(n) 算法规模,算法规模, T(n)T(n) 称算法复杂度称算法复杂度 估算办法:以算法中重复执行的次数作估算办法:以算法中重复执行的次数作 为算法时间复杂为算法时间复杂度的依据。 度的依据。
三种最常见时间复杂度:三种最常见时间复杂度: O(1) O(1) 常量级 常量级 O(n) O(n) 线性级线性级 O(nO(n22) ) 平方级平方级
算法的空间复杂度算法的空间复杂度 S(n)=O(f(n))S(n)=O(f(n))
算法执行过程中所需的最大空间算法执行过程中所需的最大空间 估算方法:输入数据所占空间估算方法:输入数据所占空间 ++
程序所占空间程序所占空间 ++
辅助变量所占空辅助变量所占空间间
第二部分 线性表、栈、队列第二部分 线性表、栈、队列 考核内容及要求:考核内容及要求:
熟练掌握顺序分配、链接分配的表示及实现方法;熟练掌握顺序分配、链接分配的表示及实现方法; 熟练掌握各种链表:单链、双链、多链、循环链表;熟练掌握各种链表:单链、双链、多链、循环链表; 理解栈、队列、双向队列的顺序、链式表示及其算理解栈、队列、双向队列的顺序、链式表示及其算
法复杂度分析;法复杂度分析; 熟练掌握表达式计算原理。熟练掌握表达式计算原理。
1. 1. 线性表的顺序表示和实现线性表的顺序表示和实现 线性表的存储结构:顺序存储、链接存储线性表的存储结构:顺序存储、链接存储 顺序存储:用一组地址连续的存储单元依次存储线性表的顺序存储:用一组地址连续的存储单元依次存储线性表的
数据元素。数据元素。
a1
a2
ai
an
bb+l
b+(i-1)l
b+(n-1)lb+nl
存储地址存储地址 存储内容存储内容
顺序存储结构顺序存储结构
基地址:起始位置基地址:起始位置
第第 ii 个元素的位置个元素的位置 LOC(aLOC(aii)=LOC(a)=LOC(a11))
+(i-1)*l+(i-1)*l
ll :每个元素占用的存储单元:每个元素占用的存储单元
顺序表的特点顺序表的特点
(( 11 )利用数据元素的存储位置表示线性表中相邻数据元素)利用数据元素的存储位置表示线性表中相邻数据元素之间的前后关系,即线性表的之间的前后关系,即线性表的逻辑结构于存储结构逻辑结构于存储结构(物理(物理结构)结构)一致一致;;
(( 22 )在访问线性表时,可以利用上述给出的数学公式,快)在访问线性表时,可以利用上述给出的数学公式,快速计算任何一个数据元素的存储地址。即速计算任何一个数据元素的存储地址。即访问每个数据元访问每个数据元素所花费的时间相等素所花费的时间相等。。
(( 33 )这种存取元素的方法被称为)这种存取元素的方法被称为随机存取随机存取法。使用这种存法。使用这种存取方法的存储结构被称为随机存储结构。取方法的存储结构被称为随机存储结构。
表示方法表示方法::在高级语言中,用一维数组表示:在高级语言中,用一维数组表示: 表示方法: 表示方法: const LIST_INIT_SIZE=100; //const LIST_INIT_SIZE=100; // 表初始分配空间表初始分配空间 const LISTINCREMENT=10;//const LISTINCREMENT=10;// 空间分配增量空间分配增量 typedef struct{ ElemType *elem;typedef struct{ ElemType *elem; //// 存储空间存储空间 int length; //int length; // 当前长度当前长度 int listsize; //int listsize; // 当前存储容量当前存储容量
int LISTINCREMENT;//int LISTINCREMENT;// 可增加存储空间可增加存储空间 }SqList;}SqList;注意:注意:1. 1. 数组指针数组指针 elemelem 指示线性表的基地址,指示线性表的基地址, length:length: 线性表的当线性表的当前长度。前长度。2. C2. C 语言数组的下标从语言数组的下标从 00 开始,即数组中的第开始,即数组中的第 ii 个元素为个元素为 L.elL.elem[i-1]em[i-1]
2. 2. 线性表的链式表示和实现线性表的链式表示和实现 顺序表的局限:插入、删除时要移动大量的元素,耗顺序表的局限:插入、删除时要移动大量的元素,耗
费大量时间。费大量时间。 链式表示:用一组链式表示:用一组任意的任意的存储单元存储线性表存储单元存储线性表
存储单元不要求连续:物理结构不反应逻辑结构存储单元不要求连续:物理结构不反应逻辑结构 不可以随机存取,但插入和删除方便不可以随机存取,但插入和删除方便 需要两个域:一个表示数据本身;一个表示数据元素间的先需要两个域:一个表示数据本身;一个表示数据元素间的先
后关联。——一个后关联。——一个结点结点。。 结点中表示关联的部分为指针域,内部存放指针或链。结点中表示关联的部分为指针域,内部存放指针或链。 nn 个个
结点链接成一个结点链接成一个链表。链表。
线性链表线性链表 线性链表的物理存储结构线性链表的物理存储结构
(Zhao,Qian,Sun,Li,Zhou,Wu,Zheng,Wang)(Zhao,Qian,Sun,Li,Zhou,Wu,Zheng,Wang)
ZhaoZhao
QianQian
SunSun
LiLi
WangWang
ZhengZheng
WuWu
ZhouZhou
数据域数据域 指针域指针域存储地址存储地址
11
77
1313
1919
2525
3131
3737
4343
4949
3131
头指针头指针L
ZhaoZhao
QianQian SunSun
WangWang ^
线性链表(单链表)的定义:线性链表(单链表)的定义: typedef struct LNode{typedef struct LNode{
ElemType data;ElemType data;
struct Lnode *next; struct Lnode *next;
}Lnode, *LinkList}Lnode, *LinkList
LLaa11 aaiiaai-1i-1 aann ^̂
LLaa11 aaiiaai-1i-1 aann ^̂
带带头结点头结点的链表的链表
循环链表循环链表 循环链表:线性表的另一种链式存储结构。循环链表:线性表的另一种链式存储结构。
HHa1a1 anan
HH
特点:特点: 从表的任何位置出发,都可以找到其他结点;从表的任何位置出发,都可以找到其他结点;
操作与单链表的差别:操作与单链表的差别: 判断表尾的条件:判断表尾的条件: P->next=HP->next=H
空表空表循环链表循环链表
双向链表双向链表 每一个结点有两个指针域:一个指向直接后继;另一个指每一个结点有两个指针域:一个指向直接后继;另一个指
向直接前驱。向直接前驱。
H a1a1 a2a2 ^̂^̂
H ^̂ ^̂双向链表存储结构:双向链表存储结构: typedef struct DuLNode{typedef struct DuLNode{
ElemType data;ElemType data;
struct DuLNode *prior;struct DuLNode *prior;
struct DuLNode *next;struct DuLNode *next;
}DuLNode, *DuLinkList;}DuLNode, *DuLinkList;
双向循环链表双向循环链表
H a1a1 a2a2
H
2个结点的双向循环链表
空的双向循环链表
3.栈的表示和实现
栈的表示:栈的表示:(( 11 )顺序栈:栈的顺序存储)顺序栈:栈的顺序存储(( 22 )链栈:栈的动态存储)链栈:栈的动态存储
顺序栈的表示和实现顺序栈的表示和实现 顺序表示顺序表示 #define STACK_INIT_SIZE 100;#define STACK_INIT_SIZE 100;
#define STACKINCREMENT 10;#define STACKINCREMENT 10;
typedef struct {typedef struct {
SElemType *base;SElemType *base;
SElemType *top;SElemType *top;
int stacksize;int stacksize;
}SqStack;}SqStack;
其中其中 stacksizestacksize 表示栈当前可以使用的最大容量。表示栈当前可以使用的最大容量。 basebase 为栈底,为栈底,toptop 为栈顶。栈顶指针指向栈顶元素的下一个位置(即下次压为栈顶。栈顶指针指向栈顶元素的下一个位置(即下次压栈时元素所放的位置)栈时元素所放的位置)
顺序栈的结构顺序栈的结构
toptop 指向压栈时下一个元素将要存放的位置。指向压栈时下一个元素将要存放的位置。toptop减一指向弹栈时下一个元素的取值位置。减一指向弹栈时下一个元素的取值位置。栈空的条件:栈空的条件: top=basetop=base
栈满的条件:栈满的条件: top-base >= stacksizetop-base >= stacksize
top
top
base空栈
base非空非满栈
top
ABC
ABC
base 满栈
DE
链栈的结构和表示 定义栈结构定义栈结构Typedef struct stack_nodeTypedef struct stack_node{{ elemtype data;elemtype data; struct stack_node *next;struct stack_node *next;} STKPTR;} STKPTR;STKPTR *stk;STKPTR *stk;问:在这里为什么没有用到问:在这里为什么没有用到 toptop 指针?这样对栈结指针?这样对栈结
构的定义有否影响?构的定义有否影响?
1 ^
7
2
8
S
栈顶
栈底
4.4. 队列的表示和实现队列的表示和实现•链式队列链式队列 typedef struct Qnode {typedef struct Qnode {
QElemType data;QElemType data;
struct Qnode *next;struct Qnode *next;
}Qnode, *QueuePtr;}Qnode, *QueuePtr;
typedef struct {typedef struct {
QueuePtr front;QueuePtr front;
QueuePtr rear;QueuePtr rear;
}LinkQueue;}LinkQueue;
课堂练习:链队列的操作入对课堂练习:链队列的操作入对列、出队列列、出队列
Q.front
Q.rear^
链队列结构链队列结构
顺序队列 #define MAXQSIZE 100#define MAXQSIZE 100
typedef struct {typedef struct {
QElemType *base;QElemType *base;
int front;int front;
int rear;int rear;
}SqQueue;}SqQueue;
其中其中 basebase 为连续空间首地址,为连续空间首地址, frontfront 为队首,为队首, rearrear为队尾。为队尾。
为什么用循环队列来实现顺序队列?为什么用循环队列来实现顺序队列?
rear
front空队
front非空非满队 1
rear
ABC C
满队
DE
Cfront
非空非满队 2
D
rearrear
front
顺序队列的结构——循环队列:顺序队列的结构——循环队列:
空队:初始化队列时,两个指针空队:初始化队列时,两个指针 rearrear == frontfront == 00
入队:队尾插入元素,尾指针入队:队尾插入元素,尾指针 rearrear 后移后移
出队:队头删除元素,头指针出队:队头删除元素,头指针 frontfront 后移后移
循环队列:循环队列:
实现循环队列的操作:实现循环队列的操作:关键问题关键问题 11 :: rearrear 和和 frontfront 指针后移指针后移
(Q.rear+1) mod MAXSIZE(Q.rear+1) mod MAXSIZE
(Q.front+1) mod MAXSIZE(Q.front+1) mod MAXSIZE
Maxsize -1
0
1
front
rear
Q.rear Q.rear 指向入队时下一个指向入队时下一个元素的存放位置元素的存放位置Q.frontQ.front 指向出队时下一个指向出队时下一个元素的存放位置元素的存放位置
关键问题关键问题 22 ::出队时,判断空队 出队时,判断空队 Q.rear = = Q.frontQ.rear = = Q.front;;
入队时,判断满队 入队时,判断满队 (Q.rear+1)mod MAXSIZE= = Q.front;(Q.rear+1)mod MAXSIZE= = Q.front;
10
rear
front
空队列
10
front
rear
满队列
典型例题典型例题1. 1. 顺序表中逻辑上相邻的元素物理位置顺序表中逻辑上相邻的元素物理位置 相相邻, 单链表中逻辑上相邻的元素物理位邻, 单链表中逻辑上相邻的元素物理位置置 相邻。相邻。
2. 2. 已知已知 PP 为单链表中的非首尾结点,在为单链表中的非首尾结点,在 PP 结点后结点后插入插入 SS 结点的语句为:结点的语句为:3. 在单链表中,指针在单链表中,指针 PP 所指的节点为最后一个节所指的节点为最后一个节点的条件是:点的条件是:4.4. 设设 headhead 指向单链表的表头,指向单链表的表头, pp 指向单链表的表尾指向单链表的表尾结点,则执行结点,则执行 p->next=headp->next=head 后,该单链表构成后,该单链表构成
P->next=NULLP->next=NULL
循环链表循环链表
也也不一定不一定
S->next=P->next;S->next=P->next; P->next=SP->next=S
2.5 2.5 画出执行下列各行语句后各指针及链表的示意画出执行下列各行语句后各指针及链表的示意图图
L=(LinkList)malloc(sizeof(LNode)); P=L;L=(LinkList)malloc(sizeof(LNode)); P=L;
for (i=1;i<=4;i++){for (i=1;i<=4;i++){
P->next=(LinkList) malloc(sizeof(LNode)); P->next=(LinkList) malloc(sizeof(LNode));
P=P->next; P->data=i*2-1;P=P->next; P->data=i*2-1;
}}
P->next=NULL;P->next=NULL;
for (i=4;i>=1;i--) Ins_LinkLIst(L,i+1;i*2);for (i=4;i>=1;i--) Ins_LinkLIst(L,i+1;i*2);
for (i=1;i<=3;i++) Del_LinkList(L,i);for (i=1;i<=3;i++) Del_LinkList(L,i);
2.8 2.8 已知已知 PP 结点是双向链表的中间结点,试写出下列操作结点是双向链表的中间结点,试写出下列操作的语句序列:的语句序列:
(1)(1) 在在 PP 结点后插入结点后插入 ss 结点结点(2)(2) 在在 PP 结点前插入结点前插入 ss 结点结点(3)(3) 删除删除 PP 结点的直接后继结点结点的直接后继结点(4)(4) 删除删除 PP 结点的直接前驱结点结点的直接前驱结点(5)(5) 删除删除 PP 结点结点
(1) S->next=P->next; S->prior=P;
p->next->prior=S; P->next=S;
(2) S->next=P; S->prior=P->prior;
p ->prior ->next=S; P->prior=S;
(3) R=P->next; P->next=R->next;
R->next->prior=R->prior; free(R);(4) R=P->prior; P->prior=R-
>prior;
R ->prior ->next=R->next; free(R);(5) P->prior->next=P->next;
P->next->prior=P->prior;
free(R);
设设 rearrear 是指向非空带头节点的单循环链表的尾指针,是指向非空带头节点的单循环链表的尾指针,则写出删除表首结点的操作的语句序列则写出删除表首结点的操作的语句序列
答案:答案:P=rear->next->next;
Rear->next->next=p->next;
Free(P);
2.332.33已知一个线性链表表示的线性表中含有三类字符的数已知一个线性链表表示的线性表中含有三类字符的数据元素(如字母、数字、和其他),试编写算法将该线性据元素(如字母、数字、和其他),试编写算法将该线性链表分割为三个循环链表,其中每个循环链表表示的线性链表分割为三个循环链表,其中每个循环链表表示的线性表中均只含一类字符。表中均只含一类字符。 要求:充分用原来的存储空间;要求:充分用原来的存储空间; 问题:如果要求建立问题:如果要求建立 33 个单链表;也利用原来的存储空间个单链表;也利用原来的存储空间
Status D_S_2.33(LinkList &L;DuLinkList &La; L;DuLinkList &Lb; L;DuLinkLiStatus D_S_2.33(LinkList &L;DuLinkList &La; L;DuLinkList &Lb; L;DuLinkList &Lc)st &Lc)
{ if (!(La=(DuLinkList)malloc(sizeof(DuNode))))return ERROR;{ if (!(La=(DuLinkList)malloc(sizeof(DuNode))))return ERROR;
if (!(Lb=(DuLinkList)malloc(sizeof(DuNode))))return ERROR;if (!(Lb=(DuLinkList)malloc(sizeof(DuNode))))return ERROR;
Lc=L; a=La; b=Lb;Lc=L; a=La; b=Lb;
q=L;p=L->next;q=L;p=L->next;
while (p){while (p){
if (p->data IN if (p->data IN 字母字符集字母字符集 ){q=p;p=p->next}){q=p;p=p->next}
if (p->data IN if (p->data IN 数字字符集数字字符集 ){ ){ q->next=p->next; q->next=p->next; ////将将 pp 结点从结点从 LL 中删除中删除
a->next=p;a->next=p; a=p;a=p; // //将将 pp 结点插入到结点插入到 LaLa 的末尾;的末尾; p=q->next; } //p=q->next; } // 重置指针重置指针 pp
if (p->data IN if (p->data IN 其他字符集其他字符集 ){){q->next=p->next; q->next=p->next; ////将将 pp 结点从结点从 LL 中删除中删除b->next=p; b=p; //b->next=p; b=p; // 将将 pp 结点插入到结点插入到 LbLb 的末尾;的末尾;
p=q->next} //p=q->next} // 重置指针重置指针 pp
} }
q->next=Lc; //q->next=Lc; // 使使 LcLc 为循环链表为循环链表a->next=La; //a->next=La; // 使使 LaLa 为循环链表为循环链表b->next=Lb; //b->next=Lb; // 使使 LbLb 为循环链表为循环链表
}
2.22 2.22 单链表的就地逆置:利用原来的存储空单链表的就地逆置:利用原来的存储空间。间。
Status D_S_2.22(LinkList &L){Status D_S_2.22(LinkList &L){
p=L->next; L->next=null;p=L->next; L->next=null;
while (p){while (p){
q=p; p=p->next;q=p; p=p->next;
}}
}} 答案:答案:q->next=L->next;
L->next=q;
算法设计题
顺序表:顺序表: #define LIST_INIT_SIZE 100#define LIST_INIT_SIZE 100 #define LISTINCREMENT 10#define LISTINCREMENT 10 typedef struct {typedef struct { ElemType *elem;ElemType *elem; int length;int length; int listsize;int listsize; }SqList; }SqList;
单链表单链表 typedef struct Lnode typedef struct Lnode {{ ElemType data;ElemType data; Struct Lnode *next;Struct Lnode *next; }Lnode, *LinkList;}Lnode, *LinkList;
线性表类型定义线性表类型定义
4.(2.19) 4.(2.19) 已知线性单链表中的元素以值递增有序排列,已知线性单链表中的元素以值递增有序排列,试写一个高效的算法,删除表中所有介于(试写一个高效的算法,删除表中所有介于( mink,mink,maxkmaxk )的元素。()的元素。( ****** ))
c e g i o q ^LL
(mink,maxk)=(h,o)(mink,maxk)=(h,o)
查找第一个大于查找第一个大于 minkmink 的结点的结点 P->nextP->next
PP
while (P->next->data<maxk) while (P->next->data<maxk) 则:删除则:删除 P->nextP->next
Status LL_DEL(LinkList &L,ElemType mink,ElemType maxk)Status LL_DEL(LinkList &L,ElemType mink,ElemType maxk){//{// 删除大于删除大于 minkmink小于小于 maxkmaxk 的所有元素的所有元素 ,L,L 是带头结点的单链表是带头结点的单链表
P=L;P=L;while (P->next!=NULL &&while (P->next!=NULL &&P->next->data<=minkP->next->data<=mink))
P=P->next;//P=P->next;// 找出第一个大于找出第一个大于 minkmink 的元素的元素if P->next=NULL return error;if P->next=NULL return error;Q=P->next;Q=P->next;while (!Q &&Q->data<maxk){while (!Q &&Q->data<maxk){
P->next=Q->next; dispose(Q); Q=P->next;P->next=Q->next; dispose(Q); Q=P->next;}}
}//LL_DEL}//LL_DEL
c e g i o q ^LL
(mink,maxk)=(h,o)(mink,maxk)=(h,o)
5.(2.24) 5.(2.24) 假设有两个按值递增有序排列的单链表假设有两个按值递增有序排列的单链表 AA 和和BB ,编写算法归并,编写算法归并 AA 和和 BB 成成 CC ,使得,使得 CC 是按值递减是按值递减有序排列(允许有值重复的结点),并且有序排列(允许有值重复的结点),并且 CC 利用利用 AA 、、BB 原来的结点空间。(原来的结点空间。( ******** ))
3 5 7 19 ^AA
4 6 8 20 ^BB
4 3CC
p
q
Status UNIT_A_B(LinkList &A,&B,&C){Status UNIT_A_B(LinkList &A,&B,&C){
//// 合并合并 AA 和和 BB 成成 CC ,, CC 利用利用 AA 、、 BB 原来的结点空间。原来的结点空间。
P=A->next; q=B->next; C=B,C->next=NULL; free(A); //P=A->next; q=B->next; C=B,C->next=NULL; free(A); // 初始化初始化 CC
While (!p&&!q){While (!p&&!q){
if (p->data<=q->data){s=p;p=p->next}if (p->data<=q->data){s=p;p=p->next}
else{s=q;q=q->next}else{s=q;q=q->next}
s->next=C->next;C->next=s;//ss->next=C->next;C->next=s;//s 结点插入到结点插入到 CC 的首结点之前;的首结点之前;
}}
if (!q) p=q;if (!q) p=q;
While (!p) {s=p;p=p->next;s->next=C->next;C->next=s}While (!p) {s=p;p=p->next;s->next=C->next;C->next=s}
}//UNIT_A_B }//UNIT_A_B
栈与队列的相关习题1.1. 栈与线性表的差别栈与线性表的差别2.2. 队列与栈两种数据类型的相同点和差异队列与栈两种数据类型的相同点和差异3.(3.4)3.(3.4) 分析以下算法的功能分析以下算法的功能 (SElemType(SElemType 为为 int)int)(1)(1) Status algo1(Stack S){Status algo1(Stack S){
int I,n,A[255];int I,n,A[255];
n=0;n=0;
while (! StackEmpty(S)){n++;Pop(S,A[n])};while (! StackEmpty(S)){n++;Pop(S,A[n])};
for (i=1;i<=n;i++) Push(S,A[i]);for (i=1;i<=n;i++) Push(S,A[i]);
}}
栈与队列
算法功能:将栈算法功能:将栈 SS中的元素逆置中的元素逆置
(2)Status algo2(2)Status algo2 (( Stack S,int eStack S,int e )) {{
Stack T; int d;Stack T; int d;
InitStack(T);InitStack(T);
while (! StackEmpty(S)){while (! StackEmpty(S)){
Pop(S,d);Pop(S,d);
if (d!=e) Push(T,d);if (d!=e) Push(T,d);
}}
while(! StackEmpty(T)){while(! StackEmpty(T)){
Pop(T,d);Pop(T,d);
Push(S,d);Push(S,d);
}}
}}算法功能:删除栈算法功能:删除栈 SS中与中与 ee相等的元素相等的元素
4.4. (( 3.133.13 )简述下列算法的功能)简述下列算法的功能void algo3(Queue &Q){void algo3(Queue &Q){
Stach S; int d;Stach S; int d;InitStack (S);InitStack (S);while (!QueueEmpty(Q)){while (!QueueEmpty(Q)){
DeQueue(Q,d); Push(S,d);DeQueue(Q,d); Push(S,d);}}while(!StackEmlpty(S)){while(!StackEmlpty(S)){
Pop(S,d); EnQueue(Q,d);Pop(S,d); EnQueue(Q,d);}}
}}
算法功能:将队列算法功能:将队列 QQ中的元素逆置中的元素逆置
类型定义类型定义:: 顺序栈 顺序栈 #define STACK_INIT_SIZE 100;#define STACK_INIT_SIZE 100;
#define STACKINCREMENT 10;#define STACKINCREMENT 10;
typedef struct {typedef struct {
SElemType *base;SElemType *base;
SElemType *top;SElemType *top;
int stacksize;int stacksize;
}SqStack}SqStack
算法设计题算法设计题
顺序循环队列:顺序循环队列:#define MAXQSIZE 100;#define MAXQSIZE 100;
typedef struct {typedef struct { QElemType *base;QElemType *base; int front;int front; int rear;int rear; }SqQueue;}SqQueue;
3.15 3.15 假设以顺序存储结构实现一个双向栈,即在一维数组假设以顺序存储结构实现一个双向栈,即在一维数组的存储空间中存在着两个栈,它们的栈底分别设在数组的的存储空间中存在着两个栈,它们的栈底分别设在数组的两个端点。试编写实现这两个双向栈的操作的算法:初始两个端点。试编写实现这两个双向栈的操作的算法:初始化化 inistack(tws)inistack(tws) 、入栈、入栈 push(tws,i,x)push(tws,i,x) 、出栈、出栈 pop(tws,i)pop(tws,i) 。。并讨论按过程或函数设计这些操作算法各有什么优缺点。并讨论按过程或函数设计这些操作算法各有什么优缺点。 分析:分析:
Length=100;
Typedef struct {
datatype data[Length]
int top1,top2} Twins
Tws
firtop sectop
Tws
top1 top2
Tws
top1top2
初始化初始化
还有最后一个存储空间还有最后一个存储空间
栈的一般状态栈的一般状态
Pop(twins tws;int i ){Pop(twins tws;int i ){
if i=0 if i=0
if top1=0 ERRORif top1=0 ERROR
else top1--;return tws.data[top1]}else top1--;return tws.data[top1]}
if i=1 if i=1
if if ERROR ERROR
else{ }else{ }
}}
top2=Length-1top2=Length-1
top2++;return tws.data[top2]top2++;return tws.data[top2]
5(3.17).5(3.17).试写一个算法,识别依次读入的一个以试写一个算法,识别依次读入的一个以 @@ 为结为结束符的字符序列是否形如‘序列束符的字符序列是否形如‘序列 1&1& 序列序列 2‘2‘ 模式的字模式的字符序列。其中序列符序列。其中序列 11 和序列和序列 22 中都不含字符’中都不含字符’ &‘, &‘, 且且序列序列 22 是序列是序列 11 的逆序列。如‘的逆序列。如‘ a+b&b+a’a+b&b+a’
分析:分析:算法中采用何种数据类型?线性表、栈、队列?算法中采用何种数据类型?线性表、栈、队列?
a.a. 初始化一个栈初始化一个栈 SS ,,
b.b. 依次读入字符,并压栈依次读入字符,并压栈
c.c. 当字符为当字符为 && 时,依次读下面的字符,并时,依次读下面的字符,并与出栈元素比较。有一个不相等,则与出栈元素比较。有一个不相等,则 ERROERRORR
d.d.字符结束时,栈空字符结束时,栈空 ,,则则 OKOK 。否则。否则 ERROERRORR
int symmetry()int symmetry() {//{// 使用栈,对读入的字符在使用栈,对读入的字符在 && 之前的都压栈,之后弹栈并之前的都压栈,之后弹栈并 //// 和读和读
入数比较,直到栈空并且读入数为入数比较,直到栈空并且读入数为 @@ 是对称,否则 是对称,否则 //// 为不对为不对称。称。
InitStack(s);InitStack(s); scanf(ch);scanf(ch); while (ch <> “&”){ push(s, ch); scanf(ch);}while (ch <> “&”){ push(s, ch); scanf(ch);} scanf(ch); pop(s,x);scanf(ch); pop(s,x); while (ch <> “@” &&!empey(s))while (ch <> “@” &&!empey(s)) { if (ch= = x){ if (ch= = x) {scanf(ch); pop(s,x);}{scanf(ch); pop(s,x);} else return 0; }else return 0; }
if (ch = = “@” && empty(s)) return 1;if (ch = = “@” && empty(s)) return 1; else return 0;else return 0; }//symmetry}//symmetry
6(3.28).6(3.28). 假设以带头结点的循环链表表示队列,并且只设一个指针指假设以带头结点的循环链表表示队列,并且只设一个指针指向队尾元素结点向队尾元素结点 (( 不设头指针不设头指针 )) ,编写相应的队列初始化、入队和,编写相应的队列初始化、入队和出队的算法。出队的算法。
Q.rear
初始化:初始化: Q.rear->next=Q.rearQ.rear->next=Q.rear
入队:入队: new p new p
p->next=Q.rear->next p->next=Q.rear->next
Q.rear->next=pQ.rear->next=p
出队操作:出队操作:
P=Q.rear->nextP=Q.rear->next
R=P->nextR=P->next
P->next=R->nextP->next=R->next
Free(R)Free(R)
问:若问:若 RR== Q.rear,Q.rear,如何?如何?
Q.rearQ.rear
出队算法:出队算法:Status DeQu(LinkQueue &Q,ElemType &e){Status DeQu(LinkQueue &Q,ElemType &e){
if Q.rear->next=Q.rear return ERROR;if Q.rear->next=Q.rear return ERROR;
P=Q.rear->next; R=P->next;P=Q.rear->next; R=P->next;
P->next=R->next;P->next=R->next;
e=R->data;e=R->data;
if R=Q.rear Q.rear=P;if R=Q.rear Q.rear=P;
free(R)free(R)
}}
课堂练习:写出入队算法课堂练习:写出入队算法
7.(3.32)7.(3.32) 利用循环队列编写求利用循环队列编写求 KK阶阶 FabonacciFabonacci 数列中前数列中前 n+1n+1 项项 (f(f00,f,f11,···,,···,
ffnn)) 的算法。要求:的算法。要求: ffnn<=max,f<=max,fn+1n+1>max,>max, 其中其中 maxmax 是某个约定的常数是某个约定的常数(注意:循环队列的最大容量是(注意:循环队列的最大容量是 K,K, 结束时队列中应该存放的是数结束时队列中应该存放的是数列的后列的后 kk 项)。项)。
Fib(n)=0
1
Fib(n-1)+fib(n-2)
n=0
n=1
n>1
算法:初始化队列算法:初始化队列 new Q.base;Q.rear=0new Q.base;Q.rear=0
f=Q.base[Q.rear-1]+ Q.base[Q.rear-2]f=Q.base[Q.rear-1]+ Q.base[Q.rear-2]
if f<=max,if f<=max, 则则 ff 入队。入队。
算法算法Status Fabonacci(int K,SqQueue &Q;int MAX){Status Fabonacci(int K,SqQueue &Q;int MAX){
Q.base=(QE.emtype*) malloc(K*sizeof(QElemType));Q.base=(QE.emtype*) malloc(K*sizeof(QElemType));if (!Q.base) exit(OVERFLOW);if (!Q.base) exit(OVERFLOW);Q.base[0]=0;Q.base[1]=1;Q.rear=2;f=1;Q.base[0]=0;Q.base[1]=1;Q.rear=2;f=1;while (f<=MAX){while (f<=MAX){
Q.base[Q.rear]=f; Q.base[Q.rear]=f; Q.rear=(Q.rear+1)%K;Q.rear=(Q.rear+1)%K;i=(Q.rear-1+K)%K;i=(Q.rear-1+K)%K; j=(Q.rear-2+K)%K;j=(Q.rear-2+K)%K;f=Q.base[i]+Q.base[j];f=Q.base[i]+Q.base[j];
}}
8(3.33). 8(3.33). 在顺序存储结构上实现输出受限的双端循环队列的入列在顺序存储结构上实现输出受限的双端循环队列的入列和出列(只允许队头出列)算法。设每个元素表示一个待处理和出列(只允许队头出列)算法。设每个元素表示一个待处理的作业,元素值表示作业的预算时间。入队列采取简化的短作的作业,元素值表示作业的预算时间。入队列采取简化的短作业优先原则,若一个新提交的作业的预计执行时间小于队头和业优先原则,若一个新提交的作业的预计执行时间小于队头和队尾作业的平均时间,则插入在队头,否则插入在队尾。队尾作业的平均时间,则插入在队头,否则插入在队尾。
分析:用顺序队列实现。分析:用顺序队列实现。出队列与普通队列没有区别;出队列与普通队列没有区别;入队:元素值入队:元素值 << 平均值,队头入队(优先考虑)平均值,队头入队(优先考虑) 元素值元素值 >=>= 平均值,队尾入队平均值,队尾入队
Status EnQueue(SqQueue &Q, QElemType e)Status EnQueue(SqQueue &Q, QElemType e)
{ //{ // 插入受限,小于平均时间入队头,否则入队尾插入受限,小于平均时间入队头,否则入队尾 if ((Q.rear+1) %MAXQSIZE = = Q.front)if ((Q.rear+1) %MAXQSIZE = = Q.front)
return ERROR; //return ERROR; // 队列满队列满 t = Q.base[Q.front]+Q.base[(Q.rear-1) %MAXQSIZE]/2t = Q.base[Q.front]+Q.base[(Q.rear-1) %MAXQSIZE]/2
if (e <t) { if (Q.front == 0) Q.front = MAXQSIZE-1;if (e <t) { if (Q.front == 0) Q.front = MAXQSIZE-1;
else Q.front = Q.front –1; else Q.front = Q.front –1;
Q.base[Q.front] = e;}Q.base[Q.front] = e;}
else { Q.base[Q.rear] = e;else { Q.base[Q.rear] = e;
Q.rear = (Q.rear+1) %MAXQSIZE;}Q.rear = (Q.rear+1) %MAXQSIZE;}
return OK; }//EnQueuereturn OK; }//EnQueue
Status DeQueue(SqQueue &Q, QElemType &e)Status DeQueue(SqQueue &Q, QElemType &e)
{ if (Q.front = = Q.rear) return ERROR;{ if (Q.front = = Q.rear) return ERROR;
e = Q.base[Q.front];e = Q.base[Q.front];
Q.front = (Q.front+1)%MAXSIZE;Q.front = (Q.front+1)%MAXSIZE;
return OK;return OK;
}}