44
栈栈栈栈栈栈 栈 --- 是是是是是是是是是 是是是是是是是是是是是是是是是 一。 a n . . . a 2 a 1 栈栈 T OP Bott 栈栈TOP -- 是是是是是是是是 是是 一。 栈栈 bottom)- - 是是 是是是是是是是 是是 一。 栈栈 -- 是是是是是是

栈的基本概念:

  • Upload
    fergus

  • View
    57

  • Download
    9

Embed Size (px)

DESCRIPTION

 栈的基本概念:. 栈 -- - 是限制仅在线性表的一端进行插入和删除运算的线性表。. 栈顶( TOP ) -- 允许插入和删除的一端。 栈底( bottom)- - 不允许插入和删除的一端。 空栈 -- 表中没有元素。. 栈顶 TOP. a n . . . a 2 a 1. 栈底 Bottom.  栈的基本概念:. 栈 -- 又称为后进先出的线性表( LIFO 表, Last In First Out ). 进栈. 退栈. 进栈 --- 最先插入的元素放在栈的底部。 退栈 --- 最后插入的元素最先退栈。. a n . . . - PowerPoint PPT Presentation

Citation preview

Page 1: 栈的基本概念:

栈的基本概念:

栈 --- 是限制仅在线性表的一端进行插入和删除运算的线性表。

an

.

.

.a2

a1

栈顶 TOP

栈底 Bottom

栈顶( TOP ) --允许插入和删除的一端。 栈底( bottom)--不允许插入和删除的一端。 空栈 -- 表中没有元素。

Page 2: 栈的基本概念:

栈的基本概念:

栈 -- 又称为后进先出的线性表( LIFO 表,Last In First Out )

an

.

.

.a2

a1

进栈 退栈

栈顶

栈底

进栈 ---最先插入的元素放在栈的底部。退栈 --- 最后插入的元素最先退栈。

Page 3: 栈的基本概念:

栈的基本运算:

置空栈进栈取栈顶元素判空栈退栈

Page 4: 栈的基本概念:

顺序栈:栈的顺序结构顺序栈:用向量定义(类似于顺序表),将栈底位置设置在向量两端的任意一个端点;用 top (整型量,栈顶指针)来指示栈当前栈顶位置。

顺序栈的定义:Typedef int datatype;/* 栈元素的数据类型 */

#define maxsize 64 /* 栈可能达到的容量,暂定为 64*/

Typedef struct

{datatype data[maxsize];

Int top;

}seqstack;/* 顺序栈类型定义 */

Seqstack *s;/* S 是顺序栈类型指针 */

Page 5: 栈的基本概念:

顺序栈:栈顶指针与栈中元素间的关系

A

3 2 1 0

3 2 1 0

3 2 1 0

Top=-1 空栈

TOP

A 进栈

D

C

B

A

B 、 C 、 D 依次进栈

TOP

3 2 1 0

B

A

TOP

D 、 C 依次退栈

3 2 1 0

Top=-1 , B 、 A退栈

Page 6: 栈的基本概念:

栈底位置固定在向量的低端,即:S->data[0]---- 表示栈底元素;进栈: S->TOP 加 1 (正向增长)。退栈: S->TOP 减 1 。空栈: s->top<0

栈满: S->TOP=maxsize-1

上溢:栈满时再做进栈运算(一种出错状态,应设法避免)。下溢:栈空时再做退栈运算将产生溢出,这是一种正常状态(因为栈的初态和终态都是空栈,下溢常用作程序控制转移的条件)。

Page 7: 栈的基本概念:

顺序栈的几种基本运算例

置空栈:

判栈空:

进栈:

退栈:

取栈顶元素:

Page 8: 栈的基本概念:

顺序栈的几种基本运算例

置空栈:SETNULL(S) /* 将顺序栈 S 置为空 */

Seqstack *s;

{s->top=-1

} /* SETNULL */

Page 9: 栈的基本概念:

顺序栈的几种基本运算例

判栈空:int EMPTY(S) /* 判定顺序栈 S 是否为空 *

/

Seqstack *s;

{if(s->top>=0) return FAULSE;

else return TRUE;

} /* EMPTY */

