交换类
冒泡排序¶
进行两两交换,一趟下来把一个最值移到了最右边
- 【最坏时间复杂度】\(O(n^2)\);待排序列逆序,基本操作总的执行次数为(n-1+1)(n-1)/2=n(n-1)/2
- 【最好时间复杂度】\(O(n)\);待排序序列已经有序,第二层循环不进行
- 【平均时间复杂度】\(O(n^2)\)
- 【空间复杂度】O(1)
快速排序¶
第一个同学出列,其他人以他为中心,比他矮的到他的左边,比他高的到他的右边
步骤:[low, high]
- 取左边第一个作为哨兵,并且保存下来
key
i=low
,然后从左到右搜索(即i++
);j=high
然后从右到左搜索(即j--
);直到i>j
,每次循环执行- 如果
arr[j] < key
,将把它放到arr[i]
的位置 - 如果
arr[i] > key
,就把它放到arr[j]
的位置
- 如果
void QuickSort(int arr[], int low, int high) {
if(low >= high) return; //超出范围,直接退出
auto key = arr[low]; //把最左边的元素作为哨兵
auto i = low;
auto j = high;
while(i < j) {
//# j从右到左进行移动
// 如果arr[j]比哨兵大就继续位移
while(i<j && arr[j] >= key) --j;
//如果遇到比key小,要放在哨兵左边,放到i空出来的位置
// 放完后,因为i的位置被填上了,因此要向右位移
if(i < j) arr[i++] = arr[j];
//# i从左到右移动
// 如果arr[i]比哨兵小就继续位移
while(i<j && arr[i] <= key) ++i;
//如果遇到比tmp大的,要放在左边
// 放完后,因为j的位置被填上了,因此要向右位移
if(i < j) arr[j--] = arr[i];
}
//比哨兵小的都排在左边了,比哨兵大的都排在右边了
// 因此这个哨兵就弄完了,继续剩下的范围
arr[i] = tmp;
QuickSort(arr, low, i-1);
QUickSort(arr, i+1, high);
}
【评价】
- 快速排序的排序趟数和初始序列有关;
- 在同级别的算法中(\(O(X*nlog_2n)\)),此算法的X最小
【最好】\(O(nlog_2n)\)序列越接近无序,越有效
【最坏】\(O(n^2)\)序列元素越有序,越无效
【平均】\(O(nlog_2n)\)
【空间复杂度】\(O(log_2n)\)递归算法,空间消耗大,需要用到系统栈