This presentation is the property of its rightful owner.
1 / 47

# 第三章 栈与队列 PowerPoint PPT Presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.

- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -

• 栈 ( Stack )

• 队列 ( Queue )

### 3.1栈 ( Stack )

• 只允许在一端插入和删除的顺序表

• 允许插入和删除

的一端称为栈顶

(top)，另一端称

为栈底(bottom)

• 特点

后进先出 (LIFO)

Push Q

Push A

Pop

Pop

Push R

Push D

Push M

Pop

Push Q

### 栈的抽象数据类型 p45

D = {ai | ai ElemSet, i = 1,2,…n }

R = {<ai-1, ai> | ai-1, ai D, i = 2,…n}

P:

InitStack(&S)

ClearStack(&S)

StackEmpty(S)

StackLength(S)

GetTop(S, &e)

Push(&S, e)

Pop(&S, &e)

StackTraverse(S, visit());

### 3.1 栈

1 栈的顺序存储结构

#define MAX 50

int stack[MAX];

int top=0;

an

an-1

a2

a1

MAX-1

n

n-1

n-2

1

0

top

x

an

an-1

a2

a1

MAX-1

n

n-1

n-2

1

0

an

an-1

a2

a1

MAX-1

n

n-1

n-2

1

0

top

top

x 进栈后

x 进栈前

1 ) 进栈操作

viod Push( int x )

{if (top>=MAX) printf(“ overflow” );

else {stack[top]=x; top++; }

}

an

an-1

a2

a1

an

an-1

a2

a1

MAX-1

n

n-1

n-2

1

0

MAX-1

n

n-1

n-2

1

0

top

top

2）出栈操作

int pop( ){if (top==0) {printf(“underflow”); return(-1);}

top--; return(0);

}

an

a3

a2

a1

### 栈的表示和实现 顺序栈 P46-47

• 在连续的存储单元内依次存放栈中的数据元素，并设指针top来指示栈顶元素的位置

• top为0时表示空栈

#define STACK_INIT_SIZE 100;

#define STACKINCREMENT 10;

typedef struct{

SElemType *base; //栈底指针

SElemType *top; //栈顶指针

int stacksize; //栈的当前最大可用容量

}SqStack;

SqStack S;

### 顺序栈的实现

Status InitStack(SqStack &S){

S.base = (SElemType *)

malloc(STACK_INIT_SIZE * sizeof(ElemType));

if (!S.base) exit(OVERFLOW);

S.top = S.base;

S.stacksize = STACK_INIT_SIZE;

return OK;

}

Status GetTop(SqStack S, SElemType &e){

if (S.top == S.base) return ERROR;

e = *(S.top –1);

return OK;

}

### 顺序栈的实现

Status Push(SqStack &S, SElemType e){

if (S.top – S.base >= S.stacksize){ //栈满，追加空间

S.base = (ElemType *)realloc(S.base,

(S.stacksize + STACKINCREMENT) * sizeof(ElemType));

if (!S.base) exit(OVERFLOW);

S.top = S.base + S.stacksize;

S.stacksize += STACKINCREMENT;

}

*S.top ++ = e; //进栈

return OK;

}

Status Pop(SqStack &S, SElemType &e){

if (S.top == S.base) return ERROR;

e = * -- S.top; //出栈

return OK;

}

### 顺序栈的实现

void ClearStack(&S) {

S.top = S.base;

}

int StackLength(S) {

return (S.top –S.base);

}

int StackEmpty(S) {

if (S.top == S.base)

return TRUE

else

return FALSE;

}

### 栈的链接表示 — 链式栈

• 链式栈无栈满问题，空间可扩充

• 插入与删除仅在栈顶处执行

• 链式栈的栈顶在链头

• 适合于多栈操作

data

next

S

### 栈的表示和实现

typedef struct{

SElemType data;

struct StackNode *next;

}StackNode, *StackPtr;

StackPtr S;

### 链栈的实现

Status InitStack(StackPtr &S){

S = (StackPtr)malloc(sizeof(StackNode));

if (!S) exit(OVERFLOW);

S.next = NULL;

return OK;

}

Status GetTop(StackPtr S, SElemType &e){

if (!S) return ERROR;

e = S->data;

return OK;

}

p

e

S

### 链栈的实现

Status Push(StackPtr &S, SElemType e){

p = (StackPtr)malloc(sizeof(StackNode));

p->data = e;

p->next = S;

S = p;

return OK;

}

Status Pop(StackPtr &S, SElemType &e){

if (!S) return ERROR; //空栈

p = S;

e = S->data;

S = S->next;

free(p);

return OK;

}

S

• 在顺序栈中有“上溢”和“下溢”的概念。顺序栈好比一个盒子，我们在里头放了一叠书，当我们要用书的话只能从第一本开始拿，那么当我们把书本放到这个栈中超过盒子的顶部时就放不下了，这时就是"上溢","上溢"也就是栈顶指针指出栈的外面，显然是出错了。反之，当栈中已没有书时，我们再去拿，看看没书，把盒子拎起来看看盒底，还是没有，这就是"下溢"。"下溢"本身可以表示栈为空栈,因此可以用它来作为控制转移的条件。

