排序模板
一、插入排序
- 特点:stable sort、In-place sort
- 最优复杂度:当输入数组就是排好序的时候,复杂度为O(n),而快速排序在这种情况下会产生O(n^2)的复杂度。
- 最差复杂度:当输入数组为倒序时,复杂度为O(n^2)
- 插入排序比较适合用于“少量元素的数组”。
伪代码:
C++模板:
template <typename T>
void Insertion_Sort(T *array, size_t length) {
if (length <= 1) {
return;
} else {
for (int i = 1; i != length; i++) {
int j = i - 1;
T key = array[i];
while (j >= 0 && array[j] > key) {
array[j + 1] = array[j];
j--;
}
array[j + 1] = key;
}
}
}
证明算法正确性:
循环不变式:在每次循环开始前,A[1…i-1]包含了原来的A[1…i-1]的元素,并且已排序。
初始:i=2,A[1…1]已排序,成立。
保持:在迭代开始前,A[1…i-1]已排序,而循环体的目的是将A[i]插入A[1…i-1]中,使得A[1…i]排序,因此在下一轮迭代开 始前,i++,因此现在A[1…i-1]排好序了,因此保持循环不变式。
终止:最后i=n+1,并且A[1…n]已排序,而A[1…n]就是整个数组,因此证毕。
二、冒泡排序
- 特点:stable sort、In-place sort
- 思想:通过两两交换,像水中的泡泡一样,小的先冒出来,大的后冒出来。
- 最坏运行时间:O(n^2)
- 最佳运行时间:O(n^2)(当然,也可以进行改进使得最佳运行时间为O(n))
伪代码:
C++模板:
template <typename T>
void Bubble_Sort(T *array, size_t length) {
for (int i = 0; i != length - 1; i++) {
for (int j = 0; j + i != length - 1; j++) {
if (array[j] > array[j + 1]) {
T temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
}
}
证明算法正确性:
运用两次循环不变式,先证明第4-6行的内循环,再证明外循环。
内循环不变式:在每次循环开始前,A[j]是A[j…n]中最小的元素。
初始:j=n,因此A[n]是A[n…n]的最小元素。
保持:当循环开始时,已知A[j]是A[j…n]的最小元素,将A[j]与A[j-1]比较,并将较小者放在j-1位置,因此能够说明A[j-1]是A[j-1…n]的最小元素,因此循环不变式保持。
终止:j=i,已知A[i]是A[i…n]中最小的元素,证毕。
接下来证明外循环不变式:在每次循环之前,A[1…i-1]包含了A中最小的i-1个元素,且已排序:A[1]<=A[2]<=…<=A[i-1]。
初始:i=1,因此A[1..0]=空,因此成立。
保持:当循环开始时,已知A[1…i-1]是A中最小的i-1个元素,且A[1]<=A[2]<=…<=A[i-1],根据内循环不变式,终止时A[i]是A[i…n]中最小的元素,因此A[1…i]包含了A中最小的i个元素,且A[1]<=A[2]<=…<=A[i-1]<=A[i]
终止:i=n+1,已知A[1…n]是A中最小的n个元素,且A[1]<=A[2]<=…<=A[n],得证。
在