Top Banner
数数数数 第 3 第 第 µç×Ó½Ì±Þ 第 101 第 第 1 第 2022第6第8第 第第第 第第第第
101

数据结构 Data Structure

Mar 18, 2016

Download

Documents

delta

数据结构 Data Structure. 精品课程. 第 2 章要点回顾. 顺序表 的类型定义. 顺序表的建立、输出、查找、插入、删除操作. 单链表 的类型定义. 单链表的建立、输出、查找、插入、删除操作. 第 3 章 栈与队列. 第 3 章 栈与队列. 3.1 栈. 3.2 栈的应用. 3.3 队列. 3.4 队列的应用. 3.1.1 栈的定义及基本操作 3.1.2 顺序栈 3.1.3 链栈. 3.1 栈. 入栈. 出栈. 栈顶. 栈顶元素. an. ……. (限定操作 一端). - PowerPoint PPT Presentation
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 1 页2023年4月24日 星期一

精品课程

Page 2: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 2 页2023年4月24日 星期一

第 2 章要点回顾顺序表的类型定义 顺序表的建立、输出、查找、插入、删除操作单链表的类型定义 单链表的建立、输出、查找、插入、删除操作

Page 3: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 3 页2023年4月24日 星期一

Page 4: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 4 页2023年4月24日 星期一

第 3 章 栈与队列3.1 栈

3.2 栈的应用3.3 队列3.4 队列的应用

Page 5: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 5 页2023年4月24日 星期一

3.1.1 栈的定义及基本操作3.1.2 顺序栈3.1.3 链栈

Page 6: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 6 页2023年4月24日 星期一

栈:限定仅在表尾进行插入或删除操作的线性表。表尾—栈顶,表头—栈底,不含元素的空表称空栈

3.1.1 栈的定义及基本操作1 、栈的定义

栈顶 an

a1a2

……

...

栈底... 出栈入栈

s=(a1,a2,……,an)(限定操作 一端)

栈顶元素

Page 7: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 7 页2023年4月24日 星期一

栈的特点:  根据栈的定义可知,最先放入栈中元素在栈底,最后放入的元素在栈顶,而删除元素刚好相反,最后放入的元素最先删除,最先放入的元素最后删除。 也就是说,栈是一种后进先出的线性表,简称为 LIFO 表。

3.1.1 栈的定义及基本操作1 、栈的定义

Page 8: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 8 页2023年4月24日 星期一

( 1 )初始化栈: InitStack(&s) 将栈 s 置为一个空栈 ( 不含任何元素 ) 。( 2 )进栈: Push(&s,x) 将元素 X 插入到栈 s 中,也称为 “入栈”、 “插入”、 “压入”。( 3 )出栈: Pop(&s) 删除栈 s 中的栈顶元素,也称为“退栈”、 “删除”、 “弹出”。

3.1.1 栈的定义及基本操作2 、栈的基本操作

Page 9: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 9 页2023年4月24日 星期一

( 4 )取栈顶元素: GetTop(S,&e) 取栈 S 中栈顶元素。( 5 )判栈空: StackEmpty(S) 判断栈 S 是否为空,若为空,返回值为 true ,否则返回值为 false 。

3.1.1 栈的定义及基本操作2 、栈的基本操作

Page 10: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 10 页2023年4月24日 星期一

【例】对于一个栈,给出输入项 A 、 B 、 C ,如果输入项序列由 ABC 组成,试给出所有可能的输出序列。

A 进 A 出 B 进 B 出 C 进 C 出ABCA 进 A 出 B 进 C 进 C 出 B 出ACBA 进 B 进 B 出 A 出 C 进 C 出BACA 进 B 进 B 出 C 进 C 出 A 出BCAA 进 B 进 C 进 C 出 B 出 A 出CBA可能产生输出序列 CAB?

3.1.1 栈的定义及基本操作2 、栈的基本操作

Page 11: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 11 页2023年4月24日 星期一

【例】一个栈的输入序列是 12345 ,若在入栈的过程中允许出栈,则栈的输出序列 43512 可能实现吗? 12345 的输出呢? 43512 不可能实现,主要是其中的 12 顺序

不能实现; 12345 的输出可以实现,只需压入一个立即

弹出一个即可。

答:

3.1.1 栈的定义及基本操作2 、栈的基本操作

Page 12: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 12 页2023年4月24日 星期一

435612 中到了 12 顺序不能实现; 135426 可以实现。

【例】如果一个栈的输入序列为 123456 ,能否得到 435612 和 135426 的出栈序列?答:

3.1.1 栈的定义及基本操作2 、栈的基本操作

Page 13: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 13 页2023年4月24日 星期一

【例】设依次进入一个栈的元素序列为 c , a , b , d ,则可得到出栈的元素序列是: A) a , b , c , d B) c , d , a , b C) b , c , d , a D) a , c , d , b

A 、 D 可以( B 、 C 不行)。答:

3.1.1 栈的定义及基本操作2 、栈的基本操作

Page 14: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 14 页2023年4月24日 星期一

