关于数据结构(c语言)中,循环队列(顺序结构)的大部分操作的代码实现

引入

        数据结构是计算机专业必学的一门课程,如果说算法是一个程序的操作动作,那么数据结构就是一个程序的灵魂,它让一段程序在运行的过程中,拥有足够强大的“内力”进行代码的实现。

        队列其实同栈类似,也是线性表的延申,它的实质是受限制的线性表,它受到限制的部分即在原有线性表的基础上增加了两个指示标识,分别为队头指针front和队尾指针rear,并规定队头指针与队尾指针都可以随着入队、出队等操作移动。这样一个受限的线性表即被称为队列,这样的限制方式也使其拥有了特殊之处,即先进先出(FIFO)或后进后出(LILO),这样也使得队列这个特殊的数据结构有了广泛的应用。而循环队列,即将一个顺序结构的数组抽象为首尾相连的状态,使得队尾指针与队头指针能够交替出现在原队头的位置,这样也克服了顺序队列中“假上溢”的情况。“假上溢”是指:在出队的过程中,队头指针只增加不减少,使得队头指针增加之后,其之前所指的空间的地址无法被访问,造成这一部分空间无法再进行入队、出队的操作,使得分配的这部分内存空间被浪费的情况。

        本篇文章将要介绍的,是循环队列(逻辑结构)的顺序(存储结构)实现。而在下文将要介绍的程序中,会通过对循环队列的初始化、判满、判空、入队、出队、遍历的分段过程,对整体代码进行分析。

第一部分 头文件与结构体的创建

        创建一个结构体,因循环队列的结构与数组结构极为类似,故其结构体中的变量也与数组大体相似,即首地址,队头标识与队尾标识。其中,利用typedef,使QUEUE等价于struct SqQueue.

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

typedef struct SqQueue
{
    int* pBase; //队列首地址
    int front; //队头标识
    int rear; //队尾标识

}QUEUE;

第二部分 函数声明

        提前对需操作的函数进行函数声明,对循环队列进行初始化、判满、判空、入队、出队、遍历的操作,便于为之后的具体代码的书写理清思路。

void init_queue(QUEUE* ); //初始化
bool full_queue(QUEUE*); //判满
bool empty_queue(QUEUE*); //判空
bool en_queue(QUEUE*, int); //入队
bool del_queue(QUEUE*,int* ); //出队
void traverse_queue(QUEUE*); //遍历

第三部分 主函数中的实例化与函数调用

        将SqQueue结构体变量实例化为Q,调用要使用的函数,对各类操作进行验证。

int main()
{
    QUEUE Q;
    int val;
    init(&Q);
    en_queue(&Q,1);
    en_queue(&Q,2);
    en_queue(&Q,3);
    en_queue(&Q,4);
    en_queue(&Q,5);
    traverse_queue(&Q);
    if(del_queue(&Q,&val))
    {
        printf("出队成功!出队的元素为:%d\n",val);
    }
    else
    {
        printf("出队失败!\n");
    }
    traverse_queue(&Q);
    return 0;
}

第四部分 各类操作的具体代码实现

1、循环队列的初始化 void init(QUEUE* pQ);

        a. 为循环队列分配一段内存空间,将其赋给循环队列的首地址(注意:这里将循环队列的长度赋予一个确定的值6,便于代码的介绍)。

        b. 判断内存是否分配成功。

        c. 若分配成功,使循环队列的队头标识与队尾标识相等,并赋值为0。

void init(QUEUE* pQ)
{
    pQ->pBase=(int*)malloc(sizeof(int)*6);
    if(NULL==pQ->pBase)
    {
        printf("动态内存分配失败!\n");
        exit(-1);
    }
    pQ->front=0;
    pQ->rear=0;
}

2、判满 bool full_queue(QUEUE* pQ);

        对队尾标识自增后取余,使其开始向后标识元素,若队尾标识与队头标识相等,则该循环队列已满。取余的作用:使队尾标识在标识到最后一个元素时可以从原队头的位置开始标识。

bool full_queue(QUEUE* pQ)
{
    if((pQ->rear+1)%6==pQ->front)
    {
        return true;
    }
    return false;
}

3、判空 bool empty_queue(QUEUE* pQ);

        当队尾标识与队头标识重合时,循环队列为空。

