67
3 3 第 第第第第 第 第第第第

第 3 章 栈和队列

  • Upload
    kimo

  • View
    96

  • Download
    4

Embed Size (px)

DESCRIPTION

第 3 章 栈和队列. 复习总结:. 线性表的顺序存储与链式存储的特点对比 链式存储的三种类型: 单链表,双向链表,循环链表. ( 1 )顺序表 优点 : 随机存取 ; 存储空间利用率高 缺点 : 插入、删除需移动元素 ( 2 )链表: 优点 : 插入、删除不需移动元素 缺点 : 不能随机存取 ; 存储空间利用率不高. s=(LNode*)malloc(sizeof(LNode)); s->data=a[i];. q=p→next; p→next=q→next; - PowerPoint PPT Presentation

Citation preview

Page 1: 第 3 章 栈和队列

第第 33 章 栈和队章 栈和队列列

Page 2: 第 3 章 栈和队列

复习总结:• 线性表的顺序存储与链式存储的特点对比

• 链式存储的三种类型:单链表,双向链表,循环链表

( 1)顺序表优点 : 随机存取 ; 存储空间利用率高缺点 : 插入、删除需移动元素( 2 )链表:优点 : 插入、删除不需移动元素缺点 : 不能随机存取 ; 存储空间利用率不高

q=p→next; p→next=q→next;e=qdata;free(q); r->next=s;

r=r->next;s->next =c->next; c->next=s;

s=(LNode*)malloc(sizeof(LNode));s->data=a[i];

Page 3: 第 3 章 栈和队列

主要内容

• 栈和队列是操作受限的线性表。• 重点:

–栈和队列的定义–表示方法、实现、–应用实例

Page 4: 第 3 章 栈和队列

3.1 3.1 栈栈

11 、栈的基本概念、栈的基本概念– 栈:栈:限定仅在限定仅在表尾表尾进行插入和删除操作的进行插入和删除操作的线性线性

表表– 空栈:空栈:不含任何数据元素的栈。不含任何数据元素的栈。– 允许插入和删除的一端称为允许插入和删除的一端称为栈顶栈顶– 另一端称为另一端称为栈底栈底。。1.1. 顺序栈:需要一个记录栈顶元素所在数组位置顺序栈:需要一个记录栈顶元素所在数组位置

标号的整形变量标号的整形变量2.2. 链式栈:需要一个记录栈顶元素所在结点地址链式栈:需要一个记录栈顶元素所在结点地址

的指针的指针

Page 5: 第 3 章 栈和队列

abc

入栈 出栈

栈底

栈顶 插入:入栈、进栈、压栈插入:入栈、进栈、压栈

删除:出栈、弹栈删除:出栈、弹栈栈顶栈顶

栈的示意图栈的示意图

11 、栈的基本概念、栈的基本概念

栈顶

Page 6: 第 3 章 栈和队列

栈的操作特性:栈的操作特性:后进先出后进先出

abc

入栈 出栈

栈底

栈顶 插入:入栈、进栈、压栈

删除:出栈、弹栈

11 、栈的基本概念、栈的基本概念

栈的示意图栈的示意图

栈顶

Page 7: 第 3 章 栈和队列

如何改造数组实现栈的顺序存储?如何改造数组实现栈的顺序存储?

1 、确定用数组的哪一端表示栈底。

2 、附设指针 top 指示栈顶元素在数组中的位置。

22 、栈的顺序存储结构及实现、栈的顺序存储结构及实现————顺序顺序栈栈

Page 8: 第 3 章 栈和队列

typedef struct { selemtype *base; // 栈底指针 Selemtype *top; // 栈顶指针 Int stacksize; // 栈当前可用的最大容量 }seqstack;

22 、栈的顺序存储结构及实现、栈的顺序存储结构及实现————顺序栈顺序栈

Int data[maxsize];Int top;

#define maxsize 100Typedef struct{Int data[maxsize];Int length;}sqlist

#define LIST_INIT_SIZE 100#define LISTINCREAMENT 10type struct{

ElemType *elem;// 存储空间基址int length;int listsize;

}SqList// 线性表顺序存储结构定义:指针

Page 9: 第 3 章 栈和队列

22 、栈的顺序存储结构及实现、栈的顺序存储结构及实现————顺序栈顺序栈

顺序栈的操作算法:(顺序栈的操作算法:( P38-39P38-39 ))初始化 初始化 SeqStack( ) SeqStack( ) 取栈顶元素 取栈顶元素 Top(S ) Top(S ) • 二个状态:二个状态:1.1. 判断栈空: 判断栈空: Empty( Empty(

)) :: st.top=-1//st.top=st.basest.top=-1//st.top=st.base

2.2. 判断栈满:判断栈满: st.top==maxsize-1 st.top==maxsize-1 • 两个操作:两个操作:1.1. 入栈 入栈 Push(St x): st.data[st.top]=x;++(st.top)Push(St x): st.data[st.top]=x;++(st.top)

