数据结构——队列(Queue)

一、概念

队列(Queue)是一种常见的数据结构,它按照先进先出(FIFO,First-In-First-Out)的原则管理数据。队列的概念可以用来描述一种数据集合,其中元素的添加和移除操作遵循特定的顺序:最先添加的元素最先被移除,而最后添加的元素最后被移除,只能在队尾插入,在队头删除。这种操作方式类似于现实生活中排队等候的情景,因此称之为队列。

二、队列的基本功能

  1. 入队(Enqueue):将元素添加到队列的末尾。
  2. 出队(Dequeue):从队列的头部移除并返回元素。
  3. 查看队首元素(Peek):查看队列的头部元素,但不移除它。
  4. 判空(isEmpty):检查队列是否为空。
  5. 获取队列长度(Size):获取队列中元素的个数。
  6. 清空队列(Clear):移除队列中的所有元素。

 三、队列实现

由于我们的队列要满足先进先出,队头删除,队尾进入,如果我们用顺序表来实现的话要频繁的挪动数据,同时我们要能够快速获得队头和队尾的数据,所以我们要使用循环链表,用单向和双向都可以。

这里我用双向链表。

头文件

#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
typedef int Data;
typedef struct queue
{
	Data x;
	struct queue* prive;
	struct queue* next;
}TQE;
typedef struct THead//为了方便我用哨兵来记录队头
{					//和队列的元素个数。
	TQE* head;
	int size;
}THD;
THD* STLSentinel();//创建哨兵
void STLEnqueue(THD* head,Data x);//入列
TQE* STLadd(Data x);//扩容
void STLDequeue(THD* sentinel);//出列
void STLTraverse(THD* sentinel);//遍历
bool STLIsEmpty(THD* sentinel);//判空
void STLPeek(THD* sentinel);//查看队首元素
void STLSize(THD* sentinel);//获取元素个数
void STLClear(THD* sentinel);//销毁队列

入队(Enqueue):将新元素添加到队列的末尾。

void STLEnqueue(THD* sentinel,Data x)//入列
{
	assert(sentinel);//首先我们的哨兵是不能没有的
	TQE* newnode=STLadd(x);
	if (sentinel->head == NULL)//如果我们还没有一个节点
	{
		sentinel->head = newnode;
		newnode->prive = newnode;
		newnode->next = newnode;
		sentinel->size++;
		return;
	}//已有节点
	TQE* a = sentinel->head;//将新节点链接入队列中
	TQE* b= sentinel->head->prive;
	a->prive = newnode;
	b->next = newnode;
	newnode->prive = b;
	newnode->next = a;
	sentinel->size++;
}

出队(Dequeue):从队列的头部移除并返回元素。

Data STLDequeue(THD* sentinel)//出列
{
	assert(sentinel);
	TQE* a = sentinel->head;
	if (a == NULL)//无节点
	{
		printf("is empty\n");
		return -1;
	}
	Data x = a->x;
	if (a->next == a)//一个节点,为什么一个节点要单独分开,
	{				//因为我们这里有一个哨兵位指向他,一个节点释放的话要将
					//指针置空,不然的话我们在入列时会认为队列中已有元素,造成野指针的问题。
					//其实入列时你可以用size来判断是否为空队列,这样就不用将一个节点的情况单独分开。
		free(a);
		sentinel->head = NULL;
		sentinel->size--;
		return x;
	}//多节点
	TQE* b = a->next;
	TQE* c = a->prive;
	b->prive = c;
	c->next = b;
	sentinel->head = b;
	sentinel->size--;
	free(a);
	return x;
}

查看队首元素(Peek):查看队列的头部元素,但不移除它

void STLPeek(THD* sentinel)//查看队首元素
{
	if (STLIsEmpty(sentinel))
	{
		printf("is empty");
		return;
	}

	printf("%d\n", sentinel->head->x);
}

判空(isEmpty):检查队列是否为空。

bool STLIsEmpty(THD* sentinel)//判空
{
	assert(sentinel);
	if (sentinel->head == NULL)//判空依旧用的是指针,你也可以用size来判断是否为空队列
		return true;
	return false;
}

获取队列长度(Size):获取队列中元素的个数。

void STLSize(THD* sentinel)//获取元素个数
{
	assert(sentinel);
	printf("%d\n", sentinel->size);
}

清空队列(Clear):移除队列中的所有元素。

void STLClear(THD* sentinel)//销毁队列
{
	assert(sentinel);
	if (STLIsEmpty(sentinel))
		return;
	TQE* a = sentinel->head;
	do//清空这个队列有两种方法,一个是用循环,另一个是用递归
	{//我只写了循环
		TQE* b = a->next;
		free(a);
		a = b;
	} while (a != sentinel->head);//单向循环链表的结束条件也是一样的。
	sentinel->head = NULL;//不置空会造成野指针的问题,如果你不用size判断的话。
	sentinel->size = 0;
}

其它的一些函数

void STLTraverse(THD* sentinel)//遍历
{
	assert(sentinel);
	TQE* a = sentinel->head;
	if (a == NULL)
		return;
	do
	{
		printf("%d ", a->x);
		a = a->next;
	} while (a != sentinel->head);
}
TQE* STLadd(Data x)//增加
{
	TQE* a = (TQE*)malloc(sizeof(TQE));
	assert(a);
	TQE* newnode = a;
	newnode->next = NULL;
	newnode->prive = NULL;
	newnode->x = x;
	return newnode;
}
THD* STLSentinel()//创建哨兵
{
	THD* a= (THD*)malloc(sizeof(THD));
	assert(a);
	THD* sentinel = a;
	sentinel->head = NULL;
	sentinel->size = 0;
	return sentinel;
}

如果你已经写过了链表和栈,队列实现是和他们相似的。

快速排序用队列实现其实就是把原先放在入栈操作变成了入队的操作。

void QuickSort2(int* nums,int left,int right)//非递归,一个参数是数组,两个参数是左、右边界下标
{
	THD* sentinel = STLSentinel();//创建哨兵
	STLEnqueue(sentinel,left);//入列,注意你是先入左边界还是右边界,后面出的时候注意
	STLEnqueue(sentinel,right);
	while (!STLIsEmpty(sentinel))
	{
		left =STLDequeue(sentinel);//出列;
		right = STLDequeue(sentinel);
		int left1 = left, right1 = right;
		int key = nums[left];
		while (right > left)
		{
			while (right > left && nums[right] >= key)
				right--;
			nums[left] = nums[right];
			while (right > left && nums[left] <= key)
				left++;
			nums[right] = nums[left];
			nums[left] = key;
		}
		if (left1 < right)
		{//更改处
			STLEnqueue(sentinel,left1);//入列
			STLEnqueue(sentinel, right-1);
		}
		if (right1 > right)
		{
			STLEnqueue(sentinel, right+1);//更改处
			STLEnqueue(sentinel,right1);
		}
	}
}

  • 11
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值