栈和队列的详细讲解
数据结构-栈与队列

栈 1.6栈的应用
运算符的优先级关系表在运算过程中非常重要,它是判定进栈、出栈的重要依据。
θ1
θ2
+
-
+
>
>
-
>
>
*
>
>
/
>
>
(
<
<
)
>
>
#
<
<
*
/
(
)
#
<
<
<
>
>
<
<
<
>
>
>
>
<
>
>
>
>
<
>
>
<
<
<
=
>
>
>
>
<
<
<
=
栈
1.6栈的应用
下面以分析表达式 4+2*3-12/(7-5)为例来说明求解过程,从而总结出表达式求值的算 法。求解中设置两个栈:操作数栈和运算符栈。从左至右扫描表达式:# 4+2*3-12/(7-5) #, 最左边是开始符,最右边是结束符。表达式求值的过程如下表所示:
1.4栈的顺序存储结构
设计进栈算法——Push 函数。首先,判断栈是否已满,如果栈已满,就运用 realloc 函 数重新开辟更大的栈空间。如果 realloc 函数返回值为空,提示溢出,则更新栈的地址以及栈 的当前空间大小。最终,新元素入栈,栈顶标识 top 加 1。
线性表-链接存储的栈和队列

索引存储的优点
查寻某个结点k,无须遍查F中的所有结点。 只需根据结点k的性质p,计算索引函数求 得i,从索引表中找到结点xi,得到子线性 表Fi的首地址。然后在线性表Fi中查找这 个结点k。
1.6.2 索引存储
4. 存储方法 (1)顺序-索引-链接,即索引表为顺序存储, 子线性表为链接存储。(常用) (2)顺序-索引-顺序,即索引表与子线性表 均为顺序存储。 (3)链接-索引-链接,即索引表与子线性表 均为链接存储。 (4)链接-索引-顺序,即索引表为链接存储, 子线性表为顺序存储。
1.6.3 散列存储
1.
概念 散列存储(也称Hash存储),通过对结点的 键值作某种运算来确定具有此结点的存放位置。 设有线性表F=(k0, k1, …, kn-1)和数组T[m], 而结点ki的键值为keyi,若h(x)是键值集合到 整数0至m-1的一个一一对应函数。对于任意 结点ki在数组T[m]中的存放位置由h(keyi)决定, 这种存放结点的方法,称为散列(Hash)存储。 函数h(x)为散列函数,数组T[m]为散列表。
9
1.6.3 散列存储
2.
问题 (1)难于选取一个从键值集合到散列表地 址空间的一一对应的函数h(x),即对于 keyi≠keyj,有可能h(keyi)=h(keyj)。这种 情况称为冲突。 (2)一旦有冲突,应选取怎样的解决方法?
这些问题留待以后解决。
0 7 78
12 9
2
-9
4 11 93
3 ^
-61
1.6.1 线性表的压缩存储
3.
压缩存储的优缺点 优点:当相同取值的结点数量较多时, 可节省存储空间。 缺点:给定序号,要求查寻相应结点, 比较困难。对于顺序存储,可用两分查 找法;对于链接存储,就需扫描几乎全 部结点。
数据结构--栈和队列基础知识

数据结构--栈和队列基础知识⼀概述栈和队列,严格意义上来说,也属于线性表,因为它们也都⽤于存储逻辑关系为 "⼀对⼀" 的数据,但由于它们⽐较特殊,因此将其单独作为⼀篇⽂章,做重点讲解。
既然栈和队列都属于线性表,根据线性表分为顺序表和链表的特点,栈也可分为顺序栈和链表,队列也分为顺序队列和链队列,这些内容都会在本章做详细讲解。
使⽤栈结构存储数据,讲究“先进后出”,即最先进栈的数据,最后出栈;使⽤队列存储数据,讲究 "先进先出",即最先进队列的数据,也最先出队列。
⼆栈2.1 栈的基本概念同顺序表和链表⼀样,栈也是⽤来存储逻辑关系为 "⼀对⼀" 数据的线性存储结构,如下图所⽰。
从上图我们看到,栈存储结构与之前所了解的线性存储结构有所差异,这缘于栈对数据 "存" 和 "取" 的过程有特殊的要求:1. 栈只能从表的⼀端存取数据,另⼀端是封闭的;2. 在栈中,⽆论是存数据还是取数据,都必须遵循"先进后出"的原则,即最先进栈的元素最后出栈。
拿图 1 的栈来说,从图中数据的存储状态可判断出,元素 1 是最先进的栈。
因此,当需要从栈中取出元素 1 时,根据"先进后出"的原则,需提前将元素 3 和元素 2 从栈中取出,然后才能成功取出元素 1。
因此,我们可以给栈下⼀个定义,即栈是⼀种只能从表的⼀端存取数据且遵循 "先进后出" 原则的线性存储结构。
通常,栈的开⼝端被称为栈顶;相应地,封⼝端被称为栈底。
因此,栈顶元素指的就是距离栈顶最近的元素,拿下图中的栈顶元素为元素 4;同理,栈底元素指的是位于栈最底部的元素,下中的栈底元素为元素 1。
2.2 进栈和出栈基于栈结构的特点,在实际应⽤中,通常只会对栈执⾏以下两种操作:向栈中添加元素,此过程被称为"进栈"(⼊栈或压栈);从栈中提取出指定元素,此过程被称为"出栈"(或弹栈);2.3 栈的具体实现栈是⼀种 "特殊" 的线性存储结构,因此栈的具体实现有以下两种⽅式:1. 顺序栈:采⽤顺序存储结构可以模拟栈存储数据的特点,从⽽实现栈存储结构。
第三章 栈和队列

