我们只是在课堂上学习循环队列,我有几个问题。由于我们将尾部定义为最后一个值旁边的空白区域,如下图所示:
|1| |3|4|5|6|
头部将指向数字 3,尾部将指向 1 和 3 之间的空白空间。我很困惑如果该空间被填满会发生什么,例如下面:
|1|2|3|4|5|6|
那么头部仍然指向3,但是尾部需要指向之前空白框之后的下一个框,因此它会指向3,或者头部。我该怎么办?
我们只是在课堂上学习循环队列,我有几个问题。由于我们将尾部定义为最后一个值旁边的空白区域,如下图所示:
|1| |3|4|5|6|
头部将指向数字 3,尾部将指向 1 和 3 之间的空白空间。我很困惑如果该空间被填满会发生什么,例如下面:
|1|2|3|4|5|6|
那么头部仍然指向3,但是尾部需要指向之前空白框之后的下一个框,因此它会指向3,或者头部。我该怎么办?
当这种情况发生时,您的队列已满。在处理可以推送的新项目时,您有几种选择:
丢弃推送的事件:只有在弹出其他项目时才能再次推送项目。既没有head
也没有tail
更新。
示例:考虑一个已填满的事件队列,新请求被简单地忽略。
丢弃(弹出)队列中最旧的事件:在这种情况下,您将和指针都更新到一个位置。head
tail
示例:缓冲来自网络摄像头的传入图像帧以进行处理。对于“实时”提要,您可能更愿意在处理出现中断时丢弃较旧的帧。
创建一个更大的队列:即动态分配更多内存
示例:您使用循环队列,因为它是一种高效的实现,在您推送项目时大部分时间不需要内存分配。但是,您不希望丢失队列中的项目,因此您允许偶尔重新分配更多内存
正确的操作取决于您的应用程序。
PS.:您的实现基于在队列中保留一个空槽以区分满缓冲区和空缓冲区。另一种选择是保留队列中元素数量的计数器以进行区分。更多信息可以在循环缓冲区(维基百科)上找到。
正如我所想的那样,循环队列是循环的,部分原因是它没有被“填满”。它将始终保持一定数量的元素,并根据需要丢弃旧的元素。
所以你永远不会填满空白;如果您插入一个新元素,您将删除一个旧元素,因此仍然会有一个空白空间。
换句话说,在您的图表中,如果您插入一个新数字,例如 0,您的队列如下所示(假设1
是最后一个元素,3
第一个元素):
|1| |3|4|5|6|
然后它将如下所示:
| |0|3|4|5|6|
但是,如果您想要的话,循环队列的某些实现会在达到其全长时简单地抛出异常/错误。看看这个例子。
这是我找到的关于队列的最简洁的解释。您可以在此基础上扩展您的队列。资料来源:“算法”,Robert Sedgewick 着。
常量最大值=100;
var queue: aray[0..max]of integer;
head,tail: integer;
procedure put(v:integer);
begin
queue[tail] := v;
tail := tail + 1;
if (tail > max) then tail := 0;
end;
function get: integer;
begin
get := queue[head];
head := head + 1;
if (head > max) then head := 0;
end;
procedure queueinitialize;
begin
head := 0;
tail := 0;
end;
function queueempty: boolean;
begin
queueempty := (head = tail);
end;
“需要维护两个索引,一个到队列的开头(头),一个到结尾(尾)。队列的内容是数组中头尾之间的所有元素,考虑到“ wraparound" 当遇到数组末尾时返回 0。如果 head = tail 则队列定义为空;如果 head = tail + 1,或 tail = max 且 head = 0,则定义为满。 "
当头部和尾部指向同一个位置时,我们说队列已满。不能添加更多元素。要添加任何元素,您必须从队列中删除一个元素。这样头部将增加并且再次生成一个空间。