数据结构---队列(代码实现)

队列

一.队列(queue)的基本概念

  • 队列也是运算受限的线性表。是一种先进先出的线性表。
  • 只允许在表的一端插入,在另外表的一端删除。
  • 队首front:允许插入的一端。
  • 队尾rear:允许删除的一端。
  • 排队购物、操作系统中的作业排队。

队列的示意图

二.队列的顺序表示和实现

  • 顺序队列:利用一组连续的存储单元(一维数组)依次存放从队首到队尾的各个元素。
  • 对于顺序队列,和顺序栈一样,有动态和静态之分。

1.静态顺序队列,其类型定义

*#define MAX_QUEUE_SIZE 100
*typedef struct queue{
*	Elemtype Queue_array[MAX_QUEUE_SIZE];
*	int front;
*	int rear;
* }SqQueue;

*设立一个队首指针front,一个队尾指针rear,分别指向队首和队尾元素。
*初始化:front=rear=0.

  • 入队:将新元素插入到rear指向的位置,然后在加1.
  • 出队:删除front指向的元素,然后加1,并返回删除的元素
  • 队列为空:front=rear。
  • 队列为满:rear=MAX_QUEUE_SIZE-1或front=rear

重点:
*在非空队列里,队首指针始终指向队头元素,而队尾指针始终指向队尾元素的下一个位置。
*
顺序队列中存在“假溢出”现象。因为在入队和出队操作中,头尾指针只增加不减小,致使别删除的元素空间永远不法重新利用。因此,尽管队列中的元素个数可能远远小于数组大小,但可能由于尾指针已超出向量空间的上界而不能做入队操作。该现象称为假溢出。
在这里插入图片描述

//循环队列

  • 为充分利用向量空间,克服上述“假溢出”现象方法是:将为队列分配的向量空间看成为一个首尾相接的圆环,并称这种队列为循环队列(Circular Queue)。
  • 在循环队列中进行出栈、入栈操作时,队首、队尾指针扔要加1,超前移动。只不过当队首、队尾指针指向向量上界(MAX_QUEUE_SIZE-1)时,其加1操作的结果是指向向量下届0.
    在这里插入图片描述

重点:真正实用的顺序队列是循环队列

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

//循环队列基本操作

//1.循环队列的初始化

SqQueue Init_CirQueue() {
	SqQueue Q;
	Q.front = Q.rear = 0;
	return Q;
}

//2.入队操作

//分析:最后一个空间不能存储元素。Q.rear 指向空的,Q.rear + 1等于队列首则不能入队

bool Insert_CirQueue(SqQueue &Q, int e) {   //加引用,不然数组的值不能传回
	//将数据元素e插入到循环队列Q的队尾
	if ((Q.rear + 1) % MAX_QUEUE_SIZE == Q.front)   return false;//队列满
	Q.Queue_array[Q.rear] = e;   //元素插入
	Q.rear = (Q.rear + 1) % MAX_QUEUE_SIZE;  //队尾指针向前移动
	return true;
}

//3.出队操作

//分析:取不到Q.rear 指向后面一位元素,Q.front + 1等于队列尾则不能出队

bool Delete_CirQueue(SqQueue &Q, int &e) {  //加引用,不然结构体的值不能传回
	//将循环队列Q的队首元素出队
	if ((Q.front + 1)  == Q.rear)   return false;//队列空
	e=Q.Queue_array[Q.front] ;   //队首取元素
	Q.front = (Q.front + 1) % MAX_QUEUE_SIZE;  //队首指针向前移动
	
	return true;
}

三.队列的链式表示和实现

//1.队列的链式存储表示

  • 队列的链式存储结构简称为链队列,它是限制仅在表头进行删除操作和表尾插入操作的单链表。
  • 需要两类不同的结点:数据元素结点,队列的队首指针和队尾指针的结点。
//q.数据元素结点类型定义:
//typedef struct QNode {
//	Elemtype  data;
//	struct QNode* next;
//}QNode;
//b.指针结点类型定义:
//typedef struct link_queue {
//	QNode  *front,*rear;
//
//}link_queue;

在这里插入图片描述

//2.链队运算即指针变化

//链队的操作实际是单链表的操作,只不过是删除在表头进行,插入在表尾进行。

//3.链队列的基本操作

//1.链队列的初始化(键队列)

link_queue* Init_LinkQueue() {
	link_queue* q;
	QNode* p;
	p = (QNode*)malloc(sizeof(QNode));  //开辟头结点
	p->next = NULL;
	q= (link_queue*)malloc(sizeof(link_queue));  //开辟队列的指针结点
	q->front = q->rear = p;
	return q;
}

//2.链队列的入队操作

bool Insert_CirQueue(link_queue* q,int e){
	QNode* p;
	p = (QNode*)malloc(sizeof(QNode));  //链队不用检查队列是否为满,插入
	if (!p)  return false;  //申请新结点失败
	p->data = e;
	p->next = NULL;    //
	(q->rear)->next = p;  //队列的尾结点内的(指针)指向 新的插入结点
	q->rear = p;		//队列的尾指针 指向新的插入结点
	return true;
}