由于栈是运算受限的线性表,因此线性表的存储结构对栈也适应。 栈的顺序存储结构简称为顺序栈,它是运算受限的线性表。因此,可用数组来实现顺序栈。因为栈底位置是固定不变的,所以可以将栈底位置设置在数组的两端的任何一个端点;栈顶位置是随着进栈和退栈操作而变化的,故需用一个整型变量 top 来指示当前栈顶的位置,通常称 top 为栈顶指针。

3.1.2 顺序栈1 、顺序栈的存储结构

Page 15: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 15 页2023年4月24日 星期一

顺序栈的类型定义只需将顺序表的类型定义中的last 域改为 top 即可。顺序栈的类型定义如下:

# define StackSize 100

typedef struct {

ElemType data[StackSize];

int top;

}SeqStack;

3.1.2 顺序栈1 、顺序栈的存储结构

Page 16: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 16 页2023年4月24日 星期一

栈顶 top 的值指示栈顶元素在栈中的位置。

top=-1

12345

0栈空

栈顶指针 top, 指向实际栈顶位置,初值为 -1

top12345

0进栈A

top

出栈

栈满

B

C

D

EF

设数组下标最大值为 Mtop=-1, 栈空,此时出栈,则下溢top=M, 栈满,此时入栈,则上溢

toptoptoptop

top

12345

0A

B

CD

E

Ftop

toptop

top

top

top

栈空3.1.2 顺序栈

Page 17: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 17 页2023年4月24日 星期一

设 S 是 SeqStack 类型的指针变量。若栈底位置在向量的低端,即 s–>data[0] 是栈底元素,那么栈顶指针 s–>top 是正向增加的,即 :

s–>top =StackSize-1 表示栈满。 当栈满时再做进栈运算必定产生空间溢出,简称“上溢” ; 当栈空时再做退栈运算也将产生溢出,简称“下溢”。

进栈时需将 s–>top加 1 ;

退栈时需将 s–>top 减 1 因此, s–>top=-1 表示空栈

3.1.2 顺序栈

Page 18: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 18 页2023年4月24日 星期一

( 1 )初始化栈void InitStack(SeqStack *s)

{ s–>top=-1; }

( 2 )判断栈空 int StackEmpty(SeqStack *s)

{ return(s–>top==-1); }

3.1.2 顺序栈2 、顺序栈的基本运算

Page 19: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 19 页2023年4月24日 星期一

s–>data[++s–>top]=x; }

( 3 )判断栈满 int StackFull(SeqStack *s)

{ return(s–>top==StackSize-1); }

( 4 )进栈 void Push(SeqStack *s , ElemType x)

{ if (StackFull(s)) error(“Stack overflow”);

3.1.2 顺序栈2 、顺序栈的基本运算

Page 20: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 20 页2023年4月24日 星期一

( 5 )退栈 void Pop(SeqStack *s,ElemType *x) { if (StackEmpty(s)) error(“Stack underflow”);

s–>top--; }

*x=s–>data[top];

3.1.2 顺序栈2 、顺序栈的基本运算

Page 21: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 21 页2023年4月24日 星期一

( 6 )取栈顶元素 ElemType GetTop(SeqStack *s) {

if (StackEmpty(s)) error(“Stack is empty”);

return s–>data[s–>top]; }

3.1.2 顺序栈2 、顺序栈的基本运算

Page 22: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 22 页2023年4月24日 星期一

栈的链式存储结构称为链栈,它是运算受限的单链表,插入和删除操作仅限制在表头位置上进行。由于只能在链表头部进行操作,故链表没有必要像单链表那样附加头结点。栈顶指针就是链表的头指针。

3.1.3 链栈1 、链栈的存储结构

Page 23: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 23 页2023年4月24日 星期一

链栈的类型定义 typedef struct node

{ ElemType data;

struct node *next;} Node, *LinkStack;

3.1.3 链栈1 、链栈的存储结构

Page 24: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 24 页2023年4月24日 星期一

( 1 )链栈的进栈LinkStack *PushLStack(LinkStack *top, ElemType x){ LinkStack *p; p = malloc(sizeof(LinkStack));

p->data = x; p->next = top;

return p; }

3.1.3 链栈2 、链栈的基本运算

Page 25: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 25 页2023年4月24日 星期一

LinkStack *PopLStack(LinkStack *top, ElemType *datap)

if (top==NULL) { printf(“under flow\n”); return NULL;}

( 2 )链栈的出栈

{ LinkStack *p;

else { *datap = top->data; p = top;

top = top->next; free(p);

return top; } }

3.1.3 链栈

Page 26: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 26 页2023年4月24日 星期一

3.2.1 数制转换3.2.2 文字编辑器3.2.3 表达式求值3.2.4 基于栈的迷宫求解

Page 27: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 27 页2023年4月24日 星期一

十进制 N 和其它进制数的转换是计算机实现计算的基本问题 , 其解决方法很多 , 其中一个简单算法基于下列原理 : N=(n div d)*d+n mod d ( 其中 :div 为整除运算 ,mod 为求余运算 )

3.2.1 数制转换

Page 28: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 28 页2023年4月24日 星期一

如: (1348)10=(2504)8 ,其运算过程如下:计算顺

序 输出顺序N N div 8 余

数1348 168 4168 21 021 2 52 0 2

3.2.1 数制转换

Page 29: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 29 页2023年4月24日 星期一

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); } }

