十大排序算法
分类
- 稳定:冒泡、插入、归并
- 非稳定:快排,选择,希尔,堆
排序复杂度
常见考点
🔥🔥🔥快速排序
描述
- 从数列中挑出一个元素,称为 “基准”(pivot)
- 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作
- 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序
代码
/*************************************************************************
> File Name: quick_sort.cpp
> Author: HuHan
> 微信公众号: 编程诗
> Created Time: Wed Apr 27 20:14:10 2022
> Description: quick sort
************************************************************************/
#include <iostream>
using namespace std;
int partition(int array[], int low, int high) {
int tmp = array[low];
while (low < high) {
while (low < high && array[high] >= tmp) {
--high;
}
array[low] = array[high];
while (low < high && array[low] <= tmp) {
++low;
}
array[high] = array[low];
}
array[low] = tmp;
return low;
}
void quickSort(int array[], int low, int high) {
if (low < high) {
int pivotIndex = partition(array, low, high);
quickSort(array, low, pivotIndex - 1);
quickSort(array, pivotIndex + 1, high);
}
}
void randQuickSort(int array[], int low, int high) {
if (low >= high) {
return;
}
int pos = low + (rand() % (high - low));
int l = low, h = high;
int pivot = array[pos];
swap(array[low], array[pos]);
while (l < h) {
while (array[h] >= pivot && l < h) {
--h;
}
if (l < h) {
array[l] = array[h];
++l;
}
while (array[l] <= pivot && l < h) {
++l;
}
if (l < h) {
array[h] = array[l];
--h;
}
}
array[l] = pivot;
randQuickSort(array, low, l-1);
randQuickSort(array, l+1, high);
}
int main() {
int i = 0;
int array[] = {11, 25, 16, 2, 3, 26, 4, 91};
int rand_arr[] = {11, 25, 16, 2, 3, 26, 4, 91};
int len = sizeof(array) / sizeof(array[0]);
cout << "array: ";
for (i = 0; i < len; ++i) {
cout << array[i] << ' ';
}
quickSort(array, 0, len - 1);
cout << endl;
cout << "sorted array: ";
for (i = 0; i < len; ++i) {
cout << array[i] << ' ';
}
cout << endl;
randQuickSort(rand_arr, 0, len - 1);
cout << "rand sorted array: ";
for (i = 0; i < len; ++i) {
cout << array[i] << ' ';
}
cout << endl;
return 0;
}
🔥🔥归并排序
描述
- 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;
- 设定两个指针,最初位置分别为两个已经排序序列的起始位置;
- 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置;
- 重复步骤 3 直到某一指针达到序列尾;
- 将另一序列剩下的所有元素直接复制到合并序列尾。
代码
#include<iostream>
#include<vector>
using namespace std;
void mergeSort(vector<int>& k, int n){
int i, next, left_min, left_max, right_min, right_max;
vector<int> temp(n);
for(int i = 1; i < n; i *= 2){//步长, 1, 2, 4, ...
for(left_min = 0; left_min < n - i; left_min = right_max){
//从0开始, 根据步长, 向右分组排序
right_min = left_max = left_min + i;
right_max = left_max + i;
if(right_max > n){
right_max = n;
}
next = 0;
//将k[]数组中小的数据备份
//结束条件:left或right有一个完全拷贝到temp
while(left_min < left_max && right_min < right_max){
if(k[left_min] < k[right_min]){
temp[next++] = k[left_min++];
} else{
temp[next++] = k[right_min++];
}
}
while(left_min < left_max){
k[--right_min] = k[--left_max];
}
while(next > 0){
k[--right_min] = temp[--next];
}
}
}
}
int main(){
vector<int> array = {11, 25, 16, 2, 3, 26, 4, 91};
cout << "array:";
for(int tmp : array) cout << tmp << ' ';
mergeSort(array, array.size());
cout << endl << "sorted array: ";
for(int tmp : array) cout << tmp << ' ';
return 0;
}
🔥🔥堆排序
堆的性质
- 是一棵完全二叉树
- 每个节点的值都大于或等于其子节点的值,为最大堆;反之为最小堆。
描述
- 将待排序的序列构造成一个最大堆,此时序列的最大值为根节点
- 依次将根节点与待排序序列的最后一个元素交换
- 再维护从根节点到该元素的前一个节点为最大堆,如此往复,最终得到一个递增序列
#include <iostream>
#include <algorithm>
using namespace std;
void max_heapify(int arr[], int start, int end) {
//建立父节点指标和子节点指标
int dad = start;
int son = dad * 2 + 1;
while (son <= end) { //若子节点指标在范围内才做比较
if (son + 1 <= end && arr[son] < arr[son + 1]) //先比较两个子节点大小,选择最大的
son++;
if (arr[dad] > arr[son]) //如果父节点大于子节点代表调整完毕,直接跳出函数
return;
else { //否则交换父子内容再继续子节点和孙节点比较
swap(arr[dad], arr[son]);
dad = son;
son = dad * 2 + 1;
}
}
}
void heap_sort(int arr[], int len) {
//初始化,i从最后一个父节点开始调整
for (int i = len / 2 - 1; i >= 0; i--)
max_heapify(arr, i, len - 1);
//先将第一个元素和已经排好的元素前一位做交换,再从新调整(刚调整的元素之前的元素),直到排序完毕
for (int i = len - 1; i > 0; i--) {
swap(arr[0], arr[i]);
max_heapify(arr, 0, i - 1);
}
}
int main() {
int arr[] = { 3, 5, 3, 0, 8, 6, 1, 5, 8, 6, 2, 4, 9, 4, 7, 0, 1, 8, 9, 7, 3, 1, 2, 5, 9, 7, 4, 0, 2, 6 };
int len = (int) sizeof(arr) / sizeof(*arr);
heap_sort(arr, len);
for (int i = 0; i < len; i++)
cout << arr[i] << ' ';
cout << endl;
return 0;
}
🔥冒泡排序
描述
- 比较相邻的元素。如果第一个比第二个大,就交换他们两个
- 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数
- 针对所有的元素重复以上的步骤,除了最后一个
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较
代码
#include <iostream>
using namespace std;
template<typename T>
void bubbleSort(T array[], int len) {
int i, j;
for (i = 0; i < len; ++i) {
for (j = 0; j < len - 1; ++j) {
if (array[j] > array[j + 1]) {
swap(array[j], array[j + 1]);
}
}
}
}
int main() {
int array_int[] = {11, 24, 8, 32, 5, 65, 27};
int len = (int) sizeof(array_int) / sizeof(array_int[0]);
int i = 0;
bubbleSort(array_int, len);
for (i = 0; i < len; ++i) {
cout << array_int[i] << " ";
}
cout << endl;
return 0;
}
选择排序
#include <iostream>
#include <vector>
using namespace std;
template<typename T>
void selection_sort(vector<T>& arr) {
for (int i = 0; i < arr.size() - 1; i++) {
int min = i;
for (int j = i + 1; j < arr.size(); j++) {
if (arr[j] < arr[min]) {
min = j;
}
}
wap(arr[i], arr[min]);
}
}
int main()
{
vector<int> arr = {12, 5, 9, 41, 25, 3, 22};
selection_sort(arr);
for(int i = 0; i < arr.size(); ++i) {
cout << arr[i] << ' ';
}
cout << endl;
return 0;
}
其他算法
希尔排序
#include <iostream>
template<typename T>
void shell_sort(T array[], int length) {
int h = 1;
while (h < length / 3) {
h = 3 * h + 1;
}
while (h >= 1) {
for (int i = h; i < length; i++) {
for (int j = i; j >= h && array[j] < array[j - h]; j -= h) {
std::swap(array[j], array[j - h]);
}
}
h = h / 3;
}
}
int main()
{
int arr[] = {12, 5, 9, 41, 25, 3, 22};
shell_sort(arr, 7);
for(int i = 0; i < 7; ++i) {
std::cout << arr[i] << ' ';
}
std::cout << std::endl;
return 0;
}
插入排序
计数排序
桶排序
基数排序
参考资料
《算法导论》
《数据结构 C++语言版》