Java Deque双端队列合并输出顺序错误问题排查与求解
问题背景
我是Java初学者,目前正在学习Deque相关知识,遇到一个合并双端队列的实现任务,代码运行结果不符合预期,需要排查问题并梳理这类问题的通用处理思路。
已知输入两个Deque:
charDeque:元素顺序为[a, e, i, o, u, b],a是队头(head),b是队尾(tail)intDeque:元素顺序为[3, 6, 9],3是队头(head),9是队尾(tail)
要求合并后从上到下(top to bottom)的输出顺序为:[3, a, 6, e, 9, i, o, u, b]。
最初的实现思路是循环遍历两个Deque,通过pollLast()获取队尾元素,将元素push到初始为空的mergedStack对象中,但实际运行输出为[o, 9, u, 6, b, 3],和预期不符。
原实现代码如下:
package QueueInterfaceExercise1; import java.util.ArrayDeque; import java.util.Deque; public class Tester { public static Deque<Object> mergeQueue(Deque<Integer> intQueue, Deque<Character> charQueue) { System.out.println(charQueue); Deque<Object> mergedStack = new ArrayDeque<Object>(); while( !intQueue.isEmpty() && !charQueue.isEmpty() ) { int number = intQueue.pollLast(); char letter = charQueue.pollLast(); mergedStack.push(number); mergedStack.push(letter); } return mergedStack; } public static void main(String[] args) { Deque<Integer> integerQueue = new ArrayDeque<Integer>(); integerQueue.add(3); integerQueue.add(6); integerQueue.add(9); Deque<Character> characterQueue = new ArrayDeque<Character>(); characterQueue.add('a'); characterQueue.add('e'); characterQueue.add('i'); characterQueue.add('o'); characterQueue.add('u'); characterQueue.add('b'); Deque<Object> mergedQueue = mergeQueue(integerQueue, characterQueue); System.out.println("The elements in the merged queue are:"); for(Object element: mergedQueue) System.out.println(element); } }
问题根因分析
原代码一共有3处逻辑错误,直接导致输出不符合预期:
- 取元素的方向完全错误:预期是从两个队列的队头开始按顺序交替取元素(先取int队头3,再取char队头a,以此类推),但原代码用
pollLast()从队尾取元素,int队列出队顺序变成9、6、3,char队列出队顺序变成b、u、o、i、e、a,从第一步就和预期顺序相反。 - 写入结果的方法选择错误:Deque的
push()方法是将元素加到队头(栈顶位置),属于栈操作,就算取元素的顺序正确,连续push也会把元素顺序倒转,和队列先进先出的需求不符。 - 循环逻辑遗漏剩余元素:循环判断条件是两个队列同时非空才执行,int队列只有3个元素,char队列有6个元素,循环执行3次int队列就空了,char队列剩余的元素根本没有被处理,直接导致结果元素不全。
修正后的代码
修正逻辑:从两个队列的队头按顺序交替取元素,用addLast()追加到结果队列的尾部,等较短的int队列全部取完后,再把char队列剩余的元素全部按顺序追加到结果尾部即可。
package QueueInterfaceExercise1; import java.util.ArrayDeque; import java.util.Deque; public class Tester { public static Deque<Object> mergeQueue(Deque<Integer> intQueue, Deque<Character> charQueue) { Deque<Object> mergedQueue = new ArrayDeque<>(); // 交替取两个队列的队头元素,直到两个队列全部为空 while (!intQueue.isEmpty() || !charQueue.isEmpty()) { if (!intQueue.isEmpty()) { mergedQueue.addLast(intQueue.pollFirst()); } if (!charQueue.isEmpty()) { mergedQueue.addLast(charQueue.pollFirst()); } } return mergedQueue; } public static void main(String[] args) { Deque<Integer> integerQueue = new ArrayDeque<Integer>(); integerQueue.add(3); integerQueue.add(6); integerQueue.add(9); Deque<Character> characterQueue = new ArrayDeque<Character>(); characterQueue.add('a'); characterQueue.add('e'); characterQueue.add('i'); characterQueue.add('o'); characterQueue.add('u'); characterQueue.add('b'); Deque<Object> mergedQueue = mergeQueue(integerQueue, characterQueue); System.out.println("The elements in the merged queue are:"); for(Object element: mergedQueue) System.out.println(element); // 输出顺序为3、a、6、e、9、i、o、u、b,完全符合预期 } }
这类Deque问题的通用处理思路
- 先明确API的操作端:Deque同时支持队列FIFO、栈LIFO两种操作模式,使用
add/remove/poll/peek/push等方法前,先确认方法操作的是队头还是队尾,避免方向搞反。 - 列清顺序再写代码:遇到顺序类问题不要直接上手写循环,先把输入队列的头、尾位置标清楚,把预期输出的元素顺序列出来,对应每一步要取哪个源队列的哪个位置的元素、放到结果的哪个位置,再匹配对应的API。
- 覆盖长度不一致的边界:两个集合做交替合并时,不要用
&&作为唯一的循环判断条件,要考虑两个集合长度不一样的场景,短集合遍历完后,需要把长集合剩余的元素全部追加到结果中,避免漏元素。 - 小数据手动走读验证:写完逻辑后拿最简单的测试用例,手动模拟2-3次循环执行过程,记录每一步源队列剩余元素、结果队列的元素顺序,很容易就能发现顺序颠倒、漏元素的问题。
内容的提问来源于stack exchange,提问作者user18049497
相关产品推荐
相关产品推荐