2.2. 出栈 出栈 Pop( St) : x= st.data[st.top]; --(st.top)Pop( St) : x= st.data[st.top]; --(st.top)

Page 10: 第 3 章 栈和队列

算法讲解 (1) 置栈空SETNULL(seqstack *s)

{ s->top=-1;

}( 2 ) 判栈空 int EMPTY ( seqstack s ){if (s->top>=0) return FALSE; else return TRUE;}

Page 11: 第 3 章 栈和队列

算法讲解( 3 ) 进栈seqstack *PUSH ( seqstack *s ,datatype x ){if (s->top= = maxsize-1)

{printf(“overflow”); return NULL;}

else { s->data[++s->top]=x; return s; }

}

( 4 ) 退栈datatype POP ( seqstack *s ){if (EMPTY(s)) {printf(“overflow”); return NULL;} else return( s->data[s->top--]);}

s->data[s->top]=x ; ++s->top

s->data[s->top]); s->top--;

Page 12: 第 3 章 栈和队列

算法讲解 P58.1 顺序栈• 编写算法,判断一个表达式中的括号是否正确配对,表达

式已存入字符数组 exp[] 中 ( 元素从数组下标 1 开始存储 ) ,表达式中字符个数为 n

Int match(char exp[],int n){char stack[maxsize]; int top=-1;Int i;For(i=1;i<=n;++i) { If(exp[i]==‘(‘) stack[++top]=‘(‘; If(exp[i]==‘)‘) {if(top==-1) return 0 else --top;} }If(top==-1) return 1; else return 0;}

Page 13: 第 3 章 栈和队列

算法实例:数制转换• 将十进制数 N 转换成 d 进制 N=(N div d)*d + N mod d• 计算过程是从低位到高位顺序产生 d 进制数的各个数位。• 算法思想:

void conversion(seqstack *s)

{SETNULL(s);

scanf(“%d%d”,N,d);

while(N)

{PUSH(s,N%d); N=N/d; }

while(!EMPTY(s))

{e=pop(s); printf(“%d”,e);}

将计算过程的 d 进制数逐位进栈,然后逐个出栈。

Page 14: 第 3 章 栈和队列

考试中实用的写法:• 声明一个栈并初始化

Int stack[maxsize]; int top=-1

• 元素 X 进栈stack[++top]=x

• 元素 X 出栈:X = stack[top--];

Page 15: 第 3 章 栈和队列

考研真题1. 名词解释:栈。【燕山大学 1999 一、 1 ( 2 分)】【吉林工

业大学 1999 一、 3 ( 2 分)】5. 有 5 个元素,其入栈次序为: A , B , C , D , E ,在各种

可能的出栈次序中,以元素 C , D 最先出栈(即 C 第一个且 D第二个出栈)的次序有哪几个?【西南交通大学 2000 二、 1 】

6. 如果输入序列为 1 2 3 4 5 6, 试问能否通过栈结构得到以下两个序列 :4 3 5 6 1 2 和 1 3 5 4 2 6; 请说明为什么不能或如何才能得到。【武汉交通科技大学 1996 二、 3 (3 分 ) 】

7. 若元素的进栈序列为: A 、 B 、 C 、 D 、 E ,运用栈操作,能否得到出栈序列 B 、 C 、 A 、 E 、 D 和 D 、 B 、 A 、 C 、 E ?为什么?【北京科技大学 98 一、 2 】

8. 设输入序列为 a,b,c,d, 试写出借助一个栈可得到的两个输出序列和两个不能得到的输出序列。【北京科技大学 2001 一、 4 ( 2分)】

9. 设输入序列为 2 , 3 , 4 , 5 , 6 ,利用一个栈能得到序列 2 ,5 , 3 , 4 , 6 吗?栈可以用单链表实现吗?【山东师范大学 1996 五、 4 ( 2 分)】

1 、栈是只准在一端进行插入和删除操作的线性表,允许插入和删除的一端叫栈顶,另一端叫栈底。最后插入的元素最先删除,故栈也称后进先出( LIFO )表。

5 、三个: CDEBA , CDBEA , CDBAE6 、输入序列为 123456 ,不能得出 435612 ,其理由是,输出序

列最后两元素是 12 ,前面 4 个元素( 4356 )得到后,栈中元素剩12 ,且 2 在栈顶,不可能栈底元素 1 在栈顶元素 2 之前出栈。

得到 135426 的过程如下: 1 入栈并出栈,得到部分输出序列 1 ;然后 2 和 3 入栈, 3 出栈,部分输出序列变为: 13 ;接着 4 和 5入栈, 5 , 4 和 2 依次出栈,部分输出序列变为 13542 ;最后 6 入栈并退栈,得最终结果 135426 。

Page 16: 第 3 章 栈和队列

如何改造链表实现栈的链接存储?如何改造链表实现栈的链接存储?

11 、将哪一端作为栈顶?、将哪一端作为栈顶?

22 、链栈需要加头结点吗?、链栈需要加头结点吗?

33 、栈的链式存储结构及实现、栈的链式存储结构及实现————链栈链栈

Page 17: 第 3 章 栈和队列

链栈• 栈的单链形式 :“前插链表”就是链栈。

由于栈的操作在栈顶,所以,链栈一般不设头结点。

typedef int datatype;

typedef struct node

{ datatype data;

struct node *next;

}node,linkstack,*top;

• 单链表中的每一个结点中只包含一个指针域的称为单链表或线性链表。可由头指针唯一确定,用结构指针来描述。

typedef struc LNode

{   ElemType data;

struct LNode *next

}LNode    

Page 18: 第 3 章 栈和队列

链栈基本算法操作• 栈空: lst->nnxt==Null• 栈满:不存在• 入栈:

• p->next=lst->next; • lst->next=p

• 出栈:• p=lst->next;• x=p->data;• lst->next=p->next; • free(p);

Page 19: 第 3 章 栈和队列

栈的基本操作在链栈下的实现• 压栈(入栈)核心语句有:

p=(linkstack*) malloc(sizeof(node));p->data=x;p->next=top; top=p; /* 无头结点栈 */

• 退栈 pop(s)if (st==null) printf(“\n underflow”);else { p=s->next; s->next=p->next; free(p); }

取栈顶元素 top(s)if (st==null) { printf(“\n underflow”); return NULL;}else return(x=s->data)判栈空 empty(s)if (s==null) return TRUE;;else return(true)

Page 20: 第 3 章 栈和队列

栈的应用• 应用的思想: 在解决问题的过程中出现了一个状态,

但凭现有条件不能判断当前的状态是否可以解决,需要记下,等待以后出现可以解决当前状态的条件后返回再解决。

栈具有记忆功能。

Page 21: 第 3 章 栈和队列

44 、栈的应用、栈的应用

• 中缀表达式求值是程序设计语言编译中的一个最中缀表达式求值是程序设计语言编译中的一个最基本问题。它的实现需要借助栈来完成。这里介基本问题。它的实现需要借助栈来完成。这里介绍一种简单直观,广为使用的算法,即“算符优绍一种简单直观,广为使用的算法,即“算符优先法”。先法”。

• 为实现算符优先算法,可以使用两个工作栈。为实现算符优先算法,可以使用两个工作栈。• 1.1. 运算符运算符 OPTROPTR 栈栈 , , 用以寄存运算符;用以寄存运算符;• 2.2. 操作数操作数 OPNDOPND 栈栈 , , 用以寄存用以寄存操作数或运算结操作数或运算结

果果。。

Page 22: 第 3 章 栈和队列

算法思想:算法思想:

• 11 )首先置操作数栈为空栈,表达式起始符)首先置操作数栈为空栈,表达式起始符““ @”@” 为运算符的栈底元素;为运算符的栈底元素;

