数据结构之队列的链式存储结构 C语言版

前言

在上次的文章中,我们实现了队列的顺序存储,也就是循环队列,既然有顺序存储,那就有链式存储。链式有个问题,究竟是需要头结点呢,还是不需要头结点呢,其实都可以,在链栈中我们使用的是没有头结点,那么在链队中我们就用有头结点的结构

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;
}

运行结果

运行结果

后记

上述代码把链队的各种操作柔和到一个方程里面,以致于代码有些庞大,但是在实际操作中还可以适当加减操作

以上就是链栈的表示和各种操作,喜欢的多多支持哦~

发布了12 篇原创文章 · 获赞 10 · 访问量 1141

猜你喜欢

转载自blog.csdn.net/bsqetuo/article/details/98314612