数据结构--队列的实现(C语言)

声明

以下内容仅供学习,如有侵权,联系作者删除。
参考文献:王道考研系列数据结构、B站up主:C语言技术网
链接: C语言技术网

一 队列的基本概念

1.队列的基本定义

队列(Queue):也是一种操作受限的线性表,只允许在表的一端进行插入,而在表的另一端进行删除。
队头(Front):允许删除的一端。
队尾(Rear):允许插入的一端。
空队列:不含任何元素的空表。

2.队列的基本操作

由以下代码给出。

二 队列的顺序存储结构

牺牲一个存储单元的方案:
int front;	//	队列的头指针
int rear;	//	队列的尾指针,指向队尾的下一个元素
初始化:front = rear = 0;
队空:front == rear
队满:((rear+1) % MAXSIZE) == front
队长:(rear - front +MAXSIZE) % MAXSIZE

1.循环队列代码实现(C语言)

/*
 * 程序名:seqqueue1.c,此程序演示循环队列的数组实现,队尾指针指向队尾的下一个元素,没有length的辅助变量。
 * 作者:jack 日期:20210617
 * 参考作者:C语言技术网(www.freecplus.net), B站UP主:C语言技术网
*/
#include <stdio.h>
#include <string.h>

#define MAXSIZE 10     // 循环队列的最大长度,最多可以存放MAXSIZE-1个元素

typedef int ElemType;  // 自定义队列的数据元素为整数

typedef struct Queue
{
	ElemType data[MAXSIZE];  // 用数组存储循环队列中的元素
	int front;               // 队列的头指针
	int rear;				 // 队列的尾指针,指向队尾的下一个元素
}SeqQueue, *PSeqQueue;

// 循环队列QQ的初始化操作
void InitQueue(PSeqQueue QQ);

// 清空循环队列
void ClearQueue(PSeqQueue QQ);

// 销毁循环队列QQ。
void DestroyQueue(PSeqQueue QQ);

// 求循环队列的长度,返回值:>=0-队列QQ元素的个数
int LengthQueue(PSeqQueue QQ);

// 判断循环队列是否为空,返回值:1-空,0-非空或失败。
int  IsEmpty(PSeqQueue QQ);   

// 判断循环队列是否已满,返回值:1-已满,0-未满或失败。
int IsFull(PSeqQueue QQ);

// 元素入队,返回值:0-失败;1-成功。
int InQueue(PSeqQueue QQ, ElemType *ee);

// 元素出队,返回值:0-失败;1-成功。
int OutQueue(PSeqQueue QQ, ElemType *ee);

// 打印循环队列中全部的元素。
void PrintQueue(PSeqQueue QQ);                    

// 获取队头元素,返回值:0-失败;1-成功。
// 只查看队头元素的值,元素不出队。
int GetHead(PSeqQueue QQ, ElemType *ee);

int main()
{
	SeqQueue Q;     // 创建循环队列

	InitQueue(&Q);  // 初始化循环队列

	ElemType e;     // 创建一个数据元素
	printf("元素(1、2、3、4、5)入队。\n");
	e=1;  InQueue(&Q, &e);
	e=2;  InQueue(&Q, &e);
	e=3;  InQueue(&Q, &e);
	e=4;  InQueue(&Q, &e);
	e=5;  InQueue(&Q, &e);
	printf("队列的长度是%d\n",LengthQueue(&Q));

	PrintQueue(&Q);

	if (OutQueue(&Q,&e)==1)  printf("出队的元素值为%d\n",e);
	if (OutQueue(&Q,&e)==1)  printf("出队的元素值为%d\n",e);
	if (OutQueue(&Q,&e)==1)  printf("出队的元素值为%d\n",e);
	if (OutQueue(&Q,&e)==1)  printf("出队的元素值为%d\n",e);
	if (OutQueue(&Q,&e)==1)  printf("出队的元素值为%d\n",e);

	printf("队列的长度是%d\n",LengthQueue(&Q));
	PrintQueue(&Q);

	printf("元素(11、12、13、14、15)入队。\n");
	e=11;  InQueue(&Q, &e);
	e=12;  InQueue(&Q, &e);
	e=13;  InQueue(&Q, &e);
	e=14;  InQueue(&Q, &e);
	e=15;  InQueue(&Q, &e);

	printf("队列的长度是%d\n",LengthQueue(&Q));

	PrintQueue(&Q);

	// 只查看队头元素的值,元素不出队。
	if (GetHead(&Q,&e)==1)  printf("队头的元素值为%d\n",e);

	return 0;
}

