数据结构 严薇敏 队列 的实现及其使用方法详解

目录

1.队列

1.1队列的概念及结构

1.2队列的实现

1.3接口以及实现

Queue.h

Queue.c 

申请一个队列的节点

初始化队列

入队列

出队列

查找队头元素

查找队尾元素

获取队列长度

判断是否为空队列

队列的销毁

测试用例


1.队列

1.1队列的概念及结构

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾 出队列:进行删除操作的一端称为队头,形象一点就是吃进去拉出来数据结构 严薇敏 队列 的实现及其使用方法详解_第1张图片
 

1.2队列的实现

可以用顺序结构来实现,也可以用链式结构实现,但是顺序结构要搬运元素 ,头插尾删就比较耗时间,所以采用链式结构来实现,一个带头借点的单链表。

1.3接口以及实现

Queue.h

#pragma once
#include
#include
#include
#include

typedef int Datatype;

typedef struct Queuenode{
	struct Queuenode* next;
	Datatype data;
}Queuenode;

typedef struct Queue {
	Queuenode* front;
	Queuenode* back;
}Queue;

//申请一个队列的节点
Queuenode* CreateQueueNode(Datatype data);

//初始化队列
void QueueInit(Queue* p);

//入队列
void QueuePush(Queue* p, Datatype data);

//出队列
void QueuePop(Queue* p);

//查找队头元素
Datatype QueueFront(Queue* p);

//查找队尾元素
Datatype QueueBack(Queue* p);

//获取队列长度
int QueueSize(Queue* p);

//判断是否为空队列
int QueueEmpty(Queue* p);

//队列的销毁
void QueueDestory(Queue* p);

Queue.c 

#include "Queue.h"
//申请一个队列的节点
//相当一个带头结点的单链表
Queuenode* CreateQueueNode(Datatype data)
{
	//直接malloc一个
	Queuenode* Newnode = (Queuenode*)malloc(sizeof(Queuenode));
	//查看是否申请成功
	if (NULL == Newnode) {
		assert(0);
		return NULL;
	}
	//更新节点数据
	Newnode->data = data;
	Newnode->next = NULL;
	return Newnode;
}

//初始化队列
void QueueInit(Queue* p)
{
	//参数传入的判断
	assert(p);
	//给一个头结点
	p->front = CreateQueueNode(0);
	p->back = p->front;
}

//入队列
//其实就是带头单链表的尾插
void QueuePush(Queue* p, Datatype data)
{
	//传入参数的合法性判断
	assert(p);
	//申请一个节点把传入数据放进去
	Queuenode* Newnode = CreateQueueNode(data);
	//直接尾插,next指针指向这个新节点,把他连接起来
	p->back->next = Newnode;
	p->back = Newnode;
}

//出队列
//其实就是带头单链表的头删
void QueuePop(Queue* p)
{

	Queuenode* Delnode = NULL;
	//先判断是否为空
	if (QueueEmpty(p)) {
		return;
	}
	//标记删除节点,头删
	Delnode = p->front->next;
	//然后在连接起来
	p->front->next = Delnode->next;
	//队列中刚好只有一个元素,删除之后应该要将队尾back放在头节点的位置
	if (Delnode == p->back) {
		p->back = p->front;
	}
	free(Delnode);
}

//查找队头元素
Datatype QueueFront(Queue* p)
{
	//对传入参数合法性的判断
	assert(p);
	return p->front->next->data;
}

//查找队尾元素
Datatype QueueBack(Queue* p)
{
	//对传入参数合法性的判断
	assert(p);
	return p->back->data;
}

//获取队列长度
int QueueSize(Queue* p)
{
	//对传入参数合法性的判断
	assert(p);
	//哎呦 这不是我的老朋友计数器吗
	int count = 0;
	//好家伙 这不是老伙计遍历指针
	Queuenode* cur = p->front->next;
	while (cur) {
		count++;
		cur = cur->next;
	}
	return count;
}

//判断是否为空队列
int QueueEmpty(Queue* p)
{
	//对传入参数合法性的判断
	assert(p);
	//俩指针都指向头结点这不就是空队列了
	return p->front == p->back;
}

//队列的销毁
void QueueDestory(Queue* p)
{
	//对传入参数合法性的判断
	assert(p);
	//先来一个便利指针
	Queuenode* cur = p->front->next;
	
	while (cur) {
		//这个队头指针一个个指向下一个节点
		p->front->next = cur->next;
		free(cur);
		cur = p->front->next;
	}
	free(p->front);
	p->back = NULL;
	p->front = NULL;
}

//测试用例
void text() {
	Queue p;
	QueueInit(&p);
	printf("size = %d\n", QueueSize(&p));
	printf("\n");
	// 入队列
	QueuePush(&p, 1);
	QueuePush(&p, 2);
	QueuePush(&p, 3);
	QueuePush(&p, 4);
	QueuePush(&p, 5);
	QueuePush(&p, 6);
	QueuePush(&p, 7);
	printf("size = %d\n", QueueSize(&p));
	printf("front = %d\n", QueueFront(&p));
	printf("back = %d\n", QueueBack(&p));
	printf("\n");
	// 出队列
	QueuePop(&p);
	printf("size = %d\n", QueueSize(&p));
	printf("front = %d\n", QueueFront(&p));
	printf("back = %d\n", QueueBack(&p));
	printf("\n");
	QueuePop(&p);
	QueuePop(&p);
	QueuePop(&p);
	QueuePop(&p);
	QueuePop(&p);
	printf("size = %d\n", QueueSize(&p));
	printf("front = %d\n", QueueFront(&p));
	printf("back = %d\n", QueueBack(&p));
	printf("\n");
	QueuePop(&p);
	QueuePop(&p);
	printf("size = %d\n", QueueSize(&p));
	QueueDestory(&p);
}
int main() {
	text();
}

申请一个队列的节点

//申请一个队列的节点
//相当一个带头结点的单链表
Queuenode* CreateQueueNode(Datatype data)
{
	//直接malloc一个
	Queuenode* Newnode = (Queuenode*)malloc(sizeof(Queuenode));
	//查看是否申请成功
	if (NULL == Newnode) {
		assert(0);
		return NULL;
	}
	//更新节点数据
	Newnode->data = data;
	Newnode->next = NULL;
	return Newnode;
}
  1. 先malloc一个节点
  2. 判断是否申请成功
  3. 再更新节点数据

初始化队列

//初始化队列
void QueueInit(Queue* p)
{
	//参数传入的判断
	assert(p);
	//给一个头结点
	p->front = CreateQueueNode(0);
	p->back = p->front;
}
  1. 直接用刚刚那个方法,创建新的节点。
  2. 首尾都指向这个头结点。

入队列

//入队列
//其实就是带头单链表的尾插
void QueuePush(Queue* p, Datatype data)
{
	//传入参数的合法性判断
	assert(p);
	//申请一个节点把传入数据放进去
	Queuenode* Newnode = CreateQueueNode(data);
	//直接尾插,next指针指向这个新节点,把他连接起来
	p->back->next = Newnode;
	p->back = Newnode;
}
  1. 先调用刚才的方法来申请一个节点,然后放在队尾。
  2. 队尾指针的next指向这个新节点,队尾指针再往后移动一下,指向现在这个节点。

出队列

//出队列
//其实就是带头单链表的头删
void QueuePop(Queue* p)
{

	Queuenode* Delnode = NULL;
	//先判断是否为空
	if (QueueEmpty(p)) {
		return;
	}
	//标记删除节点,头删
	Delnode = p->front->next;
	//然后在连接起来
	p->front->next = Delnode->next;
	//队列中刚好只有一个元素,删除之后应该要将队尾back放在头节点的位置
	if (Delnode == p->back) {
		p->back = p->front;
	}
	free(Delnode);
}
  1. 头出队列先用DelNode标记要删除的节点。
  2. 移动头指针,让头结点出队列。
  3. 队列中刚好只有一个元素,删除之后应该要将队尾back放在头节点的位置

查找队头元素

//查找队头元素
Datatype QueueFront(Queue* p)
{
	//对传入参数合法性的判断
	assert(p);
	return p->front->next->data;
}
  1. 直接指针找到头结点下一个的数据域然后返回。

查找队尾元素


//查找队尾元素
Datatype QueueBack(Queue* p)
{
	//对传入参数合法性的判断
	assert(p);
	return p->back->data;
}
  1. 直接就是队尾节点的数据域

获取队列长度

//获取队列长度
int QueueSize(Queue* p)
{
	//对传入参数合法性的判断
	assert(p);
	//哎呦 这不是我的老朋友计数器吗
	int count = 0;
	//好家伙 这不是老伙计遍历指针
	Queuenode* cur = p->front->next;
	while (cur) {
		count++;
		cur = cur->next;
	}
	return count;
}
  1. 给一个遍历指针,给个计数器,遍历一个就++最后返回count。

判断是否为空队列

//判断是否为空队列
int QueueEmpty(Queue* p)
{
	//对传入参数合法性的判断
	assert(p);
	//俩指针都指向头结点这不就是空队列了
	return p->front == p->back;
}
  1. 俩指针都指向头结点这不就是空队列了

队列的销毁

//队列的销毁
void QueueDestory(Queue* p)
{
	//对传入参数合法性的判断
	assert(p);
	//先来一个便利指针
	Queuenode* cur = p->front->next;
	
	while (cur) {
		//这个队头指针一个个指向下一个节点
		p->front->next = cur->next;
		free(cur);
		cur = p->front->next;
	}
	free(p->front);
	p->back = NULL;
	p->front = NULL;
}
  1. 创建一个遍历指针指向第一个节点。
  2. 来移动头指针,然后释放掉刚刚头指针指向的这个节点。
  3. 刚刚头指针的下一个节点的地址刚刚被保存了,这块的cur还有tmep的作用。

测试用例

void text() {
	Queue p;
	QueueInit(&p);
	printf("size = %d\n", QueueSize(&p));
	printf("\n");
	// 入队列
	QueuePush(&p, 1);
	QueuePush(&p, 2);
	QueuePush(&p, 3);
	QueuePush(&p, 4);
	QueuePush(&p, 5);
	QueuePush(&p, 6);
	QueuePush(&p, 7);
	printf("size = %d\n", QueueSize(&p));
	printf("front = %d\n", QueueFront(&p));
	printf("back = %d\n", QueueBack(&p));
	printf("\n");
	// 出队列
	QueuePop(&p);
	printf("size = %d\n", QueueSize(&p));
	printf("front = %d\n", QueueFront(&p));
	printf("back = %d\n", QueueBack(&p));
	printf("\n");
	QueuePop(&p);
	QueuePop(&p);
	QueuePop(&p);
	QueuePop(&p);
	QueuePop(&p);
	printf("size = %d\n", QueueSize(&p));
	printf("front = %d\n", QueueFront(&p));
	printf("back = %d\n", QueueBack(&p));
	printf("\n");
	QueuePop(&p);
	QueuePop(&p);
	printf("size = %d\n", QueueSize(&p));
	QueueDestory(&p);
}

数据结构 严薇敏 队列 的实现及其使用方法详解_第2张图片

 

你可能感兴趣的:(数据结构,c语言,算法,数据结构,蓝桥杯,面试)