//3.链队列的出队操作

bool Delete_CirQueue(link_queue* q, int &e) {
	QNode* p;
	if (q->front ==q->rear)  return false;  //队空
	p=(q->front)->next;
	e = p->data;
	(q->front)->next=p->next;    //
	//当队列有有一个结点时(头结点+结点),防止丢失尾指针
	if (p == q->rear)  q->rear = q->front;  
	free(p);
	return true;
}

//4.链队列的撤销(摧毁队列)

void Destroy_LinkQueue(link_queue* q) {
	while (q->front != NULL) {
		q->rear = (q->front)->next;  //令尾指针队列的第一个结点
		free(q->front);   //第一次释放头结点,后面是元素结点
		q->front = q->rear;
	}
}

代码

头文件

#pragma once

#include<iostream>

//1.静态顺序队列,其类型定义
#define MAX_QUEUE_SIZE 100
typedef struct queue{
	int Queue_array[MAX_QUEUE_SIZE];
	int front;
	int rear;
 }SqQueue;

//循环队列基本操作
//1.循环队列的初始化
SqQueue Init_CirQueue();

//2.入队操作
bool Insert_CirQueue(SqQueue &Q, int e);

//3.出队操作
bool Delete_CirQueue(SqQueue &Q, int& e);

//1.队列的链式存储表示
//a.数据元素结点类型定义:
typedef struct QNode {
	int  data;
	struct QNode* next;
}QNode;
//b.指针结点类型定义:
typedef struct link_queue {
	QNode  *front,*rear;

}link_queue;

//3.链队列的基本操作
//1.链队列的初始化(键队列)
link_queue* Init_LinkQueue();

//2.链队列的入队操作
bool Insert_CirQueue(link_queue* q, int e);

//3.链队列的出队操作
bool Delete_CirQueue(link_queue* q, int & e);

//4.链队列的撤销(摧毁队列)
void Destroy_LinkQueue(link_queue* q);

cpp文件

#include "队列queue.h"

using namespace std;

//一.队列(queue)的基本概念
/**
* 队列也是运算受限的线性表。是一种先进先出的线性表。
* 只允许在表的一端插入,在另外表的一端删除。
* 队首front:允许插入的一端。
* 队尾rear:允许删除的一端。
* 排队购物、操作系统中的作业排队。
**/


//二.队列的顺序表示和实现
/**
* 顺序队列:利用一组连续的存储单元(一维数组)依次存放从队首到队尾的各个元素。
* 对于顺序队列,和顺序栈一样,有动态和静态之分。
***/

//1.静态顺序队列,其类型定义
/**
*#define MAX_QUEUE_SIZE 100
*typedef struct queue{
*	Elemtype Queue_array[MAX_QUEUE_SIZE];
*	int front;
*	int rear;
* }SqQueue;
***/

/**
*设立一个队首指针front,一个队尾指针rear,分别指向队首和队尾元素。
*初始化:front=rear=0.
* 入队:将新元素插入到rear指向的位置,然后在加1.
* 出队:删除front指向的元素,然后加1,并返回删除的元素
* 队列为空:front=rear。
* 队列为满:rear=MAX_QUEUE_SIZE-1或front=rear
***/

/**
*在非空队列里,队首指针始终指向队头元素,而队尾指针始终指向队尾元素的下一个位置。
*
*	顺序队列中存在“假溢出”现象。因为在入队和出队操作中,头尾指针只增加不减小,致使
* 别删除的元素空间永远不法重新利用。因此,尽管队列中的元素个数可能远远小于数组大小,但
* 可能由于尾指针已超出向量空间的上界而不能做入队操作。该现象称为假溢出。
***/

//循环队列
/**
*	为充分利用向量空间,克服上述“假溢出”现象方法是:将为队列分配的向量空间看成为一个首尾
*相接的圆环,并称这种队列为循环队列(Circular Queue)。
*	在循环队列中进行出栈、入栈操作时,队首、队尾指针扔要加1,超前移动。只不过当队首、队尾
* 指针指向向量上界(MAX_QUEUE_SIZE-1)时,其加1操作的结果是指向向量下届0.
***/

//循环队列基本操作
//1.循环队列的初始化
SqQueue Init_CirQueue() {
	SqQueue Q;
	Q.front = Q.rear = 0;
	return Q;
}
//2.入队操作
//分析:最后一个空间不能存储元素。Q.rear 指向空的,Q.rear + 1等于队列首则不能入队
bool Insert_CirQueue(SqQueue &Q, int e) {   //加引用,不然数组的值不能传回
	//将数据元素e插入到循环队列Q的队尾
	if ((Q.rear + 1) % MAX_QUEUE_SIZE == Q.front)   return false;//队列满
	Q.Queue_array[Q.rear] = e;   //元素插入
	Q.rear = (Q.rear + 1) % MAX_QUEUE_SIZE;  //队尾指针向前移动
	return true;
}

//3.出队操作
//分析:取不到Q.rear 指向后面一位元素,Q.front + 1等于队列尾则不能出队
bool Delete_CirQueue(SqQueue &Q, int &e) {  //加引用,不然结构体的值不能传回
	//将循环队列Q的队首元素出队
	if ((Q.front + 1)  == Q.rear)   return false;//队列空
	e=Q.Queue_array[Q.front] ;   //队首取元素
	Q.front = (Q.front + 1) % MAX_QUEUE_SIZE;  //队首指针向前移动
	
	return true;
}


//三.队列的链式表示和实现
//1.队列的链式存储表示
/**
*	队列的链式存储结构简称为链队列,它是限制仅在表头进行删除操作和表尾插入操作的单链表。
*需要两类不同的结点:数据元素结点,队列的队首指针和队尾指针的结点。
***/
//q.数据元素结点类型定义:
//typedef struct QNode {
//	Elemtype  data;
//	struct QNode* next;
//}QNode;
//b.指针结点类型定义:
//typedef struct link_queue {
//	QNode  *front,*rear;
//
//}link_queue;


//2.链队运算即指针变化
//链队的操作实际是单链表的操作,只不过是删除在表头进行,插入在表尾进行。


//3.链队列的基本操作
//1.链队列的初始化(键队列)
link_queue* Init_LinkQueue() {
	link_queue* q;
	QNode* p;
	p = (QNode*)malloc(sizeof(QNode));  //开辟头结点
	p->next = NULL;
	q= (link_queue*)malloc(sizeof(link_queue));  //开辟队列的指针结点
	q->front = q->rear = p;
	return q;
}

//2.链队列的入队操作
bool Insert_CirQueue(link_queue* q,int e){
	QNode* p;
	p = (QNode*)malloc(sizeof(QNode));  //链队不用检查队列是否为满,插入
	if (!p)  return false;  //申请新结点失败
	p->data = e;
	p->next = NULL;    //
	(q->rear)->next = p;  //队列的尾结点内的(指针)指向 新的插入结点
	q->rear = p;		//队列的尾指针 指向新的插入结点
	return true;
}
//3.链队列的出队操作
bool Delete_CirQueue(link_queue* q, int &e) {
	QNode* p;
	if (q->front ==q->rear)  return false;  //队空
	p=(q->front)->next;
	e = p->data;
	(q->front)->next=p->next;    //
	//当队列有有一个结点时(头结点+结点),防止丢失尾指针
	if (p == q->rear)  q->rear = q->front;  
	free(p);
	return true;
}

//4.链队列的撤销(摧毁队列)
void Destroy_LinkQueue(link_queue* q) {
	while (q->front != NULL) {
		q->rear = (q->front)->next;  //令尾指针队列的第一个结点
		free(q->front);   //第一次释放头结点,后面是元素结点
		q->front = q->rear;
	}
}


int main() {
	cout<<"-----队列------" << endl;

	cout << "---队列的顺序表示和实现--" << endl;
	//1.循环队列的初始化
	int mm=0;			//取队列的元素
	SqQueue squ=Init_CirQueue();

	//2.入队操作
	cout << "---入队操作:1,2,3,4--" << endl;
	bool aaa=Insert_CirQueue( squ, 1);
	aaa = Insert_CirQueue(squ, 2);
	aaa = Insert_CirQueue(squ, 3);
	aaa = Insert_CirQueue(squ, 4);

	//3.出队操作
	cout << "---出队操作:" << endl;
	aaa=Delete_CirQueue(squ,mm);
	cout << mm << endl;
	aaa = Delete_CirQueue(squ, mm);
	cout << mm << endl;
	aaa = Delete_CirQueue(squ, mm);
	cout << mm << endl;
	//输出1  2  3

	cout << "---链队列表示和实现--" << endl;
	//3.链队列的基本操作
//1.链队列的初始化(键队列)
	int node_data;
	link_queue* ch_que=Init_LinkQueue();

	//2.链队列的入队操作
	cout << "---入队操作:3,4,5--" << endl;
	aaa= Insert_CirQueue(ch_que, 3);
	aaa = Insert_CirQueue(ch_que, 4);
	aaa = Insert_CirQueue(ch_que, 5);

	//3.链队列的出队操作
	cout << "---出队操作:" << endl;
	aaa= Delete_CirQueue(ch_que, node_data);
	cout << node_data << endl;
	aaa = Delete_CirQueue(ch_que, node_data);
	cout << node_data << endl;
	aaa = Delete_CirQueue(ch_que, node_data);
	cout << node_data << endl;

	//4.链队列的撤销(摧毁队列)
	int node_data2;
	link_queue* ch_que2 = Init_LinkQueue();
	//入队列
	for (int i = 0; i < 9; i++) {
		aaa = Insert_CirQueue(ch_que2, i);
	}
	出队列
	//for (int i = 0; i < 9; i++) {
	//	aaa = Delete_CirQueue(ch_que2, node_data2);
	//	cout << node_data2 << " ";
	//}
	//cout << endl;
	Destroy_LinkQueue(ch_que2);
	出队列
	for (int i = 0; i < 9; i++) {
		aaa = Delete_CirQueue(ch_que2, node_data2);
		cout << node_data2 << " ";
	}
	cout << endl;
	//输出错值,销毁成功

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值