bool empty_queue(QUEUE* pQ)
{
    if(pQ->front==pQ->rear)
    {
        return true;
    }
    else
    {
        return false;
    }
}

4、入队 bool en_queue(QUEUE* pQ,int val);

        a. 先判断循环队列是否已满。

        b. 若未满,在循环队列的队尾开始插入要入队的值。

        c. 使队尾标识向后移一个位置。

bool en_queue(QUEUE* pQ, int val)
{
    if(full_queue(pQ))
    {
        return false;
    }
    else
    {
        pQ->pBase[pQ->rear]=val;
        pQ->rear=(pQ->rear+1)%6;
        return true;
    }
}

5、出队 bool del_queue(QUEUE* pQ,int* pVal);

        a. 判断循环队列是否为空。

        b. 若循环队列不为空,将待出队的元素保存在临时变量中(便于在主函数具体实现中,查看已经出队的元素)。

        c. 使队头标识向后移动一位。

bool del_queue(QUEUE* pQ, int* pVal)
{
    if(empty_queue(pQ))
    {
        return false;
    }
    else
    {
        *pVal=pQ->pBase[pQ->front];
        pQ->front=(pQ->front+1)%6;
        return true;
    }
}

6、遍历 traverse_queue(QUEUE* pQ);

        a. 定义一个临时变量,使其与队头标识标识的元素相同。

        b. 当临时标识未与队尾标识重合时,输出此时该临时标识标识的元素,并使其后移一位,遍历输出。

void traverse_queue(QUEUE* pQ)
{
    int i=pQ->front;
    while(i!=pQ->rear)
    {
        printf("%d ",pQ->pBase[i]);
        i=(i+1)%6;
    }
    printf("\n");
    return;
}

附上完整代码

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

typedef struct SqQueue
{
    int* pBase; //队列首地址
    int front; //队头标识
    int rear; //队尾标识

}QUEUE;

void init_queue(QUEUE* ); //初始化
bool full_queue(QUEUE*); //判满
bool empty_queue(QUEUE*); //判空
bool en_queue(QUEUE*, int); //入队
bool del_queue(QUEUE*,int* ); //出队
void traverse_queue(QUEUE*); //遍历

int main()
{
    QUEUE Q;
    int val;
    init(&Q);
    en_queue(&Q,1);
    en_queue(&Q,2);
    en_queue(&Q,3);
    en_queue(&Q,4);
    en_queue(&Q,5);
    traverse_queue(&Q);
    if(del_queue(&Q,&val))
    {
        printf("出队成功!出队的元素为:%d\n",val);
    }
    else
    {
        printf("出队失败!\n");
    }
    traverse_queue(&Q);
    return 0;
}

void init(QUEUE* pQ)
{
    pQ->pBase=(int*)malloc(sizeof(int)*6);
    if(NULL==pQ->pBase)
    {
        printf("动态内存分配失败!\n");
        exit(-1);
    }
    pQ->front=0;
    pQ->rear=0;
}

bool full_queue(QUEUE* pQ)
{
    if((pQ->rear+1)%6==pQ->front)
    {
        return true;
    }
    return false;
}

bool empty_queue(QUEUE* pQ)
{
    if(pQ->front==pQ->rear)
    {
        return true;
    }
    else
    {
        return false;
    }
}

bool en_queue(QUEUE* pQ, int val)
{
    if(full_queue(pQ))
    {
        return false;
    }
    else
    {
        pQ->pBase[pQ->rear]=val;
        pQ->rear=(pQ->rear+1)%6;
        return true;
    }
}

bool del_queue(QUEUE* pQ, int* pVal)
{
    if(empty_queue(pQ))
    {
        return false;
    }
    else
    {
        *pVal=pQ->pBase[pQ->front];
        pQ->front=(pQ->front+1)%6;
        return true;
    }
}

void traverse_queue(QUEUE* pQ)
{
    int i=pQ->front;
    while(i!=pQ->rear)
    {
        printf("%d ",pQ->pBase[i]);
        i=(i+1)%6;
    }
    printf("\n");
    return;
}

写在最后

        以上所有的操作细节与代码具体实现的思想已叙述完毕,希望对各位读者有所帮助与启发。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

grx_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值