给定两个队列支持操作enqueue / push_back,dequeue / pop_front和size
Q1: A1 A2 A3
Q2: B1 B2 B3
如何将它们合并到第三个队列(也支持相同的操作),获取:
Q3: A1 B1 A2 B2 A3 B3
我对使用的算法更感兴趣,而不是任何特定的语言实现。
答案 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
应用其他两个参数。
这听起来像是在日常业务编程中可能遇到的合理任务。但是,如果这是一个家庭作业,我建议你仔细研究上面的代码是如何工作的,我想你会学到一些东西。
此外,上述代码中可能存在错误;证明它有效(或找到错误)将是一个很好的练习。