实验三 顺序栈和队列基本操作的实现
一、实验学时: 2学时
二、实验目的
- 实现顺序栈和队列的基本操作
三、实验内容
- 顺序栈的建立、取栈顶元素、入栈、出栈
- 队列的建立、取队中元素、入队、出队、循环队列中入队、出队操作
四、主要仪器设备及耗材
- 硬件:计算机一台
- 软件:VC++ 6.0,MSDN2003或者以上版本
五、实验步骤
- 分析问题
- 写出算法
- 编制程序
- 上机调试
- 分析结果
六、程序清单
1.顺序栈
#include<stdio.h>
#include<stdlib.h>
#define OK 0
#define ERROR -1
#define OVERFLOW -2
#define MAXSIZE 100 //顺序栈存储空间的初始分配量
//建立顺序栈
typedef struct
{
int *base; //栈底指针
int *top; //栈顶指针
int stacksize; //栈可用的最大容量
}SqStack;
//初始化顺序栈
int InitStack(SqStack &S)
{
S.base=new int[MAXSIZE];
if(!S.base) exit(OVERFLOW);
S.top=S.base; //top初始为base,空栈
S.stacksize=MAXSIZE; //stacksize置为栈的最大容量MAXSIZE
return OK;
}
//压栈
int Push(SqStack &S,int e)
{
if(S.top-S.base==S.stacksize) return ERROR;
*S.top++=e; //它等价于*S.top=e; S.top++;
return OK;
}
//弹栈
int Pop(SqStack &S,int &e)
{
if(S.top==S.base) return ERROR;
e=*--S.top;
return OK;
}
//取栈顶元素
int GetTop(SqStack S)
{
if(S.top!=S.base)
return *(S.top-1);
}
int main()
{
SqStack S;
//初始化栈
InitStack(S);
int jz,num;
printf("请问你要转换几进制:");
scanf("%d",&jz);
printf("请输入你要转换的十进制数:");
scanf("%d",&num);
while(num!=0)
{
//压榨
Push(S,(num%jz));
num/=jz;
}
//取栈顶元素
printf("栈顶元素为%d\n",GetTop(S));
while(S.top!=S.base)
{
int i;
//弹栈
Pop(S,i);
printf("%d",i);
}
}
2.链栈
#include<stdio.h>
#include<stdlib.h>
#define OK 0
#define ERROR -1
#define OVERFLOW -2
//创建链栈
typedef struct StackNode
{
int data;
struct StackNode *next;
}StackNode,*LinkStack;
//初始化
int InitStack(LinkStack &S)
{
//构造一个空栈S,栈顶指针置空
S=NULL;
return OK;
}
//入栈
int Push(LinkStack &S,int e)
{
//在栈顶插入元素e
StackNode *p;
p=new StackNode;
p->data=e;
p->next=S; //将新节点插入栈顶
S=p; //修改栈顶指针为p
return OK;
}
//出栈
int Pop(LinkStack &S,int &e)
{
//删除S的栈顶元素,用e返回其值
if(S==NULL) return ERROR;
e=S->data;
StackNode *p;
p=S; //用p临时保存栈顶元素空间,以备释放
S=S->next; //修改栈顶指针
delete p; //释放原栈顶元素空间
return OK;
}
//取栈顶元素
int GetTop(LinkStack &S)
{
if(S!=NULL)
return S->data;
}
int main()
{
LinkStack S;
//链栈初始化
InitStack(S);
int jz,num;
printf("请问你要转换几进制:");
scanf("%d",&jz);
printf("请输入你要转换的十进制数:");
scanf("%d",&num);
while(num!=0)
{
//压栈
Push(S,(num%jz));
num/=jz;
}
//取栈顶元素
printf("栈顶元素为:%d\n",GetTop(S));
while(S!=NULL)
{
int i;
//弹栈
Pop(S,i);
printf("%d",i);
}
}
3.循环队列
#include<stdio.h>
#include<stdlib.h>
#define MAXSIZE 6
//建立顺序队列
typedef struct
{
int *base; //存储空间的基地址
int front; //头指针
int rear; //尾指针
}SqQueue;
//初始化顺序队列
int InitQueue(SqQueue &Q)
{
Q.base=new int[100];
if(!Q.base) exit(-2);
Q.front=Q.rear=0; //头指针和尾指针置为0,队列为空
return 0;
}
//入队
int EnQueue(SqQueue &Q,int e)
{
//printf("rear=%d,front=%d\n",Q.rear,Q.front);
if((Q.rear+1)%MAXSIZE==Q.front) //队满
return -1;
Q.base[Q.rear]=e; //新元素加入队尾
Q.rear=(Q.rear+1)%MAXSIZE; //队尾指针加1
//printf("rear=%d,front=%d\n",Q.rear,Q.front);
return 0;
}
//出队
int DeQueue(SqQueue &Q,int &e)
{
if(Q.front==Q.rear) return -1; //队空
e=Q.base[Q.front]; //队头元素给e
Q.front=(Q.front+1)%MAXSIZE; //队头指针加1
return 0;
}
//取队头元素
int GetHead(SqQueue Q)
{
if(Q.front!=Q.rear) //队列非空
return Q.base[Q.front]; //返回队头元素的值
}
//求循环队列长度
int QueueLength(SqQueue Q)
{
return (Q.rear-Q.front+MAXSIZE)%MAXSIZE;
}
//胡乱写的...
void f1(SqQueue &Q,int &num)
{
while(num!=0){
int flag=EnQueue(Q,num);
if(!flag)
printf("%d入队成功!\n",num);
else
printf("%d入队失败!\n",num);
printf("请输入要入队的东东:");
scanf("%d",&num);
}
if(num==0)
printf("检测到0,入队结束!\n请输入要出队的元素个数:");
int count,i;
scanf("%d",&count);
if(count>QueueLength(Q))
printf("队列中元素不足...\n");
for(i=0;i<count;i++)
{
int chu;
DeQueue(Q,chu);
printf("%d已出队\n",chu);
}
printf("请输入要入队的东东:");
scanf("%d",&num);
f1(Q,num);
}
int main()
{
SqQueue Q;
//循环队列初始化
InitQueue(Q);
int num=0;
printf("请输入要入队的东东:");
scanf("%d",&num);
f1(Q,num);
}
4.链队
#include<stdio.h>
#include<stdlib.h>
#define MAXSIZE 6
//建立队列的链式存储结构
typedef struct QNode
{
int data;
struct QNode *next;
}QNode,*QueuePtr;
typedef struct
{
QueuePtr front;
QueuePtr rear;
}LinkQueue;
//初始化
int InitQueue(LinkQueue &Q)
{
Q.front=Q.rear=new QNode; //生成新结点作为头结点,队头和队尾指针指向该结点
Q.front->next=NULL; //头结点的指针域置空
return 0;
}
//入队
int EnQueue(LinkQueue &Q,int e)
{
QNode *p;
p=new QNode; //为入队元素分配结点空间,用指针p指向
p->data=e; //将新结点数据域置为e
p->next=NULL;Q.rear->next=p; //将新结点插入到队尾
Q.rear=p; //修改队尾指针
return 0;
}
//出队
int DeQueue(LinkQueue &Q,int &e)
{
if(Q.front==Q.rear) return -1; //队列为空报错
QNode *p;
p=Q.front->next; //p指向队头元素
e=p->data; //e保存队头元素的值
Q.front->next=p->next; //修改头结点的指针域
if(Q.rear==p) Q.rear=Q.front; //最后一个元素被删,队尾指针指向头结点
delete p; //释放原队头元素的空间
return 0;
}
//取队头元素
int GetHead(LinkQueue Q)
{
if(Q.front!=Q.rear)
return Q.front->next->data;
}
int main()
{
//和顺序队列测的方法差不多
}
七、运行结果及分析
1.顺序栈
2.链栈
3.循环队列
4.链队
和循环队列的测试差不多
八、小总结
1.顺序栈
- 对于顺序栈来说,就跟汉诺塔一样,先进的后出后进的先出。它里面有三个成员:栈顶指针、栈底指针和栈可用的最大容量。
- 初始化:动态分配一个最大容量大小的数组空间,栈底指针指向它。如果空间满了就溢出。没满就栈顶指针也指向栈底所指。栈可用空间为最大容量。
- 入栈:若栈满则报错,否则栈顶指针所指空间数据置为元素e,栈顶指针上移。
- 出栈:栈空报错,否则栈顶指针向下移,元素赋给e。
- 取栈顶元素:栈非空,则返回栈顶元素即可。
2.链栈
- 对于链栈来说,感觉比顺序栈简单
- 初始化:把栈顶指针置空即可。
- 入栈:开个新结点p,数据域置为e,指向S,S=p(让新加的作栈顶)
- 出栈:若栈空则报错,否则取出栈顶数据给e,p临时保存原栈顶,让S的下一个做栈顶,释放原栈顶空间。
- 取栈顶元素:若S非空,则返回栈顶元素。
3.循环队列
- n个元素的循环队列满的时候只有n-1个元素。P71。这时候(Q.rear+1)%MAXSIZE==Q.front已经成立了。最后一个位置是空着的。但是判满条件已经满足了。
- 建立队列:自定义类型SqQueue,里面有三个成员。一是base指针,指向存储空间的基地址;二是头指针三是尾指针(只是两个整型变量用来指示队首队尾位置的)。
- 初始化:基地址指针指向新开辟的基地址空间,若为NULL则溢出。头指针尾指针均置为0,。
- 入队:队满则报错。将新元素插入队尾,队尾指针加1。
- 出队:队空报错。队头元素赋给e,头指针加1。
- 取队头元素:队列非空返回队头值。
- 求队列长度:(Q.rear-Q.front+MAXSIZE)%MAXSIZE;
4.链队
…