【发布时间】:2012-07-06 08:02:04
【问题描述】:
我们只是在课堂上学习循环队列,我有几个问题。 由于我们将尾部定义为最后一个值旁边的空白区域,如下图所示:
|1| |3|4|5|6|
头部将指向数字 3,尾部将指向 1 和 3 之间的空白空间。我很困惑如果该空间被填满会发生什么,例如下面:
|1|2|3|4|5|6|
那么头部仍然指向3,但是尾部需要指向之前空白框之后的下一个框,因此它会指向3,或者头部。我该怎么办?
【问题讨论】:
标签: queue
我们只是在课堂上学习循环队列,我有几个问题。 由于我们将尾部定义为最后一个值旁边的空白区域,如下图所示:
|1| |3|4|5|6|
头部将指向数字 3,尾部将指向 1 和 3 之间的空白空间。我很困惑如果该空间被填满会发生什么,例如下面:
|1|2|3|4|5|6|
那么头部仍然指向3,但是尾部需要指向之前空白框之后的下一个框,因此它会指向3,或者头部。我该怎么办?
【问题讨论】:
标签: queue
当这种情况发生时,您的队列已满。在处理可推送的新项目时,您有几种选择:
丢弃推送事件:只有在弹出其他项目时才能再次推送项目。 head 和 tail 均未更新。
示例:想象一个事件队列已填满,新请求被简单地忽略。
丢弃(弹出)队列中最旧的事件:在这种情况下,您都将head 和tail 指针更新到一个位置。
示例:缓冲来自网络摄像头的传入图像帧以进行处理。对于“实时”提要,您可能更愿意在处理出现中断时丢弃较旧的帧。
创建一个更大的队列:即动态分配更多内存
示例:您使用循环队列,因为它是一种高效的实现方式,在您推送项目时大部分时间不需要内存分配。但是,您不想丢失队列中的项目,因此您允许偶尔重新分配更多内存
正确的操作取决于您的应用程序。
PS.:您的实现基于在队列中保留一个空槽以区分满缓冲区和空缓冲区。另一种选择是保留队列中元素数量的计数器以进行区分。更多信息可以在Circular buffer (Wikipedia)找到。
【讨论】:
在我看来,循环队列之所以是循环的,部分原因是它不会被“填满”。它将始终保持一定数量的元素,并根据需要丢弃旧的元素。
所以你永远不会填满空白空间;如果你插入一个新元素,你会删除一个旧元素,所以仍然会有一个空白空间。
换句话说,在您的图表中,如果您插入一个新数字,例如 0,您的队列如下所示(假设 1 是最后一个元素,3 是第一个元素):
|1| |3|4|5|6|
然后它将如下所示:
| |0|3|4|5|6|
但是,如果您想要的话,循环队列的某些实现会在达到其全长时简单地抛出异常/错误。例如this。
【讨论】:
head 开始打印,然后在head++ 进行打印(一旦到达分配空间的末尾,就会翻转到0)等等。停止当你到达head == tail。
head == tail会出现在“这种情况下”?头部在0,尾部在空白处。
这是我对队列最简洁的解释 有没有发现。您可以基于此扩展您的队列 基础。来源:“算法”,作者 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;
"需要维护两个索引,一个指向队列的开头(head),一个指向队列的末尾(tail)。队列的内容是数组中head和tail之间的所有元素,取入当遇到数组末尾时,将“环绕”记回 0。如果 head = tail 则队列定义为空;如果 head = tail + 1, 或者tail = max and head = 0,定义为满。”
【讨论】:
当头部和尾部指向同一个位置时,我们说队列已满。不能添加更多元素。要添加任何元素,您必须从队列中删除一个元素。这样头部将增加并再次生成空间。
【讨论】: