您的位置:首页 > 科技 > IT业 > 【数据结构之C语言实现队列】

【数据结构之C语言实现队列】

2024/10/6 10:33:35 来源:https://blog.csdn.net/2302_79546368/article/details/141275774  浏览:    关键词:【数据结构之C语言实现队列】

1.概 念 与 结 构

1.1.1 概念

   只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First in First out)的特点

1.1.2 入队列:

       进行插入数据的一端称为队尾

1.1.3 出队列:

       进行删除操作的一端称为队头

1.2 队列的底层结构类型的选择

      队列可以基于数组和链表的结构来实现,使用链表的结构更优一点, 因为如果使用数组的结构,出队列在数组头上出数据,效率比较复杂。

2.队 列 的 实 现

 根据前面的数据结构的实现我们实现队列的时候也是需要用到三个文件的,分别是Queue.h(队列的结构的定义以及函数的声明的文件),Queue.c(函数功能的实现文件),test.c(函数功能的测试文件)。

2.1 Queue.h(队列的结构的定义以及函数的声明的文件)

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>

2.1.1   队列结构的定义

//队列结构的定义
typedef int QDatatype;
typedef struct QueueNode
{QDatatype data;struct QueueNode* next;
}QueueNode;  //是基于链表实现的,所以底层结构是链表,所以队列就是包装之后的链表
typedef struct Queue
{QueueNode* phead;QueueNode* tail;int size;
}Queue;

【定义结构的思路】:

      我们选择的是基于单链表来定义并实现队列。所以我们就是相当于把链表进行包装了一下。故队列的结构是由一个一个的节点组成的为了方便入队列,出队列我们需要把第一个有效节点和尾节点的位置保存下来;除此之外,我们为了方便记录对于一列中元素的个数,用一个size整型变量进行标记队列中元素的个数。    因此在这里队列就是链表包装后的结构。

2.1.2  函数的声明

//初始化
void QueueInit(Queue* pq);//入队列
void QueuePush(Queue* pq, QDatatype x);//判空
bool QueueEmpty(Queue* pq);//出队列
void QueuePop(Queue* pq);//获取队头数据
QDatatype QueueFront(Queue* pq);//获取队尾数据
QDatatype QueueBack(Queue* pq);//获取队列中有效的元素个数
int QueueSize(Queue* pq);//队列的销毁
void QueueDestroy(Queue* pq);

2.2  Queue.c(函数功能的实现文件)

#include "Queue.h"

2.2.1 队 列 的 初 始 化

//初始化
void QueueInit(Queue* pq)
{assert(pq);pq->phead = pq->tail = NULL;pq->size = 0;
}

【实现思路】:

      先判断所传地址的有效性,再将指向头结点和指向尾节点的指针置为空,最后将队列中 元素个数置为0。

2.2.2 入 队 列

//入队列  一端入(队尾),一端出数据
void QueuePush(Queue* pq, QDatatype x)
{assert(pq);QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));if (newnode == NULL){perror("malloc fail");exit(1);}newnode->data = x;newnode->next = NULL;//分为两种情况//队列为空if (pq->phead == NULL){pq->phead = pq->tail = newnode;}//队列为非空else{pq->tail->next = newnode;pq->tail = newnode;}pq->size++;
}

【实现思路】:

       先进行判断所传地址的有效性,通过malloc 函数进行申请一个新节点,将所要插入数据放到新节点里面,然后将新节点里的next置为空即可。

      队列为空是所插入的数据(新节点)既是头又是尾,此时需要改变头节点;然而当队列非空时,插入的数据(新节点)直接向队尾插入就行,头结点并不需改变先将新节点和原来的链表结构连接起来,再将指向为节点的指针指向新节点的位置)。

2.2.3 队列判空

//判空
bool QueueEmpty(Queue* pq)
{assert(pq);return pq->size == 0;//pq->phead == NULL && pq->tail == NULL;
}

【实现思路】:

           先判断所传地址的有效性。 在这里判空的时候可以直接判断对列入中有效的元素个数也可以进行判断指向队头和队尾节点的指针(地址)是否为空

2.2.4 队列的数据的删除

//出队列
void QueuePop(Queue* pq)
{assert(pq);assert(!(QueueEmpty(pq)));//分为两种情况//分为队列中只有一个节点if (pq->phead == pq->tail&&pq->phead->next==NULL){free(pq->phead);pq->phead = pq->tail = NULL;}//队列中有两个节点else{QueueNode* next = pq->phead->next;free(pq->phead);pq->phead = next;}pq->size--;
}

【实现思路】:

          先判断所春地址的有效性,再进行队列判空,如果队列为空就不能进行数据的删除,队列非空就可以进行删除操作。

          当队列中只有一个节点的时候,删除(释放节点)一次之后队列中就没有数据了,此时就需要将头节点和尾节点都置为空;当队列中节点的个数大于一个时,需要先将头节点中next 所指向的像一个节点的位置保存在next中,然后再释放掉头节点,再将头节点指向所保存的next的位置

2.2.5 获取队头数据

//获取队头数据
QDatatype QueueFront(Queue* pq)
{assert(pq);return pq->phead->data;
}

【实现思路】:

          先判断所传地址的有效性,再直接将头结点中的值返回即可。

           

2.2.6 获取队尾数据

//获取队尾数据
QDatatype QueueBack(Queue* pq)
{assert(pq);return pq->tail->data;
}

【实现思路】:

           先判断所传节点的有效性,再直接将尾节点中的值返回即可。

2.2.7 获取队列中的有效元素的个数

//获取队列中有效的元素个数
int QueueSize(Queue* pq)
{assert(pq);return pq->size;
}

【实现思路】:

           先判断所传节点的有效性,再直接将队列中size返回即可。

2.2.8 队列的销毁

//队列的销毁
void QueueDestroy(Queue* pq)
{assert(pq);assert(!QueueEmpty(pq));QueueNode* pcur = pq->phead;while (pcur){QueueNode* next = pcur->next;free(pcur);pcur = next;}pq->phead = pq->tail = NULL;pq->size = 0;
}

【实现思路】:

         先判断所传地址的有效性,再进行队列判空。销毁链表就可以从队头向队尾逐个释放节点。

        先用pcur来指向当前的节点,然后用循环来释放每一个节点。在释放每一个节点的之前先将当前节点的下一个节点保存在next中,然后再释放掉当前节点,再将当前节点pcur指向next的位置。所有的节点释放完成之后,将指向队列头结点(队头)和尾节点(队尾)的指针都置为空,将队列的有效元素个数置为0。

 

2.3  test.c(函数功能的测试文件)

#include "Queue.h"
//ܵIJԲ
void test()
{Queue q;QueueInit(&q);QueuePush(&q, 1);QueuePush(&q, 92);QueuePush(&q, 53);QueuePush(&q, 74);/*while (!QueueEmpty(&q)){printf("%d ", QueueFront(&q));QueuePop(&q);}printf("\n");*/printf("head:%d   ", QueueFront(&q));printf("tail:%d\n", QueueBack(&q));printf("size:%d \n", QueueSize(&q));QueuePop(&q);printf("head:%d   ", QueueFront(&q));printf("tail:%d\n", QueueBack(&q));//QueuePop(&q);printf("size:%d \n", QueueSize(&q));QueueDestroy(&q);
}
int main()
{test();return 0;
}

      该函数功能的测试文件,每写完一个函数就进行函数功能测试,养成良好的代码习惯。

注:数据结构这块要多加练习,多加思考!!!

如有错误,还望指出!

关注博主,优质内容不断更新!!! 

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com