栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

数据结构--2.4 队列

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

数据结构--2.4 队列

队列
  • 链式队列
      • 结构体定义
      • 创建
      • 入队
      • 出队
      • 运行结果
  • 循环队列
      • 结构体定义
      • 创建
      • 判断空和满
      • 入队
      • 出队
      • 运行结果
  • 总结

今天敲得是队列,有两个不同的实现方式:链式队列和循环队列。
队列只允许在一端插入数据操作,称为队尾,在另一端进行删除数据操作,称为队首。队列具有先进先出的特性。

链式队列 结构体定义
#include 
#include 

typedef struct Node{
	int data;
	struct Node *next;
}NODE,*PNODE;

typedef struct Queue{
	PNODE front;
	PNODE rear;
}*QUEUE;
创建
QUEUE initLinkQueue()
{
	QUEUE resultPtr = (QUEUE)malloc(sizeof(Queue));
	PNODE headPtr = (PNODE)malloc(sizeof(Node));
	
	headPtr->next = NULL;
	
	resultPtr->front = headPtr;
	resultPtr->rear = headPtr;
	
	return resultPtr;
}

这里出了创建函数之后headPtr就不存在了,因为是临时变量。但是resultPtr依然存在,因为我们把它返回了。

入队
void enQueue(QUEUE paraQueue,int paraVal)
{
	PNODE p;
	p=(PNODE)malloc(sizeof(Node));
	
	p->data = paraVal;
	p->next = NULL;
	
	paraQueue->rear->next = p;
	paraQueue->rear = p;
}
出队
int deQueue(QUEUE paraQueue)
{
	int val;
	PNODE p;
	
	if(paraQueue->front == paraQueue->rear )
	{
		printf("the queue if empty.rn");
		return -1;
	}
	
	p = paraQueue->front->next;
	val = p->data;
	paraQueue->front->next = paraQueue->front->next->next;
	
	if(paraQueue->rear == p)
	{
		paraQueue->front = paraQueue->rear;
	}
	free(p);
	
	return val;
}
运行结果
1 2 3
deQueue is 1
2 3

链式队列的时间复杂度为O(1)。
链式队列的逻辑比较简单,所以没有过多的阐述,相比之下循环队列会稍显复杂。

循环队列

循环队列利用数组来实现。我觉得写出这个代码主要解决两个问题,一个是如何去判断满,而二是如何让整个队列循环起来。(好废话)

结构体定义
#include 
#include 

#define MAX_SIZE 5

typedef struct Circle{
	int data[MAX_SIZE];
	int head;
	int tail;
}*CIRCLE;
创建
CIRCLE initCircleQueue()
{
	CIRCLE resultPtr = (CIRCLE)malloc(sizeof(Circle));
	
	resultPtr->head = 0;
	resultPtr->tail = 0;
	
	return resultPtr;
}
判断空和满

先看代码

bool is_full(CIRCLE paraQueue)
{
	if((paraQueue->tail+1)%MAX_SIZE == paraQueue->head )
	{
		return true;
	}else
	{
		return false;
	}
}

bool is_empty(CIRCLE paraQueue)
{
	if(paraQueue->tail == paraQueue->head )
	{
		return true;
	}else
	{
		return false;
	}
}

判断空其实很简单,当我们的队首和队尾标记都相同时这个队列就空了。比较复杂的是判断满,我们先看图:

一开始感觉当我的队尾追上队首的时候就满了,但是队尾等于队尾的时候也有可能是空,所以这种判断方法就失效了。那我们可不可以少放一个元素,让rear+1等于队首的时候为满呢,就像这样:

那答案是可以的。所以判断满的方式就变成了:(paraQueue->tail+1)%MAX_SIZE == paraQueue->head。

入队

那我们又要想了,在入队的时候,我们能够一直让tail++吗?我们的数组是有大小的,当tail超过这个大小的时候我们应该如何让数组循环起来呢。
我们选择对tail取余。我们直接让tail%MAX_SIZE,这样得到的数值就会始终在MAX_SIZE的范围之内了

bool enCircleQueue(CIRCLE paraQueue,int data)
{
	if(is_full(paraQueue))
	{
		printf("the queue is full.rn");
		return false;
	}
	
	paraQueue->data[paraQueue->tail%MAX_SIZE] = data;
	paraQueue->tail ++ ;
	
	return true ;
}
出队
int deCiecleQueue(CIRCLE paraQueue)
{
	int val;
	
	if(is_empty(paraQueue))
	{
		printf("the queue is empty.rn");
		return -1;
	}
	
	val = paraQueue->data[paraQueue->head%MAX_SIZE];
	paraQueue->head ++ ;
	
	return val;
}
运行结果
the queue is full.
1 2 3 4
delete is 1
delete is 2
3 4
delete is 3
delete is 4
the queue is empty.
delete is -1

循环队列的时间复杂度也是O(1)。

总结

在理解了这两个算法之后我自己重新敲了这两个代码。我个人认为其实这两段代码都不算很复杂,最主要的是理解整个逻辑,以及注意自己对细节处的处理。
数据结构学习到现在我最大的心得就是要学会像计算机一样去思考。人的逻辑和计算机的逻辑是存在很大的差别的,应该尝试把人的逻辑转化成计算机的逻辑,用代码呈现出来。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/889486.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号