队列算法的讲解
队列算法目前还是使用得比较多的一种数据结构,比如Linux的内核监测cpu性能,一些大型的项目需要对数据进行先后采集的,等等,都基本上使用队列比较方便,今天讨论的是队列的一般性数组性质的用法。
队列的定义
队列是一种数据结构,特点是“先进先出(FIFO)”,就类似于我们排队一样,所以队列在同步数据中还是有一定的优势的,因为必须等到前一个数据处理完成之后,才能进行下一步的处理。队列被广发使用到线程同步,进程同步等情形。
队列的示意图
队列的代码
本次使用较为简单的项目管理,调用Makefile的简单来管理编译,具体包含的源码文件有四个:
1. main.c ------ 项目调用的主入口文件
2. queue.c ------ 队列的数据结构实现文件
3. queue.h ------ 队列的数据结构声明文件
4. Makefile ------ 项目编译管理文件
queue.h 文件的代码
#ifndef __QUEUE_H__
#define __QUEUE_H__
typedef struct reg_Queue
{
int front;
int rear;
int size;
unsigned int capacity;
int *array;
}Queue, *PQueue;
/* create a queue and init date. */
PQueue create_queue(unsigned int capacity);
/* Destory a queue. */
void destory_queue(PQueue queue);
/* Add a data into queue. */
int add_to_queue(PQueue queue, int item);
/* Remove a data from a queue. */
int delete_from_queue(PQueue queue);
/* Get the front position data. */
int get_front_item(PQueue queue);
/* Get the rear position data. */
int get_rear_item(PQueue queue);
/* Judge whether the queue is full. */
int is_queue_full(PQueue queue);
/* Judge whether the queue is empty. */
int is_queue_empty(PQueue queue);
#endif //__QUEUE_H__
queue.c 文件的代码
#include <stdlib.h>
#include <unistd.h>
#include "queue.h"
#define TRY_MAX_TIMES 3
PQueue create_queue(unsigned int capacity)
{
PQueue queue = NULL;
unsigned char uctries = TRY_MAX_TIMES;
while(NULL == (queue = (PQueue)malloc(sizeof(Queue))) && uctries > 0)
{
usleep(10);
uctries--;
}
if(NULL == queue)
{
return NULL;
}
uctries = 3;
while( NULL == (queue->array = (int*)malloc(capacity * sizeof(int)))
&& uctries > 0)
{
usleep(10);
uctries--;
}
if(NULL == queue->array)
{
free(queue);
queue = NULL;
return NULL;
}
queue->capacity = capacity;
queue->front = 0;
queue->size = 0;
queue->rear = capacity - 1;
return queue;
}
void destory_queue(PQueue queue)
{
if(NULL == queue)
{
return;
}
if(NULL != queue->array)
{
free(queue->array);
queue->array = NULL;
}
free(queue);
queue = NULL;
}
int add_to_queue(PQueue queue, int item)
{
if(NULL == queue || NULL == queue->array)
{
return -1;
}
if(is_queue_full(queue))
{
return -1;
}
queue->rear = (queue->rear + 1) % (queue->capacity);
queue->array[queue->rear] = item;
queue->size++;
return 0;
}
int delete_from_queue(PQueue queue)
{
if(NULL == queue || NULL == queue->array)
{
return -1;
}
if(is_queue_empty(queue))
{
return -1;
}
int item = queue->array[queue->front];
queue->front = (queue->front + 1) % (queue->capacity);
queue->size++;
return item;
}
int get_front_item(PQueue queue)
{
if(NULL == queue || NULL == queue->array)
{
return -1;
}
if(is_queue_empty(queue))
{
return -1;
}
return queue->array[queue->front];
}
int get_rear_item(PQueue queue)
{
if(NULL == queue || NULL == queue->array)
{
return -1;
}
if(is_queue_empty(queue))
{
return -1;
}
return queue->array[queue->rear];
}
int is_queue_full(PQueue queue)
{
if(NULL == queue)
{
return -1;
}
return (queue->size == queue->capacity);
}
int is_queue_empty(PQueue queue)
{
if(NULL == queue)
{
return -1;
}
return (queue->size == 0);
}
main.c 文件的代码
#include <stdio.h>
#include "queue.h"
#ifdef DEBUG_PRINT
#define DEBUG_INFO(fmt,...) fprintf(stderr, "\n"fmt"\n", ##__VA_ARGS__)
#else
#define DEBUG_INFO(fmt,...)
#endif
int main(int argc, const char *argv[])
{
PQueue queue = create_queue(10);
if(NULL == queue)
{
DEBUG_INFO("create queue failed");
return -1;
}
add_to_queue(queue, 10);
add_to_queue(queue, 20);
add_to_queue(queue, 30);
add_to_queue(queue, 40);
add_to_queue(queue, 50);
DEBUG_INFO("front: %d", get_front_item(queue));
DEBUG_INFO("rear: %d", get_rear_item(queue));
delete_from_queue(queue);
DEBUG_INFO("front: %d", get_front_item(queue));
DEBUG_INFO("rear: %d", get_rear_item(queue));
destory_queue(queue);
return 0;
}
Makefile 文件的代码
TARGET=main
${TARGET}:main.o queue.o queue.h
gcc main.c queue.c -o $@ -DDEBUG_PRINT
main.o:main.c queue.c queue.h
gcc -c $< -o $@
queue.o:queue.c queue.h
gcc -c $< -o $@
.PHONY:clean
clean:
rm ${TARGET} -rvf
.PHONY:disclean
disclean:
rm *.o ${TARGET} -rvf
运行结果
总结
本次使用的队列结构是有局限性和代码的严谨性的问题。比方说,当前的代码使用的是数组方式的队列结构,那就局限于队列的大小,只能在规定的大小才能正常使用。然后就是代码严谨性的问题,当前代码中的两个函数:
/* Get the front position data. */
int get_front_item(PQueue queue);
/* Get the rear position data. */
int get_rear_item(PQueue queue);
它的实现为:
int get_front_item(PQueue queue)
{
if(NULL == queue || NULL == queue->array)
{
return -1;
}
if(is_queue_empty(queue))
{
return -1;
}
return queue->array[queue->front];
}
int get_rear_item(PQueue queue)
{
if(NULL == queue || NULL == queue->array)
{
return -1;
}
if(is_queue_empty(queue))
{
return -1;
}
return queue->array[queue->rear];
}
可以看到,当前我们使用的数组保存类型是 **有符号整形 **的数据,那么出错或者队列为空/满 的情况下,返回值为 -1,这是有很大的问题的,因为我们的数组中也是可以保持 -1 这个数值的,所以有那么一点不太严谨的做法,读者可以自行进行修改。个人建议的修改是使用结构体来加以判断,或者使用全局变量进行错误判断。