队列 (顺序循环队列和链式队列)

1.队列基本概念:

队列也是一种特殊的线性表,线性表允许在任意位置进行插入和删除操作,而队列只允许在一端进行插入操作(入队列),而另一端进行删除操作(出队列)。
进行插入操作的端称为队尾,进行删除操作的一端称为队头。队列中没有数据元素时称为空队列。
队头和队尾分别由队头指示器(队头指针)和队尾指示器(队尾指针)指向。
所以队列是一种先进先出表(first in first out),也称FIFO表。

在这里插入图片描述

2.操作集合:

/*初始化链式队列*/
void QueueInit(q);

/*判断队列是否非空,非空返回1,空返回0*/
int QueueNotEmpty(q);

/*元素x入队列*/
void QueueAppend(q,x);

/*出队列,元素保存在x中,成功返回1,失败返回0*/
int QueuePop(q, x);

/*取队头元素,保存在x中,成功返回1,失败返回0*/
int QueueGet(q, x);

3.实现形式

3.1顺序队列

用一片连续的存储空间来存储队列中的数据元素,这样的队列称为顺序队列。
但是顺序队列存在“假溢出”现象,即当队列满之后,队尾指针指向最后一个元素空间,表示队列已满。出队列一个元素后,此时队列应该不为队满状态,但是队尾指针仍然指向最后一个元素空间,表示队列已满。解决“假溢出”现象可以用顺序循环队列。

3.2顺序循环队列

顺序循环队列可以解决假溢出的情况,但是存在队空、队满的判断条件都是rear= =front的情况
解决顺序循环队列队空、队满状态判断有三种实现形式:

  • 少用一个储存单元
    以队尾指针rear加1等于队头指针front为队满
    此时 队满:(rear+1)%QUEUE_MAXSIZE = =front 队空:front= =rear
  • 设置一个标志位
    设置标志位tag,每当入队成功tag置1,出队成功tag置0
    此时 队满:rear = =front && tag= =0 队空:rear = =front && tag= =1
  • 设置一个计数器
    设置一个计数器count,入队加1,出队减1。
    此时 队满 count >0 && front= =rear 队空count= =0

其实计数器是标志位的一个升级版,也可之间把count当标志位用
因此下方给出少用一个储存空间和设置计数器两种代码实现。

少用一个储存空间

代码实现:

//#pragma once				//作为头文件时加上这行
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#define MAXSIZE 50
#define DataType char
typedef struct {
	DataType queue[MAXSIZE];
	int rear;
	int front;
}SeqQueue;

void QueueInit(SeqQueue* q);
int QueueNotEmpty(SeqQueue* q);
int QueueAppend(SeqQueue* q, DataType x);
int QueuePop(SeqQueue* q, DataType *x);
int QueueGet(SeqQueue* q, DataType *x);

void QueueInit(SeqQueue* q)
{
	q->rear = 0;
	q->front = 0;
}

int QueueNotEmpty(SeqQueue* q)
{
	if (q->rear != q->front)return 1;
	else return 0;
}

int QueueAppend(SeqQueue* q, DataType x)
{
	if ((q->rear + 1) % MAXSIZE == q->front) {
		printf("队列已满,无法插入\n");
		return 0;
	}
	q->queue[q->rear] = x;
	q->rear = (q->rear + 1) % MAXSIZE;
	return 1;
}

int QueuePop(SeqQueue* q, char *x)
{
	if (QueueNotEmpty(q)) {
		*x = q->queue[q->front];
		q->front = (q->front + 1) % MAXSIZE;
		return 1;
	}
	printf("队列中元素为空,无元素出队列\n");
	return 0;
}

int QueueGet(SeqQueue* q, char *x)
{
	if (QueueNotEmpty(q)) {
		*x = q->queue[q->front];
		return 1;
	}
	printf("队列中元素为空,无元素可取\n");
	return 0;
}

设置一个计数器(标志位)

代码实现:

/#pragma once				//作为头文件时加上这行
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#define DataType char
#define QUEUE_MAXSIZE 30
typedef struct {
	DataType queue[QUEUE_MAXSIZE];
	int rear;
	int front;
	int count;
}SeqQueue;
void QueueInit(SeqQueue* q);
int QueueNotEmpty(SeqQueue* q);
int QueueAppend(SeqQueue* q, DataType x);
int QueuePop(SeqQueue* q, DataType *x);
int QueueGet(SeqQueue* q, DataType *x);

void QueueInit(SeqQueue* q)
{
	q->rear = 0;
	q->front = 0;
	q->count = 0;
}
int QueueNotEmpty(SeqQueue* q)
{
	if (q->count != 0)return 1;
	else return 0;
}
int QueueAppend(SeqQueue* q, DataType x)
{
	if (q->count == QUEUE_MAXSIZE) {
		printf("队列已满,无法插入\n");
		return 0;
	}
	q->queue[q->rear] = x;
	q->count++;
	q->rear = (q->rear + 1) % QUEUE_MAXSIZE;
	return 1;
}

