如何将两个队列合并为一个队列?

时间:2009-05-18 01:16:31

标签: algorithm merge queue

给定两个队列支持操作enqueue / push_back,dequeue / pop_front和size

Q1: A1 A2 A3
Q2: B1 B2 B3

如何将它们合并到第三个队列(也支持相同的操作),获取:

Q3: A1 B1 A2 B2 A3 B3

我对使用的算法更感兴趣,而不是任何特定的语言实现。

3 个答案:

答案 0 :(得分:4)

这是一些伪代码:

Queue mergeQueues(Queue A, Queue B)
{
    Queue newQ;
    while(A.nonempty() OR B.nonempty())
    {
        if (A.nonempty())
            newQ.push(A.pop());
        if (B.nonempty())
            newQ.push(B.pop());
    }
    return newQ;
}

push将一个元素插入队列,pop删除队列中的下一个元素并返回它。

请注意,这不适用于堆栈。你最终会得到这些元素。如果您可以反转堆栈(例如,通过重复转移到另一个堆栈),那么它将起作用。

答案 1 :(得分:2)

虽然两个队列都不为空,但是将项目从A中出列并将其排入newQ。然后将一个项目从队列B中取出。如果队列中的任何一个(A或B)为空,则将其他队列的其余部分出列,并将每个元素排入newQ。

答案 2 :(得分:1)

似乎非常适合递归实现:

mergeQueues :: Queue a -> Queue a -> Queue a
mergeQueues qa qb =
    merge qa qb emptyQueue
    where
        merge qa qb qr
            | isEmpty qa = append qb qr
            | otherwise  = move (merge qb) qa qr
        append q qr
            | isEmpty q  = qr
            | otherwise  = move append q qr
        move f q qr =
            let (val,q') = pop q
             in f q' (push val qr)

请注意,我们只是在我们递归时来回移动队列,以便在它们之间交替,直到一个为空,此时我们只是将它们从一个追加到另一个。

请注意,虽然这比ribond提供的命令式版本更长,但这会进行最少量的isEmpty检查。如果您不介意在稍微更优化的版本中执行尽可能多的检查(将isEmpty值分配给变量以便在下面重复使用),则可以删除append函数并继续调用{{1相反,在向merge添加初始测试后,测试两个队列为空并终止递归(如果是)。

对于那些不熟悉Haskell的人,我们传入下一个函数来调用(这是高阶函数编程);在merge情况下,只是追加,append情况下是“部分应用”移动函数:它在我们调用move之前获取第一个参数qb ,然后move应用其他两个参数。

这听起来像是在日常业务编程中可能遇到的合理任务。但是,如果这是一个家庭作业,我建议你仔细研究上面的代码是如何工作的,我想你会学到一些东西。

此外,上述代码中可能存在错误;证明它有效(或找到错误)将是一个很好的练习。