第3章 栈和队列
数据结构-Java语言描述 第三章 栈和队列
System.exit(1);
}
栈顶指针top的初始值决
top=-1;
定了后续其他方法的实现
stackArray=(T[])new Object[n];
}
【算法3-2】入栈
public void push(T obj)
{
if(top==stackArray.length-1){
T []p=(T[])new Object [top*2];
(b)元素a2入栈
an … … a2 a1
(c)元素an入栈
an-1 … a2 a1
(d)元素an出栈
a2 a1
(e)元素a3出栈
a1
(f)元素a2出栈
【例3-1】一个栈的输入序列是1、2、3、4、5,若在 入栈的过程中允许出栈,则栈的输出序列4、3、5、1、 2可能实现吗?1、2、3、4、5的输出呢?
型 正序遍历:依次访问栈中每个元素并输出
3.1.2 顺序栈
顺序栈泛型类的定义如下:
public class sequenceStack<T> {
顺序栈中一维数组 的初始长度
final int MaxSize=10;
private T[] stackArray; 存储元素的数组对象
private int top;
public void nextOrder() {
for(int i=top;i>=0;i--) System.out.println(stackArray[i]);
}
【算法3-8】清空栈操作
public void clear() {
top=-1; }
3.1.3 链栈
栈的链接存储结构称为链栈。结点类的定义,同 第二章Node类。
数据结构(C语言)第3章 栈和队列
Data Structure
2013-8-6
Page 13
栈的顺序存储(顺序栈)
利用一组地址连续的存储单元依次存放自栈底到栈顶的数 据元素。 结构定义: #define STACK_INIT_SIZE 100; // 存储空间初始分配量 #define STACKINCREMENT 10; // 存储空间分配增量 typedef struct { SElemType *base; // 存储空间基址 SElemType *top; // 栈顶指针 int stacksize; // 当前已分配的存储空间,以元素位单位 } SqStack;
解决方案2:
顺序栈单向延伸——使用一个数组来存储两个栈
Data Structure 2013-8-6 Page 21
两栈共享空间 两栈共享空间:使用一个数组来存储两个栈,让一个 栈的栈底为该数组的始端,另一个栈的栈底为该数组 的末端,两个栈从各自的端点向中间延伸。
Data Structure
2013-8-6
链栈需要加头结点吗? 链栈不需要附设头结点。
Data Structure
2013-8-6
Page 27
栈的链接存储结构及实现
Data Structure
2013-8-6
Page 11
GetTop(S, &e) 初始条件:栈 S 已存在且非空。 操作结果:用 e 返回S的栈顶元素。 Push(&S, e) 初始条件:栈 S 已存在。 操作结果:插入元素 e 为新的栈顶元素。 Pop(&S, &e) 初始条件:栈 S 已存在且非空。 操作结果:删除 S 的栈顶元素,并用 e 返回其值。
Data Structure
数据结构课件第3章
0
1
2
3
4
5
6
7
a1
a2
a3
a4
a5
a6
a7
队头 F=0
队尾 R=7
a3 2 1 3 0 4 7 a3 5 6 3 a2 2 1 a1 0 F=0 a4 4 a5 5 6 a6 7 a7 R=0 R=7 3 a2 2 1 a1 0
a4 4 a5 5 6 a6 7
a8
F=0
a7
R=0
F=0
删除所有元素
top X W … B top
top=0 空栈
top
W
…
B A
top=m-1 元素X出栈
top
A
A
top=m 满栈
top=1 元素A入栈
例:堆栈的插入、删除操作。 出栈操作程序如下: # define m 1000; /*最大栈空间*/ 出栈操作算法: 1)栈顶指针top是否为0: typedef struct stack_stru 若是,则返回;若不是, { int s[m]; int top; }; 则执行2。 void pop (stack, y) 2)将栈顶元素送给y, struct stack_stru stack; 栈顶指针减1。 int *y; { if (stack.top = = 0) printf (“The stack is empty ! \n”); top Y Y else { top B B *y=stack.s[stack.top]; A A stack.top - -; } 出栈操作 }
top=p;
} 栈的入栈、出栈操作的时间复杂度都为O(1)。
栈的应用
一、 表达式求值 表达式由操作数、运算符和界限符组成。 运算符可包括算术运算符、关系运算符、逻辑运算符。
大学数据结构课件--第3章 栈和队列
栈满 top-base=stacksize
top
F
E
D C B
top top top top top top base
入栈PUSH(s,x):s[top++]=x; top 出栈 POP(s,x):x=s[--top]; top
base
4
A
3.1 栈
例1:一个栈的输入序列为1,2,3,若在入栈的过程中 允许出栈,则可能得到的出栈序列是什么? 答: 可以通过穷举所有可能性来求解:
3.2 栈的应用举例
二、表达式求值
“算符优先法”
一个表达式由操作数、运算符和界限符组成。 # 例如:3*(7-2*3) (1)要正确求值,首先了解算术四则运算的规则 a.从左算到右 b.先乘除后加减 c.先括号内,后括号外 所以,3*(7-2*3)=3*(7-6)=3*1=3
9
3.2 栈的应用举例
InitStack(S); while (!QueueEmpty(Q))
{DeQueue(Q,d);push(S,d);}
while (!StackEmpty(S)) {pop(S,d);EnQueue(Q,d);} }
第3章 栈和队列
教学要求:
1、掌握栈和队列的定义、特性,并能正确应用它们解决实 际问题;
用一组地址连续的存储单元依次存放从队头到队尾的元素, 设指针front和rear分别指示队头元素和队尾元素的位置。
Q.rear 5 4 Q.rear 3 2 3 2 5 4 Q.rear 3 3 5 4 5 4
F E D C
C B A
Q.front
2 1 0
C B
Q.front 2 1 0
第三章 栈和队列
栈和队列的基本操作是线性表操作的子集,是限定性(操作受限制)的数据结构。
第三章栈和队列数据结构之栈和队列23. 1 栈¾定义:是限定仅在表尾进行插入或删除操作的线性表。
(后进先出线性表LIFO)¾栈底指针(base) :是线性表的基址;¾栈顶指针(top):指向线性表最后一个元素的后面。
¾当top=base 时,为空栈。
¾基本操作:InitStack(&S), DestroyStack(&S),StackEmpty(S) , ClearStack(&S),GetTop(S ,&e), StackLength(S) ,Push(&S, e): 完成在表尾插入一个元素e.Pop(&S,&e): 完成在表尾删除一个元素。
数据结构之栈和队列3¾栈的表示和实现¾顺序栈:是利用一组地址连续的存储单元依次存放自栈底到栈顶的数据元素;栈满之后,可再追加栈空间即为动态栈。
¾顺序栈的结构类型定义:typedef int SElemType;typedef struct{SElemType *base; /* 栈底指针*/SElemType *top; /* 栈顶指针*/int stacksize; /* 栈空间大小*/ }SqStack;数据结构之栈和队列4¾基本算法描述¾建立能存放50个栈元素的空栈#define STACK_INIT_SIZE 50#define STACKINCREMENT 10Status InitStack_Sq(Stack &S){S.base=(SET*)malloc(STACK_INIT_SIZE *sizeof(SET)); /*为栈分配空间*/if(S.base==NULL)exit(OVERFLOW); /*存储分配失败*/ S.top=S.base;S.stacksize = STACK_INIT_SIZE;return OK; }数据结构之栈和队列5¾出栈操作算法void pop(Sqstack s,SElemType e){if(s.top= = s.base)return ERROR;else{s.top--;e= *s.top;}return OK;}出栈操作topABY topABYbase base数据结构之栈和队列6¾压栈操作算法void Push(SqStack s,SElemType e)if(s.top-s.base>= S.stacksize;) {S.base=(SET*)realloc(S,base,(S.stacksize+STACKINCREMEN T) *sizeof(SET)); /*为栈重新分配空间*/if(!S.base)exit(OVERFLOW);S.top=S.base+S.stacksize;S.stacksize+=STACKINCREMENT;}*S.top=e;S.top++;}return OK; }topAB压栈操作topABebase base数据结构之栈和队列7¾栈的销毁void DestroyStack_Sq(Stack &S){ if (S.base) free(S.base);S.base=NULL;S.top=NULL;S.stacksize=0;}¾栈的清除void ClearStack_Sq(Stack &S){ S.top = S.base ;}数据结构之栈和队列8¾判断栈是否为空栈Status StackEmpty_Sq(Stack S){ if(S.top==S.base) return TRUE;else return FALSE;}¾获得栈的实际长度int StackLength_Sq(Stack S){return(abs(S.top-S.base));}数据结构之栈和队列9¾多个栈共享邻接空间两个栈共享一空间::::::top1top21m中间可用空间栈1栈2地址Base1Base 2……数据结构之栈和队列103. 3 栈与递归¾递归函数:一个直接调用自己或通过一系列的调用语句间接地调用自己的函数。
第3章栈和队列-数据结构与算法(第2版)-汪沁-清华大学出版社
an
队头
队尾
队列示意图
入队
13
2、队列的基本运算
初始化队列 INIQUEUE(&Q)
将队列Q设置成一个空队列。
入队列
ENQUEUE(&Q,X)
将元素X插入到队尾中,也称“进队” ,“插入”。
出队列
DLQUEUE(&Q)
将队列Q的队头元素删除,也称“退队”、“删除”。
取队头元素 GETHEAD(Q)
也就是说,栈是一种后进先出(Last In First Out)的线性表,简称为LIFO表。
3
2、栈的运算
初始化栈:INISTACK(&S)
将栈S置为一个空栈(不含任何元素)。
进栈:PUSH(&S,X)
将元素X插入到栈S中,也称为 “入栈”、 “插入”、 “压 入”。
出栈: POP(&S)
删除栈S中的栈顶元素,也称为”退栈”、 “删除”、 “弹 出”。
9
三、链栈
typedef struct Lsnode { ElemType data;
struct Lsnode *next; } Lsnode *top;
一个链表栈由ቤተ መጻሕፍቲ ባይዱ顶指针top唯一确定。
10
1、链栈的主要运算
进栈操作 void Push(Lsnode *top; ElemType x)
{ p=(Lsnode *)malloc(sizeof(Lsnode)); p->data=x; p->next=top->next; top->next=p; }/*Push*/
第3章 栈和队列
1
栈和队列是二种特殊的线性表。是操作受 限的线 性表。 一、栈
《数据结构(C语言)》第3章 栈和队列
栈
❖ 栈的顺序存储与操作 ❖ 1.顺序栈的定义
(1) 栈的静态分配顺序存储结构描述 ② top为整数且指向栈顶元素 当top为整数且指向栈顶元素时,栈空、入栈、栈满 及出栈的情况如图3.2所示。初始化条件为 S.top=-1。
(a) 栈空S.top==-1 (b) 元素入栈S.stack[++S.top]=e (c) 栈满S.top>=StackSize-1 (d) 元素出栈e=S.stack[S.top--]
/*栈顶指针,可以指向栈顶
元素的下一个位置或者指向栈顶元素*/
int StackSize; /*当前分配的栈可使用的以 元素为单位的最大存储容量*/
}SqStack;
/*顺序栈*/
Data structures
栈
❖ 栈的顺序存储与操作 ❖ 1.顺序栈的定义
(2) 栈的动态分配顺序存储结构描述 ① top为指针且指向栈顶元素的下一个位置 当top为指针且指向栈顶元素的下一个位置时,栈空 、入栈、栈满及出栈的情况如图3.3所示。初始化条 件为S.top=S.base。
…,n-1,n≥0} 数据关系:R={< ai-1,ai>| ai-1,ai∈D,i=1,2
,…,n-1 } 约定an-1端为栈顶,a0端为栈底 基本操作:
(1) 初始化操作:InitStack(&S) 需要条件:栈S没有被创建过 操作结果:构建一个空的栈S (2) 销毁栈:DestroyStack(&S) 需要条件:栈S已经被创建 操作结果:清空栈S的所有值,释放栈S占用的内存空间
return 1;
}
Data structures
栈
第三章栈和队列
续8
//循环队列实现方案二 在SqQueue结构体中增设计数变量c,记录队列中当前 元素个数 void clearQueue(SqQueue &q) { q.r=q.f=-1; q.c=0; //r=f=-1~n-1区间任意整数均可 } int empty(SqQueue &q) { return q.c==0; } int full(SqQueue &q) { return q.c==q.n; } //队空、队满时q.f==q.r均为真 //优点:队满时没有空闲元素位置(充分利用了空间)
西南交通大学信息科学与技术学院软件工程系‐赵宏宇 数据结构A 第3章‐19
西南交通大学信息科学与技术学院软件工程系‐赵宏宇
数据结构A 第3章‐20
3.3 栈的应用
续1
3.3 栈的应用
续2
2. 栈与递归 (1) 递归程序的存储空间消耗 由于函数调用的指令返回地址、形式参数以及断 点状态均用系统堆栈实现存储,因此递归调用的层次 数(深度)决定了系统堆栈必须保留的存储空间容量大小。 例1 以下函数用递归法实现n元一维数组元素逆序存储, 试分析所需栈的深度。 void reverse(ElemTp a[], int i, int j) //数组a下标范围i..j实现元素逆序存储 { if(i<j) { a[i]a[j]; reverse(a, i+1, j-1); } }
西南交通大学信息科学与技术学院软件工程系‐赵宏宇 数据结构A 第3章‐7
3. 堆栈习题举例 例1 若元素入栈次序为ABC,写出所有可能的元素出栈 次序。 答: 所有可能的元素出栈次序共5种,即 ABC 操作PXPXPX (P表示入栈,X表示退栈) ACB PXPPXX BAC PPXXPX BCA PPXPXX CBA PPPXXX
第3章_栈和队列
(Chapter 3. பைடு நூலகம்tack and Queue)
栈的概念、存储结构及其基本操作
栈的应用举例 队列的概念、存储结构及其基本操作
§3.1 栈
3.1.1 栈的定义及基本运算
• 定义:只能在表尾(栈顶)进行插入和删除操 作进行的线性表。 • 特点: 后进先出(LIFO—Last In First Out )
top 栈顶
an an-1
. . .
a1 ∧
栈底
空栈: top == NULL
16
入栈
LinkStack Push_LS (LinkStack top,datatype x) { StackNode *p ; top p = (StackNode *) malloc (sizeof( StackNode)); p->data = x; top p->next = top; top = p; return top; }
23
2
括号匹配的检验:
问题:两种括号,可以嵌套使用,但不能重叠 解决:使用栈。 {([ ][ ])} 左括号进栈, 右括号就从栈顶出栈一个左括号, 检查是否能够匹配。 算法开始和结束时,栈都应该是空的。
匹配一个字符串中的左、右括号。如
[ a * ( b + c ) + d ]
( 出栈
( )匹配
[ 出栈
3.1.2 栈的存储及运算实现
顺序栈 -- 栈的顺序存储表示 链栈 -- 栈的链式存储表示
4
1 顺序栈
顺序栈类型的定义 – 本质 顺序表的简化,唯一需要确定的是栈顶、栈底。 – 通常 栈底:下标为0的一端 栈顶:由top指示,空栈时top=-1
第3章 栈和队列
例五、 表达式求值 例五、
限于二元运算符的表达式定义:
操作数) 运算符 运算符) 操作数 操作数) 表达式 ::= (操作数 + (运算符 + (操作数 操作数 操作数 ::= 简单变量 | 表达式 简单变量 :: = 标识符 | 无符号整数
表达式的三种标识方法: 表达式的三种标识方法: 设 Exp = S1 + OP + S2 则称 OP + S1 + S2 S1 + OP + S2 S1 + S2 + OP 为前缀表示法 前缀表示法 为中缀表示法 中缀表示法 为后缀表示法 后缀表示法
例如:(1348)10 = (2504)8 ,其 例如: 运算过程如下:
计 算 顺 序
N N div 8 N mod 8 1348 168 4 168 21 0 21 2 5 2 0 2
输 出 顺 序
void conversion () { InitStack(S); scanf ("%d",&N); while (N) { Push(S, N % 8); N = N/8; } while (!StackEmpty(S)) { Pop(S,e); printf ( "%d", e ); } } // conversion
栈和队列是两种常用的数据类型
3.1 栈的类型定义 3.2 栈的应用举例 3.3 栈类型的实现 3.4 队列的类型定义 3.5 队列类型的实现
3.1 栈的类型定义
ADT Stack { 数据对象: 数据对象 D={ ai | ai ∈ElemSet, i=1,2,...,n, n≥0 } 数据关系: 数据关系 R1={ <ai-1, ai >| ai-1, ai∈D, i=2,...,n } 约定an 端为栈顶,a1 端为栈底。 基本操作: 基本操作: } ADT Stack
数据结构课件第3篇章栈和队列
循环队列实现原理
01
循环队列定义
将一维数组看作首尾相接的环形结构,通过两个指针(队头和队尾指针)
在数组中循环移动来实现队列的操作。当队尾指针到达数组末端时,再
回到数组起始位置,形成循环。
02
判空与判满条件
在循环队列中,设置一个标志位来区分队列为空还是已满。当队头指针
等于队尾指针时,认为队列为空;当队尾指针加1等于队头指针时,认
栈在函数调用中应用
函数调用栈
在程序执行过程中,每当发生函数调用时,系统会将当前函数的执行上下文压入一个专门的栈中,称为函数调用 栈。该栈用于保存函数的局部变量、返回地址等信息。当函数执行完毕后,系统会从函数调用栈中弹出相应的执 行上下文,并恢复上一个函数的执行状态。
递归调用实现
递归调用是一种特殊的函数调用方式,它通过在函数调用栈中反复压入和弹出同一函数的执行上下文来实现对问 题的分解和求解。在递归调用过程中,系统会根据递归深度动态地分配和管理函数调用栈的空间资源。
栈和队列的应用
栈和队列在计算机科学中有着广泛的应用,如函数调用栈、表达式求 值、缓冲区管理等。
常见误区澄清说明
误区一
栈和队列的混淆。虽然栈和队列都是线性数据结构,但它们的操作方式和应用场景是不同的。栈是后进先出,而队列 是先进先出。
误区二
认为栈和队列只能通过数组实现。实际上,栈和队列可以通过多种数据结构实现,如链表、循环数组等。具体实现方 式取决于应用场景和需求。
后缀表达式求值
利用栈可以方便地实现后缀表达式的求值。具体步骤 为:从左到右扫描表达式,遇到数字则入栈,遇到运 算符则从栈中弹出所需的操作数进行计算,并将结果 入栈,最终栈中剩下的元素即为表达式的结果。
中缀表达式转换为后缀表达式
数据结构实用教程(C语言版) 第3章 栈和队列
3.1.1 栈的概念
假设有一个栈S=(a1,a2,…,an),栈 中元素按a1,a2,…,an的次序进栈后, 进栈的第一个元素a1为栈底元素,出栈的第 一个元素an为栈顶元素,也就是出栈的操作 是按后进先出的原则进行的,其结构如图31所示。
图3-1栈结构示意图
返回到本节目录
3.1.2栈的基本操作
3.1.3顺序栈
由于栈是操作受限制的线性表,因此与线性表类似,栈也 有两种存储结构,即顺序存储结构和链式存储结构。 1. 顺序栈的定义 栈的顺序存储结构称为顺序栈。类似于顺序表的类型定义,顺 序栈是用一个预设的足够长度的一维数组和一个记录栈顶元素 位置的变量来实现。顺序栈中栈顶指针与栈中数据元素的关1.3顺序栈
3. 顺序栈的基本操作实现
(3)进栈操作 进栈操作的过程如图3-3所示。先判断栈S如图3-3(a) 是否为满,若不满再将记录栈顶的下标变量top加1如 图3-3(b),最后将进栈元素放进栈顶位置上如图33(c)所示,算法描述见算法3.3。
图3-3 进栈操作过程图
返回到本节目录
栈除了在栈顶进行进栈与出栈外,还有初始化、判空 等操作,常用的基本操作有: (1)初始化栈InitStack(S)。其作用是构造一个空 栈 S。 (2)判断栈空EmptyStack(S)。其作用是判断是 否是空栈,若栈S为空,则返回1;否则返回0。 (3)进栈Push(S,x)。其作用是当栈不为满时,将 数据元素x插入栈S中,使其为栈S的栈顶元素。 (4)出栈Pop(S,x)。其作用是当栈S不为空时,将 栈顶元素赋给x,并从栈S中删除当前栈顶元素。 (5)取栈顶元素GetTop(S,x)。其作用是当栈S不 为空时,将栈顶元素赋给x并返回,操作结果只是 读取栈顶元素,栈S不发生变化。 返回到本节目录
第3章栈和队列
3.1.2 栈的表示和算法实现
1.顺序栈 2.链栈
第3章栈和队列
1. 顺序栈 顺序栈是用顺序存储结构实现的栈,即利 用一组地址连续的存储单元依次存放自栈 底到栈顶的数据元素,同时由于栈的操作 的特殊性,还必须附设一个位置指针top( 栈顶指针)来动态地指示栈顶元素在顺序 栈中的位置。通常以top=-1表示空栈。
第 3 章 栈和队列
3.1 栈 3.2 队列 3.3 栈和队列的应用
第3章栈和队列
3.1 栈
3.1.1 栈的抽象数据类型定义 3.1.2 栈的表示和算法实现
第3章栈和队列
3.1.1 栈的定义
1.栈的定义 栈(stack)是一种只允许在一端进行插入和删除的线 性表,它是一种操作受限的线性表。在表中只允许进
行插入和删除的一端称为栈顶(top),另一端称为 栈 底 (bottom) 。 栈 的 插 入 操 作 通 常 称 为 入 栈 或 进 栈 (push),而栈的删除操作则称为出栈或退栈(pop)。 当栈中无数据元素时,称为空栈。
栈是按照后进先出 (LIFO)的原则组 织数据的,因此, 栈也被称为“后进 先出”的线性表。
第3章栈和队列
(2)入栈操作
Status Push(SqStack &S, Elemtype e)
【算法3.2 栈的入栈操作】
{ /*将元素e插入到栈S中,作为S的新栈顶*/
if (S->top>= Stack_Size -1) return ERROR;
else { S->top++;
S->elem[S->top]=e;
return OK;}
Push(S,’you’)
数据结构与算法C版课件第三章栈和队列
不改变栈的状态。
4.栈的存储 (1)采用顺序方式存储的栈称为顺序栈(sequential stack) (2) 采用链接方式存储的栈称为链栈(linked stack)
3.1.2 顺序栈及运算的算法实现
用栈来实现括号匹配检查的原则是,对表达式从左到右扫描。 (1)当遇到左括号时,左括号入栈; (2)当遇到右括号时,首先检查栈是否空,若栈空,则表明该“右括弧”多余;否则比 较栈顶左括号是否与当前右括号匹配,若匹配,将栈顶左括号出栈,继续操作;否则,表明 不匹配,停止操作。 (3)当表达式全部扫描完毕,若栈为空,说明括号匹配,否则表明“左括弧”有多余的。
出队
a1 a2 a3 a4 a5
入队
队列图示
4.队列的应用
5. 在队列上进行的基本运算
(1)队列初始化initQueue(q):构造一个空队列。 (2)判队空emptyQueue(q):若q为空队则返回为1,否
则返回为0。
(3)入队enQueue(q,x):对已存在的队列q,插入一个元素x
到队尾,队发生变化。
队列中元素个数的计算公式。
(4)出队deQueue(q,x):删除队头元素,并通过x返回其值,
队发生变化。
(5)读队头元素frontQueue(q):读队头元素,并返回其值,
队不变。
3.2.2 顺序队列及运算的实现
采用顺序方法存储的队列称为顺序队列(sequential queue)
顺序队列的存储结构用c语言定义如下:
#define MAXSIZE 1024
运算受限的线性 表
表两端插删
数据结构(C语言版)第3章 栈和队列
typedef struct StackNode {
SElemType data;
S
栈顶
struct StackNode *next;
} StackNode, *LinkStack;
LinkStack S;
∧
栈底
链栈的初始化
S
∧
void InitStack(LinkStack &S ) { S=NULL; }
top
C
B
base A
--S.top; e=*S.top;
取顺序栈栈顶元素
(1) 判断是否空栈,若空则返回错误 (2) 否则通过栈顶指针获取栈顶元素
top C B base A
Status GetTop( SqStack S, SElemType &e) { if( S.top == S.base ) return ERROR; // 栈空 e = *( S.top – 1 ); return OK; e = *( S.top -- ); ??? }
目 录 导 航
Contents
3.1 3.2 3.3 3.4 3.5
栈和队列的定义和特点 案例引入 栈的表示和操作的实现 栈与递归 队列的的表示和操作的实现
3.6
案例分析与实现
3.2 案例引入
案例3.1 :一元多项式的运算
案例3.2:号匹配的检验
案例3.3 :表达式求值
案例3.4 :舞伴问题
目 录 导 航
top B base A
清空顺序栈
Status ClearStack( SqStack S ) { if( S.base ) S.top = S.base; return OK; }
第3章数据结构栈和队列
第3章数据结构栈和队列数据结构是计算机科学中重要的基础知识之一,它是用于组织和管理数据的方法。
栈和队列是其中两种常见的数据结构,它们分别以后进先出(Last In First Out,LIFO)和先进先出(First In First Out,FIFO)的方式操作数据。
本文将详细介绍栈和队列的概念、特点以及应用。
一、栈栈是一种限制仅在表尾进行插入和删除操作的线性表。
插入和删除操作称为入栈和出栈,即数据项的入栈相当于把数据项放入栈顶,而数据项的出栈相当于从栈顶移除数据项。
栈具有后进先出的特点,即后入栈的数据项先出栈,而最先入栈的数据项最后出栈。
类比现实生活中的例子就是一叠盘子,我们只能从最上面取盘子或放盘子。
栈的实现方式有两种:基于数组和基于链表。
基于数组的栈实现相对简单,通过一个数组和一个指向栈顶的指针来完成栈的操作。
基于链表的栈实现则需要定义一个节点结构,每个节点包含一个数据域和一个指向下一个节点的指针,通过头指针来操作栈。
栈的应用非常广泛,比如浏览器中的返回功能就是通过栈来实现的。
当我们点击浏览器的返回按钮时,当前页面会入栈,点击前进按钮时,当前页面会出栈。
在编程中,栈也被广泛应用,比如函数调用栈用于存储函数调用的上下文信息。
二、队列队列是一种限制仅在表头删除和在表尾插入的线性表。
表头删除操作称为出队列,表尾插入操作称为入队列。
和栈不同,队列采用先进先出的原则,即最先入队列的元素最先出队列。
队列的实现方式也有两种:基于数组和基于链表。
基于数组的队列实现和栈类似,通过一个数组和两个指针(一个指向队头,一个指向队尾)来完成队列的操作。
基于链表的队列实现则需要定义一个节点结构,每个节点包含一个数据域和一个指向下一个节点的指针,通过头指针和尾指针来操作队列。
队列同样具有广泛的应用,比如操作系统中的进程调度就是通过队列来实现的。
CPU会按照进程到达的顺序,依次从队列中取出进程进行执行。
在编程中,队列也常用于解决一些需要按顺序处理数据的问题。
数据结构第三章栈和队列
性能比较与选择依据
性能比较
栈和队列的时间复杂度均为O(1),空间复杂度均为O(n)。在实际应用中,栈通常用于 需要后进先出(LIFO)的场景,而队列则用于需要先进先出(FIFO)的场景。
选择依据
在选择使用栈还是队列时,应根据具体需求和应用场景进行判断。如果需要后进先出的 特性,应选择栈;如果需要先进先出的特性,则应选择队列。同时,还需要考虑数据结
栈中的元素只能在栈顶进行插入和删 除操作。
栈具有记忆功能,能保存数据元素进 入栈的先后顺序。
栈的基本操作
01
入栈(Push):在栈顶 插入一个元素。
02
出栈(Pop):删除栈 顶元素并返回其值。
03
查看栈顶元素(Top) :返回栈顶元素的值, 但不删除该元素。
04
判断栈是否为空( IsEmpty):检查栈中 是否还有元素。
回溯到上一个状态。
广度优先搜索中的队列应用
搜索队列
广度优先搜索使用队列来保存待 搜索的节点,按照先进先出的原
则进行搜索。
状态转移
在广度优先搜索中,队列用于保存 状态转移的信息,以便在搜索过程 中根据状态转移规则进行状态的扩 展和搜索。
最短路径问题
广度优先搜索可用于解决最短路径 问题,通过队列保存待访问的节点 ,并按照距离起始节点的远近进行 排序和访问。
其他算法中的栈和队列应用
深度优先搜索
在深度优先搜索中,栈用于保存当前路径的状态信息,以便在需要时 回溯到上一个状态。
括号匹配问题
栈可用于解决括号匹配问题,遇到左括号时将其压入栈中,遇到右括 号时从栈中弹出左括号并判断是否匹配。
表达式求值
栈可用于表达式求值中,保存操作数和运算符,并按照运算优先级进 行求值。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
5
4 3 2 1 0
F E D C
B A 出栈
5 4 3
4 3
2 1 top=-1 0 栈空
top top
top top
2 1 0
栈顶指针top,指向实际栈顶 位置,初值为-1
设数组维数为M top=-1,栈空,此时出栈,则下溢 (underflow) top=M-1,栈满,此时入栈,则上溢 (overflow)
存储结构的实现(顺序栈的类型描述)
#define MAXSIZE 1000
/*设定栈的最大长度*/
typedef struct { datatype data[MAXSIZE]; int top; }SeqStack; /*SeqStack为结构变量,包含两个域*/ 定义一个指向顺序栈的指针:SeqStack *s;
3 ( ( 4 + + 2 + 2 2 对象栈 算符栈 对象栈 算符栈 对象栈 算符栈 6 1 * 1 + + 2 2 对象栈 算符栈 对象栈 算符栈
(2) 判空栈
【算法3-2】 int Empty_SeqStack(SeqStack *s) { if(s->top==-1) return 1; else return 0; }
(3) 入栈
【算法3-3】 int Push_SeqStack(SeqStack *s,datatype x) {if(s->top==MAXSIZE-1) return 0; /*若栈满,便不能入栈*/ s->top++; s->data[s->top]=x; /*入栈的数据元素值为x*/ return 1; }
(1) 入栈算法
top
p top
x
…...
栈底 ^
【算法3-7】 LinkStack Push_LinkStack(LinkStack top,datatype x) { StackNode *p; p=(StackNode *)malloc(sizeof(StackNode)); p->data=x; p->next=top; top=p; return top; }
+ #
to top p top base
中缀表达式 a*b+c a+b*c a+(b*c+d)/e
后缀表达式 ab*c+ abc*+ abc*d+e/+
例 计算 2+(4-3)*6
右括号遇到左括号 左括号在栈内 ,左括号直接出栈 (1)中缀表达式求值: 左括号在栈外 优先级比-低 在栈外优先级最高 优先级最高
top
E D C
5
4 3 2 1
B
A 0 出栈
(5) 取栈顶元素
【算法3-5】 datatype Top_SeqStack(SeqStack *s) { if(s->top==-1) error("栈空,无法取"); return (s->data[s->top]); } F
top
F E D C
5
2
,
3
+,
4
-,
3)算符优先关系表 表达式中任何相邻运算符1、2的优先关系有: 1<2:1的优先级低于2 1=2:1的优先级等于2 1>2:1的优先级高于2 由四则运算法则,可得到如下的算符优先关系表:
算符间的优先关系表
θ1 θ2
+
> > > > <
> > > > <
第3章 栈和队列
3.1 栈
3.2 栈的应用举例
3.3 队列 3.4 队列应用举例
[例3-1] 数制转换问题: 将十进制N转换为r进制的数。 数制转换方法基于下列原理: N = (N div 8)10 8+N mod 8 N:十进制数,div:整除运算, mod:求余运算; (1348)10 = 283+5 82+08+4 = (2504)8 N N div 8 N mod 8 1348 168 21 2 168 21 2 0 4 0 5 2
(2) 出栈算法
top top …... p 栈底 ^
【算法3-8】 LinkStack Pop_LinkStack(LinkStack top,datatype *x) { StackNode *p; if(top==NULL) return NULL; *x=top->data; p=top; top=top->next; free(p); return top; }
进栈
出栈
...
栈顶
an ……... a2
栈底
a1
栈的基本操作
1) 栈初始化Init_Stack(S) 功能:构造一个空栈S; 2) 销毁栈操作Destroy_Stack(S) 功能:销毁一个已存在的栈; 3) 置空栈操作Clear_Stack(S) 功能:将栈S置为空栈; 4) 读栈顶元素Top_Stack(S) 功能:取栈顶元素,栈未发生变化; 5)入栈Push(S, x) 功能:元素x进栈,栈发生了变化; 6)出栈Pop(S) 功能:栈顶元素退栈,栈发生了变化; 7)判空操作Empty_Stack (S) 功能:若栈S为空,则返回True,否则返回False;
推荐参考书目:
1. 严蔚敏,吴伟民,米宁编著:《数据结构题 集(C语言版)》,清华大学出版社,2005年 11月。 2.徐孝凯编著:《数据结构实用教程(第二 版)》.清华大学出版社. 2006年8月。 3.徐孝凯编著:《数据结构实用教程(第二版) 习题参考解答》,清华大学出版社,2006年8 月。 4.李春葆编著:《数据结构习题与解析——A级 (第3版)》,清华大学出版社,2006年9月。 5.宁正元编著:《算法与数据结构 》,清华大 学出版社,2006年5月 。
由上述求解过程可以 看出,在计算过程中是从 低位到高位顺序产生八进 制数的各个数位,而显示 时按照我们的习惯是从高 位在前,低位在后,即按 从高位到低位的顺序输出 , 即后计算出的(高)位 数先输出,具有后进先出 的特点,因此可将计算过 程中得到的八进制数顺序 进栈,出栈序列打印输出 的就是对应的八进制数。
/*将栈的操作抽象为模块调用,使问题的层次更加清晰*/
typedef int datatype; void conversion(int N,int r) { SepStack *s; datatype x; s=Init_SeqStack();
while(N) /* N不为0,即整除还未完成时,入栈*/ { Push_SeqStack(s,N%r); N=N/r; } while(!Empty_SeqStack(s)) /* 整除完成后,若栈不为空则出栈*/ { Pop_SeqStack(s,&x); printf("%d",x); } }
进栈 栈顶
出栈
an ……... a2
栈顶(top):允许插入和删除 的一端;
...
栈底
a1
栈底(bottom):不允许插入和删 除的一端。
设线性表(a1, a2, a3, …, an ) 是一个栈 1)表尾称为栈顶,表头称为栈底 , 即a1为栈底元素,an为栈顶元素, 2)在表尾插入元素的操作称进栈操 作,在表头删除元素的操作称为出栈 操作; 3)元素按a1, a2, a3, …, an 的次 序进栈, 第一个进栈的元素一定在栈 底,最后一个进栈的元素一定在栈顶 , 第一个出栈的元素为栈顶元素; 4)栈的元素具有后进先出的特点,所 以栈又称为后进先出表(LIFO表) 5)由于进栈、出栈操作总是在栈顶 一端进行,通常设置称为栈顶指针的 变量指示栈顶的位置。
顺序栈运算实现
(1) 置空栈
【算法3-1】 SeqStack *Init_SeqStack() {SeqStack *s; s=(SeqStack *)malloc(sizeof(SeqStack));/*建立栈空间*/ s->top=-1; /*初始化栈顶指针,-1表示为空栈*/ return s; }
a1
链式栈图示
栈底
链栈的结点定义: 与链表的结点结构相同
typedef struct node { datatype data; struct node *next; }StackNode,* LinkStack;
LinkStack top;
/*说明top为栈顶指针*/
链栈的基本操作包括:
置空栈、 判栈空、 入栈、 出栈,等等
*
< < > > <
/
< < > > <
(
< < < < <
)
> > > > =
#
> > > >
+ * / (
)
#
> <
> <
> <
> < <
>
> =
注: θ1 θ2是相邻算符, θ1在左, θ2在右
4)算符优先算法 从左向右扫描表达式: 遇操作数:入栈保存; 遇运算符号j:与前面的刚扫描过的运算符i比较,后面也许 有优先级更大的算符 若i<j , 则保存j,( 因此已保存的运算符的优先关系为 1<2<3<4。。 ) 若i>j , 则说明i是已扫描的运算符中优先级最高者,可进 行运算; 若i = j ,则i为(,j 为 ),说明括号内的式子已计算完,需 要消去括号;
栈的存储与运算实现
与线性表类似,栈也可以用顺序结构或链式结构 存储。