Page 10: 栈的基本概念:

顺序栈的几种基本运算例进栈:Seqstack *PUSH(S,X) /* 将元素 X 插入顺序栈 S 顶部 */

Seqstack *s;

datatype x;

{if(s->top==maxsize-1) { 输出“上溢” ; return NUL

L;}

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

return s;

} /* PUSH */

Page 11: 栈的基本概念:

顺序栈的几种基本运算例退栈:Seqstack POP(S) /* 若栈 S 非空,取出栈顶元素删除之 */

Seqstack *s;

{if(EMPTY(S)) { 输出“下溢” ; return NULL;}

else {s->top--;return(s->data[s->top+1]);}

/* 删除栈顶元素,并返回被删值 */

} /* POP */

Page 12: 栈的基本概念:

顺序栈的几种基本运算例取栈顶: datatype TOP(S) /* 取顺序栈 S 的栈顶 */

Seqstack *s;

{if(EMPTY(S)) { 输出“栈空” ; return NULL;}

else {return(s->data[s->top]);}

} /* TOP */

Page 13: 栈的基本概念:

关于顺序栈的约定和主要运算的思考:

如果约定顺序栈栈空为: s->top=0 (教材的约定),则顺序栈下述的几种运算如何描述?置空栈:判栈空:进栈:退栈:取栈顶元素:

Page 14: 栈的基本概念:

栈上溢的解决方法当程序中同时使用几个栈时,如何防止栈的上溢?方法一:将栈的容量加到足够大,但这种方法由于事先难以估计容量,有可能浪费空间。

方法二:使用两个(或多个)栈共享存储空间办法。两栈的栈底分别设在给定存储空间的两端,然后各自向中间伸延,当两栈的栈顶相遇时才可能发生溢出。

Page 15: 栈的基本概念:

栈上溢的解决方法之 ----- 方法二(两栈共享存储空间)

讨论:向第 i ( i=1 或 i=2) 个栈插入元素 x 和删除一个元素的算法(参见教材)。

Page 16: 栈的基本概念:

链栈链栈 --- 栈的链式存储结构(当顺序栈的最大容量事先无法估计时,可采用链栈 结构)。

TOP

data link

栈顶

.

.

链栈的定义:

Typedef struct node{

int data;

struct node *link;}JD

Page 17: 栈的基本概念:

链栈链栈的特点 ---

( 1 )插入和删除(进栈 / 退栈)仅能在表头位置上(栈顶)进行。( 2 )链栈中的结点是动态产生的,可不考虑上溢问题。( 3 )不需附加头结点,栈顶指针就是链表(即链栈)的头指针。

Page 18: 栈的基本概念:

链栈链栈进栈运算 ---

JD *lzjz(JD *top,int x)

{/* 将元素 x 进链栈 */

JD *p;

p=(JD *)malloc(sizeof(JD));

P->data=x;

p->link=top;

return(p);

}

Page 19: 栈的基本概念:

链栈链栈退栈运算 ---

JD *lztz(JD *top,int *p)

{/* 从链栈顶取出元素存至( *p ) */

JD *q;

if(top!=NULL)

{q=top; *p=top->data; top=top->link;

free(p);}

return (top);

}

Page 20: 栈的基本概念:

栈小结:•顺序栈有发生上溢 的可能,而链栈通常不会发生栈满(除非整个空间均被占满)•只要满足 LIFO 原则,均可采用栈结构。•栈的应用:递归调用。

Page 21: 栈的基本概念:

迷宫问题

(a) 迷宫的图形表示 (b) 迷宫的二维数组表示

Page 22: 栈的基本概念:

求解迷宫问题的简单方法是:从入口出发,沿某一方向进行探索,若能走通,则继续向前走;否则沿原路返回,换一方向再进行探索,直到所有可能的通路都探索到为止。

为避免走回到已经进入的点(包括已在当前路径上的点和曾经在当前路径上的点),凡是进入过的点都应做上记号。

