前言
在上次的文章中,我们实现了队列的顺序存储,也就是循环队列,既然有顺序存储,那就有链式存储。链式有个问题,究竟是需要头结点呢,还是不需要头结点呢,其实都可以,在链栈中我们使用的是没有头结点,那么在链队中我们就用有头结点的结构
1.循环队列和链队列的区别
在空间上,链队列比较灵活。在可以确定队列长度最大值的情况下,建议使用循环队列,如果你无法预估队列的长度时,则用链队列
2.链队的定义
链队也和链栈一样,需要两个结构体来定义,但是在实现过程中发现统计队列长度时不好统计,那么我们就和链栈一样,给直接他设置一个计数器。来统计队列的长度。统计时直接返回计数器的值。
//定义结点
typedef struct QNode
{
QElemType data;
struct QNode* next;
}QNode,*QueuePtr;
//定义链队列
typedef struct
{
QueuePtr front,rear;//队头指针和队尾指针
int count;//计数器
}LinkQueue;
3.有无头结点之分
有无头结点之分,其实是体现在初始化上
1.在链栈中,我们没有使用头结点,从代码中可以看到,没有头结点时栈顶指针直接指向空,其初始化:
//没有头结点的链栈初始化
Status InitStack(LinkStack *s)
{
s->top = NULL;
s->count = 0;
return OK;
}
2.在这片链队的初始化中,有头结点,利用第一个结构体创造出头结点,让队头和队尾指针都指向这个创造的头结点,其初始化:
//有头结点链队的初始化
Status InitQueue(LinkQueue *Q)
{
QueuePtr head = (QueuePtr)malloc(sizeof(QNode));
head->next = NULL;
Q->front = head;
Q->rear = head;
Q->count = 0;
return OK;
}
4.内容布局
本篇文章所涉及的主要操作有:
1.入队:
Q->rear->next = s;
Q->rear = s;
Q->count++;
2.出队:
QueuePtr p;
QElemType e;
if(Q->front == Q->rear)//队空
return ERROR;
p = Q->front->next;
e = p->data;
Q->front->next = p->next;
if(Q->rear == p)
Q->front=Q->rear;
free(p);
Q->count--;
3.显示
先定义一个指针,显示之后再逐渐为空,直到指针移到空
QueuePtr p=Q->front->next;
printf("栈内容为:\n");
while(p)
{
printf("%d ",p->data);
p = p->next;
}
代码如下
/*
程序名称:链栈的建立与基本操作
编译环境:vs2010
最后修改:2019.8.3
作者:xuan
*/
#include<stdio.h>
#include<stdlib.h>
#define M 5
#define OK 1
#define ERROR 0
typedef int Status;
typedef int QElemType;
//定义结点
typedef struct QNode
{
QElemType data;
struct QNode* next;
}QNode,*QueuePtr;
//定义链队列
typedef struct
{
QueuePtr front,rear;//队头指针和队尾指针
int count;//计数器
}LinkQueue;
Status InitQueue(LinkQueue *Q);//初始化循环队列
Status EnQueue(LinkQueue *Q);//入队
Status DeQueue(LinkQueue *Q);//出队
Status Display(LinkQueue *Q);//显示
Status Clear(LinkQueue *Q);//置空
int main()
{
Status i;
LinkQueue Q;
int n=0;
InitQueue(&Q);
while(n!=-1)
{
printf(" \n");
printf(" 1.入队 2.出队 3.清空队 -1.退出 \n");
scanf("%d",&n);
switch(n)
{
case 1:
i = EnQueue(&Q);
if(i == ERROR)
printf("失败\n");
Display(&Q);
break;
case 2:
i = DeQueue(&Q);
if(i == ERROR)
printf("失败\n");
Display(&Q);
break;
case 3:
Clear(&Q);
printf("操作后的顺序栈:\n");
Display(&Q);
break;
}
}
return 0;
}
//初始化循环队列
Status InitQueue(LinkQueue *Q)
{
QueuePtr head = (QueuePtr)malloc(sizeof(QNode));
head->next = NULL;
Q->front = head;
Q->rear = head;
Q->count = 0;
return OK;
}
//入队
Status EnQueue(LinkQueue *Q)
{
QElemType x = 0;
printf("请输入数据,-1时停止\n");
while(x != -1)
{
scanf("%d",&x);
if(x != -1)
{
QueuePtr s = (QueuePtr)malloc(sizeof(QNode));
s->data = x;
s->next = NULL;
Q->rear->next = s;
Q->rear = s;
Q->count++;
}
}
return OK;
}
//出队
Status DeQueue(LinkQueue *Q)
{
QueuePtr p;
QElemType e;
if(Q->front == Q->rear)//队空
return ERROR;
p = Q->front->next;
e = p->data;
Q->front->next = p->next;
if(Q->rear == p)
Q->front=Q->rear;
free(p);
Q->count--;
printf("出队的元素为:%d\n",e);
return OK;
}
//显示
Status Display(LinkQueue *Q)
{
QueuePtr p=Q->front->next;
printf("栈内容为:\n");
while(p)
{
printf("%d ",p->data);
p = p->next;
}
printf("\n");
printf("队列的长度为:%d\n",Q->count);
return OK;
}
//置空
Status Clear(LinkQueue *Q)
{
Q->front = Q->rear;
Q->count = 0;
return OK;
}
运行结果
后记
上述代码把链队的各种操作柔和到一个方程里面,以致于代码有些庞大,但是在实际操作中还可以适当加减操作
以上就是链栈的表示和各种操作,喜欢的多多支持哦~