• 22 )依次读入表达式中每个字符,若是操作)依次读入表达式中每个字符,若是操作数则进数则进 OPNDOPND 栈,若是运算符,则与栈,若是运算符,则与OPTROPTR 栈的栈顶运算符进行优先级的比较,栈的栈顶运算符进行优先级的比较,若优先级高于栈顶操作符,则入栈;否则,栈顶运算符退栈作相应操作,直至整个表作相应操作,直至整个表达式求值完毕(即达式求值完毕(即 OPTROPTR 栈的栈顶元素和栈的栈顶元素和当前读入的字符均为“当前读入的字符均为“ @”@” )。)。

Page 23: 第 3 章 栈和队列

运算优先级

+ - × / ( ) @

+ > > < < < > >

- > > < < < > >

× > > > > < > >

/ > > > > < > >

( < < < < < =

) > > > > > >

@ < < < < < =

当前运算符

栈顶运算符

Page 24: 第 3 章 栈和队列

考研真题• 19. 用栈实现将中缀表达式 8-(3+5)*(5-6/2)

转换成后缀表达式• 20. 在表达式中,有的运算符要求从右到左

计算,如 A**B**C 的计算次序应为(A**(B**C)) ,这在由中缀生成后缀的算法中是怎样实现的 ?( 以 ** 为例说明 ) 【东南大学1993 一、 2(6 分 ) 1997 一、 1(8 分 ) 】

19 、中缀表达式 8-(3+5)*(5-6/2 )的后缀表达式是: 8 3 5 + 5 6 2 / - * - £¨ 2 £©8 3 5 + 5 6 2

#

*

#

£¨ 3 £©8 3 5 + 5 6 2 / - £¨ 4 £©8 3 5 + 5 6 2 / - * -

-#

*£¨

/ £©

-

-£©

£¨ 1 £©8 3 5

#

£¨+

-

中缀表达式 exp1 转为后缀表达式 exp2 的规则如下:设操作符栈 s ,初始为空栈后,压入优先级最低的操作符‘ #’ 。对中缀表达式从左向

