双端队列(C语言实现)

文章详细介绍了双端队列的概念,与普通队列的区别在于它可以同时在两端进行入队和出队操作。接着,文章提供了双端队列使用循环数组实现的C语言代码,包括创建、清空、销毁队列以及各种入队、出队、获取头尾元素的方法。最后,给出了测试代码以展示其功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

队列是一种操作受限的线性表,它只允许从队头出队,从队尾入队,就像生活中的排队一样。双端队列放宽了这种限制,它可以从队头出队或入队,也可以从队尾出队或入队。

一般队列:

 

双端队列:

 

双端队列可以从两端进行出队和入队,也可以对一种操作进行限制,例如,入队受限(一端入队)的双端队列和出队(一端出队)的双端队列。

双端队列可以使用循环数组来实现,也可以使用双链表来实现,下面给出双端队列的循环数组实现,链表实现的原理与队列的实现也是类似的,但由于双端队列可能会从尾部删除结点,所以为了效率,使用能够找到前驱结点的双链表。

循环数组实现:

#define MAX_SIZE 20

//双端队列可以使用数组或链表实现,使用双链表应该比较简单,但这里使用循环数组来实现双端队列的增删改查等操作
typedef struct DoubleQueue {
	int front;//头指针
	int rear;//尾指针
	int numofele;//队列中的元素数量
	int arr[MAX_SIZE];//假设队列中只存储非负整数,最大容量为MAX_SIZE
}DoubleQueue;

//创建队列
DoubleQueue* CreatQueue() {

	DoubleQueue* q = (DoubleQueue*)malloc(sizeof(DoubleQueue));
	if (q == NULL) {
		perror("malloc");
		return NULL;
	}
	//假设队列的队头入队和队尾入队都是从数组下标为0处开始
	q->front = q->rear = -1;
	q->numofele = 0;
	return q;
}

//清空队列
void ClearQueue(DoubleQueue* q) {
	if (q == NULL) {
		printf("队列不存在\n");
		return;
	}
	//清空队列时,只需要改变头尾指针和队列中元素的数量即可
	q->front = q->rear = -1;
	q->numofele = 0;
}

//销毁队列
void DestoryQueue(DoubleQueue* q) {
	if (q == NULL) {
		printf("队列不存在\n");
		return;
	}
	//由于队列只使用了一次动态内存分配,所以直接free
	free(q);
	q = NULL;
}

//判断队列是否为空
bool IsEmpty(DoubleQueue* q) {
	if (q == NULL) {
		printf("队列不存在\n");
		return true;//返回true为了防止在队列为空时的操作引用空指针
	}
	return q->numofele == 0;
}

//判断队列是否为满
bool IsFull(DoubleQueue* q) {
	if (q == NULL) {
		printf("队列不存在\n");
		return true;//为了防止在队列不满情况下对空指针的操作
	}
	return q->numofele == MAX_SIZE;
}

//返回队头元素
int GetHead(DoubleQueue* q) {
	if (q == NULL) {
		printf("队列不存在\n");
		return -1;//假设队列中存储非负整数,返回-1表示错误
	}
	if (IsEmpty(q)) {
		printf("队列为空,不存在队头元素\n");
		return -1;
	}
	return q->arr[q->front];
}

//返回队尾元素
int GetTail(DoubleQueue* q) {
	if (q == NULL) {
		printf("队列不存在\n");
		return -1;//假设队列中存储非负整数,返回-1表示错误
	}
	if (IsEmpty(q)) {
		printf("队列为空,不存在队尾元素\n");
		return -1;
	}
	return q->arr[q->rear];
}

//获得从队头入队的下标
int GetHeadIndex(DoubleQueue* q, int size) {
	if (IsEmpty(q)) {
		q->rear = 0;//如果从对头入队的是第一个元素,则需要将队头队尾指针都设为0
		return 0;
	}
	if (q->front - 1 < 0) {
		return (q->front - 1) + size;
	}
	else {
		return q->front - 1;
	}
}

//从队头入队
void EnqueueFromHead(DoubleQueue* q, int k) {
	if (q == NULL) {
		printf("队列不存在\n");
		return;
	}
	if (IsFull(q)) {
		printf("队列已满,无法入队\n");
		return;
	}
	q->front = GetHeadIndex(q, MAX_SIZE);
	q->numofele++;
	q->arr[q->front] = k;
}

//得到从队尾入队的下标
int GetTailIndex(DoubleQueue* q, int size) {
	if (IsEmpty(q)) {
		q->front = 0;
		return 0;
	}
	return (q->rear + 1) % size;
}

//从队尾入队
void EnqueueFromTail(DoubleQueue* q, int k) {
	if (q == NULL) {
		printf("队列不存在\n");
		return;
	}
	if (IsFull(q)) {
		printf("队列已满,无法入队\n");
		return;
	}
	q->rear = GetTailIndex(q, MAX_SIZE);
	q->numofele++;
	q->arr[q->rear] = k;
}

//从队头出队
int DequeueFromHead(DoubleQueue* q) {
	if (q == NULL) {
		printf("队列不存在\n");
		return -1;
	}
	if (IsEmpty(q)) {
		printf("队列为空,无法出队\n");
		return -1;
	}
	q->numofele--;
	int ret = q->arr[q->front];
	q->front = (q->front + 1) % MAX_SIZE;
	return ret;
}

//从队尾出队
int DequeueFromTail(DoubleQueue* q) {
	if (q == NULL) {
		printf("队列不存在\n");
		return -1;
	}
	if (IsEmpty(q)) {
		printf("队列为空,无法出队\n");
		return -1;
	}
	int ret = q->arr[q->rear];
	q->numofele--;
	if (q->rear - 1 < 0) {
		q->rear = q->rear - 1 + MAX_SIZE;
	}
	else {
		q->rear = q->rear - 1;
	}
	return ret;
}

//从队头开始打印队列数据
void Print(DoubleQueue* q) {
	if (q == NULL) {
		printf("队列不存在\n");
		return;
	}
	if (IsEmpty(q)) {
		printf("队列为空,无法打印\n");
		return;
	}
	int count = q->numofele;
	int p = q->front;
	while (count--) {
		printf("%d ", q->arr[p]);
		p = (p + 1) % MAX_SIZE;
	}
	printf("\n--------------------------\n");
}

测试代码:

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>

int main() {

	DoubleQueue* q = CreatQueue();

	//从队头入队10个元素
	for (int i = 0; i < 10; i++) {
		EnqueueFromHead(q, i);
	}
	Print(q);

	for (int i = 10; i < 20; i++) {
		EnqueueFromTail(q, i);
	}
	Print(q);
	
	printf("从队头删除的元素是 %d\n", DequeueFromHead(q));
	Print(q);
	printf("从队尾删除的元素是:%d\n", DequeueFromTail(q));
	Print(q);

	printf("队头元素是:%d\n", GetHead(q));
	printf("队尾元素是:%d\n", GetTail(q));

	return 0;
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值