为了记录当前位置以及在该位置上所选的方向,算法中设置了一个栈,栈中每个元素包括三项,分别记录当前位置的行坐标、列坐标以及在该位置上所选的方向(即 directon数组的下标值)

Page 23: 栈的基本概念:

栈用顺序存储结构实现,栈中元素的说明如下: struct NodeMaze{ int x,y,d; };typedef struct NodeMaze DataType;

算法 4.15 求迷宫中一条路径的算法void mazePath(int *maze[],int *direction[],int x1,int y1,i

nt x2,int y2)/* 迷宫 maze[M][N] 中求从入口 maze[x1][y1] 到出口

maze[x2][y2] 的一条路径 *//* 其中 1<=x1,x2<=M-2 , 1<=y1,y2<=N-2 */

Page 24: 栈的基本概念:

{ int i,j,k,kk; int g,h; PSeqStack st; DataType element; st = createEmptyStack_seq( ); maze[x1][y1] = 2; /* 从入口开始进入 , 作标记 */ element.x = x1; element.y = y1; element.d = -1; push_seq(st,element); /* 入口点进栈 */ while (not isEmptyStack_seq(st)) /* 走不通时 , 一步步回退 */ { element = top_seq(st);

i = element.x;j = element.y;k = element.d + 1;

Page 25: 栈的基本概念:

pop_seq(st);while (k<=3) /* 依次试探每个方向 */{ g = i + direction[k][0]; h = j + direction[k][1]; if (g==x2 && h==y2 && maze[g][h]==0) /* 走到

出口点 */ { printf("The path is:\n"); /* 打印路径上的每一

点 */ for (kk=1;kk<=st->t;kk++)

printf("the %d node is: %d %d \n",kk, st->s[kk].x,st->s[kk].y);

printf("the %d node is: %d %d \n",kk,i,j); printf("the %d node is: %d %d \n",kk+1,g,h)

; return;

}

Page 26: 栈的基本概念:

if (maze[g][h]==0) /* 走到没走过的点 */ { maze[g][h] = 2; /* 作标记 */ element.x = i;

element.y = j; element.d = k; push_seq(st,element); /* 进栈 */

i = g; /* 下一点转换成当前点 */ j = h; k = -1;

} k = k + 1;}

} printf("The path has not been found.\n"); /* 栈退完 ,未找到路径 */}

Page 27: 栈的基本概念:

队列的概念 --- 只允许在表的一端进行插入,而在表的另一端进行删除,是一种先入先出的线性表( FIFO )。

出队 入队

队头 队尾

a1 a2 …….an

Page 28: 栈的基本概念:

队列的基本概念:队头( front): 允许删除(出队)的一端。队尾( Rear): 允许插入的一端。空队列:队列中没有元素。进队:队的插入运算,即插入新的队尾元素。出队:队的删除运算,删除队首元素。

Page 29: 栈的基本概念:

队列的基本运算:入队出队取队头元素置空队列判队列是否为空

Page 30: 栈的基本概念:

顺序队列:顺序队列:

----队列的顺序存储结构,用一组连续的存储单元依次存放队列中的元素。

顺序队列的类型说明:typedef struct

{datatype data[m];

int f,r; /*队首、队尾 */

}sequeue;

sequeue *sq

Page 31: 栈的基本概念:

顺序队列运算时的头、尾指针变化:

B

A

D

C

3

2

1

0Sq->r

Sq->f

Sq->f

Sq->r

Sq->r

Sq->fSq->f

Sq->r

空队列 A、 B相继入队

A、 B相继出队

C、 D相继入队

Page 32: 栈的基本概念:

顺序队列的约定和主要运算:队头指针: f总是指向当前队头元素的前一个位置。

队尾指针: r 指向当前队尾元素的位置。初始状态: f=r=-1

入队运算:sq->r++; /* 尾指针加 1 */

sq->data[sq->r]=x; /* x 入队 */

出队运算:sq->f++; /* 头指针加 1 */

Page 33: 栈的基本概念:

顺序队列的约定和主要运算:队列长度:

(sq->r)-(sq->f)

队空:(sq->r)=(sq->f)

下溢:队空时再作出队操作。队满:

(sq->r)-(sq->f)=m

