栈的顺序实现
注意:每一个代码请对照教材相应的图,这样方便理解
顺序栈定义
const int maxsize=6;
typedef struct seqstack
{
DataType data[maxsize];
int top;
}SeqStk;
基本运算
1 初始化
int InitStack(SeqStk *stk)
{
stk->top=0;
return 1;
}
2 判栈空
int EmptyStack(SeqStk *stk)
//若栈为空,则返回值1,否则返回值0
{
if (stk->top==0)
return 1;
else return 0;
}
3 进栈
int Push(SeqStk *stk,DataType x)
{//若栈未满,元素x进栈stk中,否则提示出错信息
if (stk->top == maxsize-1)
{
error("栈已满");
return 0;
}
else
{
stk->top++;
stk->data[stk-top]=x;
return 1;
}
}
4 出栈
int Pop(SeqStk *stk)
{
if (EmptyStack(stk))
{
error("下溢");
return 0;
}
else
{
stk->top--;
return 1;
}
}
5 取栈顶元素
DataType GetTop(SeqStk *stk)
{//取栈顶数据元素,栈顶数据元素通过参数返回
if (EmptyStack(stk))
return NULLData;
else
return stk->data[stk->top];
}
6 两栈相遇初始化
const int max=40;
typedef struct Dbstack
{
DataType data[max];
int top1,top2;
}DbStk;
两栈相遇时,top1=top2
判断上溢,top1+1=top2
当top1=0时栈1为空栈,top2=0时栈2 为空栈
栈的链接实现
链栈定义
typedef struct node
{
DataType data;
struct node *next;
}LkSk;
栈的基本运算在链栈上的实现算法
1 初始化
void InitStack(LkStk *LS)
{
LS=(LkStk *)malloc(sizeof(LkStk));
LS->next=NULL;//建立一个空栈
}
2 判栈空
int EmptyStack(LkStk *LS)
//若栈为空,则返回值1,否则返回值0
{
if (LS->next == NULL)
return 1;
else
return 0;
}
3 进栈-头插法
void Push(LkStk *LS,DataType x)
{
LkStk *temp;
temp=(LkStk *)malloc(sizeof(LkStk));
temp->data=x;
temp->next=LS->next;
LS->next=temp;
}
4 出栈
int Pop(LkStk *LS)
//栈顶数据元素通过参数返回,它的直接后继成为新的栈顶
{
LkStk *temp;
if (! EmptyStack(LS))
{
temp=LS->next;
LS->next=temp->next;
free(temp);
return 1;
}
else return 0;
}
5 取栈顶元素
DataType GetTop(LkStk *LS)
{
if ( !EmptyStack(LS))
return LS->next-data;
else return NULLData;
}
6 栈的简单应用
写一个算法,借助栈将带头结点的单链表逆置,教材67
分析:扫描链表,将链表中数据元素依次进栈,然后,再一次扫描链表,同时依次进行出栈操作,将出栈的元素依次填到链表中去
void ReverseList(LKStk *head)
{
LKStk *S;
DataType x;
InitStack(S);
p=head->next;
while (p != NULL)
{
Push(S,p->data);
p=p->next;
}
p=head->next;
while (!EmptyStack(S))
{
p->data=Gettop(S);
Pop(S);
p=p->next;
}
}
队列的顺序实现
定义顺序队列
const int maxsize=20;
typedef struct seqqueue
{
DataType data[maxsize];
int front,rear;
}SeqQue;
SeqQue SQ;
循环队列
定义循环队列
typedef struct cycqueue
{
DataType data[maxsize];
int front,rear;
}CycQue;
CycQue SQ;
循环队列的基本运算
1 队列的初始化
void InitQueue(CycQue CQ)
{
CQ.front=0;
CQ.rear=0;
}
2 判队列空
int EmptyQueue(CycQue CQ)
{
if (CQ.rear == CQ.front)
return 1;//队列空返回1
else return 0;
3 人队列
int EnQueue(CycQue CQ,DataType x)
{
if ((CQ.rear+1) % maxsize == CQ.front)
{
error(“队列满");
return 0;
}
else
{
CQ.rear=(CQ.rear+1)%maxsize;
CQ.data[CQ.rear]=x;
return 1;
}
}
4 出队列
int OutQueue(CycQue CQ)
{
if (EmptyQueue(CQ))
{
error(“队列空");
return 0;
}
else
{
CQ.front=(CQ.front+1)%maxsize;
return 1;
}
}
5 取队列首元素
DataType GetHead(CycQue CQ)
{
if (EmptyQueue(CQ))
return NULLData;
else
return CQ.data[(CQ.front+1)%maxsize];
}
队列应用
在日常生活中,到银行办理业务时,往往需要排队等候,也就是按照“先到先服务”的原则。
在排队等候的过程中,主要有两件事:
(1)客户到达银行时,在电脑上取号;
(2)客户等待银行电脑语音报号,当报出某客户的序号时,客户到相应的窗口接受服务。
用类C语言算法描述如下:
void GetService()
{
LkQue LQ;
int n;
char ch;
InitQueue(&LQ)
while(1)
{
printf("\n请输入命令:”);
scanf("%c",&ch);
switch(ch)
{
case 'A':
printf("客户取号\n");
scanf("%d",&n);
EnQueue(&LQ,n);
break;
case 'N’:
if (!EmptyQueue(LQ))
{
n=Gettop(LQ);
OutQueue(&LQ);
printf("号为 %d的客户接受服务",n);
}
else printf("无人等待服务\n");
break;
case 'Q':
printf("排队等待的人依次接受服务\n");
break;
}
if (ch=='Q')
{
while (!EmptyQueue(LQ))
{
n=Gettop(LQ);
OutQueue(&LQ);
printf("号为 %d的客服接受服务",n);
}
break;
}
}
}
数组
应用举例:设停车场(图3-32)内只有一个可停放几辆汽车的狭长通道,且只有一个大门可供汽车进出。汽车在停车场内按车辆到达时的先后顺序,依次由北向南排列(大门在最南端,最先到达的第一辆车停 放在车场的最北端),若车场内已停满汽车,则后来的汽车只能在门外的便道上等候,一日停车场内有车开走,则排在便道上的第一 辆车即可开入;当停车场内某辆车要离开时,由于停车场是狭长的通道,在它之后开入车场的车辆必须先开出去为它让路,待该辆车开出大门外后,为它让路的车辆再按原次序进入停车场。在这里假设汽车不能从便道上开走。试设计这样一个停车场管理程序(这里只是个假想的停车场管理)。
分析:汽车在停车场内进出方式和栈的特征相似。当有空位时,汽车进入停车场:停车场的汽车离开停车场时,车场内其他汽车为该辆汽车让路,是按栈的方式进行:汽年在便道上等候是按队列的方式进行。因此,将停车场设计成一 个栈,汽车让路也需要另一个栈来协助完成,汽车进出便道用队列来实现。本程序中,栈采用顺序存储结构,队列用链式存储结构,分别在头文件Seqstack.h和Lkqueue.h中定义。
//以下是头文件Seqstack.h
const int stacksize=40;
typedef struct SQstack
{
int data[stacksize];
int top;
}SQStackTp;
//以下为顺序栈的各运算符的函数
int InitStack(SeqStk *SQ) //栈的初始化
{
SQ->top=0;
return 1;
}
int EmptyStack(SeqStk *SQ)
//若栈为空,则返回值1,否则返回值0
{
if (SQ->top==0)
return 1;
else return 0;
}
int Push(SeqStk *SQ,int x)
{//进栈、若栈未满,元素x进栈stk中,否则提示出错信息
if (SQ->top ==stacksize-1)
return 0;
else
{
SQ->top++;
SQ->data[SQ-top]=x;
return 1;
}
}
int Pop(SeqStk *stk) //出栈
{
if EmptyStack(SQ)
{
error("下溢");
return 0;
}
else
{
SQ->top--;
return 1;
}
}
int GetTop(SeqStk *SQ)
{//取栈顶数据元素
if (EmptyStack(SQ)
return -1;//栈空,返回-1
else return SQ->data[SQ->top];
}
//以下为头文件Lkqueue.h
typedef struct LinkQueueNode //队列的存储结构
{
int data;
struct LinkQueueNode *next;
}LkQueNode;
typedef struct LkQueue
{
LkQueNode *front,*rear;
}LkQue;
//以下为链队各运算的函数
IntQueue(LkQue *LQ)
{
LkQueNode *p;
p=(LkQueNode*)malloc(sizeof(LkQueNode));
LQ->front=p;
LQ->rear=p;
(LQ->front)->next=NULL;
}
int EmptyQueue(LkQue LQ)
{
if (LQ.rear==LQ.front)
return 1;
else return 0;
}
void EnQueue(LkQue *LQ,int x) //入队列
{
LkQueNode *p;
p=(LkQueNode*)malloc(sizeof(LkQueNode));
p->data=x;
p-next=NULL;
(LQ->rear)->next=p;
LQ->rear=p;
}
int OutQueue(LkQue *LQ) //出队列
{
LkQueNode *s;
if EmptyQueue(LQ);
{
error("队空");
return 0;
}
else {
s=(LQ->front)-next;
(LQ->front)->next=s->next;
if (s->next==NULL)
LQ->rear=LQ->front;
free(s);
return 1;
}
}
int GetHead(LkQue LQ) //取队首元素
{
LkQueNode *p;
if EmptyQueue (LkQue LQ)
return -1;
else {
p=LQ.front->next;
return p->next;
}
}
分析:汽车在停车场内进出方式和栈的特征相似。当有空位时,汽车进入停车场:停车场的汽车离开停车场时,车场内其他汽车为该辆汽车让路,是按栈的方式进行;汽车在便道 上等候是按队列的方式进行。因此,将停车场设计成 一个栈,汽车让路也需要另一个栈来协助完成,汽车进出便道用队列来实现。本程序中,栈采用顺序存储结构,队列用链式存储结构,分别在头文件Seqstack.h 和Lkqueue.h中定义。
下面是解决问题的应用程序
#include <stdio.h>
#include <alloc.h>
#include "Seqstack.h"
#include "LkQueue.h"
void main()
{
SeqStk ps,ts;
LkQue LQ;
int out,number,temp;
char ch;
InitStack(&ps); //初始化ps栈,它存储停车场车辆
InitStack(&ts); //初始化ts栈,它存储临时退出停车场的车辆
InitQueue(&LQ); //初始化LQ队列,它存储便道上车辆
out=0; //out=0表示在停车场未找到车号为number的车辆
//out=1表示找到了
scanf("%c",&ch); //读入命令
scanf("%d",&number); //读入车号,当车号为0时程序结束
while (number>0);
{
switch(ch)
{
case 'A' : //车辆进入停车场
if (ps.top==stacksize-1)//停车场满
{
EnQueue(&LQ,number);
printf("停车场已满! 第%d号车入便道!\n",number);
}
else {
Push(&ps,number);
printf("第 %d号车入车场!\n",number);
}
break;
case 'D': //车辆开出停车场
while (!EmptyStack(ps))
{
temp=Gettop(ps);
Pop(&ps);
if (temp!=number)
Push(&ts,temp);
else {
printf("第%d号离开停车场!\n",number);
out=1;
break;
}
}
while (!EmptyStack(ts)) //临时开出停车场的车开回停车场
{
temp=Gettop(ts);
Pop(&ts);
Push(&ps,temp);
}
if (out && !EmptyQueue(LQ))
{
temp=GetHead(&LQ);
OutQueue(&LQ);
printf("第%d号车由便道->停车场!\m",temp);
Push(&ps,temp);
}
out=0;
break;
}
scanf("%c",&ch); //继续读入命令
scanf("%d",&number); //继续读入车号
}
}