int QueuePop(SeqQueue* q, DataType *x)
{
	if (QueueNotEmpty(q)) {
		*x = q->queue[q->front];
		q->count--;
		q->front = (q->front + 1) % QUEUE_MAXSIZE;
		return 1;
	}
	printf("队列中元素为空,无元素出队列\n");
	return 0;
}

int QueueGet(SeqQueue* q, DataType *x)
{
	if (QueueNotEmpty(q)) {
		*x = q->queue[q->front];
		return 1;
	}
	printf("队列中元素为空,无元素可取\n");
	return 0;
}

测试函数:

void test()
{
	char c;
	SeqQueue q;
	QueueInit(&q);	//初始化队列
	//入队列
	QueueAppend(&q, 'T');
	QueueAppend(&q, 'h');
	QueueAppend(&q, 'i');
	QueueAppend(&q, 's');
	QueueAppend(&q, ' ');
	QueueAppend(&q, 'a');
	QueueAppend(&q, ' ');
	QueueAppend(&q, 't');
	QueueAppend(&q, 'e');
	QueueAppend(&q, 's');
	QueueAppend(&q, 't');
	//出队列,并输出。
	while (QueueNotEmpty(&q))
	{
		QueueGet(&q, &c);
		printf("%c ", c);
		QueuePop(&q, &c);
	}
}

运行结果:
在这里插入图片描述

3.3链式队列

代码实现:

//#pragma once				//作为头文件时加上这行
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#define DataType char

/*链式队列中结点的结构体定义*/
typedef struct queue_node{
	DataType data;
	struct queue_node* next;
}queue_node;

/*链式队列结构体*/
typedef struct {
	queue_node *front;	//队头指针
	queue_node *rear;	//队尾指针
}LinkedQueue;

/*初始化链式队列*/
void QueueInit(LinkedQueue* q);
/*判断队列是否非空,非空返回1,空返回0*/
int QueueNotEmpty(LinkedQueue* q);
/*元素x入队列*/
void QueueAppend(LinkedQueue* q, DataType x);
/*出队列,元素保存在x中,成功返回1,失败返回0*/
int QueuePop(LinkedQueue* q, DataType *x);
/*取队头元素,保存在x中,成功返回1,失败返回0*/
int QueueGet(LinkedQueue* q, DataType *x);
/*撤销队列结点的内存*/
void QueueDestroy(LinkedQueue* q);

void QueueInit(LinkedQueue* q)
{
	q->front = NULL;
	q->rear = NULL;
}

int QueueNotEmpty(LinkedQueue* q)
{
	if (q->front != NULL)return 1;
	else return 0;
}

void QueueAppend(LinkedQueue* q, DataType x)
{
	queue_node *p = (queue_node *)malloc(sizeof(queue_node));
	p->data = x;
	p->next = NULL;
	if (q->rear != NULL)q->rear->next = p;	//队列原来非空时,队尾加新结点
	q->rear = p;	//修改队尾指针
	if (q->front == NULL)q->front = p;		//队列原来为空是,修改队头指针
}

int QueuePop(LinkedQueue* q, DataType *x)
{
	queue_node *p = NULL;
	if (q->front==NULL) {
		printf("队列中元素为空,无元素出队列\n");
		return 0;
	}
	*x = q->front->data;
	p = q->front;
	q->front = p->next;	//出队列结点脱离队列
	if (q->front == NULL)q->rear = NULL;	//删除最后一个结点时要置队尾指针为空
	free(p);
	return 1;
}

int QueueGet(LinkedQueue* q, DataType *x)
{
	if (q->front == NULL) {
		printf("队列中元素为空,无元素可取\n");
		return 0;
	}
	*x = q->front->data;
	return 1;
}

void QueueDestroy(LinkedQueue* q)
{
	queue_node *p1 = NULL, *p2 = NULL;
	p1 = q->front;
	while (p1 != NULL)
	{
		p2 = p1;
		p1 = p1->next;
		free(p2);
	}
}

测试函数:

void test()
{
	char c;
	LinkedQueue q;
	QueueInit(&q);	//初始化队列
	//入队列
	QueueAppend(&q, 'T');
	QueueAppend(&q, 'h');
	QueueAppend(&q, 'i');
	QueueAppend(&q, 's');
	QueueAppend(&q, ' ');
	QueueAppend(&q, 'a');
	QueueAppend(&q, ' ');
	QueueAppend(&q, 't');
	QueueAppend(&q, 'e');
	QueueAppend(&q, 's');
	QueueAppend(&q, 't');
	//出队列,并输出。
	while (QueueNotEmpty(&q))
	{
		QueueGet(&q, &c);
		printf("%c ", c);
		QueuePop(&q, &c);
	}
}

运行结果:
在这里插入图片描述

发布了24 篇原创文章 · 获赞 11 · 访问量 5368

猜你喜欢

转载自blog.csdn.net/weixin_44339734/article/details/89265475