栈可以用链表实现。 使用归并排序可以对链表进行排序: 时间复杂度为O(n log n) 空间复杂度为O(n)
使用归并排序对栈进行排序是有意义的。
如果这样,代码会是什么样子呢?
(在快速搜索网络后,我只找到了暴力算法O(n^2))
栈可以用链表实现。 使用归并排序可以对链表进行排序: 时间复杂度为O(n log n) 空间复杂度为O(n)
使用归并排序对栈进行排序是有意义的。
如果这样,代码会是什么样子呢?
(在快速搜索网络后,我只找到了暴力算法O(n^2))
可以的。诀窍在于理解堆栈排序后,头是最大元素 - 我们希望从低到高迭代它。但是我们可以在O(n)时间内反转一个堆栈。
reverse(stack):
s <- new stack
while stack.isEmpty() == false:
s.push(stack.pop)
return s
mergeSort(stack):
if stack.isEmpty():
return stack
s1 <- new stack
s2 <- new stack
// O(n):
while s1.size() < stack.size():
s1.push(stack.pop())
while (stack.isEmpty() == false):
s2.push(stack.pop())
mergeSort(s1) //half the size of stack
mergeSort(s2) //half the size of stack
//head of s1 and s2 is the largest element
s1 <- s1.reverse() //easily implemented in O(n)
s2 <- s2.reverse()
//now head of s1 and s2 is the smallest element
while (s1.isEmpty() == false and s2.isEmpty() == false):
if (s1.peek() < s2.peek()):
stack.push(s1.pop())
else:
stack.push(s2.pop())
//the 'tail' of one stack:
while (s1.isEmpty() == false):
stack.push(s1.pop())
while (s2.isEmpty() == false):
stack.push(s2.pop())
//head is the largest, stacks are sorted
return stack
正确性:
基础:停止条件是一个已排序的空栈。
假设:s1和s2已经排序。
步骤:在翻转之后,使用pop()方法移除元素时,s1和s2基本上按从小到大的顺序遍历,在排序区域中。由于我们总是从每个栈中插入较小的元素,并且我们正在从低到高遍历每个栈 - 因此得到的结果堆栈是有序的。
复杂度:
不包括递归调用,每一步都是 O(stack.size()) = O(n)
。这与常规归并排序的行为相同,其余的复杂度遵循原始归并排序的相同步骤,以获得O(nlogn)
。
void mergesortStack(Stack input) {
if (input.isEmpty()) {
return;
}
Stack stackLeft = new Stack();
Stack stackRight = new Stack();
// split
while (!input.isEmpty()) {
stackLeft.push(input.pop());
if (!input.isEmpty()) {
stackRight.push(input.pop());
}
}
// recurse
if (!stackLeft.isEmpty() && !stackRight.isEmpty()) {
mergesortStack(stackLeft);
mergesortStack(stackRight);
}
// merge
Stack tmpStack = new Stack();
while (!stackLeft.isEmpty() || !stackRight.isEmpty()) {
if (stackLeft.isEmpty()) {
tmpStack.push(stackRight.pop());
} else if (stackRight.isEmpty()) {
tmpStack.push(stackLeft.pop());
// set an appropriate compare method
} else if (stackLeft.peek().compareTo(stackRight.peek()) >= 0) {
tmpStack.push(stackLeft.pop());
} else {
tmpStack.push(stackRight.pop());
}
}
// reverse stack
while (!tmpStack.isEmpty()) {
input.push(tmpStack.pop());
}
}