【问题标题】:Sorting a Queue Using Recursion使用递归对队列进行排序
【发布时间】:2012-01-31 10:16:12
【问题描述】:

问题是这样的:

您需要在添加到队列的新成员方法void sort() 中对队列进行排序。

规则是:

  • 您不能使用任何循环。只允许递归。
  • 您可以创建任意数量的私有方法。
  • 您可以创建和使用 两个 相同类型的辅助队列(称为队列 - 具有默认构造函数)。
  • 您对队列的内部结构一无所知。
  • 给你的唯一方法是:bool empty(), Data peek(), Data dequeue(), void enqueue(Data d)
  • 如果列表为空,dequeue() 返回 null,enqueue() 忽略 null 输入。
  • 排序顺序需要升序(队列前面应该有最小值)。
  • 可比较的值在Data 结构中以整数形式存在,称为x

我知道它可以解决。我还没有找到答案。任何想法将不胜感激。

【问题讨论】:

  • 到目前为止你有什么?这是作业吗?
  • @userunknown 是的,这是作业。到目前为止,我所拥有的是一种辅助方法,它对队列进行排序,并将其拆分为 2 个新队列,高和低,每次从队列中取出 2 个元素并将它们放入正确的辅助队列中。这适用于偶数长度的队列,但不适用于奇数长度的队列。
  • 好吧 a) 向我们展示代码。 b) 奇数队列有什么问题?如果这是您唯一的问题 - 也许您可以将最后一个元素添加两次,最后删除其中一个?

标签: algorithm sorting queue


【解决方案1】:

开始对包含 N=2 个元素的队列进行排序。

现在 - 在解决这个问题之后 - 如果对 N 个元素进行排序,则改进对 N+1 个元素进行排序的解决方案。


更新:

现在,在你完成作业后,我可以在 scala 中展示另一种解决方案:

   private def insert (a: Int): Unit = {
     if (isEmpty || a <= peek) enqueue (a)
     else {
       val h = dequeue 
       insert (a)
       enqueue (h)
     }
   }
   
   def sort (): Unit = 
    if (! isEmpty) {
      val head = dequeue
      sort 
      insert (head)
    }

它可以在没有明确的第二个队列的情况下工作。插入是一个 sortedInsert。

val q = new Queue (List (4))
q.enqueue (7)
q.enqueue (9)
q.enqueue (8)
q.enqueue (2)
q.enqueue (3)

val x = q.debug 
x: List[A] = List(3, 2, 8, 9, 7, 4)

q.sort 
val x = q.debug 
x: List[A] = List(2, 3, 4, 7, 8, 9)

我使用 List 来实现队列,但仅用于创建新队列和出于调试原因。避免它没什么大不了的,但它更快,我想从排序开始。 :)

【讨论】:

  • 我相信您在使用排序插入时存在错误。我认为这与偷看然后在你应该“推”的地方排队有关。换句话说,我认为它不适用于队列。不过,这个想法非常好。如果您愿意再试一次并给出正确答案,我会接受您的答案。
【解决方案2】:

看看归并排序。它用于对磁带上的数据进行分类。我相信你可以轻松地采用它来排队。

