null第三章 栈和队列第三章 栈和队列栈(Stack)
栈的应用
队列(Queue)
队列的应用 定 义定 义3.1 栈与线性表相同,数据元素之间仍为一对一的关系。用顺序栈或链栈存储均可。只能在栈顶运算,且访问结点时依照后进先出(LIFO)或先进后出(FILO)的原则。关键是编写入栈、出栈等函数,具体实现按顺序栈或链栈的存储结构的不同而不同。限定只能在表的一端进行插入和删除运算的线性表。基本操作 建栈、判断栈满或栈空、入栈、出栈、读栈顶元素值,等等。null栈 是仅在表尾进行插入、删除操作的线性表。
表尾(即 an 端)称为栈顶 (top) ;
表头(即 a1 端)称为栈底(bottom)。例如: 栈 S= (a1 , a2 , a3 , ……….,an-1 , an )插入元素到栈顶的操作,称为入栈。
从栈顶删除元素的操作,称为出栈。an称为栈顶元素a1称为栈底元素强调:插入和删除都只能在表的一端(栈顶)进行!栈的基本操作栈的基本操作InitStack(S): 构造一个空栈S
ClearStack(S): 清除栈S中的所有元素
StackEmpty(S):判断栈S是否为空,若为空,则返回 true;否则返回false
GetTop(S) : 返回S的栈顶元素,但不移动栈顶指针
Push(S, x) :插入元素x为新的栈顶元素(入栈操作)
Pop(S) : 删除S的栈顶元素并返回其值(出栈操作)null顺序栈的存储结构和操作的实现 顺序栈:是利用一组地址连续的存储单元依次存放从栈底到栈顶的数据元素。
在C语言中,预设一个数组的最大空间,栈底设置在0下标端,栈顶随着插入和删除元素而变化,用一个整型变量top来指示栈顶的位置。0n压入(PUSH): S[++top]=an+1
弹出( POP) : e=S[top - -]null顺序栈存储结构的描述:
#define Maxsize 100 /*设顺序栈的最大长度为100,可依实现情况而修改*/
typedef int datatype;
typedef struct
{
datatype stack[Maxsize];
int top; /*栈顶指针*/
}SeqStack; /*顺序栈类型定义*/
SeqStack *s; /*s为顺序栈类型变量的指针*/
null顺序栈的几种状态以及在这些状态下栈顶指针top和栈中结点的关系 栈为空的条件 : top==-1;
栈满的条件 : top==Maxsize-1顺序栈的基本操作顺序栈的基本操作若入栈动作使地址向高端增长,称为“向上生成”的栈;
若入栈动作使地址向低端增长,称为“向下生成”的栈;
对于向上生成的堆栈:
入栈:栈指针top “先加后压” : S[++top]=an+1
出栈:栈指针top “先弹后减” : e=S[top--]null构造一个空顺序栈 SeqStack *InitStack()
{ SeqStack *S ;
S=(SeqStack *)malloc(sizeof(SeqStack));
if(!S)
{printf(“空间不足”);
return NULL;}
else
{S->top=-1;
return S;}
}
null取顺序栈栈顶元素 datatype GetTop(SeqStack *S)
{if (S->top== -1)
{ printf("\n栈是空的!");
return FALSE;}
else
return S->stack[S->top];
} null判别空栈int StackEmpty(SeqStack *S)
{if(S->top== -1)
return TRUE;
else
return FALSE;
}
顺序栈的入栈操作——例如用堆栈存放(A,B,C,D)顺序栈的入栈操作——例如用堆栈存放(A,B,C,D)A
A
C
B
A
B
A核心语句:
顺序栈入栈函数PUSH()
SeqStack*Push(SeqStack*S,datatype x)
{if(S->top==Maxsize-1) return NULL;/*栈满*/
else
{S->top++;
S->stack[S->top]=x;
return s;}
} Push (B);Push (C);Push (D);低地址LPush (A);高地址MBCD顺序栈出栈操作——例如从栈中取出‘B’顺序栈出栈操作——例如从栈中取出‘B’核心语句:
Pop ( );顺序栈出栈函数POP()
datatype Pop( SeqStack *S)
{if(S->top==-1) /*栈空*/
{printf("\nThe sequence stack is empty!");
return FALSE;}
else {S->top- -;
return S->stack[S->top+1];}
} Pop ( );Printf( Pop () );链 栈链 栈链栈的构造方式——用top指向栈顶,只能在栈顶插入或删除。栈顶栈底栈也可以用链式结构来表示,用链式结构来表示的栈就是链栈。链栈中每个结点由两个域构成:
data域和next域,其定义为:Typedef struct node
{datatype data; /*数据域*/
struct node *next; /*指针域*/
}LinkStack;
LinkStack *top; /* top为栈顶指针*/ null将x入栈,修改栈顶指针:top=pan出栈,修改栈顶指针:top=top->next链栈的入栈操作和出栈操作nullLinkStack *Push((LinkStack *top,datatype x)
{ LinkStack *p;
p=( Linkstack *)malloc(sizeof(LinkStack));
p->data=x;
p->next=top;
top=p;
return top;
}链栈入栈操作null LinkStack *Pop( LinkStack *top)
{ LinkStack *q;
if(!top) {printf("\n链栈是空的!");return NULL;}
else
{q=top; /*q指向要删除的栈顶结点*/
top=top->next; /*栈顶指针下移*/
free(q); /*释放q指向结点空间*/
return top;
}
}链栈出栈操作3.2 栈的应用举例3.2 栈的应用举例1、数制转换(十进制数N转换为r进制数)
设计思路:用栈暂存余数(低位值)
2、括号匹配问题
设计思路:用栈暂存左括号
3、子程序的调用
设计思路:用栈暂存指令地址
4、逆置一个单链表
设计思路:用栈暂存每一结点的数据
null例3.2 将十进制整数转换成二至九之间的任一进制数输出 将一个十进制数4327转换成八进制数(10347)8:
null⑴ 当N≠0,将N%r压入栈s中;
⑵ N/r ⇒ N;
⑶ 若N>0,则重复⑴、⑵两步;若N=0,则将栈s的内容依次出栈。
解题思路如下:void conversion(int N, int r)
{ int x=N,y=r;
SeqStack *s;
s=InitStack(); while(N!=0)
{ Push(s, N %r );
N=N/r ;
}
printf(“\n十进制数%d所对应的%d进制数是:”,x,y);
while(!StackEmpty(s)) printf(“%d”,Pop(s));
printf(“\n”);
}
null例3.5 利用一个顺序栈将一个带头结点的单链表(a1,a2,…,an)(其中n>=0)逆置为(an,an-1,…,a1)。null1、建立一个带头结点的单链表head;
2、输出该单链表;
3、建立一个空栈s(顺序栈);
4、依次将单链表的数据入栈;
5、依次将单链表的数据出栈,并逐个将出栈的数据存入单链表的数据域(自前向后);
6、再输出单链表。 解题思路如下:linklist*backlinklist(linklist *head)
{linklist *p;
p=head->next;
initstack();
while(p)
{push(&s, p->data); p=p->next ;
}
p=head->next;
while(!stackempty(s))
{p->data=pop(&s); p=p->next;
}
return (head);
}
; 3.3 队列 3.3 队列 与线性表相同,仍为一对一关系。顺序存储方式:顺序队列(循环队列)和链式存储方式:链队列。只能在队尾入队、队头出队,并遵循先进先出(FIFO)的原则。关键是掌握入队和出队操作,具体实现按存储方式的不同(顺序队列或链队列)而不同。只能在表的一端进行插入运算,在表的另一端进行删除运算的线性表。基本操作 入队、出队、建空队列、判队空或队满等。尾部插入头部删除队列定义null队列 (Queue)是仅在表尾进行插入操作、在表头进行删除操作的线性表。它是一种先进先出(FIFO)的线性表。例如:队列 Q= (a1 , a2 , a3 , ……….,an-1 , an )在队尾插入元素称为入队;在队首删除元素称为出队。队首队尾 队列的实现方式是本节重点,关键是掌握入队和出队等操作。 具体实现按存储结构的不同(顺序队列或链队列)而不同。队列的基本操作队列的基本操作(1)InitQueue(Q): 构造一个空队列Q
(2)QueueEmpty(Q): 判断队列是否为空
(3)QueueLength(Q):求队列的长度
(4)GetHead(Q): 返回Q的队头元素,不改变队列状态
(5)EnQueue(Q,x): 入队列:插入元素x为Q的新的队尾元素
(6)DeQueue(Q): 出队列:删除Q的队头元素
(7)ClearQueue(Q): 清除队列Q中的所有元素
链队列链队列链队列类型定义:
typedef struct
{
Qnode *front ; /*队头指针*/
Qnode *rear ; /*队尾指针*/
}LinkQueue;
LinkQueue *q; /*q是链队列指针,其中封装了队头指针和队尾指针*/结点类型定义:
typedef Struct Qnode
{
datatype data; /*数据域*/
Struct Qnode *next; /*指针域*/
}Qnode; null链队列的几种状态示意图:此时,front==rear修改rear指针修改头结点的指针域
①链队列为空的特征:front==rear② 链队列会满吗?一般不会,因为删除时有free动作,除非内存不足!修改rear指针null入队(尾部插入):rear->next=S;
rear=S;
出队(头部删除):front->next=front->next->next;③ 怎样实现链队列的入队操作和出队操作?
假设S所指结点为入队结点,则有nullLinkQueue *InitQueue()
{LinkQueue *q; /*q为链队列指针,q中封装了队头指针和队尾指针*/
Qnode *p; /*p为指向链队列结点的指针*/
Q=(LinkQueue*)malloc(sizeof(LinkQueue));
p=(Qnode*)malloc(sizeof(Qnode));
p->next=NULL;
q->front =q->rear=p;
return q;
}构造一个空链队列nulldatatype GetHead(LinkQueue *Q)
{if(Q->front==Q->rear)
{printf(“\n链队列为空!”);
return FALSE;}
else
return Q->front->next->data; /*返回队头元素的值*/
}取链队列的队头元素nullvoid EnQueue(LinkQueue *Q,datatype x)
{ Qnode *p; /*p为指向链队列结点的指针*/
p = (Qnode *)malloc(sizeof(Qnode));
p->data = x;
p->next = NULL;
Q->rear->next = p;
Q->rear=p;
} 链队列的入队操作nulldatatype DeQueue(LinkQueue *Q)
{ Qnode *p; /*p为指向链队列结点的指针*/
datatype x;
if (Q->front == Q->rear)
{printf("队列为空,无法删除!"); return FALSE;}
else
{p = Q->front->next; /*p指向链队列的队头结点*/
x = p->data; /*将队头元素的值赋给变量x*/
Q->front->next = p->next; /*出队列,修改队头指针*/
if(Q->rear == p) Q->rear=Q->front; /*若出队列后队列为空,
则还应当修改队尾指针,使队尾指针指向头结点*/
free(p); /*释放空间*/
return x; /*返回已出队元素(即原队头元素)的值*/
}
}链队列的出队操作null循环(顺序)队列的类型定义:#define MAXSIZE 100 /* 最大队列长度 */
typedef struct
{
datatype data[MAXSIZE]; /* 存储队列的数据空间 */
int front; /* 队头指针,若队列不空,则指向队头元素 */
int rear; /* 队尾指针,若队列不空,则指向队尾元素的下一个位置 */
}SeqQueue; 头、尾指针与队列中元素之间的关系示意图:null入队操作时的尾指针运算: rear=(rear+1)%Maxsize
出队操作时的头指针运算: front=(front+1)%Maxaize
问题:在循环队列中,由于队空时有front==rear;队满时也有front==rear;因此我们无法通过front==rear来判断队列是“空”还是“满”。
循环队列示意图循环队列的几种状态null循环队列空的条件 : front = =rear
循环队列满的条件: front == (rear+1) % MAXSIZE
循环队列长度为:L=(rear-front +MAXSIZE)% MAXSIZE 解决
办法
鲁班奖评选办法下载鲁班奖评选办法下载鲁班奖评选办法下载企业年金办法下载企业年金办法下载
:少用一个元素空间,约定以“队头指针在队尾指针的下一位置(指环状的下一位置)”作为队列“满”的标志。也就是说,若数组的大小是MAXSIZE,则该数组所表示的循环队列最多允许存储MAXSIZE-1个结点。注意: rear所指的结点始终为空。循环队列满的示意图:null经过约定后的循环队列操作示意图 (p.70,图3.13改)null循环队列的基本操作实现
以创建队列、入队和出队三种基本操作为例1、构造(初始化)一个空队列算法要求:生成一空队列
算法步骤:
①为队列分配存储空间;
②设置队列为空队列,其特征为:
front=rear=0null构造一个空队列qSeqQueue *InitQueue()
{ SeqQueue *q;
q=(SeqQueue *)malloc(sizeof(SeqQueue));
/* 开辟一个足够大的存储队列空间 */
q->front = q->rear = 0;
/* 将队列头尾指针置为零 */
return q; /* 返回队列的首地址 */
} null算法说明:向循环队列的队尾插入一个元素。
分 析:
(1)入队前应当先判断队列是否已满?
if((q->rear+1)% Maxsize)==q->front)
return false;
(2)入队动作如下:
q->data[q->rear] = x;
q->rear=(q->rear+1)% Maxsize;2、入队操作nullint EnQueue(SeqQueue *q, datatype x)
{ if((q->rear+1)%MAXSIZE==q->front)
{printf(“\n循环队列满!”); return FALSE;}
q->data[q->rear] = x;
q->rear = (q->rear+1)%MAXSIZE;
return TRUE;
}循环队列入队操作null3、出队操作算法说明:删除循环队列的队头元素,返回其值 x。
分 析:
(1)在出队前应当判断队列是否为空?
if (q->front==q->rear) return false;
(2)出队动作如下:
x= q->data[q->front];
q->front=(q->front+1)% Maxsize; nulldatatype DeQueue(SeqQueue *q)
{ datatype x;
if (q->front = = q->rear)
{printf(“\n循环队列空!不能做删除操作!”);
return FALSE;}
x = q->data[ q->front ];
q->front = (q->front+1)%MAXSIZE;
return x;
}循环队列出队操作null3.4 队列的应用1、打印杨辉三角形2、迷宫问题:寻找一条从迷宫入口到出口的最短路径 null例3.7 打印杨辉三角形。 此问题是一个初等数学问题。系数表中的第i行有i+1个数,除了第1个和最后一个数为1外,其余的数则为上一行中位于其左、右的两数之和。null算法分析 如果要计算并输出二项式系数表(即杨辉三角形)的前n行的值,则所设循环队列的最大空间应为n+2。假设队列中已存有第i行的值,为计算方便,在两行之间均加一个“0”作为行间的分隔符,则在计算第i+1行之前,头指针正指向第i行的“0”,而尾元素为第i+1行的“0”。由此,从左至右输出第i行的值,并将计算所得的第i+1行的值插入队列。
null分析第 i 行元素与第 i+1行元素的关系如图所示 :null 假设n=4,i=3,则输出第3行元素并求解第4行元素值的循环执行过程中队列的变化状态如图所示 :null程序如下: (n≤7)
#define MAXSIZE 10 /*定义队列的最大长度*/
#include
#include
typedef int datatype;
typedef struct
{ int data[MAXSIZE];
int front;
int rear;
}SeqQueue;
SeqQueue *InitQueue() /*队列初始化*/
{ SeqQueue *q;
q=(SeqQueue*)malloc(sizeof(SeqQueue));
q->front = q->rear = 0;
return q;
}
nullvoid EnQueue(SeqQueue *q, datatype x) /*入队列*/
{ if((q->rear+1)%MAXSIZE==q->front)
{printf("\n顺序循环队列是满的!");}
else
{q->data[q->rear] = x;
q->rear = (q->rear+1)%MAXSIZE;
}
}
datatype DeQueue (SeqQueue *q) /*出队列*/
{datatype x;
if(q->front==q->rear)
{ printf("\n顺序队列是空的!不能做删除操作!"); return 0;}
x = q->data[q->front];
q->front = (q->front+1)%MAXSIZE;
return x;
}
nullint QueueEmpty(SeqQueue *q) /*判队空*/
{ return(q->front==q->rear);
}
int GetHead(SeqQueue *q) /*取队头元素*/
{int e;
if(q->front==q->rear) e=0;
else e=q->data[q->front];
return e;
}
void YangHui( int n ) /*打印杨辉三角形的前n行, n≤7*/
{ SeqQueue *q;
int i, j,s,t;
for(i=1;i<=n;i++)
printf(" ");
printf(“1\n”); /*在中心位置输出杨辉三角最顶端的1(第0行)*/
q=InitQueue(); /*设置容量为n+2的空队列*/
EnQueue(q,0); /*添加行分隔符*/
EnQueue(q,1);EnQueue(q,1); /*第1行的值入队*/
nullfor(j=1;j
本文档为【数据结构DS03-栈和队列】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑,
图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。