• 链栈则没有上溢的限制，它就象是一条一头固定的链子，可以在活动的一头自由地增加链环(结点)而不会溢出，

### 3.2栈的应用举例

• 数制转换

• 括号匹配的检验[( [ ] [ ] )]

• 行编辑程序p49

3.2.1 数制转换

N=(n div d)*d+n mod d

( 其中:div为整除运算,mod为求余运算)

n n div 8 n mod 8

1348 168 4

168 21 0

21 2 5

2 0 2

void conversion( ) {

initstack(s);

scanf (“%”,n);

while(n){

push(s,n%8);

n=n/8;

}

while(! Stackempty(s)){

pop(s,e);

printf(“%d”,e);

}

}

3.2.4 迷宫求解

## 迷宫问题 示例

4

3

5

2

1

7

6

4

3

5

2

1

7

6

1 (入口) 正向走 进到 2

2左拐弯 进到 3

3右拐弯 进到 4

4 (堵死) 回溯 退到 3

3 (堵死) 回溯 退到 2

2正向走 进到 5

5 (堵死) 回溯 退到 2

2右拐弯 进到 6

6左拐弯 进到7

(出口)

6

0 0 4

0 0 0

0 0 0

7 0 0

7

### 设计算法判断一个算术表达式的圆括号是否正确配对

• 提示： 对表达式进行扫描，凡遇到‘(’就进栈，遇‘)’就退掉栈顶的‘(’，表达式被扫描完毕，栈应为空。

• 根据提示，可以设计算法如下：#include <string.h>#include “stack.h”int PairBracket( char *S){//检查表达式中括号是否配对int i;SeqStack openings; //定义一个栈InitStack (&T);for (i=0; i<strlen(S) ; i++){ if ( S[i]==‘(’ ) Push(& openings, S[i]); //遇‘(’时进栈if ( S[i]==‘)’ ) Pop(& openings); //遇‘)’时出栈 }return !EmptyStack(&T); // 由栈空否返回正确配对与否}

• int main( )

{Seq_Stack openings; InitStack (&openings);

char symbol;

bool is matched = true;

while (is matched && (symbol = cin.get( )) != ‘\n’) {

if (symbol == ‘{‘ || symbol ==‘(‘ || symbol == ‘[‘)

Push(&openings, symbol);

if (symbol == ‘}’ || symbol == ‘)’ || symbol == ‘]’) {

if (EmptyStack(&openings )) {

cout << "Unmatched closing bracket " << symbol

<< " detected." << endl;

is matched = false;

}

else ……

else {

char match;

Get_top(openings, match);

Pop(openings);

is matched = (symbol == ‘}’ && match ==‘{‘)

|| (symbol == ‘)’ && match == ‘(‘)

|| (symbol == ‘]’ && match == ‘[‘);

if (!is matched)

cout << "Bad match " << match << symbol << endl;

}

}

}

if (!openings.empty( ))

cout << "Unmatched opening bracket(s) detected." << endl;

}

### 递归的概念

• 递归的定义 若一个对象部分地包含它自己, 或用它自己给自己定义, 则称这个对象是递归的；若一个过程直接地或间接地调用自己, 则称这个过程是递归的过程。

• 在以下三种情况下，常常用到递归方法。

• 定义是递归的

• 数据结构是递归的

• 问题的解法是递归的

### 定义是递归的

long Factorial (long n ) {

if ( n == 0 )return 1;

else return n*Factorial (n-1);

}

### 求解阶乘 n! 的过程

longFib (longn ) { if ( n <= 1 )return n;else returnFib (n-1) + Fib (n-2);

}

### Towers of Hanoi

Rules: Move only one disk at a time.

No larger disk can be on top of a smaller disk.

### Program for HanoiMain program:

const int disks = 64; // Make this constant much smaller to run program.

void move(int count, int start, int nish, int temp);

main( )

{

move(disks, 1, 3, 2);

}

### 递归函数

void move(int count, int start, int finish, int temp)

{

if (count > 0) {

move(count - 1, start, temp, finish);

cout << "Move disk " << count << " from " << start<< " to " << nish << "." << endl;

move(count - 1, temp, finish, start);

}

}

Ackerman 函数定义如下：请写出递归算法。

n+1　　　 当m=0时

AKM ( m , n ) = AKM( m-1 ,1) 当m≠0 ，n=0时

AKM( m-1, AKM( m,n-1)) 当m≠0, n ≠ 0时

int AKM( int m, int n){ if ( m== 0) return n+1; if ( m<>0 && n==0 ) return AKM( m-1, 1); if ( m<>0 && n<>0 ) return AKM( m-1, AKM( m,

n-1));}

### 习题

1、设将整数1、2、3、4依次进栈，但只要出栈时栈非空，则可将出栈操作按任何次序夹入其中，请回答下有问题：

（1）若入栈次序为push(1)，pop()，push(2，push(3)，pop()，pop( )，push(4)，pop( )，则出栈的数字序列为什么？

（2）能否得到出栈序列为1423和1432？并说明为什么不能得到或如何得到。

（3）请分析1、2、3、4的24种排列中，哪些序列可以通过相应的入出栈得到。