数据结构:队列

文章详细介绍了队列的逻辑行为,包括插入(入队)和删除(出队)操作,以及先入先出的原则。在顺序存储的循环队列中,通过数组和索引管理解决了假溢出问题,采用模运算实现队列的循环。同时,文章也提到了链式存储的队列实现,通过动态创建节点进行入队和出队操作。此外,还提供了顺序队列和链式队列的C语言代码实现。
摘要由CSDN通过智能技术生成

一、队列的逻辑行为和操作说明
1. 逻辑行为
插入和删除分别在队列两端进行,队尾进,队头出
插入元素: 从队尾插入   入队 
删除元素: 从队头删除   出队
先入先出    例如排队  银行的叫号系统


场景 什么时候需要队列:
    队列可以作为快速处理的设备(程序)和慢速设备(程序)之间的中转站
    常用队列来缓存,例如银行处理客户的服务人员很少,这时候就需要队列来缓存,假如只有1个服务人员,在10分钟内有7个人到银行,1可以不用排队,队列 2 3 4 5 6 7需要排队,结束1的业务之后就轮到2了。

2. 顺序存储的问题和解决方案
int data[5]; //为保证数组先入先出,需要有队头和队尾的索引,数组索引可以用下标表示
int rear;  // 队尾 
int front; // 队头
队列顺序存储时, data[rear] = e; rear++;
                             *e = data[front]; front++;

开始时,队列为空

元素开始入队,如下图,a,b,c三个元素依次入队

然后a,b依次出队

这时队列中只剩下c元素,d,e入队。我们发现e入队时,发生了溢出,但队列中只有3个元素,我们本来应该能存5个元素的,这种现象称为假溢出。


假溢出怎么解决 :

如果rear能回到索引为0的位置就可以了,原来弹出来的空间也可以用了。

rear,front只要在+的过程中一直在[0,4]之间就可以了,我们可以进行求模
    rear = (rear + 1) % 5
    front = (front + 1) % 5
循环队列
   队满  不能入队  front == rear 
   队空  不能出队  front == rear 

两个条件一样,无法判断条件满足时是队满还是队空。
那么如何区分循环队列的满和空的条件:

我们有两种常用方法
  方法a.空余一个空间不用  
            满:front == (rear + 1) % max
            空:front == rear

开始时,队列为空,front == rear

由于第一个空间要空出来不用,故rear先+1,然后再放入元素a,a入队

同样的,b,c,d入队

这时,front == (rear+1)%5,队满。

入队操作:rear = (rear+1)%5

出队操作:front = (front+1)%5

  方法b. 加一个标志位(rear+1标志位的值为0,front+1标志位的值为1)

3. 链式存储的设计
入队:
    新节点
       rear->next = n;
       rear = n;


出队:(备份思想)
    tmp = front;
    front = tmp->next;
    free(tmp);


二、代码

先写一个头文件common.h来存放都要用的部分

#ifndef COMMON_H
#define COMMON_H
#include <stdio.h>
#include <stdlib.h>

typedef int Element;
#endif //COMMON_H

顺序队列(循环队列)

arrayQueue.h


#ifndef ARRAYQUEUE_H
#define ARRAYQUEUE_H
#include "common.h"
#define MaxQueue 5 //定义数据域
// 定义顺序队列的结构
typedef struct {
	Element data[MaxQueue];
	int front;//队首
	int rear;//队尾
}ArrayQueue;

//产生队列
ArrayQueue *createArrayQueue();
//释放队列
void releaseArrayQueue(ArrayQueue *queue);
//入队(元素e进哪个队)
int enArrayQueue(ArrayQueue *queue, Element e);
//出队
int deArrayQueue(ArrayQueue *queue, Element *e);

#endif //ARRAYQUEUE_H

arrayQueue.c

#include "arrayQueue.h"

ArrayQueue *createArrayQueue() {
	ArrayQueue *queue = (ArrayQueue *)malloc(sizeof(ArrayQueue));//申请队列
	if (queue == NULL) {
		printf(".....!\n");
		return NULL;
	}
	queue->front = queue->rear = 0;//初始化开始时队首队尾索引都为0
	return queue;
}

void releaseArrayQueue(ArrayQueue *queue) {
	if (queue) {
		free(queue);
	}
}

