以非传统方式反转队列

时间:2013-03-22 04:18:02

标签: algorithm recursion queue

假设我有一个填充了某种类型元素的队列,并且它们以这样的方式填充:如果任何两个元素被指定的比较器评估为相同,则它们将彼此相邻。

现在我想以下列方式反转队列:如果队列中的所有元素都是唯一的,那么将其反转为反向的正常定义。

如果某些元素相同(并且它们将如何填充它们将彼此相邻),则反转队列但保持非唯一元素的相对位置不变。

图表可能更容易理解问题所在。

如果队列如下:

[11 22 33 44 55]

并且我的比较器通过查看它们的第一个数字来比较两个整数,然后上面的队列的反向将是:

[55 44 33 22 11]

但是,如果我的输入队列是:

[11 22 23 44 55]

反过来应该是:

[55 44 22 23 11]

给出比较器。

我试图以递归方式执行此操作,只有一个堆栈作为附加辅助存储。但是,我很难找到正确有效的方法。能否请你帮忙?非常感谢你!

PS:我使用堆栈作为额外存储的原因是因为以传统方式反转队列最容易使用堆栈(出队并将所有进入堆栈,然后弹出并入队回队列)。 / p>

4 个答案:

答案 0 :(得分:2)

方法1)

首先反转整个队列(不考虑21,22等的相等),然后使用堆栈反转每个单独的块(即21,22等)。这可以迭代完成。

这类似于句子问题中的反向词(着名的访谈问题)。

(参见下面的实例和伪代码)

方法2)

如果你想绝对做递归,那么我建议你使用Queue作为辅助存储,而不是堆栈。

将一个块插入辅助队列,以递归方式反转列表的其余部分,然后将元素重新排入主队列。

代码将是这样的(handwavy pseudo)

StrangeReverse(Queue <T> q) {
    Queue<T> aux;
    // this removes first block from q, and places them in aux
    while (elem_of_first_block(q)) {
        aux.Enque(elem);
    }
    // Recursively reverse the rest of the q.
    StrangeReverse(q);

    // place the first block back in q, at the end.
    // in the order they appeared originally.
    while (aux.HasElements()) {
        q.Enque(aux.Deque());
    }
}

通过拥有一堆队列,可以将递归版本转换为迭代版本!您可以从每个块中创建一个队列,并将它们堆叠起来。然后弹出堆栈,使用队列。

方法1的实例

[11, 12, 21, 22, 43, 44]

反转这个(使用堆栈或递归方法)

[44, 43, 22, 21, 12, 11]

现在反转每个块:

push 44, the 43.

Stack = [44, 43]. Queue = [22, 21, 12, 11]

现在从群组中弹出

Stack = [], Queue = [22, 21, 12, 11, 43, 44]

push 22, 21

Stack = [22, 21], Queue = [12, 11, 43, 44]

通过弹出堆栈来获取。

Stack = [], Queue = [12, 11, 43, 44, 21, 22]

最后我们得到

[43, 44, 21, 22, 11, 12]

注意:要确定一个块,您可能需要在队列上使用peek方法。

方法1的伪代码

void StrangeReverse(Queue<T> q) {
    Stack<T> s;
    int count = q.Count();
    if (count < 2) return;
    for (i = 0; i < count; i++) {
        T elem = q.Deque();
        s.Push(elem);
    }    
    while (s.HasElements()) {
        T elem = s.Pop();
        q.Enque(elem);
    }
    // Now the queue has been reversed,
    // in the normal fashion.
    ReverseBlocks(q);
}

void ReverseBlocks(Queue<T> q) {
    int reversed = 0;
    int count = q.Count();
    while (reversed < count) {
        reversed += ReverseSingleBlock(q);
    }
}

int ReverseSingleBlock(Queue <T> q) {
    Stack <T> s;
    T prevElem = q.Deque();
    s.Push(prevElem);
    T curElem = q.Peek();
    while(curElem == prevElem) {
        s.Push(curElem);
        q.Deque();
        prevElem = curElem;
        curElem = q.Peek();
    }
    int count = 0;
    while(s.HasElements()) {
        T elem = s.Pop();
        q.Enque(elem);
        count++;
    }
    return count;
}

答案 1 :(得分:0)

仍然假设: enque - &gt; [11,21,22,23,30] - &gt;双端队列/偷看
现在应该会更好:

first = queue.peek();
start = true;
while (queue.peek() != first || start) {
  start = false;
  el = queue.deque();
  if (el.compare(queue.peek())) {
    stack.push(el);
    while (el.compare(queue.peek())) {
      el1 = queue.dequeue();
      if (first.compare(el1)) {
        first = el1;
      }
      stack.push(el1);
    }
    while (!stack.isEmpty()) {
      queue.enque(stack.pop());       
    }
  } else {
    queue.enque(el);
  }
}
while (!queue.isEmpty()) {
  stack.push(queue.deque());
}
while (!stack.isEmpty()) {
  queue.enque(stack.pop());
}

所以首先我要旋转队列,改变“等效”元素的顺序 最后我正在做一个普通的队列逆转

答案 2 :(得分:0)

 class ReverseQueue(object):
    def __init__(self, limit=5):
        self.rear = None
        self.front = None
        self.que = []
        self.size = 0
        self.limit = limit

   def enQueue(self, item):
        if self.size >= self.limit:
            print "Queue Overflow"
            return
        else:
            self.que.append(item)

        # two case
        # 1. if front is None then the queue is empty.
        #    so if item is added both front
        #    end point to the same position i.e 0
        # 2. if front is not None then item is added to the end of the
        #    list(append does that). we then increase the size of rear

        # note: rear is 0 indexed but size is not
        # that's why there's a diff of 1 always b/w these rear and size
        if self.front is None:
            self.rear = self.front = 0
            self.size = 1
        else:
            self.rear = self.size
            self.size += 1

        return

    def deQueue(self):
          if self.size <= 0:
              print "Queue Underflow"
              return
          else:
              temp = self.que.pop(0)

          # change the size
          self.size -= 1

          # if list is empty set both front and rear = None
          # This is in sync with the queue method
          #  where we check if front = none when adding item
          # change front and rear
          if self.size is 0:
             # if only one element
             self.rear = self.front = None
          else:
             # more then one element
             self.rear -= 1

          return temp

      def isEmpty(self):
          return self.size <= 0

      def reverse(self):
          if not self.isEmpty():
              temp = self.deQueue()
              self.reverse()
              self.enQueue(temp)

myQueue = ReverseQueue()

myQueue.enQueue( “第一”)

myQueue.enQueue( “第二”)

myQueue.enQueue( “第三”)

myQueue.enQueue( “第四”)

myQueue.enQueue( “第五”)

打印myQueue.que

myQueue.reverse()

打印myQueue.que

答案 3 :(得分:0)

这是使用递归来反转C ++ STL队列的代码片段。

void reverseQueue(queue<int>& q){
    while(q.size() != 0){
        q.pop();

        reverseQueue(q);

        q.push(value);
        break;
    }
}