栈和队列的基本操作是线性表操作的子集,是限定性(操作受限制)的数据结构。
第三章栈和队列数据结构之栈和队列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 栈与递归¾递归函数:一个直接调用自己或通过一系列的调用语句间接地调用自己的函数。
数据结构栈和队列ppt课件

栈的运用 例3.1 将一个十进制正整数N转换成r进制的数
N 〕
1835
229
28
3
N / 8 〔整除〕 N % 8〔求余
229
3
低
28
5
3
4
0
3
高
❖例3.2 算术表达式中括号匹配的检查
❖用栈来实现括号匹配检查的原那么是,对表达式从左 到右扫描。
❖〔1〕当遇到左括号时,左括号入栈;
❖〔2〕当遇到右括号时,首先检查栈能否空,假设栈 空,那么阐明该“右括弧〞多余;否那么比较栈顶左 括号能否与当前右括号匹配,假设匹配,将栈顶左括 号出栈,继续操作;否那么,阐明不匹配,停顿操作 。
❖在顺序栈上实现五种根本运算的C函数 ❖〔3〕入栈 ❖int push (SeqStack *s, DataType x) ❖{ if (s->top==MAXSIZE-1) /*栈满不能入栈*/ ❖{ printf("overflow"); ❖return 0; ❖} ❖ s->top++; ❖ s->data[s->top]=x; ❖ return 1; ❖}
链队列及运算的实现
采用链接方法存储的队列称为链队列〔Linked Queue〕
采用带头结点的单链表来实现链队列,链队列中 的t结ype点de类f st型ruc与t N单od链e 表一样。将头指针front和尾指针 re{arD封at装aTy在pe一da个ta;构造体中,链队列用C言语描画如 下:struct Node *next;
❖只设了一个尾指针r ❖头结点的指针,即r->next ❖队头元素的指针为r->next->next ❖队空的断定条件是r->next==r
信息学奥赛知识点(十二)—栈和队列

栈和队列是信息学竞赛中经常涉及的数据结构,它们在算法和程序设计中有着广泛的应用。
掌握栈和队列的基本原理和操作方法,对于参加信息学竞赛的同学来说是非常重要的。
本文将深入探讨栈和队列的相关知识点,帮助大家更好地理解和掌握这两种数据结构。
一、栈的定义与特点栈是一种先进后出(LIFO)的数据结构,它的特点是只允许在栈顶进行插入和删除操作。
栈可以用数组或链表来实现,常见的操作包括压栈(push)、出栈(pop)、获取栈顶元素(top)等。
栈的应用非常广泛,比如在计算机程序中,函数的调用和返回值的存储就是通过栈来实现的。
二、栈的基本操作1. 压栈(push):将元素压入栈顶2. 出栈(pop):将栈顶元素弹出3. 获取栈顶元素(top):返回栈顶元素的值,但不把它从栈中移除4. 判空:判断栈是否为空5. 获取栈的大小:返回栈中元素的个数三、栈的应用1. 括号匹配:利用栈来检查表达式中的括号是否匹配2. 表达式求值:利用栈来实现中缀表达式转换为后缀表达式,并进行求值3. 迷宫求解:利用栈来实现迷宫的路径搜索4. 回溯算法:在深度优先搜索和递归算法中,通常会用到栈来保存状态信息四、队列的定义与特点队列是一种先进先出(FIFO)的数据结构,它的特点是只允许在队尾进行插入操作,在队首进行删除操作。
队列同样可以用数组或链表来实现,常见的操作包括入队(enqueue)、出队(dequeue)、获取队首元素(front)、获取队尾元素(rear)等。
队列在计算机领域也有着广泛的应用,比如线程池、消息队列等都可以用队列来实现。
五、队列的基本操作1. 入队(enqueue):将元素插入到队列的末尾2. 出队(dequeue):从队列的头部删除一个元素3. 获取队首元素(front):返回队列的头部元素的值4. 获取队尾元素(rear):返回队列的尾部元素的值5. 判空:判断队列是否为空6. 获取队列的大小:返回队列中元素的个数六、队列的应用1. 广度优先搜索算法(BFS):在图的搜索中,通常会用队列来实现BFS算法2. 线程池:利用队列来实现任务的调度3. 消息队列:在分布式系统中,常常会用队列来进行消息的传递4. 最近最少使用(LRU)缓存算法:利用队列实现LRU缓存淘汰在信息学竞赛中,栈和队列的相关题目经常出现,并且有一定的难度。
第三章栈和队列

续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章 栈和队列

例五、 表达式求值 例五、
限于二元运算符的表达式定义:
操作数) 运算符 运算符) 操作数 操作数) 表达式 ::= (操作数 + (运算符 + (操作数 操作数 操作数 ::= 简单变量 | 表达式 简单变量 :: = 标识符 | 无符号整数
表达式的三种标识方法: 表达式的三种标识方法: 设 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
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
22
退栈算法(算法 ) 退栈算法(算法4.9)
void pop_link( PLinkStack plstack ) { PNode p; if( isEmptyStack_link( plstack ) ) printf( "Empty stack pop.\n" ); else { p = plstack->top; plstack->top = plstack->top->link; free(p); } }
19
pLinkstack plstack; plstack top
/*变量声明 变量声明*/ 变量声明 info link
^
栈的链接表示
3.1.3 链栈
进栈 相当于链表在 top 结点前插入 出栈 相当于链表在将 相当于链表在将top 结点删除
21
进栈算法(算法 ) 进栈算法(算法4.8)
void push_link( PLinkStack plstack, DataType x ) /* 在栈中压入一元素 */ 在栈中压入一元素x { PNode p; p = (PNode)malloc( sizeof( struct Node ) ); if ( p == NULL ) printf("Out of space!\n"); else { p->info = x; p->link = plstack->top; plstack->top = p; } }
4
3.1.2 顺序栈
栈的顺序存储结构简称为顺序栈, 栈的顺序存储结构简称为顺序栈,它是运算受限 的顺序表。 的顺序表。 #define MAXNUM 100 /* 栈中能达到的最大容量 栈中能达到的最大容量*/
typedef int DataType; /* 定义栈元素的数据类型 / 定义栈元素的数据类型* struct SeqStack /* 顺序栈类型定义 */ { DataType s[MAXNUM]; int t; /*栈顶 栈顶*/ 栈顶 }; ; typedef struct SeqStack, *PSeqStack; PSeqStack pastack; /*指向顺序栈的指针变量 指向顺序栈的指针变量*/ 指向顺序栈的指针变量
算法4.4 4.4) 4. 退栈(算法4.4)
pop_seq(pastack)
PSeqStack pastack; { if (pastack->t==-1 ) (pastack->t==print(“underflow ); print( underflow”); underflow else pastack->t--; pastack->t--; -} /* pop_seq */
27
例3.2
栈与递归
递归函数的特点:在函数内部可以直接或间接地 递归函数的特点: 调用函数自身。如阶乘函数: 调用函数自身。如阶乘函数: 1 n!= n*(n-1)! n*(n, n>0 , n=0
28
阶乘的递归计算(算法 阶乘的递归计算(算法4.11 ) int fact (int n) { if (n = = 0) return 1; else return(n*fact(n-1)); }; r2 main( ) { int n; scanf(“%d\n”,&n); printf(“%8d%8d\n”,n,fact(n)); } r1
25
设计一个简单的文字编辑器, 例3.1 设计一个简单的文字编辑器,使其具有删除打 错字符的功能。 错字符的功能。 /*顺序栈 是全程变量* PSeqStack str; /*顺序栈 str 是全程变量*/ /*编辑好的字符串在 EDIT( ) /*编辑好的字符串在 str 中*/ { char c; str=createEmptyStack(); c=getchar( ); while(c!=‘* ) /*字符 字符‘ 为编辑结束符* while(c!= *’) /*字符‘*’为编辑结束符*/ (c==‘# ) { if (c== #’) POP(str); else (c==‘@ ) if (c== @’) str=createEmptyStack(); else PUSH(str,c); ); c=getchar( ); } 26 } /*EDIT*/
5
注意: 注意
t是 int型简单变量 ,指向栈顶元素在栈中 是 型简单变量 指向栈顶元素在栈中 的位置(序号 序号) 的位置 序号
约定: 约定
1、栈空时,t=-1 、栈空时, 2、栈满时,t=MAXNUM-1 、栈满时, 3、栈顶元素:S[t] 、栈顶元素: 4、若t=-1时,执行 产生“ 、 时 执行pop,产生“下溢” 产生 下溢” 5、若t=MAXNUM-1时,执行 产生“ 、 时 执行push,产生“上溢 产生 6 ”
push_seq(pastack,x)
先修改 t 值,再放入数据
t++
s[t]=x
(*pastack).t++ (*pastack).s[(*pastack).t]=x
11
进栈(算法4.3 4.3) 3. 进栈(算法4.3)
push_seq(pastack,x)
PSeqStack pastack; datatype { if else pastack{ pastack->t++; pastack->s[pastackpastack->s[pastack->t]=x;} } /* push_seq */
23
3.2
栈的应用
栈的应用非常之广,只要问题满足LIFO 原则, 栈的应用非常之广,只要问题满足LIFO 原则,
均可使用栈做数据结构。我们先看几个例子。 均可使用栈做数据结构。我们先看几个例子。 例3.1 例3.2 例3.3 例3.4 例3.5 文字编辑器 栈与递归 数制转换 括号匹配的检验 表达式求值 表达式求值
24
设计一个简单的文字编辑器, 例3.1 设计一个简单的文字编辑器,使其具有删除打 错字符的功能。 错字符的功能。 每读入一个字符 ‘#’ # ‘@’ ‘*’ —— —— —— 删除前面一个字符 删除前面所有字符 输入结束 退栈 置空栈 编辑结束
“abc#d@efg*” 我们用栈来实现这种功能的文字编辑器
14
栈顶元素(算法4.5 4.5) 5. 取栈顶元素(算法4.5) datatype top_seq(pastack) PSeqStack pastack; { if (pastack->t==-1 ) { print(“stack is empty”); return NULL; } else return(pastack->s[pastack->t]; } /* top_seq */
3.1.2 顺序栈
进栈和退栈
6 5 4 3 2 1 0 -1
D C B A
7
3.1.2 顺序栈
在顺序栈下实现栈的五种基本运算 (1)置空栈 (2)判栈空 (3)进栈 (4)退栈 (5)取栈顶 当程序中同时使用两个栈时, 当程序中同时使用两个栈时, 共享存储空间 存储空间。 可共享存储空间。
8
置空栈(算法4.1 4.1) 1. 置空栈(算法4.1) PSeqStack createEmptyStack_seq(void) { PSeqStack pastack; pastack=malloc(sizeof(struct SeqStack)); if(pastack==NULL) printf(“out space!\ ); printf( out of space!\n”); else pastack->t= -1; pastackreturn pastack; } /*SETNULL*/
12
x;
(pastack->t==MAXNUM-1) (pastack->t==MAXNUMprint(“overflow ); print( overflow”); overflow
算法4.4 4.4) 4. 退栈(算法4t 值
t-pastack->t - 13
9
判栈空(算法4.2 4.2) 2. 判栈空(算法4.2)
int { if
isEmptyStack_seq(pastack) (pastack(pastack->t>=0) return FALSE; TRUE; return
PSeqStack pastack;
else }
10
进栈(算法4.3 4.3) 3. 进栈(算法4.3)
15
多个栈共享存储空间 栈1 栈2
…
栈1顶
…
栈2顶
...
栈2底
栈1底
让多个栈共享存储空间,可以相互调节余缺, 让多个栈共享存储空间,可以相互调节余缺, 节约存储空间,降低发生上溢的概率。 节约存储空间,降低发生上溢的概率。
16
多个栈共享存储空间 Typedef struct { datatype s[MAXNUM]; int top1,top2; }DStack;
例3.2
栈与递归
递归的定义 如果一个对象部分的由自己组成, 如果一个对象部分的由自己组成,或者 是按它自己定义的,则称为递归 递归的 是按它自己定义的,则称为递归的。 一个递归定义必须一步比一步简单, 一个递归定义必须一步比一步简单,最 后是有终结的,决不能无限循环下去。 后是有终结的,决不能无限循环下去。在n 阶乘的定义中, 时定义为1 阶乘的定义中,当n为0时定义为1,它不再 用递归来定义,称为递归定义的出口, 递归定义的出口 用递归来定义,称为递归定义的出口,简称 递归出口。 为递归出口。
an
...
a2 a1
3