数据结构随笔——两种队列,及STL中的queue

我们在操作系统中会遇到疑似死机后,你的鼠标随便点也没什么作用,但过一会后,就会把你的鼠标操作都执行一遍,在这个过程中,就使用了队列这种数据结构的排序功能。

队列( queue )是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。允许插入的一端称为队尾,允许删除的一端称为队头。

一、链式队列

链式队列,类似于链表的一种队列,从空间上来说链式队列没有固定长度,比起顺序储存的循环队列来说,多了个指针域而已。

定义

需要定义两个结构体,一个是结点,一个是首尾指针

typedef int datatype;
typedef struct queue_node
{
	datatype data;
	queue_node* next; //下一个结点(结构体指针)
}node,*queueptr; //节点结构的指针
struct linked_queue //链式队列的结构
{
	queueptr front, rear;
};

队列初始化

在队列初始化中,仅仅需要给队列结构体进行初始化,至于结点则在插入时申请。

int initqueue(linked_queue &q) //初始化链式队列结构,引用传递
{
	q.front = q.rear = (queueptr)(malloc(sizeof(node)));
	if (!q.front)
	{
		cout << "初始化失败" << endl;
		return 0;
	}
	q.front->next = NULL; //此处一定要置空
	cout << q.front->next << endl;
	return 1;
}

插入操作

值得注意的一点是,如何把第一个元素的地址赋给头部结点的next ?
首先在初始化时,把头尾front,rear相等,而后赋值时使用rear.next=(节点地址),则可以解决。

int insert_queue(linked_queue &q, datatype x)//将x插入队列
{
	queueptr s = (queueptr)malloc(sizeof(node));
	if (!s)
	{
		cout << "申请失败" << endl;
		return 0;
	}
	else
	{
		s->data = x;
		s->next = NULL; //生成新的结点
		q.rear->next = s; 
		//插入尾部,刚开始第一步时,因为头尾指针相同,所以头指针被赋予了第一个元素的地址
		q.rear = s; //修改队尾指针
		return 1;
	}
}

弹出元素

在弹出时需要判断,是否队列为空?是否是首元素弹出?如果是首元素弹出还需要让头尾指针再次相等。

int pop_queue(linked_queue &q, datatype& e)//用e返回其值
{
	queueptr p;
	if (q.front == q.rear)
	{
		cout << "队列为空" << endl;
		return 0;
	}
	p = q.front->next; //暂存头元素指针
	e = p->data; 
	q.front = p->next;
	if (q.rear = p) //若队头是队尾,删除后队尾指向队头
		q.rear = q.front;
	free(p);
	return 1;
}

至于显示,计算队列中元素数量和链表中的一致。

二、循环队列

首先我们先来看一个问题,假设是长度为5的数组,初始状态为空队列,front 与rear指针均指向下标为0的位置。然后入队a1、a2,a3,a4,front指针依旧指向下标为0位置,rear指向4的位置。

出队a1、a2,则front指针指向下标为2的位置,rear 不变,再入队a5,此时front 指针不变,rear 指针移动到数组之外。可此时我们在0,1位置上还是空余的,这种现象称为假溢出。

所以解决这个问题的办法,就是后面满了,就再从头开始。我们把队列的这种头尾相接的顺序存储结构称为循环队列。

在写代码时,我们需要考虑以下几个问题。

什么时候队列为空呢 ?很显然时front==rear的时候,为了防止两者相等时不知道是为空还是为满。我们修改规则,当队列满时,数组还有一个空余单位。

在这里插入图片描述

队列满的情况 :我们定义队列最大最大尺寸位queuesize,那队列满的条件就是(rear+1)%queuesize==front

队列的长度 :当rear<front时,长度为rear-front+queuesize,但当rear>front时,长度为rear-front,于是通用公式为(rear-front+queuesize)%queuesize

定义及基本操作

typedef int datatype;
#define maxsize 1024
typedef struct circular_queue
{
	datatype data[maxsize];
	int front;
	int rear;
}queue;
int initqueue(queue *q) //初始化
{
	q->front = q->rear = 0;
	return 1;
}
int length(queue* q) //求长度
{
	return (q->rear - q->front + maxsize) % maxsize;
}

插入

int insert_queue(queue* q, datatype e)
{
	if ((q->rear + 1) % maxsize == q->front)
	{
		cout << "循环队列为满" << endl;
		return 0;
	}
	q->data[q->rear] = e;
	q->rear = (q->rear + 1) % maxsize;
	return 1;
}

删除

int pop_queue(queue* q, datatype* x)//弹出元素放到地址x中
{
	if (q->front == q->rear)
	{
		cout << "循环队列为空" << endl;
		return 0;
	}
	*x = q->data[q->front];
	q->front = (q->front + 1) % maxsize;
	return 1;
}

显示所有元素

int show_queue(queue* q)
{
	if (q->front == q->rear)
	{
		cout << "循环队列为空" << endl;
		return 0;
	}
	int i = q->front;
	while ( i% maxsize != q->rear) //从头到尾
	{
		cout << q->data[i] << endl;
		i++;
	}
}

三、STL中的queue

首先是基本的队列,操作是十分简单的,毕竟轮子造好了。

#include<queue>//头文件
queue<typename>name;
back()返回最后一个元素
empty()如果队列空则返回真
front()返回第一个元素
pop()删除第一个元素
push()在末尾加入一个元素
size()返回队列中元素的个数

优先队列的基本操作

在优先队列中,元素被赋予优先级。当访问元素时,具有最高优先级的元素最先删除。操作函数与上类似。

定义:priority_queue<Type, Container, Functional>

Type 就是数据类型,Container 就是容器类型(Container必须是用数组实现的容器,比如vector,deque等等,但不能用 list。STL里面默认用的是vector),Functional 就是比较的方式。当需要用自定义的数据类型时才需要传入这三个参数,使用基本数据类型时,只需要传入数据类型,默认是大顶堆。priority_queue<>的可支持的容器必须是用数组实现的容器

 priority_queue<int> a; 
//等同于 priority_queue<int, vector<int>, less<int> > a;
priority_queue<int, vector<int>, greater<int> > b;  
//这样就是小顶堆
堆:通俗来讲利用完全二叉树的结构来维护的一维数组
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值