c语言;队列的实现

159 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第29天,点击查看活动详情

  • 今天简单写一个c语言的队列实现,首先来只吐舌猫做一个文章的开头。 WechatIMG14.jpeg

实现方案

队列是一种先入后出的数据结构,head出队,从tail入队。 image.png 一般实现方案有两种,一般有数组,空间固定稳定,实现复杂;或者链表,实现简单,动态申请空间。
在实际使用中,动态空间如果频繁申请释放,效率是不太好的,如果逻辑有出现不释放的空间的可能性,那不出意外,代码在不久的将来肯定跑飞。所以本文仅实现基于数组的队列实现方案。
实现循环数组,出入对列移出数组时,返回数组开头处继续操作,就是把数组开头和结尾在逻辑上接在一起。

接口实现

front标识正要处理的索引对象,rear标识未保存数据的索引值。

入队

从front出队,rear入队,所以有节点的情况下,都是rear在前,front在后追赶。
入队一个对象,则rear加一。入队之前需要判断是否为满队列。
image.png

出队

出队操作,front索引值减一,效果如下图所示。出队之前需判断是否为空队列。
image.png

空状态

image.png
       头尾指针 指向同一个索引值,代表队列为空。禁止出队操作,返回错误

满状态

image.png
可以看出来,rear追上front的位置了。这就是满队列的状态,需要禁止入队操作,返回错误。
最后一个空间不使用,这样可以把空状态和满状态区分起来,代码逻辑更简单一点,性价比更高。

代码示例

#include<stdio.h>
#include <stdlib.h>
#include<unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

typedef struct{
    int cnt;
    int front;
    int rear;
    void** dat;
}MYQUEUE,*MYQUEUEPtr;

static MYQUEUE MyQueue;
int queur_init(int Cnt)
{
    int ArrCnt = Cnt+1;
    MyQueue.cnt = ArrCnt;
    MyQueue.front = MyQueue.rear = 0;
    MyQueue.dat = (void**)malloc(ArrCnt*sizeof(void*));
    memset(MyQueue.dat,0,ArrCnt*sizeof(void*));
    return 1;
}

//return :1 is empty; 0 not empty
int queue_is_empty()
{
    if(MyQueue.front == MyQueue.rear)  return 1;
    return 0;
}
//return :1 is full; 0 not full
int queue_is_full()
{
    int Posi = MyQueue.cnt <= (MyQueue.rear + 1)?0:(MyQueue.rear+1);
    if(MyQueue.front == Posi)  return 1;
    return 0;
}

//入队
// return: 1 入队失败;0 成功
int enqueue(void *dat)
{
   if(queue_is_full() == 1){
        return 1;
   }
    MyQueue.dat[MyQueue.rear] = dat;
    MyQueue.rear = MyQueue.cnt <= (MyQueue.rear+1)?0:(MyQueue.rear+1);
    return 0;
}

//出队
// return: NULL 出队失败
void* dequeue()
{
      //  printf("dequeue front[%d]MyQueue.rear[%d]\n",MyQueue.front,MyQueue.rear);
    void* ret = NULL;
    if(queue_is_empty() == 1)  return ret;
 //   printf("dequeue [%d]\n",MyQueue.front);

    ret = MyQueue.dat[MyQueue.front];
    MyQueue.front = MyQueue.cnt <= (MyQueue.front + 1)?0:(MyQueue.front+1);
    return ret;
}

int main(int argc, char** argv)
{
    int * paraD = NULL;
    int ArrCnt = 100;
    queur_init(ArrCnt);
    printf("this is empty? [%s]\n",queue_is_empty()==1?"yes":"no");
    while(ArrCnt--){
        paraD = (int*)malloc(4);
        *paraD = ArrCnt;
        enqueue(paraD);
    }
    printf("this is full? [%s]\n",queue_is_full()==1?"yes":"no");

    ArrCnt = 100;
    while(ArrCnt--){
        paraD = (int*)dequeue();
        if(paraD) printf("var [%d]\n",*paraD);
    }
    
    return 0;
}
加进去一个简单的接口测试,有兴趣的同学可以编译试试看,有问题联系我哈。
代码已经单独提出来接口,与代码无关。
使用一个全局变量,所以只能创建一个队列。
后续优化可以采用动态申请空间保存队列句柄,由接口申请并返回给应用保存,使用的时候一定再发回给接口。
这样就可以实例挺多实例。接口不是线程安全的,如果多线程使用,最好加一些锁,保持数据同步。