// 初始化循环队列
void InitQueue(PSeqQueue QQ)
{
	ClearQueue(QQ);
}

// 清空循环队列
void ClearQueue(PSeqQueue QQ)
{
	if (QQ == NULL)  return;  // 检查空指针

	memset(QQ->data, 0, sizeof(ElemType)*MAXSIZE);  // 数组元素清零
	QQ->front = QQ->rear = 0;
}

// 销毁循环队列QQ。
void DestroyQueue(PSeqQueue QQ)
{
	// 静态循环队列无需释放内存,不需要销毁操作

	ClearQueue(QQ); // 清空循环队列
}

// 求循环队列的长度,返回值:>=0-队列QQ元素的个数
int LengthQueue(PSeqQueue QQ)
{
	if (QQ == NULL)  return 0;  // 检查空指针

	return (QQ->rear - QQ->front + MAXSIZE)%MAXSIZE;
}

// 判断循环队列是否为空,返回值:1-空,0-非空或失败。
int  IsEmpty(PSeqQueue QQ)
{
	if (QQ == NULL)  return 0;  // 检查空指针

	if (QQ->front == QQ->rear) return 1;

	return 0;
}

// 判断循环队列是否已满,返回值:1-已满,0-未满或失败。
int IsFull(PSeqQueue QQ)
{
	if (QQ == NULL)  return 0;  // 检查空指针

	if( ((QQ->rear+1)%MAXSIZE) == QQ->front )  return 1;

	return 0;
}

// 元素入队,返回值:0-失败;1-成功
int InQueue(PSeqQueue QQ, ElemType *ee)
{
	if ((QQ == NULL) || (ee == NULL))  return 0;  // 检查空指针
	if (IsFull(QQ) == 1)  { printf("循环队列已满,不能插入。\n"); return 0; }
	
	memcpy(QQ->data+QQ->rear, ee, sizeof(ElemType));
	QQ->rear = (QQ->rear+1)%MAXSIZE;
	return 1;
}

// 元素出队,返回值:0-失败;1-成功
int OutQueue(PSeqQueue QQ, ElemType *ee)
{
	if ((QQ == NULL) || (ee == NULL))  return 0;  // 检查空指针
	if (IsEmpty(QQ) == 1) { printf("队列为空。\n"); return 0; }

	memcpy(ee, QQ->data+QQ->front, sizeof(ElemType));  // 采用指针运算
	QQ->front = (QQ->front+1)%MAXSIZE;  // 队列头指针后移
	return 1;
}

// 打印循环队列中全部的元素
void PrintQueue(PSeqQueue QQ)
{
	if (QQ == NULL)  return;  // 检查空指针
	if (IsEmpty(QQ) == 1) { printf("队列为空。\n"); return; }
	int kk;
	for (kk = 0; kk < LengthQueue(QQ); kk++)
	{
		// 用数组的下标访问。
		printf("data[%d],value=%d\n",(QQ->front+kk)%MAXSIZE,QQ->data[(QQ->front+kk)%MAXSIZE]);     

		// 采用指针运算也可以。
		// printf("data[%d],value=%d\n",(QQ->front+kk)%MAXSIZE,*(QQ->data+(QQ->front+kk)%MAXSIZE));
	}
}

// 获取队头元素,返回值:0-失败;1-成功
// 只查看队头元素的值,元素不出队
int GetHead(PSeqQueue QQ, ElemType *ee)
{
	if ( (QQ == NULL) || (ee == NULL) ) return 0;   // 检查空指针
	if (IsEmpty(QQ) == 1) { printf("队列为空。\n"); return 0; }

	memcpy(ee,&QQ->data[QQ->front],sizeof(ElemType));  // 用数组的下标访问
	// memcpy(ee,QQ->data+QQ->front,sizeof(ElemType));    // 采用指针运算
	return 1;
}

顺序存储运行结果如下:

在这里插入图片描述

三 队列的链式存储结构

1.代码实现(C语言)

