队列的数据元素又称为队列元素。在队列中插入一个队列元素称为入队,从队列中删除一个队列元素称为出队。因为队列只允许在一端插入,在另一端删除,所以只有最早进入队列的元素才能最先从队列中删除,故队列又称为先进先出(FIFO—first in first out)线性表。
队列可以用链表实现,也可以用数组实现。本文先讲用链表实现队列。后续有时间再写一篇用数组实现的队列。
链式队列说到底是链表的子集,有一些普遍的方法实现,如入队、出队是最常用的方法,在项目中经常用到。下面是实现的链式队列程序的一个例子,完全可以套用到实际开发的项目中。
#include <stdio.h>
#include <cstdlib>
#include <string.h>
#include <stdarg.h>
#define PNAME_BUFF_SIZE 256
#define MAX_PARAM_PATH_LEN 256
typedef struct parameterValue{
char name[MAX_PARAM_PATH_LEN];
struct parameterValue *next;
struct parameterValue *prev;
}ParameterValue;
//初始化队列 ,分配一个头结点,不存放数据
parameterValue * InitQueue()
{
char chInit[MAX_PARAM_PATH_LEN] = {0};
parameterValue * head = (ParameterValue *)malloc(sizeof(ParameterValue));
strncpy(head->name, chInit,MAX_PARAM_PATH_LEN);
head->prev = head->next ;
head->next = NULL;
return head;
}
bool node_enqueue(parameterValue *head , parameterValue * node)
{
parameterValue *pTmp= head;
if(head == NULL)
{
return false;
}
else
{
while(pTmp->next)
{
pTmp = pTmp->next;//循环过后pTmp指向最尾的元素
}
node->prev = pTmp;//新增的元素前一个指向链表队列尾端
node->next= NULL;
pTmp->next = node;//尾端的元素的next指针指向node
return true;
}
}
bool node_delqueue(parameterValue *head )
{
parameterValue *pTmp = head;
parameterValue *p = NULL;
while(pTmp != NULL)
{
if(pTmp->next != NULL)
{
//当队列中不止一个结点时
pTmp->next->prev = NULL;
p = pTmp;
pTmp = pTmp->next;//pTmp指向下一个节点
free(p);//释放第一个节点
}
else
{
//当只剩下一个结点时
pTmp ->next = pTmp ->prev= NULL;
free(pTmp);
pTmp = NULL;
return true;
}
}
}
int main()
{
ParameterValue *pHead = NULL;
ParameterValue *pNew = NULL;
ParameterValue *pTmp = NULL;
char chArray[][PNAME_BUFF_SIZE] =
{
{"one"},
{"two"},
{"three"}
};
int count = sizeof(chArray)/PNAME_BUFF_SIZE;
pHead = InitQueue();
//把数组的内容指针添加进链表队列CHAR name[TR069_MAX_PARAM_PATH_LEN]
for (int i = 0; i < count; i++)
{
pNew = (ParameterValue *)malloc(sizeof(ParameterValue));
if (!pNew)
{
printf("malloc memeny failed\n");
exit(-1);
}
memset(pNew, 0, sizeof(ParameterValue));
strcpy(pNew->name, chArray[i]);
node_enqueue(pHead, pNew);
}
//遍历链式队列
pTmp = pHead;
while(pTmp != NULL)
{
printf("param is %s\n",pTmp->name);
pTmp = pTmp->next;
}
//释放队列
node_delqueue(pHead);
pHead = NULL;
}
从上面的程序可以看到,程序功能比较简单,且大部分关键点都有相对应的注释。这里主要讨论的是,在实际项目中能怎么运用链式队列。正如上面的程序一样,定义一个chArray[][PNAME_BUFF_SIZE]二维数组,这个数组其实就是项目中存放数组的核心。我们先初始化队列头,分配一个头结点,但是不存放数据。然后,分别读取这个数组的字符串到每一个成员中,接着让成员入队。这样做有什么好处呢?思考一下,我们写程序难道仅仅是为了完成当前的任务吗?我们应该考虑的是,以后如何能方便并且尽可能少改动代码就能扩展程序的功能。所以,这里我们采用随时可以扩展或删减数组的成员来控制队列的长度,而不必改动其他队列相关的代码。再讲一个具体事例。实际项目中,我们可以定义一个 processFun 结构体数组cmdFunc[],每一个processFun 结构体,里面有两个成员,一个是name字符串指针,另一个是返回char *型的函数指针。如下面代码。
typedef char *(*func)();
struct processFun {
char *name;
func process;
};
char *doOneFunc()
{//do something}
char *doTwoFunc()
{//do something}
char *doThreeFunc()
{//do something}
char *doFourFunc()
{//do something}
char *doFiveFunc()
{//do something}
struct processFun cmdFunc[] = {
{"one", doOneFunc},
{"two", doTwoFunc},
{"Three", doThreeFunc},
{"four", doFourFunc},
{"five", doFiveFunc}
};
可以实现这样的功能,程序从队列中读取数据,然后解析数据,调用对应的函数去干各种各样的事情。
当我们需要扩展命令和对应的函数时,我们可以在队列中的chArray数组添加”four”,这样有另外一个解析队列的程序就会获得到four对应的函数指针,然后调用函数去做某件事。
char chArray[][PNAME_BUFF_SIZE] =
{
{"one"},
{"two"},
{"three"},
{"four"}
};
这样子程序是不是方便扩展了呢?
程序是自己实现的,已调试过,如有错误,欢迎指正,谢谢!