//入队
int enArrayQueue(ArrayQueue *queue, Element e) {
	// 先判断队列满不满
	if ((queue->rear + 1) % MaxQueue == queue->front) {
		printf("Queue full!\n");
		return -1;
	}
	queue->rear = (queue->rear + 1) % MaxQueue;
	queue->data[queue->rear] = e;
	return 0;
}

//出队
int deArrayQueue(ArrayQueue *queue, Element *e) {
	// 先判断队列空不空
	if (queue->rear == queue->front) {
		printf("Queue empty!\n");
		return -1;
	}
	queue->front = (queue->front + 1) % MaxQueue;
	*e = queue->data[queue->front];
	return 0;
}

链式队列

linkQueue.h

#ifndef LINKQUEUE_H
#define LINKQUEUE_H
#include "common.h"
// 链式节点类型
typedef struct queNode {
	Element data;
	struct queNode *next;
}QueNode;
// 队列结构
typedef struct {
	QueNode *front;
	QueNode *rear;
	int cnt;			// 队列的元素个数
}LinkQueue;

LinkQueue *createLinkQueue();
void releaseLinkQueue(LinkQueue *queue);

int enLinkQueue(LinkQueue *queue, Element e);
int deLinkQueue(LinkQueue *queue, Element *e);

#endif //LINKQUEUE_H

linkQueue.c


#include "linkQueue.h"
#include "linkQueue.h"

LinkQueue *createLinkQueue() {
	LinkQueue *linkQueue = (LinkQueue *) malloc(sizeof(LinkQueue));
	if (linkQueue == NULL) {
		printf(".....!\n");
		return NULL;
	}
	linkQueue->front = linkQueue->rear = NULL;
	linkQueue->cnt = 0;
	return linkQueue;
}

int enLinkQueue(LinkQueue *queue, Element e) {
	// 先申请节点
	QueNode *node = (QueNode *) malloc(sizeof(QueNode));
	if (node == NULL) {
		printf("........!\n");
		return -1;
	}
	node->data = e;
	node->next = NULL;
	if (queue->rear) {					// 队尾已经指向了有效数据
		queue->rear->next = node;
		queue->rear = node;
	} else {							// 队尾为空,说明队列里没有元素
		queue->rear = queue->front = node;
	}
	queue->cnt++;
	return 0;
}

int deLinkQueue(LinkQueue *queue, Element *e) {
	// 出队要进行判断,有没有元素
	if (queue->front == NULL) {
		printf("queue empty!\n");
		return -1;
	}
	*e = queue->front->data;
	QueNode *tmp = queue->front;
	queue->front = tmp->next;
	free(tmp);
	queue->cnt--;
	if (queue->front == NULL) {			// 队列已经没有元素了
		queue->rear = NULL;
	}
	return 0;
}

void releaseLinkQueue(LinkQueue *queue) {
	if (queue) {
		QueNode *node;
		// 从队头开始逐个释放元素
		while (queue->front) {
			node = queue->front;
			queue->front = node->next;
			free(node);
			queue->cnt--;
		}
		printf("queue have %d node!\n", queue->cnt);
		free(queue);
	}
}

main.c结果来测试

#include "arrayQueue.h"
#include "linkQueue.h"

// 测试顺序存储的循环队列
int test01() {
	ArrayQueue *queue = createArrayQueue();//先产生一个队列
	Element e;
	//MaxQueue为5,我们要空一个空间不用,故我们只能存四个值
	for (int i = 0; i < 4; ++i) {
		enArrayQueue(queue, i + 100);
	}
	printf("===========!\n");
	enArrayQueue(queue, 500);
	printf("Queue:");
	for (int i = 0; i < 4; ++i) {
		deArrayQueue(queue, &e);
		printf("\t%d", e);
	}
	printf("\n");
	deArrayQueue(queue, &e);//这块要写成e的地址&e才能更新e
	releaseArrayQueue(queue);
	return 0;
}

// 测试链式队列
int test02() {
	LinkQueue *queue = createLinkQueue();
	Element e;
	for (int i = 0; i < 6; ++i) {
		enLinkQueue(queue, i + 50);
	}
	printf("cnt: %d\n", queue->cnt);
	printf("Que:");
	for (int i = 0; i < 5; ++i) {
		deLinkQueue(queue, &e);
		printf("\t%d", e);
	}
	printf("\n");
	releaseLinkQueue(queue);
	return 0;
}

int main() {
	test01();
	test02();
	return 0;
}

顺序队列测试结果:

链式队列测试结果:

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值