【问题标题】:Full Circular Queue?全循环队列?
【发布时间】:2012-07-06 08:02:04
【问题描述】:

我们只是在课堂上学习循环队列,我有几个问题。 由于我们将尾部定义为最后一个值旁边的空白区域,如下图所示:

|1| |3|4|5|6|

头部将指向数字 3,尾部将指向 1 和 3 之间的空白空间。我很困惑如果该空间被填满会发生什么,例如下面:

|1|2|3|4|5|6|

那么头部仍然指向3,但是尾部需要指向之前空白框之后的下一个框,因此它会指向3,或者头部。我该怎么办?

【问题讨论】:

    标签: queue


    【解决方案1】:

    当这种情况发生时,您的队列已满。在处理可推送的新项目时,您有几种选择:

    1. 丢弃推送事件:只有在弹出其他项目时才能再次推送项目。 headtail 均未更新。

      示例:想象一个事件队列已填满,新请求被简单地忽略。

    2. 丢弃(弹出)队列中最旧的事件:在这种情况下,您headtail 指针更新到一个位置。

      示例:缓冲来自网络摄像头的传入图像帧以进行处理。对于“实时”提要,您可能更愿意在处理出现中断时丢弃较旧的帧。

    3. 创建一个更大的队列:即动态分配更多内存

      示例:您使用循环队列,因为它是一种高效的实现方式,在您推送项目时大部分时间不需要内存分配。但是,您不想丢失队列中的项目,因此您允许偶尔重新分配更多内存

    正确的操作取决于您的应用程序。

    PS.:您的实现基于在队列中保留一个空槽以区分满缓冲区和空缓冲区。另一种选择是保留队列中元素数量的计数器以进行区分。更多信息可以在Circular buffer (Wikipedia)找到。

    【讨论】:

    • 他在问一个循环队列。
    • @houbysoft:是的,我知道。还有?
    • 循环队列并没有“满”,这就是循环的意义。
    • 换句话说,只有你的答案的“丢弃(弹出)”部分是相关的。
    • 确实,它是固定大小队列的有效实现。队列也可以实现为链表(大小固定或不固定),或者通过低效地在内存中移动而天真地在数组中实现。对于它的价值,我认为我们大多相互理解,只是对“循环队列”一词的含义存在分歧(具体行为与具体实现)。
    【解决方案2】:

    在我看来,循环队列之所以是循环的,部分原因是它不会被“填满”。它将始终保持一定数量的元素,并根据需要丢弃旧的元素。

    所以你永远不会填满空白空间;如果你插入一个新元素,你会删除一个旧元素,所以仍然会有一个空白空间。

    换句话说,在您的图表中,如果您插入一个新数字,例如 0,您的队列如下所示(假设 1 是最后一个元素,3 是第一个元素):

    |1| |3|4|5|6|
    

    然后它将如下所示:

    | |0|3|4|5|6|
    

    但是,如果您想要的话,循环队列的某些实现会在达到其全长时简单地抛出异常/错误。例如this

    【讨论】:

    • 感谢您的回复,但是在这种情况下,如果列表已满,当我们尝试打印出所有值时,通常是使用带有诸如 head
    • @NhatLe:这真的只是常识...从head 开始打印,然后在head++ 进行打印(一旦到达分配空间的末尾,就会翻转到0)等等。停止当你到达head == tail
    • @nhatle:为什么head == tail会出现在“这种情况下”?头部在0,尾部在空白处。
    • @houbysoft 顺便说一句,您链接到的实现不仅会丢弃最旧的元素,还会显示错误消息。作者称之为“队列溢出”状态(因此队列确实可以填满)。
    • @catchmeifyoutry:哈哈,你说得对。很公平,似乎人们在您考虑的意义上更多地想到了“循环队列”......给了你一个 +1。
    【解决方案3】:

    这是我对队列最简洁的解释 有没有发现。您可以基于此扩展您的队列 基础。来源:“算法”,作者 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,定义为满。”

    【讨论】:

      【解决方案4】:

      当头部和尾部指向同一个位置时,我们说队列已满。不能添加更多元素。要添加任何元素,您必须从队列中删除一个元素。这样头部将增加并再次生成空间。

      【讨论】:

        猜你喜欢
        • 2018-04-01
        • 2013-03-22
        • 1970-01-01
        • 2012-08-05
        • 2014-01-04
        • 2011-04-02
        • 1970-01-01
        • 2011-07-17
        • 2023-03-07
        相关资源
        最近更新 更多