右扫描,遇操作数,直接写入 exp2 ;若是操作符(记为 w ),分如下情况处理,直至表达式 exp1扫描完毕。

( 1 ) w 为一般操作符(’ +’ ,’ -‘ ,’ *’ ,’ /’ 等),要与栈顶操作符比较优先级,若 w 优先级高于栈顶操作符,则入栈;否则,栈顶运算符退栈到 exp2 , w 再与新栈顶操作符作上述比较处理,直至 w 入栈。

( 2 ) w 为左括号(’(’), w 入栈。( 3 ) w 为右括号(’)’),操作符栈退栈并进入 exp2 ,直到碰到左括号为止,左

括号退栈(不能进入 exp2 ),右括号也丢掉,达到 exp2 中消除括号的目的。( 4 ) w 为‘ #’ ,表示中缀表达式 exp1 结束,操作符栈退栈到 exp2 ,直至碰到‘ #’

,退栈,整个操作结束。

简单方法:中缀表达式转为后缀表达式有三步:1. 将中缀表达式中所有的子表达式按计算规则用嵌套

括号括起来;2. 顺序将每对括号中的运算符移到相应括号的后面;3. 删除所有括号。

如,将中缀表达式 8-(3+5)*(5-6/2 )转为后缀表达式。执行完上面第一步后为: (8-((3+5)*(5-(6/2)))) ;执行完上面第二步后为: (8((35)+(5(62)/)-)*)- ;执行完上面第三步后为: 8 3 5 + 5 6 2 / - * - 。

Page 25: 第 3 章 栈和队列

算法讲解:表达式求值:算符优先法OperandType EvaluateExpression(){ //op 为运算符集合InitStack(optr); Push(optr,’#’); //optr 是运算符栈Initstack(opnd); c=getchar(); //opnd 是运算数栈While(c!=‘#’||gettop(optr)!=‘#’){if (!In(c,op){push((opnd,c);c=getchar();} // 不是运算符则进栈Else switch(precede(gettop(optr),c)){Case’<‘:push(optr,c);c=getchar();break;// 栈顶元素优先权低Case’=‘:pop(optr,x); c=getchar();break;Case’>’:pop(optr,theta); //theta 变量用于暂存要计算的算符Pop(opnd,b);pop(opnd,a);push(opnd,operate(a,theta,b));break;}//swich}//whileRetrun gettop(opnd);}evaluateexpression

Page 26: 第 3 章 栈和队列

写出后缀表达式• A*B*C

• (A+B)*D+E/(F+A*D)+C

• (A&&B)||(!(E>F))

Page 27: 第 3 章 栈和队列

算法练习二 P67.1为充分利用空间,顺序栈 S0 , S1共享一个存储区

elem[0,maxsize-1].试设计共享栈 S0 和 S1 ,及有关入栈和出栈的操作算法。栈中

元素为 int 型。1. 给出基本设计思想2. 用 C 描述算法(对于共享栈要写出其结构定义),关键之处给出注释。

思想:顺序栈栈底固定不变,因此将栈底设在存储区的两端, S0 栈底在 0处,S1 栈底在 maxsixe-1处,栈顶在 0 - maxsize-1 之间变动。当两栈相遇时为栈满入栈和出栈的思想:S0 栈顶为 top0, 入栈时: top0 先自增 1 ,然后存入元素出栈时:先取出栈顶元素, top0 再自减 1S1 栈顶为 top1, 入栈时: top1 先自减 1 ,然后存入元素出栈时:先取出栈顶元素, top1 再自增 1算法: P68

Page 28: 第 3 章 栈和队列

小结• 栈的含义及性质• 栈的顺序存储:

• 顺序栈定义•四个操作

• 栈的链式存储:• 链栈的定义• 操作

• 栈的应用

Page 29: 第 3 章 栈和队列

考研英语三、并列关系• P42. 2011年阅读 3 P2S7

• Besides generating income, the presence of other marketers makes the site seem objective, gives companies opportunities to learn valuable information about the appeal of other companies’ marketing, and may help expand user traffic for all companies concerned.

其它营销者的投放除了可以带来收入,也能使该网站看起来客观公正,使企业有机会了解其他公司市场营销的独到之处,还能有助于扩大所有相关企业的用户流量。

Page 30: 第 3 章 栈和队列
Page 31: 第 3 章 栈和队列

复习:• 栈的含义及性质• 栈的顺序存储:

• 顺序栈定义•四个操作

• 栈的链式存储:• 链栈的定义• 操作

• 栈的应用

Page 32: 第 3 章 栈和队列

新课:

• 队列的含义及性质• 队列的顺序存储:循环队列• 队列的链式存储• 假溢出

Page 33: 第 3 章 栈和队列

3.23.2 队列队列

11 、队列的逻辑结构、队列的逻辑结构– 队列:队列:只允许在只允许在一端一端进行插入操作,而进行插入操作,而另一端另一端

进行删除操作的线性表。进行删除操作的线性表。

队尾队头

a1 a2 a3

入队出队

队列的操作特性:队列的操作特性: 先进先出先进先出

Page 34: 第 3 章 栈和队列

typedef struct{

int data[maxsize];

int front;// 指向队列头元素 // 指向刚出队的元素所占的位置

int rear; // 指向队尾元素的下一个位置 // 指向刚入队的元素的位置}SqQueue;

22 、队列的顺序存储结构及实现(顺序队列)、队列的顺序存储结构及实现(顺序队列)

Page 35: 第 3 章 栈和队列

如何改造数组实现队列的顺序存储?如何改造数组实现队列的顺序存储?

11 、仿照顺序表,将、仿照顺序表,将 nn 个元素存放在前个元素存放在前 nn 个连续单元中。个连续单元中。

入队操作时间性能为入队操作时间性能为 OO(1)(1) ,出队操作时间性能为,出队操作时间性能为 OO((nn))

22 、、放宽队列的所有元素必须存储在数组的前放宽队列的所有元素必须存储在数组的前 nn 个连续单元这一条件 ,只要个连续单元这一条件 ,只要求队列的元素存储在数组中连续的位置。求队列的元素存储在数组中连续的位置。————设置队头、队尾两个指示设置队头、队尾两个指示

入队操作时间性能为入队操作时间性能为 OO(1)(1) ,出队操作时间性能为,出队操作时间性能为 OO((11)) ,但会出现,但会出现假上假上溢溢

33 、循环队列、循环队列————将存储队列的数组头尾相接。将存储队列的数组头尾相接。

22 、队列的顺序存储结构及实现(顺序队列)、队列的顺序存储结构及实现(顺序队列)

Page 36: 第 3 章 栈和队列

11 、不存在物理的循环结构、不存在物理的循环结构22 、如何判断循环队列队空? 、如何判断循环队列队空? front=rear front=rear

如何判断循环队列队满? 如何判断循环队列队满? front=rearfront=rear

如何实现循环队列?如何实现循环队列?

22 、队列的顺序存储结构及实现(顺序队列)、队列的顺序存储结构及实现(顺序队列)

Page 37: 第 3 章 栈和队列

队空、队满的判定条件出现二义性。队空、队满的判定条件出现二义性。如何将队空和队满的判定条件分开?如何将队空和队满的判定条件分开?

方法一:方法一:浪费一个元素空间。将图浪费一个元素空间。将图 3-83-8 (( cc )所示的情况视为队满,此时)所示的情况视为队满,此时的状态是,队尾指针加的状态是,队尾指针加 11 就会从后面赶上队头指针,就会从后面赶上队头指针,此时队满的条件是此时队满的条件是(rear+1) % MaxSize==front(rear+1) % MaxSize==front ,,这样就能与空队区别开。这样就能与空队区别开。

方法二:方法二:使用一个计数器记录队列中元素的个数。附设一个存储队列中元使用一个计数器记录队列中元素的个数。附设一个存储队列中元素个数的变量如素个数的变量如 numnum ,当,当 num==0num==0 时队空,当时队空,当 num==MaxSizenum==MaxSize 时时队满。队满。

22 、队列的顺序存储结构及实现(顺序队列)、队列的顺序存储结构及实现(顺序队列)

Page 38: 第 3 章 栈和队列

循环队列顺序存储• 二个状态:• 队空状态: qu.rear==qu.front• 队满状态 : (qu.rear+1)%maxsize==qu.front• 二个操作:元素 X 进队操作: Qu.rear=(qu.rear+1)%maxsize; qu.data[qu.rear]=x元素 X 出队操作: qu.front=(qu.front+1)%mazsize;

x=qu.data[qu.front];

Page 39: 第 3 章 栈和队列

算法讲解: P74.7如果允许在循环队列的两端都可以进行插入和删除操作,要求:1. 写出循环队列的类型定义2. 分别写出从队尾删除和从队头插入的算法

Typedef struct{int data[maxsize];Int front,rear;}cycqueue;

Int dequeue(cycqueue &Q, int &x){// 从队尾删除If (O.front==Q.rear) return 0;//队列为空?Else{x=Q.data[Q.rear];Q.rear=(Q.rear-1+maxsize)%maxsize;Return 1;}}

Int enqueue(cycqueue &Q, int x){// 从队头插入If (O.rear==(Q.front-1+maxsize)%maxsizereturn 0;// 判断队列满则不能插入Else{Q.data[Q.front]=x;Q.front=(Q.front-1+maxsize)%maxsize;Return 1;}}

Int dequeue(cycqueue &Q, int &x){// 从队头删除If (O.front==Q.rear) return 0;Else{Q.front=(Q.front+1)%maxsize;x=Q.data[Q.front];Return 1;}}

Int enqueue(cycqueue &Q, int x){// 从队尾插入If (O.front==(Q.rear+1)%maxsizereturn 0;Else{Q.rear=(Q.rear+1)%maxsize;Q.data[Q.rear]=x;Return 1;}}

Page 40: 第 3 章 栈和队列

考研真题2. 名词解释:队列【大连海事大学 1996

一、 6 ( 1 分 ) 】3. 什么是循环队列?【哈尔滨工业大学

2001 三、 2 ( 3 分)】【河南大学 1998 一、 4 ( 3 分)】

2 、队列是允许在一端插入而在另一端删除的线性表,允许插入的一端叫队尾,允许删除的一端叫队头。最先插入队的元素最先离开(删除),故队列也常称先进先出( FIFO )表。

3 、用常规意义下顺序存储结构的一维数组表示队列,由于队列的性质(队尾插入和队头删除),容易造成“假溢出”现象,即队尾已到达一维数组的高下标,不能再插入,然而队中元素个数小于队列的长度(容量)。循环队列是解决“假溢出”的一种方法。通常把一维数组看成首尾相接。在循环队列下,通常采用“牺牲一个存储单元”或“作标记”的方法解决“队满”和“队空”的判定问题。

Page 41: 第 3 章 栈和队列

考研真题30. 举例说明顺序队的“假溢出”现象,并给出解决方案。【福州大学 1998 三、 5 (6 分 ) 】

31. 怎样判定循环队列的空和满【燕山大学 99 二、 3 ( 4 分)32. 简要叙述循环队列的数据结构,并写出其初始状态、队列空、队列满时的队首指针与队尾指针的值。 【南京航空航天大学 1995 七( 5 分)】

33. 利用两个栈 sl,s2模拟一个队列时,如何用栈的运算实现队列的插入,删除以及判队空运算。请简述这些运算的算法思想。【北京邮电大学 92 一、 5 分东南大学 99 一、 1 ( 7 分)

34.一个循环队列的数据结构描述如下【西北工大 1999 三 (8分 ) 】

TYPE sequeuetp=RECORD elem : ARRAY[1..MAXSIZE] OF elemtp ; front , rear : 0..MAXSIZE ; END ;给出循环队列的队空和队满的判断条件,并且分析一下该条件对队列实际存储空间大小的影响,如果为了不损失存储空间,你如何改进循环队列的队空和队满的判断条件?

30 、设顺序存储队列用一维数组 q[m] 表示,其中 m 为队列中元素个数,队列中元素在向量中的下标从 0 到 m-1 。设队头指针为front ,队尾指针是 rear ,约定 front 指向队头元素的前一位置, rear 指向队尾元素。当 front 等于 -1时队空, rear 等于 m-1时为队满。由于队列的性质(“删除”在队头而“插入”在队尾),所以当队尾指针 rear 等于 m-1时,若 front 不等于 -1 ,则队列中仍有空闲单元,所以队列并不是真满。这时若再有入队操作,会造成假“溢出”。其解决办法有二,一是将队列元素向前“平移”(占用 0 至 rear-front-1 );二是将队列看成首尾相连,即循环队列( 0..m-1 )。在循环队列下,仍定义 front=rear时为队空,而判断队满则用两种办法,一是用“牺牲一个单元”,即 rear+1=front(准确记是( rear+1 ) %m=front , m 是队列容量)时为队满。另一种解法是“设标记”方法,如设标记 tag , tag 等于 0情况下,若删除时导致 front=rear 为队空; tag=1情况下,若因插入导致front=rear 则为队满。

Page 42: 第 3 章 栈和队列

二个指针二个指针 front front 和和 rearrear 指示队列头元素和尾元素的位置。指示队列头元素和尾元素的位置。初始化空队列:初始化空队列: front=rear=0front=rear=0

插入新的队尾元素:插入新的队尾元素:尾指针增尾指针增 1,1, 尾指针始终指向队列尾元素的下一个位置尾指针始终指向队列尾元素的下一个位置 //// 指向链表的尾结点指向链表的尾结点

删除队列头元素:删除队列头元素:头指针增头指针增 11 ,头指针始终指向队列头元素。,头指针始终指向队列头元素。 //// 指向链表的头结点指向链表的头结点

如何改造单链表实现队列的链接存储?如何改造单链表实现队列的链接存储?

33 、队列的链式存储结构及实现(链队列)、队列的链式存储结构及实现(链队列)

Page 43: 第 3 章 栈和队列

非空链队列非空链队列

head a1 a2 an ∧

rear空链队列空链队列

front ∧

rear

33 、队列的链式存储结构及实现(链队列)、队列的链式存储结构及实现(链队列)

Page 44: 第 3 章 栈和队列

链队列:用链表示的队列typedef struct QNode{

QelemType data ;

struct QNode *next ;

}QNode, *QueuePtr;

typedef struct{

QueuePtr *front ; //队头指针,指向头结点QueuePtr *rear ;//队尾指针,指向尾结点}• 空链队列:队头指针和队尾指针均指向头结点。

Page 45: 第 3 章 栈和队列

单链表的链队• 二个状态队空状态: lqu->rear==NULL 或 lqu->front==NULL

队满状态:不存在

• 二个操作:元素入队 : lqu->rear->next=p; lqu->rear=p;

元素出队: p=lqu->front; lqu->front=p->next;

X=p->data; free(p);

Page 46: 第 3 章 栈和队列

链队列的运算:1. 初始化链队 initqueue

2. 判队列是否为空 Queueempty(Q) 若队列Q 为空,返回 true ,否则,返回 false

3. 入队 Enqueue(&Q, e) 在队列 Q 中插入元素 e 。

4. 出队 Dequeue(&Q, &e) 若队列 Q 不空,则删除其队头元素。

Page 47: 第 3 章 栈和队列

队列操作在链式存储结构下的实现• 初始化链队Void initqueue(Liqueue *&lqu){ Lqu=(liQueue*)malloc(sizeof(Liqueue));lqu->front= lqu->rear;}

• 判队列是否为空Int queueempty(Liqueue *lqu){ if ( lqu->rear==null || lqu->front==null ) return 1;Else return 0;}

Page 48: 第 3 章 栈和队列

队列操作在链式存储结构下的实现• 入队Enqueue(&Q, e){p=(QueuePtr) malloc(sizeof(node)); p->data=e;p->next=NUll; Q.rear->next=p; Q.rear=p}

出队 Dequeue(&Q, &e){if (Q.front==Q.rear) return Error; p=Q.front->next;//带头结点

e=p->data;Q.front->next=p->next;if(Q.rear==p) Q.rear=Q.front;free(p); }

尾插法

Page 49: 第 3 章 栈和队列

算法实例 P68,2

• 利用二个栈 S1 和 S2 来模拟一个队列,栈中元素为 int 型,栈中元素最多为maxsize, 已知栈的三个运算定义如下:

• PUSH(ST,x), POP(ST,&x); Sempty(ST);

• 如何利用栈的运算来实现队列的入队、出队、判对空的三个运算?

1. 给出基本设计思想2. 用 C 描述算法,关键处给出注释

Page 50: 第 3 章 栈和队列

栈 S1 和 S2 来模拟一个队列,栈中元素为 int 型,栈中元素最多为 maxsize, 已知 PUSH(ST,x), POP(ST,&x); Sempty(ST);

利用栈的运算来实现队列的入队、出队、判对空的运算思想: S1 作输入栈,模拟队列元素的入队;出队时, S1 退栈压入 S2 栈中, S2 出栈即相当于队列的出队。当 S2 和 S1都为空时,队列空。

Int enqueue(Sqstack &s1,Sqstack &s2,int x){//S1 容量为 maxsizeInt y;If(S1.top==maxsize-1)// 栈 s1 满, S2 有空 ? {if (!sempty(s2)) return 0; elseif(sempty(s2)) {While(!sempty(s1)) {pop(S1,y); push(s2,y);} Push(S1,x); return1;}Else(push(s1,x); return 1;} }

Int dequeue(SqStack&s2,SqStack&s1,int &x){Int y;If(!Sempty(s2)) {pop(s2,x); return 1;}Else {if(sempty(S1)) return 0; Else{ while(!Sempty(s1)) {pop(s1,y); push(s2,y);} Pop(s2,x);Return 1; } }}

Int queue_empty(SqStack s1, SqStack s2){ if(Sempty(s1)&&Sempty(s2) return 1; Else return 0 }

Page 51: 第 3 章 栈和队列

附二:特殊矩阵的压缩存储• 分析:二维数组对于行优先,则先将行标 i之前的行的

所有元素填满,行标 i 所指的行的元素个数由列标指示出。如:对于 int a[4][5] 来说, a[2][3] 是第 14 个元素,其前有 13 个元素。

• P65 例 3-4

设二维数组 A[6][10] ,每个数组元素占 4 个存储单元,若按行优先顺序存放的数组元素 A[3][5] 的存储地址是 1000 ,求 A[0][0]的存储地址。

1000- ( 3*10+5 ) *4 = 860

Page 52: 第 3 章 栈和队列

概念理解

• P71习题• 2 , 3 , 5 , 7 , 8 , 9 , 13 , 16 , 17 ,

23 , 26 , 29 , 30 , 32 , 33

• P75 4 , 5 , 6 , 7

Page 53: 第 3 章 栈和队列

作业: P74.8

• 设计一个循环队列,用 front 和 rear 分别作为队头和队尾的指针,另外用一个标志 tag表示队列是空还是不空,约定当 tag 为 0队空,当 tag 为 1时队不空,这样可以用front==rear 作为队满 的条件。要求设计队列的结构和相关基本运算算法。(队列元素为int 型)。

Page 54: 第 3 章 栈和队列

小结1. 理解概念:理解栈的特点,顺序栈与链栈

的特点,队列的含义2. 理解各种存储方式的基本算法,由图形帮

助理解,写出算法思想3. 题型:

1. 概念理解2. 循环队列的空、满判断?3. 栈可实现的输出序列?4. 用栈表示表达式

Page 55: 第 3 章 栈和队列

四、考研英语 -- 形式主语P49. 2011 年 part B P5S2• But it’s interesting to wonder if the images we

see every week of stress-free, happiness-enhancing parenthood aren’t in some small, subconscious way contributing to our own dissatisfactions with the actual experience, in the same way that a small part of us hoped getting” the Rachel” might make us look just a little bit like Jennifer Aniston.

•但是,我们每周看到的那些无忧无虑的幸福感越来越强的父母形象,是不是在以一种不明显的、无意识的方式不让我们对养育孩子的实际情形感到不满,就像我们中的少数人希望剪个瑞秋式的发型可能会使我们看起来有一点像珍妮弗 .安妮斯顿一样,想想这些,确实非常有趣。

Page 56: 第 3 章 栈和队列
Page 57: 第 3 章 栈和队列

关于兴趣的五点建议

1. 选你所爱2. 爱你所选 3. 把握每一个选择兴趣的机会4. 忠于自己的兴趣5. 找到最佳结合点

Page 58: 第 3 章 栈和队列

关于兴趣的五点建议• 选你所爱

– 自己喜欢什么?自己的天赋是什么?• 有趣的不见得是自己真正喜欢的• 有兴趣的不见得可以成为自己的职业• 喜欢的不见得有天赋,但能培养出能力

– 如何找到真正的兴趣?• 渴望重复?愉快成功的完成?一直向往?让你满足?人生中

最快乐的事与此相关?• 多接触,尝试,才能找到最爱

• 找到之后――――课外学习、选修,旁听,打工,社会实践,转系,考研?

Page 59: 第 3 章 栈和队列

关于兴趣的五点建议• 爱你所选

– 你对想转的专业了解多少?– 寻找专业中喜欢的领域– 找一个有激情的同伴– 寻找快乐:

• 今天比昨天做的好?发现了新问题?解决了新问题?学到新知识?技能提高了?比别人做的好?用专业对他人有帮助?被夸奖?

Page 60: 第 3 章 栈和队列

关于兴趣的五点建议• 把握每一个选择兴趣的机会

– 高考:– 大学转系、考研、出国:是方法,不是目标

• 转专业录取难,就业易。– 就业:最初几年可以尝试不同类型的职业。

Page 61: 第 3 章 栈和队列

关于兴趣的五点建议• 忠于自己的兴趣:

– 坚持你的兴趣。– 娱乐快乐,工作辛苦枯燥– 调整态度:享受,忍受。

Page 62: 第 3 章 栈和队列

关于兴趣的五点建议找到最佳结合点:

– 理想、兴趣、天赋、就业相结合。– 兴趣与天赋的矛盾:天赋来赚钱,兴趣来丰富生活

– 兴趣与就业的矛盾:解决生活底线再追求理想

Page 63: 第 3 章 栈和队列
Page 64: 第 3 章 栈和队列
Page 65: 第 3 章 栈和队列

template <class T>template <class T>class LinkStackclass LinkStack{{ Node<T> *top; //Node<T> *top; // 栈顶指针栈顶指针public:public: LinkStack( ); //LinkStack( ); // 构造函数构造函数 ~LinkStack( ); //~LinkStack( ); // 析构函数析构函数 void Push(T x); //void Push(T x); // 入栈入栈 T Pop( ); //T Pop( ); // 出栈出栈 T Top( ); //T Top( ); // 取栈顶元素(元素不出栈)取栈顶元素(元素不出栈) bool Empty( ); //bool Empty( ); // 判断链栈是否为空栈判断链栈是否为空栈}; };

33 、栈的链式存储结构及实现、栈的链式存储结构及实现————链栈链栈链栈的类模板链栈的类模板

Page 66: 第 3 章 栈和队列

33 、栈的链存储结构及实现、栈的链存储结构及实现————链栈链栈链栈的操作算法:(链栈的操作算法:( P39-40P39-40 ))• 初始化 初始化 SeqStack( ) SeqStack( )

• 入栈 入栈 Push(T x) Push(T x)

• 出栈 出栈 Pop( ) Pop( )

• 取栈顶元素 取栈顶元素 Top( ) Top( )

• 判栈空 判栈空 Empty( ) Empty( )

Page 67: 第 3 章 栈和队列

44 、栈的应用、栈的应用

• 例例 1 1 把十进制整数转换为二至十六之间的把十进制整数转换为二至十六之间的任一进制数输出。任一进制数输出。 p52p52

• 例例 2 2 括号匹配问题。试编写一个算法,用括号匹配问题。试编写一个算法,用来检查一个来检查一个 C++C++ 语言程序中的花括号、方语言程序中的花括号、方括号和圆括号是否配对,若能够全部配对括号和圆括号是否配对,若能够全部配对则返回则返回 11 ,否则返回,否则返回 00 。。 p52p52

• 例例 3 3 判回文判回文