3.2.1 数制转换

ÊýÖÆת»»

ÊýÖÆת»»£¨ÔËÐУ©

Page 30: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 30 页2023年4月24日 星期一

功能:接受用户从终端输入的程序或数据,并存入用户数据区。较好做法:设立输入缓冲区,接受一行字符,有错可及时纠正。 # :退格符; @ :退行符

3.2.2 文字编辑器

Page 31: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 31 页2023年4月24日 星期一

SqStack s;EDIT(){ char c;

InitStack(&s); c = getchar(); while (c!=‘`’) { if (c==‘#’) Pop(&s); else if (c==‘@’) InitStack(&s);

else Push(&s,c); c = getchar();}}

3.2.2 文字编辑器

Page 32: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 32 页2023年4月24日 星期一

( 这是栈应用的典型例子 )这里,表达式求值的算法是 “算符优先法”。

如: 3* ( 7 – 2 ) ( 1 )要正确求值,首先了解算术四则运算的规则: 从左算到右;先乘除,后加减;先括号内,后括号外 由此,此表达式的计算顺序为: 3* ( 7 – 2 ) = 3 * 5 = 15

3.2.3 表达式求值

Page 33: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 33 页2023年4月24日 星期一

( 2 )根据上述三条运算规则,在运算的每一步中,对任意相继出现的算符 1 和 2 ,都要比较优先权关系。 算符优先法所依据的算符间的优先关系见下表

算符间的优先关系Ø1      Ø2

 +  -  *    / ( ) #

+-*/()#

> > < < < > >> > < < < > > > > < < < > >> > < < < > > > > > > < > >> > > > < > > > > > > < > >> > > > < > > < < < < < =< < < < < = > > > > > >> > > > > > < < < < < =< < < < < =

3.2.3 表达式求值

Page 34: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 34 页2023年4月24日 星期一

( 3 )算法思想:• 设定两栈:操作符栈 OPTR ,操作数栈 OPND• 栈初始化:设操作数栈 OPND 为空;操作符栈

OPTR 的栈底元素为表达式起始符 ‘ #’ ;• 依次读入字符:是操作数则入 OPND 栈,是操作符则要判断: 若 操作符 < 栈顶元素,则退栈、计算,结果压

入 OPND 栈; 操作符 = 栈顶元素且不为‘ #’ ,脱括号(弹出左括号); 操作符 > 栈顶元素,压入 OPTR 栈。

3.2.3 表达式求值

Page 35: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 35 页2023年4月24日 星期一

OPTR OPND INPUT OPERATE

3*(7-2)# Push(opnd,’3’)

#*(7-2)#3# Push(optr,’*’)

#,* 3 (7-2)# Push(optr,’(’)#,*,( 3 7-2)# Push(opnd,’7’

)#,*,( 3,7 -2)# Push(optr,’-’)#,*,(,- 3,7 2)# Push(opnd,’2’

)#,*,(,- 3,7,2 )# Operate(7-2)#,*,( 3,5 )# Pop(optr)#,* 3,5 # Operate(3*5)# 15 # GetTop(opnd)

3.2.3 表达式求值

Page 36: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 36 页2023年4月24日 星期一

Status EvaluateExpression( OperandType &result) {

InitStack(OPND); InitStack(OPTR);Push(OPTR ,’#’);c=getchar(); while((c!=‘#’)||(GetTop(OPTR)!=‘#’)) {

if (!In(c,OP) { Push(OPND,c); c=getchar();}

else switch(compare(c,GetTop(OPTR)))

{case ‘>’ : Push(OPTR , c); c=getchar();break;

case ‘=’: Pop(OPTR);c=getchar();break;

case ‘<’ : temat=Pop(OPTR); b=Pop(OPND);a=Pop(OPND); result= Operate(a,temat,b);Push(OPND,result);result= Operate(a,temat,b);Push(OPND,result);

3.2.3 表达式求值

Page 37: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 37 页2023年4月24日 星期一

c=getchar();break; } //switch }//while

result=GetTop(OPND);}//EvaluateExpression

3.2.3 表达式求值

Page 38: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 38 页2023年4月24日 星期一

Status In(char Test,char* TestOp) { bool Find=false; for (int i=0; i< OPSETSIZE; i++) { if (Test == TestOp[i]) Find= true; } return Find; }

float Operate(float a,unsigned char theta, float b) { switch(theta) { case '+': return a+b; case '-': return a-b; case '*': return a*b; case '/': return a/b; default : return 0; } }

3.2.3 表达式求值

Page 39: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 39 页2023年4月24日 星期一

int ReturnOpOrd(char op,char* TestOp) { int i; for(i=0; i< OPSETSIZE; i++) { if (op == TestOp[i]) return i; } return 0; }

char precede(char Aop, char Bop) { return Prior[ReturnOpOrd(Aop,OPSET)][ReturnOpOrd(Bop,OPSET)];}

3.2.3 表达式求值

Page 40: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 40 页2023年4月24日 星期一

#define OPSETSIZE 7unsigned char Prior[7][7] = { // 表 3.1 算符间的优先关系 '>','>','<','<','<','>','>',

'>','>','<','<','<','>','>', '>','>','>','>','<','>','>', '>','>','>','>','<','>','>', '<','<','<','<','<','=',' ', '>','>','>','>',' ','>','>', '<','<','<','<','<',' ','=‘ };

float Operate(float a, unsigned char theta, float b);char OPSET[OPSETSIZE]={'+' , '-' , '*' , '/' ,'(' , ')' , '#'};Status In(char Test,char* TestOp);char precede(char Aop, char Bop);

3.2.3 表达式求值

Page 41: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 41 页2023年4月24日 星期一

通常用的是“穷举求解”的方法3.2.4 基于栈的迷宫求解

Page 42: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 42 页2023年4月24日 星期一

求迷宫路径算法的基本思想是:(回溯)若当前位置“可通”,则纳入路径,继续前进 ;

若当前位置“不可通”,则后退,换方向继续探索 ;

若四周“均无通路”,则将当前位置从路径中删除出去并退回到前一位置继续下一方向的探索。 为了保证在任何位置上都能沿原路退回,显然需要用一个后进先出的结构来保存从入口到当前位置的路径。因此,在本算法中应用“栈”是很自然的事。

3.2.4 基于栈的迷宫求解

Page 43: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 43 页2023年4月24日 星期一

需要解决的 4 个问题 :( 1 )表示迷宫的数据结构。设迷宫为 M 行 N 列,利用 maze[M][N] 来表示一个迷宫, maze[i][j] = 0或 1 ,其中 0 表示通道, 1 表示墙(不通)。当从某点向下试探时,中间点有 8 个方向可以试探,而 4个角点有 3 个方向,其他边缘点有 5 个方向,为使问题简单化我们用 maze[M + 2][N + 2] 来表示迷宫,而迷宫四周的值全部为 1 。这样,每个点都有 8 个试探方向,不用再判断当前点的试探方向有几个,同时与迷宫周围是墙壁这一实际问题相一致。

3.2.4 基于栈的迷宫求解

Page 44: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 44 页2023年4月24日 星期一

设入口坐标为( 1 , 1 ),出口坐标为( 6 ,8 )迷宫的定义如下: #define M 6 //迷宫的实际行 #define N 8 //迷宫的实际列 int maze [M+2][N+2];

3.2.4 基于栈的迷宫求解

Page 45: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 45 页2023年4月24日 星期一

3.2.4 基于栈的迷宫求解

Page 46: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 46 页2023年4月24日 星期一

( 2 )试探方向。在上述迷宫中,每个点有 8 个方向可以试探,若当前点的坐标为( x , y ),则与其相邻的 8 个点的坐标都可根据与该点的相邻方位而得到。因为出口在( M , N ),因此试探顺序规定为:从当前位置向前试探的方向为从正东沿顺时针方向进行。为了简化问题,方便地求出新点的坐标,将从正东开始沿顺时针进行的这 8 个方向的坐标增量放在一个结构体数组 move[8] 中,在move 数组中,每个元素由两个域组成, x :横坐标增量, y :纵坐标增量。

3.2.4 基于栈的迷宫求解

Page 47: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 47 页2023年4月24日 星期一

3.2.4 基于栈的迷宫求解

Page 48: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 48 页2023年4月24日 星期一

move 数组定义如下: typedef struct { int x, y; } item ; item move[8] ; 这样可以很方便地求出从某点( x , y )按某一方向 v ( 0≤v≤7 )到达的新点( i , j )的坐标: i =x + move[v].x ; j = y + move[v].y 。

3.2.4 基于栈的迷宫求解

Page 49: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 49 页2023年4月24日 星期一

( 3 )栈的设计。当到达了某点而无路可走时需返回前一点,再从前一点开始向下一个方向继续试探。因此,压入栈中的不仅是顺序到达的各点的坐标,而且还要有从当前点到达下一点的方向序号。对于前述迷宫,依次入栈的顺序如下图

3.2.4 基于栈的迷宫求解

Page 50: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 50 页2023年4月24日 星期一

3.2.4 基于栈的迷宫求解

Page 51: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 51 页2023年4月24日 星期一

栈中每一组数据是所到达的每点的坐标及从该点沿哪个方向向下走的,对于所述迷宫,走的路线为:(1 , 1)1→(2 , 2)1→(3 , 3)0→(3 , 4)0→(3 , 5)0→(

3 , 6)0 (下标表示方向)。当从点( 3 , 6 )沿方向 0 到达点( 3 , 7 )之后,无路可走,则应回溯,即退回到点( 3 , 6 ),对应的操作是出栈,接着沿下一个方向即方向 1继续试探,方向 1 、 2 试探失败,在方向 3 上试探成功,因此将( 3 , 6 , 3 )压入栈中,即到达了点( 4 , 5 )。

3.2.4 基于栈的迷宫求解

Page 52: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 52 页2023年4月24日 星期一

栈中元素是一个由行、列、方向组成的三元组,栈中元素的类型定义如下: typedef struct { int x , y , d ; //横纵坐标及方向 }ElemType ; SqStack s ; // 栈的定义

3.2.4 基于栈的迷宫求解

Page 53: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 53 页2023年4月24日 星期一

( 4 )如何防止重复到达某点,以避免发生死循环。 一种方法是另外设置一个标志数组 mark[M][N] ,它的所有元素都初始化为 0 ,一旦到达了某一点( i ,j )后,使 mark[i][j] 置 1 ,下次再试探这个位置时就不能再走了。另一种方法是当到达某点( i , j )后使 maze[i][j] 置- 1 ,以便区别未到达过的点,同样也能起到防止走重复点的目的,我们采用后面一种方法。

3.2.4 基于栈的迷宫求解

Page 54: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 54 页2023年4月24日 星期一

①栈初始化。②将入口点坐标及到达该点的方向 ( 设为- 1) 入栈。③while (栈不空){ 栈顶元素出栈 ; 求出下一个要试探的方向 d++; while (还有剩余试探方向 ) { if (d 方向可走 ) 则 {(x,y,d) 入栈 ; 求新点坐标 (i,j); 将新点 (i,j)切换为当前点 (x,y); if ( 点 (x, y ) 为出口点 ) 结束 ; else 重置 d=0 ; } else d++; } }

3.2.4 基于栈的迷宫求解

Page 55: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 55 页2023年4月24日 星期一

int mazepath(int maze[M+2][N+2], item move[8]){ // 若迷宫maze 中存在从入口 (1,1) 到出口 (M,N) 的

通 // 道 , 则 求得一条存放在栈中 , 并返回 1; SqStack s; ElemType temp; int x,y,d,i,j; InitStack(&s); // 栈初始化 temp.x=1; temp.y=1; temp.d=-1; Push(&s,temp); while(!StackEmpty(s)) { Pop(&s,&temp); x=temp.x; y=temp.y; d=temp.d+1;

3.2.4 基于栈的迷宫求解

Page 56: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 56 页2023年4月24日 星期一

while(d<8){ i=x+move[d].x; j=y+move[d].y; if (maze[i][j]==0) { temp.x=x; temp.y=y; temp.d=d; //坐标及方向 Push(&s,temp); //坐标及方向入栈 x=i; y=j; maze[x][y]=-1; // 到达新点 if (x==M&&y==N) { printpath (s); // 输出路径 return 1; } //迷宫有路 else d=0; }// if else d++; } } return 0; } //迷宫无路

3.2.4 基于栈的迷宫求解

Page 57: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 57 页2023年4月24日 星期一

void printpath(SqStack s){ // 输出迷宫路径,栈中保存的就是一条迷宫的通路 ElemType temp; printf("(%d,%d)<--", M, N); while(!StackEmpty(s)) { Pop(&s, &temp); printf ("(%d,%d)<--", temp.x, temp.y); } printf("\n"); }

3.2.4 基于栈的迷宫求解

»ùÓÚÕ»µÄÃÔ¹¬Çó½â»ùÓÚÕ»µÄÃÔ¹¬Çó½â

Page 58: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 58 页2023年4月24日 星期一

3.3.1 队列的定义及基本操作3.3.2 顺序队列3.3.3 链队列

Page 59: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 59 页2023年4月24日 星期一

队列 (Queue) 也是一种运算受限的线性表。它只允许在表的一端进行插入,而在另一端进行删除。允许删除的一端称为队头 (front) ,允许插入的一端称为队尾 (rear) 。

如:排队购物。操作系统中的作业排队。先进入队列的成员总是先离开队列。因此队列亦称作先进先出(First In First Out) 的线性表,简称 FIFO 表。

3.3.1 队列的定义及基本操作1 、队列的定义

Page 60: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 60 页2023年4月24日 星期一

   当队列中没有元素时称为空队列。在空队列中依次加入元素 a1,a2,…an之后, a1 是队头元素, an 是队尾元素。显然退出队列的次序也只能是 a1,a2,…an ,也就是说队列的修改是依先进先出的原则进行的。

3.3.1 队列的定义及基本操作1 、队列的定义

Page 61: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 61 页2023年4月24日 星期一

数据对象: D={ai|ai ElemSet,i=1,∈ …n,n ≥ 0}

队列的抽象数据定义:ADT Queue{

数据关系: R1={< ai-1,ai>|a i-1,ai D, i=1,∈ …n

}约定 a1 端为队列头, an 端为队列尾。基本操作 : (见后面)} ADT Queue

3.3.1 队列的定义及基本操作

Page 62: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 62 页2023年4月24日 星期一

( 1 )初始化队列 InitQueue(&Q) 将队列 Q 设置成一个空队列。( 2 )入队列 EnQueue(&Q,X) 将元素 X 插入到队尾中,也称“进队” ,“插入”。( 3 )出队列 DeQueue(&Q,&e) 将队列 Q 的队头元素删除,并用 e 返回其值,也称“退队”、“删除”。

3.3.1 队列的定义及基本操作2 、队列的基本操作

Page 63: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 63 页2023年4月24日 星期一

( 4 )取队头元素 GetHead(Q,&e) 得到队列 Q 的队头元素之值,并用 e 返回其值。( 5 )判队空 QueueEmpty(Q) 判断队列 Q 是否为空,若为空返回 1 ,否则返回0 。

3.3.1 队列的定义及基本操作2 、队列的基本操作

Page 64: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 64 页2023年4月24日 星期一

队列的顺序存储结构称为顺序队列。由于队列的队头和队尾的位置是变化的,因而要设两个指针分别指示队头和队尾元素在队列中的位置,它们的初始值在队列初始化时均应置为0。入队时将新元素插入所指的位置,然后尾指针加1。出队时,删去所指的元素,然后头指针加1并返回被删元素。由此可见,当头尾指针相等时队列为空。在非空队列里,头指针始终指向队头元素,而尾指针始终指向队尾元素的下一位置。

3.3.2 顺序队列1 、顺序队列的存储结构

Page 65: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 65 页2023年4月24日 星期一

#define MAXQSIZE 100typedef struct{ ElemType data[MAXQSIZE];

int front;

int len;

}SqQueue;

int rear;

3.3.2 顺序队列1 、顺序队列的存储结构

Page 66: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 66 页2023年4月24日 星期一

0  1 2  3 0 1 2 3

 Frontrear

a b c

Front rear

(a) 队列初始为空 0 1  2  3    0  1  2  3

b c

front rear

( b ) a,b,c 入队

front

rear ( c) a 出队 (d) b,c 出队,队为空

3.3.2 顺序队列

Page 67: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 67 页2023年4月24日 星期一

队空: Q.front==Q.rear

队满: Q.rear==maxsize (假溢出)求队长: Q.rear-Q.front

入队: 新元素按 rear 指示位置加入,再将队尾指针加一 ,即 rear = rear + 1

出队: 将 front 指示的元素取出,再将队头指针加一,即 front = front + 1

3.3.2 顺序队列1 、顺序队列的存储结构非循环队列

Page 68: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 68 页2023年4月24日 星期一

和栈类似,队列中亦有上溢和下溢现象。此外,顺序队列中还存在“假上溢”现象。因为在入队和出队的操作中,头尾指针只增加不减小,致使被删除元素的空间永远无法重新利用。因此,尽管队列中实际的元素个数远远小于向量空间的规模,但也可能由于尾指针巳超出向量空间的上界而不能做入队操作。该现象称为假上溢。

3.3.2 顺序队列1 、顺序队列的存储结构

Page 69: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 69 页2023年4月24日 星期一

为充分利用向量空间,克服上述假上溢现象,可以将向量空间想象为一个首尾相接的圆环,并称这种向量为循环向量,存储在其中的队列称为循环队列( Circular Queue) 。在循环队列中进行出队、入队操作时,头尾指针仍要加 1 ,朝前移动。只不过当头尾指针指向向量上界( QueueSize-1 )时,其加 1 操作的结果是指向向量的下界 0 。

3.3.2 顺序队列1 、顺序队列的存储结构

Page 70: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 70 页2023年4月24日 星期一

显然,因为循环队列元素的空间可以被利用,除非向量空间真的被队列元素全部占用,否则不会上溢。因此,除一些简单的应用外,真正实用的顺序队列是循环队列。

3.3.2 顺序队列1 、顺序队列的存储结构

Page 71: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 71 页2023年4月24日 星期一

由于入队时尾指针向前追赶头指针,出队时头指针向前追赶尾指针,故队空和队满时头尾指针均相等。因此,我们无法通过 Q.front==Q.rear 来判断队列“空”还是“满”。 解决此问题的方法至少有两种: 其一是另设一个布尔变量以区别队列的空和满;其二是少用一个元素的空间,约定入队前,测试尾指针在循环意义下加 1 后是否等于头指针,若相等则认为队满(注意: rear 所指的单元始终为空)

3.3.2 顺序队列1 、顺序队列的存储结构

Page 72: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 72 页2023年4月24日 星期一

01

234

5

rearfront

J4J5

J601

234

5

rear

frontJ3

J8J7

J3

J4J5

01

234

5

rear

front

初始状态

J3,J4,J5 出队J6,J7,J8 入队

队空: front==rear队满: front==rear

解决方案:(1)另设一个标志区别队空、队满(2)少用一个元素空间: 队空: front==rear 队满: (rear+1)%M==front

Page 73: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 73 页2023年4月24日 星期一

队空:循环队列

Q.front ==Q. rear

队满: Q.front ==(Q.rear + 1) % maxSize

入队 : Q.rear = (Q.rear + 1) % maxSize

出队 : Q.front = (Q.front + 1) % maxSize

求队长 : (Q.rear-Q.front+maxSize)%maxSize

3.3.2 顺序队列1 、顺序队列的存储结构

Page 74: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 74 页2023年4月24日 星期一

3.3.2 顺序队列1 、顺序队列的存储结构

Page 75: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 75 页2023年4月24日 星期一

①检查队列是否已满,若队满,则进行溢出处理;②将新元素赋给队尾指针所指单元; ③将队尾指针后移一个位置,指向下一单元。

Status EnQueue (SqQueue &Q, ElemType e) { if((Q.rear+1)%MAXQSIZE==Q.front)

return(ERROR); Q.data[Q.rear]=e;

Q.rear=(Q.rear+1)%MAXQSIZE; return(OK); }

( 1 )进队列3.3.2 顺序队列

2 、顺序队列的基本运算

Page 76: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 76 页2023年4月24日 星期一

( 2 )出队列①检查队列是否为空,若队空,则进行下溢处理;②取队首元素的值。③将队首指针后移一个位置(即加 1 );Status DeQueue (SqQueue &Q, ElemType &e)

{ if (Q.rear== Q.front) return(ERROR); e=Q.data[Q.front]; Q.front=(Q.front+1)%MAXQSIZE; return(OK); }

3.3.2 顺序队列2 、顺序队列的基本运算

Page 77: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 77 页2023年4月24日 星期一

( 4 )取队头元素( 3 )队列初始化

Q.front=Q.rear=0;

ElemType GetHead(SqQueue Q ){ if (Q.front= =Q.rear) return(ERROR);

return (Q.data[Q.front]); }( 5 )判队列空否int QueueEmpty(SqQueue Q ){ if (Q.front= =Q.rear) reurn (1);

else return (0); }

3.3.2 顺序队列

Page 78: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 78 页2023年4月24日 星期一

队列的链式存储结构简称为链队列,它是限制仅在表头删除和表尾插入的单链表。显然仅有单链表的头指针不便于在表尾做插入操作,为此再增加一个尾指针,指向链表的最后一个结点。于是,一个链队列由头指针和尾指针唯一确定。

3.3.3 链队列1 、链队列的存储结构

Page 79: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 79 页2023年4月24日 星期一

∧*q

q.frontq.rear

非空队列q.frontq.rear ∧

空队列

*q

3.3.3 链队列1 、链队列的存储结构

Page 80: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 80 页2023年4月24日 星期一

和顺序队列类似,我们也是将这两个指针封装在一起,将链队列的类型 LinkQueue 定义为一个结构类型: typedef struct queuenode{

ElemType data; struct queuenode *next; }QueueNode;typedef struct{ QueueNode *front; QueueNode *rear; }LinkQueue;

3.3.3 链队列1 、链队列的存储结构

Page 81: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 81 页2023年4月24日 星期一

( 1 )构造一个空队列 void InitQueue(LinkQueue &Q){ Q.front=Q.rear=(queuenode *)malloc (sizeof(queuenode ));

Q.front->next=Q.rear->next=NULL;}

3.3.3 链队列2 、链队列的基本运算

Page 82: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 82 页2023年4月24日 星期一

( 2 )队列的判空 int QueueEmpty(LinkQueue Q) {

return (Q.front->next= =NULL && Q.rear->next= =NULL); }

3.3.3 链队列2 、链队列的基本运算

Page 83: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 83 页2023年4月24日 星期一

void EnQueue(LinkQueue &Q,ElemType e){ QueueNode *p;

p=(QueueNode * )malloc(sizeof(QueueNode)); p–>data=x; p–>next=NULL; Q.rear–>next=p; Q.rear=p; }

*qq.frontq.rear

( 3 )入队x

p

∧∧

3.3.3 链队列2 、链队列的基本运算

Page 84: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 84 页2023年4月24日 星期一

∧*q

q.rear x ∧q.front

p

存储池

( 4 )出队

Status DeQueue(LinkQueue &Q,ElemType &e) { QueueNode *p;

if (QueueEmpty(Q)) return ERROR; p=Q.front->next; e=p–>data; Q.front->next=p–>next; if(Q.rear = =p) Q.rear=Q.front; free(p); return OK; }

3.3.3 链队列

Page 85: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 85 页2023年4月24日 星期一

frontrear

x ^ 元素 x 入队frontrear

x y ^ 元素 y 入队frontrear

x ^y 元素 x 出队

frontrear ^

空队列^ frontrear NULL 空队列

3.3.3 链队列2 、链队列的基本运算

Page 86: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 86 页2023年4月24日 星期一

3.4.1 CPU 资源的竞争问题3.4.2 主机与外设速度不匹配问题3.4.3 基于队列的迷宫求解

Page 87: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 87 页2023年4月24日 星期一

3.4.1 CPU 资源的竞争问题 第一个例子: CPU资源的竞争问题。在具有多个终端的计算机系统中,有多个用户需要使用CPU各自运行自己的程序,它们分别通过各自终端向操作系统提出使用 CPU 的请求,操作系统按照每个请求在时间上的先后顺序,将其排成一个队列,每次把 CPU分配给队头用户使用,当相应的程序运行结束,则令其出队,再把 CPU分配给新的队头用户,直到所有用户任务处理完毕。

Page 88: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 88 页2023年4月24日 星期一

第二个例子:主机与外部设备之间速度不匹配的问题。以主机和打印机为例来说明,主机输出数据给打印机打印,主机输出数据的速度比打印机打印的速度要快得多,若直接把输出的数据送给打印机打印,由于速度不匹配,显然是不行的。

3.4.2 主机与外设速度不匹配问题

Page 89: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 89 页2023年4月24日 星期一

解决的方法是设置一个打印数据缓冲区,主机把要打印输出的数据依次写入到这个缓冲区中,写满后就暂停输出,继而去做其它的事情,打印机就从缓冲区中按照先进先出的原则依次取出数据并打印,打印完后再向主机发出请求,主机接到请求后再向缓冲区写入打印数据,这样利用队列既保证了打印数据的正确,又使主机提高了效率。

3.4.2 主机与外设速度不匹配问题

Page 90: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 90 页2023年4月24日 星期一

【例】求迷宫的最短路径,要求设计一个算法找一条从迷宫入口到出口的最短路径。 【算法思想】 从迷宫入口点( 1 , 1 )出发,向四周搜索,记下所有一步能到达的坐标点;然后依次再从这些点出发,再记下所有一步能到达的坐标点,……,依此类推,直到到达迷宫的出口点( M , N )为止,然后从出口点沿搜索路径回溯直至入口。这样就找到了一条迷宫的最短路径,否则迷宫无路径。

3.4.3 基于队列的迷宫求解

Page 91: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 91 页2023年4月24日 星期一

搜索路径存储:在搜索过程中必须记下每一个可到达的坐标点,以便据此继续向四周搜索。由于先到达的点先向下搜索,故引进队列来保存已到达的坐标点。到达迷宫的出口点( M , N )后,为了能够从出口点沿搜索路径回溯直至入口,对于每一点,记下坐标点的同时,还要记下到达该点的前驱点。

3.4.3 基于队列的迷宫求解

Page 92: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 92 页2023年4月24日 星期一

因此,用一个结构体数组 elem[MAXSIZE] 作为队列的存储空间,因为迷宫中每个点至多被访问一次,所以 MAXSIZE至多等于 M×N 。该结构体有三个域:x 、 y 和 pre ,其中 x 、 y分别为所到达的点的坐标,pre 为前驱点在 elem 中的下标。除此之外,还需设定头、尾指针: front 和 rear分别指向队头和队尾元素 。

3.4.3 基于队列的迷宫求解

Page 93: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 93 页2023年4月24日 星期一

队列的类型定义:#define M 6#define N 8#define MAXSIZE M*Ntypedef struct{ int x, y; int pre;}ElemType;Typedef struct{ ElemType elem[MAXSIZE]; int front, rear;}SqQueue;

初始状态:队列中只有一个元素 elem[0] ,记录的是入口点的坐标( 1 , 1 ),因为该点是出发点,因此没有前驱点, pre 域为- 1 ,头指针 front 和尾指针 rear均指向它,此后搜索时都是以front 所指点为搜索的出发点。

3.4.3 基于队列的迷宫求解

Page 94: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 94 页2023年4月24日 星期一

Page 95: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 95 页2023年4月24日 星期一

【算法】基于队列的迷宫求解算法 int mazepath(int maze[M+2][N+2], item move[8]){ //采用队列的迷宫算法。 Maze[M+2][N+2] 表示迷宫 // 数组 , move[8] 表示坐标增量数组SqQueue q; int x,y,i,j,v; ElemType head,e; InitQueue(&q); e.x=1; e.y=1; e.pre=-1; EnQueue(&q, e); // 入口点入队 maze[1][1]=-1; while (!QueueEmpty(q)) { GetHead(q, &head); //读出队头元素 x=head.x; y=head.y;

3.4.3 基于队列的迷宫求解

Page 96: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 96 页2023年4月24日 星期一

for(v=0; v<8; v++) { i=x+move[v].x; j=y+move[v].y; if(maze[i][j]==0) { e.x=i; e.y=j; e.pre=q.front; EnQueue(&q, e); // 将可到达点入队 maze[i][j]=-1; } if(i==M&&j==N) { printpath(q); // 输出路径 return 1; } //迷宫有路 } DeQueue(&q, &head); // 当前点搜索完 8 个方向后出队 }// while return 0; } //迷宫无路

3.4.3 基于队列的迷宫求解

Page 97: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 97 页2023年4月24日 星期一

void printpath (SqQueue q){// 输出迷宫路径 int i; i=q.rear-1; do{ printf("(%d,%d)<--", (q.elem[i]).x,

(q.elem[i]).y); i=(q.elem[i]).pre; // 回溯 }while(i!=-1); printf("\n");}

3.4.3 基于队列的迷宫求解

Page 98: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 98 页2023年4月24日 星期一

运行结果:( 6 , 8 )←( 5 , 7 )←( 4 , 6 )←( 4 , 5 )←( 3 , 4 )←( 3 , 3 )←( 2 , 2 )←( 1 ,1 ) 该例若用“基于栈的迷宫求解”算法得到的路径是 :( 6 , 8 )←( 5 , 8 )←( 5 , 7 )←( 4 , 6 )←( 4 , 5 )←( 3 , 4 )←( 3 , 3 )←( 2 ,2 )←( 1 , 1 )

»ùÓÚ¶ÓÁеÄÃÔ¹¬Çó½â »ùÓÚ¶ÓÁеÄÃÔ¹¬Çó½â

3.4.3 基于队列的迷宫求解

Page 99: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 99 页2023年4月24日 星期一

顺序栈的存储结构及基本运算 链栈的存储结构及基本运算 栈的应用:数制转换、表达式求值、迷宫

问题 顺序队列的存储结构及基本运算 链队列的存储结构及基本运算 栈的应用:迷宫问题

本章小结

Page 100: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 100 页2023年4月24日 星期一

作业第 3 章习题: 2 、 3 、 5 、 7 、 8

Page 101: 数据结构 Data Structure

数据结构 第 3 章 栈与队列

µç×Ó½Ì±Þ 共 101 页 第 101 页2023年4月24日 星期一