上溢:队满时再作入队操作。

Page 34: 栈的基本概念:

顺序队列的上溢:队上溢:真上溢( r-f=m) :队列真正满时再入队。假上溢: r 已指向队尾,但队列前端仍有空位置。

解决假上溢的方法:•方法一:每次删除队头一个元素后,把整个队列往前移一个位置(造成时间浪费)。•方法二:循环队列

Page 35: 栈的基本概念:

循环队列将所用的数组 sq->data[m] 设想为首尾相接的循环数组(即: data[0]连在 data[m-1] 之后 ) 。

r f

m-1 0 1

Page 36: 栈的基本概念:

• 循环意义下的队列入队:若尾指针 r等于向量的上界,再入队,令尾指针等于向量的下界 , 即:在循环意义下的尾指针的加 1操作可描述为:

If(sq->r+1>=m) sq->r=0;Else sq->r++;

• 利用“模运算”,则下述运算可描述为:入队: sq->r=(sq->r+1)%m出队: sq->f=(sq->f+1)%m队空: sq->r=(sq->f)队满: ( sq->r+1 ) %m=sq->f

• 循环队列的几种运算描述:置空队、判空队、入队、出队、取队头元素(略)

Page 37: 栈的基本概念:

链队列• 链队列 ---队列的链式存储结构,它是限

制仅在表头删除和表尾插入的单链表。• 链队列的描述和几种基本运算(自学):• 置空队、判队空、取队头结点数据、入队、出队。

Page 38: 栈的基本概念:

0 1 1 1 0 1 1 1

1 0 1 0 1 0 1 0

0 1 0 0 1 1 1 1

0 1 1 1 0 0 1 1

1 0 0 1 1 0 0 0

0 1 1 0 0 1 1 0

1 2 3 4 5 6 7 8

1

2

3

4

5

6

队列的应用举例--求迷宫的最短路径

Page 39: 栈的基本概念:

x y

0 0 +1

1 +1 +1

2 +1 0

3 +1 -1

4 0 -1

5 -1 -1

6 -1 0

7 -1 +1

需要解决的问题 1 :如何从某一坐标点出发搜索其四周的邻点

Page 40: 栈的基本概念:

需要解决的问题 2 :如何存储搜索路径

需要解决的问题 3 :如何防止重复到达某坐标点

步 x y pre

1 1 1 0

2 2 2 1

3 3 3 2

4 3 1 3

… … … …

Page 41: 栈的基本概念:

需要解决的问题 4 :如何输出搜索路径

1 … 12 13 14 15 16 17 18 19 20

x 1 … 5 2 5 6 5 6 6 5 6 …

y 1 … 6 6 3 1 7 5 4 8 8 …

pre 0 … 8 9 10 10 11 12 14 16 16 …

Page 42: 栈的基本概念:

#define r 64

#define m2 10

#define n2 10

int m = m2-2,n = n2-2;

 

typedef struct

{ int x,y;

int pre;

} sqtype;

sqtype sq[r];

struct moved

{ int x,y;

} move[8];

 

int maze[m2][n2];

Page 43: 栈的基本概念:

int SHORTPATH(int maze[][2])

{ int i,j,v,front,rear,x,y;

sq[1].x = 1; sq[1].y = 1; sq[1].pre = 0;

front = 1; rear = 1;

maze[1][1] = -1;

while(front<=rear)

{ x = sq[front].x; y = sq[front].y;

for (v=0;v<8;v++)

{ i = x+move[v].x;

j = y+move[v].y;

if (maze[i],[j]==0)

{ rear++’

sq[rear].x = i; sq[rear].y = j;

sq[rear].pre = front;

maze[i][j] = -1;

}

if ((i==m)&&(j==n))

{ PRINTPATH(sq,rear);

RESTORE(maze);

return(1);

}

}

front++;

}

return(0);

}

Page 44: 栈的基本概念:

PRINTPATH(sqtype sq[],int rear)

{ int i;

i=rear;

do

{ printf(“\n(%d,%d)”,sq[i].x,sq[i].y);

i = sq[i].pre;

} while (i!=0);

}