【讨论】:

    【解决方案3】:

    首先,感谢您的回答。他们为我指出了正确的解决方案。我投票给他们以表扬他们,但既然我设法解决了这个问题,我会接受我自己的答案(至少在更好的答案出现之前)。

    所以首先,作业是关于“出租车”(你知道作业是怎样的......)和 Java 中的 TaxiQueue。

    解决办法是:

    public void sort() {
        sort(this);
    }
    
    private void sort(TaxiQueue toSort) {
        // Prepare split parts for later merging   
        TaxiQueue m1 = new TaxiQueue(), m2 = new TaxiQueue();
    
        // Return if there's only 1 element in the queue
        // since it's essentially "sorted".
        if(singleItem(toSort))
            return;
    
        // Split toSort into 2 parts
        split(toSort, m1, m2);
        // Sort each part recursively (by splitting and merging)
        sort(m1);
        sort(m2);
        // Merge each part into 1 sorted queue
        merge(toSort,  m1, m2);
    }
    
    private boolean singleItem(TaxiQueue tq) {
        Taxi temp = tq.dequeue();
        boolean retVal = tq.empty();
        tq.enqueue(temp);
        return retVal;
    }
    
    private void merge(TaxiQueue toSort, TaxiQueue m1, TaxiQueue m2) {
        // Notice that m1 and m2 are already sorted, and now we need
        // to merge them.
        // In the case that one of them is empty and the other one isn't,
        // simply append all remaining "higher" values into toSort.
        if(m1.empty()) {
            appendQueue(m2, toSort);
            return;
        }
        else if (m2.empty()) {
            appendQueue(m1, toSort);
            return;
        }
        // The critical comparison part...
        if(m1.peek().getId() < m2.peek().getId())
            toSort.enqueue(m1.dequeue());
        else
            toSort.enqueue(m2.dequeue());
        // Continue merging elements into toSort.
        merge(toSort, m1, m2);
    }
    
    // Split toSort into m1 and m2 as equally as possible
    private void split(TaxiQueue toSort, TaxiQueue m1, TaxiQueue m2) {
        if(toSort.empty())
            return;
        m1.enqueue(toSort.dequeue());
        split(toSort,  m2, m1);
    }
    
    // Enqueue everything in src to dest.
    private void appendQueue(TaxiQueue src, TaxiQueue dest) {
        if (src.empty())
            return;
        dest.enqueue(src.dequeue());
        appendQueue(src, dest);
    }
    

    我希望其他学生有一天会发现它有用!

    【讨论】:

      【解决方案4】:

      @Yam Marcovic:你的回答很好。尽管您最终会创建与原始队列中的元素一样多的队列。可能这是你不想做的事情。相反,您可以尝试一种更简单的方法,您只需总共创建 2 个新队列(称它们为 originalQ、Q1、Q2)。

      我将描述递归步骤。

      • 假设 Q1 有 n1 个元素已经排序。
      • 让来自 originalQ 的新元素为 s。如果 s 无法通过一个入队操作正确定位在 Q 中,则继续从 Q1 弹出元素(将它们与 s 进行比较)并将它们正确放置在 Q2 中。
      • 现在您的 Q2 使用 n1+1 个元素排序,Q1 为空。 originalQ 少了一个元素。继续重复上述步骤。

      【讨论】:

        【解决方案5】:

        以下方法旨在仅使用一个附加队列来解决此问题。

        算法使用递归对队列进行排序。

        假设我们有一个函数 copy_from 可以从一个队列复制到另一个队列,如下所示:-

          void copy_from (ArrayQueue&Q_from,ArrayQueue& Q_to){
        
               while(!Q_from.empty()){
        
               int t= Q_from.front();
               Q_to.enqueue(t);
               Q_from.dequeue();
             }
          }
        

        主要排序功能如图:-

        void sort(ArrayQueue &Q, int element, ArrayQueue& Q2){
        
        if(Q.size()==1){
        
            if(Q.front()>element){
        
                 int front = Q.front();
                 Q.dequeue();
                 Q.enqueue(element);
                 Q.enqueue(front);      
            }
            else{
                Q.enqueue(element);
            }
        
        }
        else{
        
         int front = Q.front();
         Q.dequeue();
         sort_v2(Q,front,Q2);
        
         int sorted_front = Q.front();
         if(element<sorted_front){
        
            Q2.enqueue(element);
            copy_from(Q,Q2);
            copy_from(Q2,Q);     
        
         }
         else{
        
              Q2.enqueue(sorted_front);
              Q.dequeue();
              //push into Q2 those elements which are smaller than element in Q.
              while(!Q.empty()&&Q.front()<element){
                 Q2.enqueue(Q.front());
                 Q.dequeue();
              }
        
              Q2.enqueue(element);
              copy_from(Q,Q2);
              copy_from(Q2,Q);
        
         }
        
        }
        }
        

        当我们最初调用排序函数时,我们可以这样调用它:-

         Queue Q, Q2; //Assume Q is the queue we want to sort and Q2 is an empty queue.
        int front = Q.front();
        Q.dequeue();
        sort(Q,front,Q2);
        

        【讨论】: