1、冒泡排序
void bubble_sort(int arr[], int len)
{
//没有排序完毕
bool flag = true;
for(int i = 0; i < len && flag; i++)
{
//认为已经有序了
flag = false;
for(int j = len - 1; j > i; j--)
{
if(arr[j] < arr[j-1])
{
flag = true;
int tmp = arr[j];
arr[j] = arr[j-1];
arr[j-1] = tmp;
}
}
}
}
2、选择排序
void select_sort(int arr[], int len)
{
for(int i=0; i<len; i++)
{
int min = i;
for(int j=min+1; j<len; j++)
{
if(arr[j] < arr[min])
{
min = j;
}
}
if(min != i)
{
int tmp = arr[i];
arr[i] = arr[min];
arr[min] = tmp;
}
}
}
3、插入排序
基本思想:将整个数组a分为有序和无序的两个部分。前者在左边,后者在右边。开始有序的部分只有a[0] , 其余都属于无序的部分。每次取出无序部分的第一个(最左边)元素,把它加入有序部分。假设插入合适的位置p,则原p位置及其后面的有序部分元素都向右移动一个位置,有序的部分即增加了一个元素。一直做下去,直到无序的部分没有元素。
void insert_sort(int arr[], int len)
{
for(int i=1; i<len; i++)
{
if(arr[i]<arr[i-1])
{
int tmp = arr[i];
int j = 0;
for(j=i-1; j>=0 && tmp<arr[j]; j--)
{
arr[j+1] = arr[j];
}
arr[j+1] = tmp;
}
}
}
4、希尔排序
void shell_sort(int arr[], int len)
{
int increasement = len;
do{
increasement = increasement/3 + 1;
for(int i=0; i<increasement; i++)
{
for(int j=i+increasement; j<len; j+=increasement)
{
if(arr[j] < arr[j-increasement])
{
int tmp = arr[j];
int k = j - increasement;
for(; k>=i && tmp < arr[k]; k-=increasement)
{
arr[k+increasement] = arr[k];
}
arr[k+increasement] = tmp;
}
}
}
}while(increasement>1);
}
5、快速排序
基本思想:从一个数组中随机选出一个基准数,通过一趟排序后编程基准数左边的数都比它小,基准数右边的数都比它大,然后再分别对左边和右边的数进行一次快排,如此递归下去
void quick_sort(int arr[], int start, int end)
{
int i = start;
int j = end;
int pivot = arr[start];
if(i<j)
{
while(i<j)
{
//从右向左找比基准数小的
while(i<j && arr[j] > pivot)
{
j--;
}
if(i<j)
{
arr[i] = arr[j];
i++;
}
//从左向右找比基准数大的
while(i<j && arr[i] > pivot)
{
i++;
}
if(i<j)
{
arr[j] = arr[i];
i++
}
}
//基数数找到合适的位置
arr[i] = pivot;
//递归左半边快排
quick_sort(arr, start, i-1);
//递归右半边快排
quick_sort(arr, i+1, end);
}
}
6、归并排序
//合并两个有序序列
void merge(int arr[], int start, int end, int mid, int temp_space[])
{
int i_start = start;
int i_end = mid;
int j_start = mid+1;
int j_end = end;
int length = 0;
while(i_start <= i_end && j_start <= j_end)
{
if(arr[i_start] < arr[j_start])
{
temp_space[length] = arr[i_start];
i_start++;
}
else
{
temp_space[length] = arr[j_start];
j_start++;
}
length++;
}
while(i_start<=i_end)
{
temp_space[length] = arr[i_start];
i_start++;
length++;
}
while(j_start<=j_end)
{
temp_space[length] = arr[j_start];
j_star++;
length++;
}
for(int i=0; i<length; i++)
{
arr[start+i] = temp_space[i];
}
}
//归并排序
void merge_sort(int arr[], int start, int end, int temp_space[])
{
if(start == end)
{
return ;
}
//拆分左边进行归并排序
merge_sort(arr, start, mid, temp_space);
//拆分右边进行归并排序
merge_sort(arr, mid+1, end, temp_space);
//合并两个有序序列
merge(arr, start, end, mid, temp_space);
}
7、堆排序
void swap(int arr[], int pos1, int pos2)
{
int temp = arr[pos1];
arr[pos1] = arr[pos2];
arr[pos2] = temp;
}
//调整堆
void heap_adjust(int arr[], int len, int index)
{
int leftChild = 2*index + 1;
int rightChild = 2*index + 2;
int max = index;
if(index < len)
{
if(leftChild < len && arr[leftChild] > arr[max])
{
max = leftChild;
}
if(rightChild < len && arr[rightChild] > arr[max])
{
max = rightChild;
}
if(max != index)
{
//交换元素
swap(arr, index, max);
//递归调整堆
heap_adjust(arr, len, max);
}
}
}
//堆排序
//基本思想:
//1、大头堆:所有叶子节点大于左右子节点,那么就使得根节点元素为成为最大
//2、将要排序的数组调整成大头堆,交换数组头尾两个元素
//3、排除数组最后一个元素组成新的数组,然后再对新的数组进行调整使其满足大头堆的条件,交换数组头尾两个元素
//4、重复上面操作,直到新的数组只有一个元素为止,即完成了整个数组排序
//5、这里需要理解的是数组的头和尾对应是大头堆的根节点和最后一个节点,数组与堆的节点对应关系是: left_child_index = 2*parent_index+1; right_child_index=2*parent+2
void heap_sort(int arr[], int len)
{
//初始化堆
for(int i=len/2-1; i>=0; i--)
{
heap_adjust(arr, len, i);
}
for(int i=len-1; i>0; i--)
{
//交换头尾两个元素
swap(arr, 0, i);
//从头部开始调整调整堆
heap_adjust(arr, i, 0);
}
}
排序算法 | 平均时间复杂度 | 最坏时间复杂度 | 平均空间复杂度 | 稳定性 |
---|---|---|---|---|
冒泡排序 | O(n^2) | O(n^2) | O(1) | 稳定 |
选择排序 | O(n^2) | O(n^2) | O(1) | 不稳定 |
插入排序 | O(n^2) | O(n^2) | O(1) | 稳定 |
希尔排序 | O(nlog^n) | O(n^2) | O(1) | 不稳定 |
快速排序 | O(nlog^n) | O(n^2) | O(log^n) | 不稳定 |
归并排序 | O(log^n) | O(log^n) | O(n) | 稳定 |
堆排序 | O(log^n) | O(log^n) | O(1) | 不稳定 |