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

Algorithm 如何将两个队列合并为一个队列?,algorithm,merge,queue,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 我更感兴趣的是要使用的算法,而不是任何特定的语言实现 当两个队列都不为空时,将项目从A中移出队列,并将其排入newQ。然后将一个项目从队列B中移出。如果其中一个队列(A或B)为空,则将另一个队列的其余部分移出队列,并将每个元素排入

给定两个支持操作的队列,分别为enqueue/push_back、dequeue/pop_front和size

Q1: A1 A2 A3
Q2: B1 B2 B3
如何将它们合并到第三个队列(也支持相同的操作),以获得:

Q3: A1 B1 A2 B2 A3 B3

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

当两个队列都不为空时,将项目从A中移出队列,并将其排入newQ。然后将一个项目从队列B中移出。如果其中一个队列(A或B)为空,则将另一个队列的其余部分移出队列,并将每个元素排入newQ。

以下是一些伪代码:

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
删除队列中的下一个元素并返回它


请注意,这对堆栈不起作用。您将以元素向后结束。如果可以反转堆栈(例如,通过重复传输到另一个堆栈),那么它就可以工作。

它似乎非常适合递归实现:

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
检查。如果您不介意在稍微优化的版本中执行与his一样多的检查(将isEmpty值分配给变量以便在下面重复使用),您可以删除
append
函数并继续调用
merge
,将初始测试添加到
merge
后,测试两个队列是否为空,如果为空,则终止递归

对于那些不熟悉Haskell的人,我们将传递以移动下一个要调用的函数(这是高阶函数编程);在
append
案例中,这只是append,在
move
案例中,这是一个“部分应用”的移动函数:它在调用
move
之前获得第一个参数
qb
,然后
move
应用其他两个参数

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


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

当一个队列比另一个队列排得早时,您想做什么?停止继续,忽略短队列中缺少的元素?继续,把空元素替换掉丢失的元素?