数据结构C语言版:栈与队列之队列

        3.4队列

3.4.1抽象数据类型队列的定义

        与栈相反,队列是一种先进先出的线性表。它只允许在表的一端插入,另一端删除元素。类似于日常生活中的排队,最先进入队列的元素最先离开。在队列中,允许插入的一端叫队尾,允许删除的一端叫做队头。

 

队列在程序设计中经常出现,最典型的例子就是操作系统中的作业排队。 

3.4.2链队列--队列的链式表示和实现

        和线性表类似,队列也有两种存储表示

        用链表表示的队列简称为链队列,如图3.10。一个链队列需要两个分别指示队头(头指针)和队尾(尾指针)才能唯一确定。为了方便操作也添加一个头结点,并令头指针指向头结点。所以,空的链队列的判决条件为头指针和尾指针均指向头结点。如图3.11(a)。

 链队列基本操作:

#include <iostream>
#include <stdlib.h>
using namespace std;
typedef int QElemType;
#define ERROR 0;
#define OK 1;
//#define OVERFLOW -2;
// 结点定义 
typedef struct QNode {
	QElemType data;     // 数据域
	struct QNode* next;  // 指针域
}QNode,*QueuePtr;

// 链队列定义
typedef struct {
	QueuePtr  front;        // 队列的头指针 
	QueuePtr  rear;         // 队列的尾指针
	int      length;
}Queue;      // 链队列

//始化链队列为空队列 
bool InitQueue(Queue& Q) {
	Q.front = Q.rear = (QueuePtr)malloc(sizeof(QNode));
	if (!Q.front)//内存分配失败
	{
		return ERROR;
	}
	Q.front->next = NULL;//头指针指针域为空
	Q.length = 0;//链队列当前长度为0
	return OK;
}

//新元素e入队列,成功返回true,失败返回false 
bool EnQueue(Queue& Q, QElemType e) {
	QNode* p;
	p = (QueuePtr)malloc(sizeof(QNode));//新建一个结点P
	if (!p) exit(OVERFLOW);//分配失败返回
	p->data = e;//数据域为输入的e
	p->next = NULL;//指针域为空
	Q.rear->next = p;//插入队尾
	Q.rear = p;//队尾指针重新指向队尾
	return OK;
}

//出队列,即删除队首元素,并用e返回出元素值 ,成功返回true,失败返回false  
bool DeQueue(Queue& Q, QElemType& e) {
	if (Q.front == Q.rear) return ERROR;//如果是空队列,返回错误值
	QNode* p;//新建指针P
	p = Q.front->next;//指针p指向队头元素准备删除
	e = p->data;//队头元素赋值给e
	Q.front->next = p->next;//对头指针向下移动一位
	if (Q.rear == p) Q.rear = Q.front;//如果队尾指针等于P,空队。队尾指针重新指向对头指针,如果不把队尾指针指向对头指针,队尾指针会丢失
	free(p);
	return OK;
}

//读队首元素,用e返回队首元素,不出队 ,成功返回true,失败返回false 
bool GetHead(Queue& Q, QElemType& e) {
	QNode* p;//指针p
	if (Q.front == Q.rear) return ERROR;//空队错误
	p = Q.front->next;
	e = p->data;
	return OK;
}
//遍历链队列,将队列数据元素依次输出
void Traverse(Queue Q) {
	QNode* p;
	p = Q.front->next;
	while (p) {
		cout << p->data << " ";
		p = p->next;
	}
}

//销毁链队列 
void Destroy(Queue& Q) {
	while (Q.front) {//只要头指针存在
		Q.rear = Q.front->next;
		free(Q.front);
		Q.front = Q.rear;
	}
}

int main(void)
{
	Queue Lque;
	Queue Q;
	QElemType e;
	int n;
	int c = 0;
	while (c != 7)
	{
		cout << endl << "1. 初始化链队";
		cout << endl << "2. 入队";
		cout << endl << "3. 出队";
		cout << endl << "4. 读队首";
		cout << endl << "5. 遍历队列";
		cout << endl << "6. 销毁队列";
		cout << endl << "7. 退出";
		cout << endl << "选择功能(1~7):";
		cin >> c;
		switch (c)
		{
		case 1:
		{
			InitQueue(Q);
			cout << "初始化链队成功!" << endl;
			break;
		}
		case 2:
		{
			cout << "请输入要入队的元素个数:" << endl;
			cin >> n;
			for (int i = 1; i <= n; i++) {
				cout << "请输入要入队的元素:" << endl;
				cin >> e;
				EnQueue(Q, e);
			}
			cout << "入队的元素为:" << endl;
			Traverse(Q);
			break;
		}
		case 3:
		{
			cout << "出队成功!" << endl;
			DeQueue(Q, e);
			break;
		}
		case 4:
		{
			GetHead(Q, e);
			cout << "队首元素为:" << e << endl;
			break;
		}
		case 5:
		{
			cout << "队列元素为:" << endl;
			Traverse(Q);
			break;
		}
		case 6:
		{
			Destroy(Q);
			cout << "销毁成功!" << endl;
			break;
		}
		case 7:
		{
			cout << "感谢您的使用!" << endl;
			break;
		}
		}
	}
}

