前言
列举了常用排序算法,并给出代码
对算法的核心思想进行了简明扼要地说明
选择排序
从数组中选出最小的元素,将其与前面的元素互换
#include <cstdio>
void select_sort(int *arr, size_t arr_size)
{
for (int i=0; i<arr_size; ++i){
for (int j=i+1; j<arr_size; ++j){
if (arr[j] < arr[i]){
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
}
}
int main()
{
int arr[]= {56,7,8,8,0,1};
select_sort(arr, sizeof(arr)/sizeof(arr[0]));
for (auto c: arr) std::printf("%d ", c);
}
时间复杂度:O(n^2)
n-1+n-2+······+1+0 ~ n^2
空间复杂度:O(1)
占用常量空间
冒泡排序
比较相邻的两元素,确定是否互换,经过一边遍历后最大/小的元素像泡泡一样冒出来,经过多次遍历后完成排序
void bubble_sort(int *arr, size_t arr_size)
{
for (int i=0; i<arr_size; ++i){
for (int j=1; j<arr_size-i; ++j){
if (arr[j-1] > arr[j]){
int tmp = arr[j-1];
arr[j-1] = arr[j];
arr[j] = tmp;
}
}
}
}
int main()
{
int arr[]= {56,7,8,8,0,1};
bubble_sort(arr, sizeof(arr)/sizeof(arr[0]));
for (auto c: arr) std::printf("%d ", c);
}
- 时间复杂度:O(n^2)
n-1+n-2+······+1+0 ~ n^2
- 空间复杂度:O(1)
占用常量空间
优化版
void bubble_sort(int *arr, size_t arr_size)
{
for (int i=0; i<arr_size; ++i){
bool flag = true;
for (int j=1; j<arr_size-i; ++j){
if (arr[j-1] > arr[j]){
int tmp = arr[j-1];
arr[j-1] = arr[j];
arr[j] = tmp;
flag = false;
}
}
if ( flag) break;
}
}
堆排序
堆是用数组存储的完全二叉树,并且父节点比孩子节点小(小顶堆)/大(大顶堆)
可用于解决topK问题
leftchild = 2\*parent + 1
rightchild = 2\*parent +2
parent = [ (leftchld - 1) / 2]
parent = [ (rightchild- 1) / 2]
#include <cstdio>
void shift_below(int *arr, int parent, int end )
{
int child = 2*parent + 1;
while (child < end){
if ( child+1 < end && arr[child] < arr[child+1]){
++child;
}
if (arr[parent] < arr[child]){
int tmp = arr[parent];
arr[parent] = arr[child];
arr[child] = tmp;
parent = child;
child = 2*parent + 1;
} else {
break;
}
}
}
void create_heap(int *arr, int arr_size)
{
int parent = (arr_size - 1 - 1) / 2;
for (int i=parent; i>=0; --i){
shift_below(arr, i, arr_size);
}
}
void heap_sort(int *arr, int arr_size)
{
create_heap(arr, arr_size);
for (int i=arr_size-1; i>0; --i){
int tmp = arr[0];
arr[0] = arr[i];
arr[i] = tmp;
shift_below(arr, 0, i);
}
}
int main()
{
int arr[]= {56,7,8,8,0,1};
heap_sort(arr, sizeof(arr)/sizeof(arr[0]));
for (auto c: arr) std::printf("%d ", c);
}
- 时间复杂度: O(n * logN)
2*(logn + logn-1 + logn-2 ······ log 1) - 空间复杂度: O(1)
快速排序
分治思想:将大问题简化为小问题,解决每个小问题,从而大问题得到解决
减治思想:将大问题简化为小问题,解决一个小问题,从而大问题得到解决
// 选择第一个作为基准,它左边的都比他小(<=),右边的都比他大(>=)
// 返回这个基准的索引
// 左右两边都能取到
int partition(int *arr, int start, int last)
{
int base = arr[start];
while (start < last)
{
while (start < last && arr[elastnd] >= base){
--last;
}
arr[start] = arr[last];
while (start < last && arr[start] <= base){
++start;
}
arr[last] = arr[start];
}
arr[start] = base;
return start;
}
void quick_sort(int *arr, int start, int last)
{
if (start >= last) return ;
int i = partition(arr, start, last);
quick_sort(arr, start, i-1);
quick_sort(arr, i+1, last);
}
int main()
{
int arr[]= {7,2,6,4,5,1,7,8,9};
// 左右两边都能取到
quick_sort(arr, 0, sizeof(arr)/sizeof(arr[0])-1 );
for (auto c : arr)
std::printf("%d ", c);
}
归并排序
将一个无序数组递归的的分成两个数组,将仅有两个元素的数组排序。将两个有序的数组合并成一个。
核心代码是将两个有序的数组合并成一个有序的数组
#include <cstdio>
// 左边取得到,右边取不到
void merge_sort(int *arr, int start, int mid, int end)
{
int p1 = start;
int p2 = mid;
int tmp[end-start] = {0};
int point = 0;
while (1){
if ( p1 >= mid){
while (point < end-start && p2<end){
tmp[point++] = arr[p2++];
}
break;
}
if ( p2 >= end){
while (point < end-start && p1<mid){
tmp[point++] = arr[p1++];
}
break;
}
if (arr[p1] < arr[p2]){
tmp[point++] = arr[p1++];
} else {
tmp[point++] = arr[p2++];
}
}
for (int c:tmp){
arr[start++] = c;
}
}
void m_sort(int *arr, int start, int end)
{
if (start >= end) return ;
if (end - start == 1){
if (arr[start] > arr[end]){
int tmp = arr[start];
arr[start] = arr[end];
arr[end] = tmp;
}
return ;
}
int mid = (start+end) / 2;
m_sort(arr, start, mid);
m_sort(arr, mid, end);
merge_sort(arr, start, mid, end);
}
int main()
{
int arr[] = {5,7,6,9,1,5,0,9,8,7,3,7};
m_sort(arr, 0, sizeof(arr)/sizeof(arr[0]) );
for (int c: arr){
std::printf("%d ", c);
}
}
- 时间复杂度: O(N * logN)
- 空间复杂度:O(N)
- 稳定性: 稳定