队列你真的懂了吗?队列用来干嘛?什么场景用队列有优势?
一、循环队列
颜色说明如下:
假设有一个空队列,长度为len = 10 fornt对头,rear队尾初始化时,指向0位置。
注意,这里指向可不是指针的意思,就是front = =rear == 0。
向队列写入1个数据,rear队尾向后移动一个位置,此时,front == 0,rear = rear + 1,也就是 rear == 1。
继续向队列写入9个数据,rear队尾向后移动一个位置,此时,front = 0,rear = 9。如果是传统队列,此时是不能再写入数据了,rear 不能等于10。
队列里有9个数据,此时为非空,读走5个数据,此时,front == 5,rear == 9, rear - front == 4。如果是顺序队列,再写数据,此时是从5位置写入数据,前面5个就浪费了。
队列里有4个数据,此时为非空,再写入1个数据,此时,front == 5,rear =rear + 1, rear == 0。如果是传统顺序队列,
rear - front 是 < 0,不可操作的,不允许再写入,但是本文研究设计的循环队列,是可以写入的,如下。
再继续看下面。继续写入3个数据,红色为队列满之后写入的数据,此时,front== 5不变,rear == 3,没啥问题啊,为啥前人,会发明顺序队列,是因为不可判断队列数据个数吗,rear - front < 0,是不可以判断的,但是,可不可以增加一种判读机制呢,引入一个count,记录数据个数,每次增加一个数,就加1,读走一个数,就减1。上面步骤最开始是写1个数,count == 1,再写入8个数,就是是9个数,再读走5个数,就还剩4个数,再写入一个数,就是5个,最后,下面步骤,写入3个数,就是8个数,下图,红色和绿色都是代表有数据,刚好是8个数。
再继续分析如下,读走一个数,front队头向后移动一个位置,还剩7个数。
再继续读走3个数到最后一个位置,此时,还剩4个数,继续读,会怎么样?
继续读,如下,队头又回到队尾前面了,此时count == 2。front == 0,rear == 3。
读走最后两个,此时,front == rear == 3,空队列。
再来分析,和我们最开始的队列,front == rear == 0,有啥区别?也是空对列,好像是 front == rear,,只是位置在0和3,但是都是队头队尾相等,没有数据的空队列。,此时可以根据front == rear来判断空队列下结论吗?
继续看,如果把队列都写满,此时,front == rear,为满队列,和上面的空队列一样的情况,所以,不能只靠这个条件进行判读,我们可以加入一个判断条件,count
如果count == 0,且front == rear,则为空队列,如果count != 0,front == rear,为满队列。
到这里结束了?但是有个毛病,满之后,再继续写,会怎么样?如下图,再写入3个数据,原来是10个,加3个,本来是10+ 3 == 13,现在是把10个满队列的数,前面3个覆盖掉,那不是丢失数据了,就算不考虑丢失的问题,此时要去读取数据时,front == 0,读第0个数,现在读出来的是第11个位置数据,也就是第11个位置的数,而不是被覆盖之前的第0个位置数据,这显然不符合先进先出的思想,因为最现在被覆盖后,最新的数据应该是从第3个数据开始的后面一段数据。
所以,我们要做一个改进,当队列已满时,不再允许写入数据,只有再次为空时,才允许写入数据。
如果我们希望,可以覆盖,真正实现循环,就需要做如下改进,把队头移动到队尾,front == rear,不关心数据丢失的问题,只希望数据是最新的数据。
如下,验证设计的正确性,读取2个数据,此时front = front + 2,front == 5。完全正确,为了验证安全性,可以写代码
增加长度,和轮询次数,本文没有验证过,只是理论研究。
**总结;
1、传统的循环队列其实没有实现真正的循环队列,只是队头队尾可以循环移动,此时可以只根据
front == rear 来判断空。
front== ( rear + 1)% len 来判断满队列。
但是本文真正实现了数据循环覆盖,循环队列。列外判断机制加入了count,与别人有所区别。
1、满队列时,如果希望不覆盖前面的数据,防止数据丢失,可以加判断,满队列将不被允许写入,直到不满。
2、满队列时,如果希望,实现循环写入,将可以通过移动队头到队尾,将数据覆盖。
以上设计,各有各的用处场景,不能说哪个好,场景不同,就要选用不同的方式。**
demo代码:
#include"queue_cmd.h"
PT_QUEUE_CMD QUEUE_CMD_Open(SX_S32 depth)
{
PT_QUEUE_CMD handle = (PT_QUEUE_CMD)xine_xmalloc(sizeof(T_QUEUE_CMD));
if( handle == NULL )
{
TRACE(DL_ERROR, "DL_ERROR\n");
return NULL;
}
if (pthread_mutex_init( &handle->mutex, NULL ) != 0)
{
TRACE(DL_ERROR, "DL_ERROR\n");
QUEUE_CMD_Close( handle );
return NULL;
}
if( pthread_cond_init(&handle->cond, NULL) != 0 )
{
TRACE(DL_ERROR, "DL_ERROR\n");
QUEUE_CMD_Close( handle );
return NULL;
}
handle->ptCmd = (PT_NET_Pkt)xine_xmalloc(sizeof(T_NET_Pkt) * depth);
if( handle->ptCmd == NULL )
{
TRACE(DL_ERROR, "DL_ERROR\n");
QUEUE_CMD_Close( handle );
return NULL;
}
handle->s32QueueDepth = depth;
handle->s32IndexR = 0;
handle->s32IndexW = 0;
handle->s32Count = 0;
handle->bAbortRequest = SX_FALSE;
return handle;
}
void QUEUE_CMD_Close( PT_QUEUE_CMD handle )
{