3.4.3循环队列--队列的顺序表示和实现

        和顺序栈类似,除了使用一组地址连续的存储单元,还需要附设两个指针front和rear分别指示队列头元素和队列尾元素的位置。非空队列中,头指针始终指向对头元素,尾指针始终指向队尾元素下一个位置。如图。 

        当处于d状态时,已经不可以再继续插入新的队尾元素,又不宜类似栈一样扩大数组空间,一个巧妙地办法是臆造一个环状空间,如图3.13,称之为循环队列。指针和队列元素关系不变,但是此时判断空/满条件均为Q.front=Q.rear。有两种处理方法:1)另外设置一个标志位区域区别空或满; 2)少用一个元素空间,约定以“队列头指针在队列尾指针的下一位置(环的下一位置)”作为队列“满”的标志。

 

 

        如果无法预估最大队列长度,最好采用链队列

#include <iostream>
#include <stdlib.h>
using namespace std;
typedef int QElemType;
#define ERROR 0;
#define OK 1;
#define MAXQSIZE 100
//循环队列定义 
typedef struct {
	QElemType* base;    // 存储空间基址
	int  rear;             // 队尾指针
	int  front;            // 队头指针
	int  queuesize;     // 允许的最大存储空间
} SqQueue;

//初始化长度为MAXQSIZE的空队列 
bool InitQueue(SqQueue& Q) {
	//用malloc申请一块内存,大小是MAXQSIZE*sizeof(ElemType)。
	//将此函数返回的内存地址强制转换成QElemtype类型的指针,即QElemType*
	Q.base = (QElemType*)malloc(MAXQSIZE * sizeof(QElemType));
	if (!Q.base)
		return ERROR;
	Q.front = Q.rear = 0; return OK;
	return OK;
}

//新元素e入队列,成功返回true,失败返回false 
bool EnQueue(SqQueue& Q, QElemType e) {
	if ((Q.rear + 1) % MAXQSIZE == Q.front)
		return ERROR;
	Q.base[Q.rear] = e;
	Q.rear = (Q.rear + 1) % MAXQSIZE;
	return OK;
}
//出队列,即删除队首元素,并用e返回出元素值 ,成功返回true,失败返回false  
bool DeQueue(SqQueue& Q, QElemType& e) {
	if (Q.front == Q.rear) return ERROR;//空,返回错误
	e = Q.base[Q.front];
	Q.front = (Q.front + 1) % MAXQSIZE;
	return OK;
}
//读队首元素,用e返回队首元素,不出队 ,成功返回true,失败返回false 
bool GetHead(SqQueue& Q, QElemType& e) {
	if (Q.front == Q.rear) return ERROR;
	e = Q.base[Q.front];
	return OK;
}

//遍历队列 
bool Traverse(SqQueue Q) {
	int i;
	if (Q.front == Q.rear) return ERROR;
	for (i = Q.front; i != Q.rear; i = (i + 1) % MAXQSIZE)
		cout << Q.base[i] << endl;
	return OK;
}

//销毁循环队列 
bool Destroy(SqQueue Q) {
	if (Q.base) free(Q.base);
	Q.base = NULL;
	Q.front = Q.rear = 0;
	return OK;
}

int main(void)
{
	SqQueue Sque;
	QElemType e;
	SqQueue Q;
	int n;
	int c = 0;
	while (c != 7)
	{
		cout << endl << "1. 初始化循环队列";
		cout << endl << "2. 入队";
		cout << endl << "3. 出队";
		cout << endl << "4. 读队首";
		cout << endl << "5. 遍历队列";
		cout << endl << "6. 销毁循环队列";
		cout << endl << "7. 退出";
		cout << endl << "选择功能(1~7):";
		cin >> c;
		switch (c)
		{
		case 1:
		{
			InitQueue(Q);
			cout << "初始化循环队列成功!" << endl;
			break;
		}
		case 2:
		{
			cout << "请输入要入队的元素个数:" << endl;
			cin >> n;
			for (int i = 1; i <= n; i++) {
				cout << "请输入要入队的元素:" << endl;
				cin >> e;
				EnQueue(Q, e);
			}
			cout << "入队的元素为:" << endl;
			Traverse(Q);
			break;
		}
		case 3:
		{
			cout << "出队成功!" << endl;
			DeQueue(Q, e);
			break;
		}
		case 4:
		{
			GetHead(Q, e);
			cout << "队首元素为:" << e << endl;
			break;
		}
		case 5:
		{
			cout << "队列元素为:" << endl;
			Traverse(Q);
			break;
		}
		case 6:
		{
			Destroy(Q);
			cout << "销毁成功!" << endl;
			break;
		}
		case 7:
		{
			cout << "感谢您的使用!" << endl;
			break;
		}
		}
	}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值