/*
 * 程序名:linkqueue1.c,此程序演示队列的链表实现(带头结点)
 * 作者:jack 日期:20210617
 * 参考作者:C语言技术网(www.freecplus.net), B站UP主:C语言技术网
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MAXSIZE 10

typedef int ElemType;

typedef struct LNode
{
	ElemType data;
	struct LNode *next;
}LNode;

typedef struct 
{
	LNode *front, *rear;
}LinkQueue, *PLinkQueue;

// 队列QQ的初始化操作
int InitQueue(PLinkQueue QQ);

// 清空队列
void ClearQueue(PLinkQueue QQ);

// 销毁队列QQ。
void DestroyQueue(PLinkQueue QQ);

// 求队列的长度,返回值:>=0-队列QQ元素的个数
int LengthQueue(PLinkQueue QQ);

// 判断队列是否为空,返回值:1-空,0-非空或失败。
int  IsEmpty(PLinkQueue QQ);   

// 判断队列是否已满,返回值:1-已满,0-未满或失败。
int IsFull(PLinkQueue QQ);

// 元素入队,返回值:0-失败;1-成功。
int InQueue(PLinkQueue QQ, ElemType *ee);

// 元素出队,返回值:0-失败;1-成功。
int OutQueue(PLinkQueue QQ, ElemType *ee);

// 打印队列中全部的元素。
void PrintQueue(PLinkQueue QQ);                    

// 获取队头元素,返回值:0-失败;1-成功。
// 只查看队头元素的值,元素不出队。
int GetHead(PLinkQueue QQ, ElemType *ee);

int main()
{
	LinkQueue Q;  // 创建队列
	memset(&Q,0,sizeof(LinkQueue));
	InitQueue(&Q);

	ElemType e;     // 创建一个数据元素
	printf("元素(1、2、3、4、5)入队。\n");
	e=1;  InQueue(&Q, &e);
	e=2;  InQueue(&Q, &e);
	e=3;  InQueue(&Q, &e);
	e=4;  InQueue(&Q, &e);
	e=5;  InQueue(&Q, &e);
	printf("队列的长度是%d\n",LengthQueue(&Q));

	PrintQueue(&Q);

	if (OutQueue(&Q,&e)==1)  printf("出队的元素值为%d\n",e);
	if (OutQueue(&Q,&e)==1)  printf("出队的元素值为%d\n",e);
	if (OutQueue(&Q,&e)==1)  printf("出队的元素值为%d\n",e);
	if (OutQueue(&Q,&e)==1)  printf("出队的元素值为%d\n",e);
	if (OutQueue(&Q,&e)==1)  printf("出队的元素值为%d\n",e);

	printf("队列的长度是%d\n",LengthQueue(&Q));
	PrintQueue(&Q);

	printf("元素(11、12、13、14、15)入队。\n");
	e=11;  InQueue(&Q, &e);
	e=12;  InQueue(&Q, &e);
	e=13;  InQueue(&Q, &e);
	e=14;  InQueue(&Q, &e);
	e=15;  InQueue(&Q, &e);

	printf("队列的长度是%d\n",LengthQueue(&Q));

	PrintQueue(&Q);

	// 只查看队头元素的值,元素不出队。
	if (GetHead(&Q,&e)==1)  printf("队头的元素值为%d\n",e);

	return 0;
}

// 初始化队列,返回值:0-失败;1-成功
int InitQueue(PLinkQueue QQ)
{
	LNode *head = (LNode *)malloc(sizeof(LNode));  // 分配头结点
	if (head == NULL)  return 0;			// 内存不足,返回失败

	head->next = NULL;		// 头结点的下一结点暂时不存在,置空
	QQ->front = QQ->rear = head;
	return 1;
}

// 清空队列
void ClearQueue(PLinkQueue QQ)
{
	if (QQ == NULL)  return;  // 检查空指针
	if (QQ->front == NULL) { printf("队列QQ未初始化。\n"); return; } // 队列未初始化
	// 清空队列QQ是指释放链表全部的数据结点,但保留头结点
	LNode *tmp = QQ->front->next;
	LNode *tmpnext;

	while(tmp != NULL)
	{
		tmpnext = tmp->next;  // tmpnext保存下一结点的地址
		free(tmp);			  // 释放当前结点。
		tmp = tmpnext;		  // tmp指针移动到下一结点
	}
	QQ->rear=QQ->front;       // 尾指针指向头结点
	QQ->front->next=NULL;
}

// 销毁队列QQ。
void DestroyQueue(PLinkQueue QQ)
{
	if (QQ == NULL)  return;  // 检查空指针
	if (QQ->front == NULL) { printf("队列QQ未初始化。\n"); return; } // 队列未初始化
	// 清空队列QQ是指释放链表全部的数据结点,但保留头结点
	LNode *tmp = QQ->front;
	LNode *tmpnext;

	while(tmp != NULL)
	{
		tmpnext = tmp->next;  // tmpnext保存下一结点的地址
		free(tmp);			  // 释放当前结点。
		tmp = tmpnext;		  // tmp指针移动到下一结点
	}
	QQ->rear=QQ->front=NULL;  // 防止野指针
	return;
}

// 求队列的长度,返回值:>=0-队列QQ元素的个数
int LengthQueue(PLinkQueue QQ)
{
	if (QQ == NULL)  return 0;	    // 检查空指针
	if (QQ->front == NULL) { printf("队列QQ未初始化。\n"); return 0; } // 队列未初始化

	LNode *tmp = QQ->front->next;  // 头结点不算,从第1个结点开始
	int length = 0;
	while(tmp != NULL)
	{
		length++;
		tmp = tmp->next;
	}
	return length;
}

// 判断队列是否为空,返回值:1-空,0-非空或失败。
int  IsEmpty(PLinkQueue QQ)
{
	if (QQ == NULL)  return 0;  // 检查空指针
	if (QQ->front == NULL) { printf("队列QQ未初始化。\n"); return 0; } // 队列未初始化

	if (QQ->front->next == NULL) return 1;

	return 0;
}

// 判断队列是否已满,链式队列不存在队满的说法
int IsFull(PLinkQueue QQ)
{
	if (QQ == NULL)  return 0;  // 检查空指针

	return 0;
}

// 元素入队,返回值:0-失败;1-成功
int InQueue(PLinkQueue QQ, ElemType *ee)
{
	if ((QQ == NULL) || (ee == NULL))  return 0;  // 检查空指针
	if (QQ->front == NULL) { printf("队列QQ未初始化。\n"); return 0; } // 队列未初始化
	
	LNode *tmp = (LNode *)malloc(sizeof(LNode));
	if (tmp == NULL)  return 0;

	memcpy(&tmp->data, ee, sizeof(ElemType));
	tmp->next = NULL;
	
	QQ->rear->next = tmp;
	QQ->rear = tmp;
	return 1;
}

// 元素出队,返回值:0-失败;1-成功
int OutQueue(PLinkQueue QQ, ElemType *ee)
{
	if ((QQ == NULL) || (ee == NULL))  return 0;  // 检查空指针
	if (QQ->front == NULL) { printf("队列QQ未初始化。\n"); return 0; } // 队列未初始化
	if (IsEmpty(QQ) == 1) { printf("队列为空。\n"); return 0; }

	LNode *tmp = QQ->front->next;
	memcpy(ee, &tmp->data, sizeof(ElemType));  // 采用指针运算
	QQ->front->next = tmp->next;  // 队列头指针后移

	// 如果出队的是最后一个结点。
	if (QQ->rear==tmp) QQ->rear=QQ->front;

	free(tmp);

	return 1;
}

// 打印队列中全部的元素
void PrintQueue(PLinkQueue QQ)
{
	if (QQ == NULL)  return;  // 检查空指针
	if (QQ->front == NULL) { printf("队列QQ未初始化。\n"); return; } // 队列未初始化

	LNode *pp = QQ->front->next;
	while(pp != NULL)
	{
		printf("%-3d", pp->data);  // 如果元素ee为结构体,这行代码要修改
		pp = pp->next;
	}
	printf("\n");
}

// 获取队头元素,返回值:0-失败;1-成功
// 只查看队头元素的值,元素不出队
int GetHead(PLinkQueue QQ, ElemType *ee)
{
	if ( (QQ == NULL) || (ee == NULL) ) return 0;   // 检查空指针
	if (QQ->front == NULL) { printf("队列QQ未初始化。\n"); return 0; } // 队列未初始化
	if (IsEmpty(QQ) == 1) { printf("队列为空。\n"); return 0; }

	memcpy(ee,&QQ->front->next->data,sizeof(ElemType));
	
	return 1;
}

链式存储运行结果如下:
在这里插入图片描述

四 小结

1.栈和队列都已经介绍完毕,接下来介绍栈和队列的应用。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值