本期和大家主要分享的是数据结构中的队列,队列是一种常见的数据结构,那么它的最大特点就是先进先出(跟平时排队买早点一样,先排队的人会先买完然后走);
队列是一种常见的数据结构,那么它的最大特点就是先进先出(跟平时排队买早点一样,先排队的人会先买完然后走);
特点:
(1)先进先出(2)进队在队尾 (3)出队在队头
接下来先来看以下队列数据类型的构造,首先定义了Datatype存放整型数据,队列结构体中包括了指针类型的pData指向队列中的元素,这个结构体中也包含了队头、队尾以及队列当前的总体长度,有助于我们更好的进行数据管理,但是其实是不需要队头和队尾的,因为通过队列长度就可以找到最后一个元素的位置,通过队头就可以找到第一个元素,也是非常方便的;
#ifndef __SEQQUEUE_H__
#define __SEQQUEUE_H__
#include
#include
#include
typedef int DataType;
typedef struct queue
{
DataType *pData;
int Head;
int tail;
int tLen;
}SeqQueue;
extern SeqQueue *CreateSeqQueue(int MaxLen);
extern int IsFullSeqQueue(SeqQueue *pTmpSeqQueue);
extern int IsEmptySeqQueue(SeqQueue *pTmpSeqQueue);
extern int EnterSeqQueue(SeqQueue *pTmpSeqQueue, DataType TmpData);
extern DataType QuitSeqQueue(SeqQueue *pTmpSeqQueue);
extern int DestroySeqQueue(SeqQueue **pTmpSeqQueue);
#endif
创建队列的时候必须先创建一个队头,指向队列空间的首地址,这样才能使得后续更好的控制这个队列;之后再为队列开辟空间,顺序队列的缺点就是它的存储个数需要自己提前预设,所以会出现未知数据量存储不下的情况,但是链式队列就能够解决这样的问题;
#include "seqqueue.h"
/* 创建一个顺序循环队列 */
SeqQueue *CreateSeqQueue(int MaxLen)
{
SeqQueue *pTmpSeqQueue = NULL;
pTmpSeqQueue = malloc(sizeof(SeqQueue));
if (NULL == pTmpSeqQueue)
{
perror("fail to malloc");
return NULL;
}
pTmpSeqQueue->pData = malloc(sizeof(DataType) * MaxLen + 1);
if (NULL == pTmpSeqQueue->pData)
{
perror("fail to malloc");
return NULL;
}
pTmpSeqQueue->Head = 0;
pTmpSeqQueue->tail = 0;
pTmpSeqQueue->tLen = MaxLen;
return pTmpSeqQueue;
}
循环队列判断是否为满的判断条件需要认真理解,不像前面栈的一些判断容易理解;就是判断队尾元素的下一个元素是不是队头的元素;
/* 判断一个队列是否为为满 */
int IsFullSeqQueue(SeqQueue *pTmpSeqQueue)
{
return (pTmpSeqQueue->tail + 1) % (pTmpSeqQueue->tLen) == pTmpSeqQueue->Head;
}
/* 判断一个队列是否为空 */
int IsEmptySeqQueue(SeqQueue *pTmpSeqQueue)
{
return pTmpSeqQueue->tail == pTmpSeqQueue->Head;
}
/* 进入队列 */
int EnterSeqQueue(SeqQueue *pTmpSeqQueue, DataType TmpData)
{
if (IsFullSeqQueue(pTmpSeqQueue))
{
printf("队列已满\n");
return -1;
}
pTmpSeqQueue->pData[pTmpSeqQueue->tail] = TmpData;
pTmpSeqQueue->tail = (pTmpSeqQueue->tail + 1) % (pTmpSeqQueue->tLen + 1);
return 0;
}
/* 退出队列 */
DataType QuitSeqQueue(SeqQueue *pTmpSeqQueue)
{
DataType TmpData;
if (IsEmptySeqQueue(pTmpSeqQueue))
{
printf("队列中无元素\n");
return -1;
}
TmpData = pTmpSeqQueue->pData[pTmpSeqQueue->Head];
pTmpSeqQueue->Head = (pTmpSeqQueue->Head + 1) % (pTmpSeqQueue->tLen + 1); //head++,但是是在长度内进行加加,控制在0到tLen-1内
return TmpData;
}
/* 销毁队列 */
int DestroySeqQueue(SeqQueue **pTmpSeqQueue)
{
free((*pTmpSeqQueue)->pData);
free(*pTmpSeqQueue);
*pTmpSeqQueue = NULL;
return 0;
}
链式队列是在链表这种存储结构的基础上实现队列的一种新的数据结构,它的特点和链表的一样,存储空间比较大且增删改查比较方便;下面具体来看一下:
链式队列不仅需要定义队列结构体,也需要定义链表节点的结构体;并且队列中的头和尾均为链表节点指针类型;
#ifndef __LINKQUEUE_H__
#define __LINKQUEUE_H__
#include
#include
#include
typedef int DataType;
typedef struct node
{
DataType Data;
struct node *pNext;
}LinkNode;
typedef struct queue
{
LinkNode *pHead;
LinkNode *pTail;
int cLen;
int tLen;
}LinkQueue;
extern LinkQueue *CreateLinkQueue(int MaxLen);
extern int IsFullLinkQueue(LinkQueue *pLinkQueue);
extern int IsEmptyLinkQueue(LinkQueue *pLinkQueue);
extern int EnterLinkQueue(LinkQueue *pLinkQueue, DataType TmpData);
extern DataType QuitLinkQueue(LinkQueue *pLinkQueue);
extern int DestroyLinkQueue(LinkQueue **pLinkQueue);
#endif
链式队列的创建:先创建链表头节点,再创建一个空节点为了后续链表操作简便;
#include "linkqueue.h"
LinkQueue *CreateLinkQueue(int MaxLen)
{
LinkQueue *pTmp = NULL;
pTmp = malloc(sizeof(LinkQueue));
if (NULL == pTmp)
{
perror("fail to pTmp");
return NULL;
}
pTmp->cLen = 0;
pTmp->tLen = MaxLen;
pTmp->pHead = malloc(sizeof(LinkNode));
if (NULL == pTmp->pHead)
{
perror("fail to malloc");
return NULL;
}
pTmp->pHead->pNext = NULL;
pTmp->pTail = pTmp->pHead;
return pTmp;
}
int IsFullLinkQueue(LinkQueue *pLinkQueue)
{
return pLinkQueue->cLen == pLinkQueue->tLen;
}
int IsEmptyLinkQueue(LinkQueue *pLinkQueue)
{
return pLinkQueue->cLen == 0;
}
链式队列入队操作需要先为数据开辟节点空间,再将此节点赋值插入;
int EnterLinkQueue(LinkQueue *pLinkQueue, DataType TmpData)
{
if (IsFullLinkQueue(pLinkQueue))
{
printf("空间已满\n");
return -1;
}
LinkNode *pTmpNode = NULL;
pTmpNode = malloc(sizeof(LinkNode));
if (NULL == pTmpNode)
{
perror("fail to pTmpNode");
}
pTmpNode->Data = TmpData;
pTmpNode->pNext = NULL;
pLinkQueue->pTail->pNext = pTmpNode;
pLinkQueue->pTail = pTmpNode;
pLinkQueue->cLen++;
return 0;
}
链式队列出队时需要销毁被删除的节点,再将前后链表进行链接即可;
DataType QuitLinkQueue(LinkQueue *pLinkQueue)
{
if (IsEmptyLinkQueue(pLinkQueue))
{
printf("栈区已空\n");
return -1;
}
LinkNode *pTmpNode = NULL;
DataType TmpData;
pTmpNode = pLinkQueue->pHead->pNext;
TmpData = pTmpNode->Data;
pLinkQueue->pHead->pNext = pTmpNode->pNext;
pLinkQueue->cLen--;
return TmpData;
}
int DestroyLinkQueue(LinkQueue **pLinkQueue)
{
LinkNode *prepTmpNode = NULL;
LinkNode *despTmpNode = NULL;
prepTmpNode = (*pLinkQueue)->pHead;
while (despTmpNode != NULL)
{
despTmpNode = prepTmpNode->pNext;
free(prepTmpNode);
}
free(*pLinkQueue);
*pLinkQueue = NULL;
return 0;
}
本期主要分享的是顺序队列和链式队列,其实内容上来说并不是非常难,只要认真还是可以将其融汇贯通的,所以各位小伙伴们一定得多练习,如果手头有使用到链表存储的项目就抓紧练习起来,体验和感受队列这种数据结构的快捷;加油,小伙伴们!
最后,各位小伙伴们如果喜欢我的分享可以点赞收藏哦,你们的认可是我创作的动力,一起加油!