参考:https://blog.csdn.net/qq_41998576/article/details/81635566
堆排序:https://blog.csdn.net/daiyudong2020/article/details/52529791
归并排序:https://www.cnblogs.com/agui521/p/6918229.html
一、 排序的分类
►插入排序:直接插入排序 希尔排序
►交换排序:冒泡排序 快速排序
►选择排序:简单选择排序 堆排序
二、排序算法比较
排序方法 | 最好时间 | 平均时间 | 最坏时间 | 辅助存储 | 稳定性 |
---|---|---|---|---|---|
插入排序 | O(n) | O(n^2) | O(n^2) | O(1) | 稳定 |
希尔排序 | O(n^1.3) | O(nlogn) | O(n^2) | O(1) | 不稳定 |
冒泡排序 | O(n) | O(n^2) | O(n^2) | O(1) | 稳定 |
快速排序 | O(nlogn) | O(nlogn) | O(n^2) | O(nlogn) | 不稳定 |
选择排序 | O(n^2) | O(n^2) | O(n^2) | O(1) | 不稳定 |
选择排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(1) | 不稳定 |
从平均情况看:堆排序、归并排序、快速排序胜过希尔排序。
从最好情况看:冒泡排序和直接插入排序更胜一筹。
从最差情况看:堆排序和归并排序强过快速排序。
虽然直接插入排序和冒泡排序速度比较慢,但是当初始序列整体或局部有序是,这两种算法的效率比较高。当初始序列整体或局部有序时,快速排序算法效率会下降。当排序序列较小且不要求稳定性是,直接排序效率较好;要求稳定性时,冒泡排序法效率较好。
三、排序代码
// 直接插入排序 – 插入排序
/方法:对于给定的一组记录,初始时假定第一个记录自成一个有序的序列,
其余的记录为无序序列;接着从第二个记录开始,
按照记录的大小依次将当前处理的记录插入到其之前的有序序列中,
直至最后一个记录插入到有序序列为止。/
void sort_insert(int *nums, int nums_length) {
int i = 0;
int j = 0;
// 小 到 大
for (i = 1; i < nums_length; i++) {
int tmp = nums[i];
for (j = i - 1; j >= 0 ; j--) {
if (tmp < nums[j]) {
nums[j + 1] = nums[j];
}
else {
break;
}
}
nums[j + 1] = tmp;
}
}
// 希尔排序 – 插入排序
/*希尔排序也称为“缩小增量排序”,基本原理是:首先将待排序的元素分为多个子序列,
使得每个子序的元素个数相对较少,对各个子序分别进行直接插入排序,
待整个待排序序列“基本有序后”,再对所有元素进行一次直接插入排序。
具体步骤如下:
(1)选择一个步长序列t1, t2, ..., tk,满足ti > tj(i <j),tk = 1。
(2)按步长序列个数k,对待排序序列进行k趟排序。
(3)每趟排序,根据对应的步长ti,将待排序的序列分割成ti个子序列,
分别对各个子序列进行直接插入排序。
void shellsort(int *arr, int arr_len)
{
int i = 0;
int j = 0;
int step = 0;
for (step = arr_len / 2; step > 0; step = step / 2)
{
for (i = step; i <= arr_len - 1; i++)
{
int tmp = arr[i];
for (j = i - step; j >= 0; j -= step)
{
if (arr[j] > tmp) // 小到大(>) 大到小(<)
{
arr[j + step] = arr[j];
}
else{
break;
}
}
arr[j + step] = tmp;
}
}
}
// 冒泡排序
void maopaosort(int *arr, int arr_len)
{
int i = 0;
int j = 0;
for (i = 1; i <= arr_len - 1; i++)
{
for (j = 0; j < arr_len - 1; j++)
{
if (arr[j + 1] < arr[j])
{
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
}
// 快速排序
/采用“分而治之”的思想,把大的拆分为小的,小的在拆分为更小的。
原理:对于一组给定的记录,通过一趟排序后,将原序列分为两部分,
其中前部分的所有记录均比后部分的所有记录小,然后再依次对前后两部分的记录进行快速排序,
递归该过程,直到序列中的所有记录均为有序为止。/
void quick_sort(int *arr, int start, int end){
if (start >= end) return;
int i = start;
int j = end;
while (i < j)
{
while (arr[j] >= arr[start] && i < j) // 从基准数的对面开始走
j--;
while (arr[i] <= arr[start] && i < j)
i++;
if (i < j){
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
int tmp = arr[start];
arr[start] = arr[i];
arr[i] = tmp;
quick_sort(arr, start, i -1);
quick_sort(arr, i + 1, end);
}
// 选择排序
/对于给定的一组记录,经过第一轮比较后得到最小的记录,然后将记录与第一个记录的位置进行交换;
接着对不包括第一个记录以外的其他记录进行第二轮排序,得到最小的记录并与第二个记录进行位置交换;
重复该过程,直到进行比较的记录只有一个为止。/
void select_sort(int *arr, int arr_len)
{
int i = 0;
int j = 0;
int min = 0;
for (i = 0; i < arr_len - 1; i++) // time
{
int min = i;
for (j = i + 1; j <= arr_len - 1; j++)
{
if (arr[j] < arr[min])
{
min = j;
}
}
if (min != i) {
int tmp = arr[i];
arr[i] = arr[min];
arr[min] = tmp;
}
}
}
// 堆排序
/*
将序列构造成一棵完全二叉树 ;
把这棵普通的完全二叉树改造成堆,便可获取最小值 ;
输出最小值 ;
删除根结点,继续改造剩余树成堆,便可获取次小值 ;
输出次小值 ;
重复改造,输出次次小值、次次次小值,直至所有结点均输出,便得到一个排序 。
*/
void swap_heap(int *a, int *b) {
int tmp = *a;
*a = *b;
*b = tmp;
}
void adjust_min_heap(int *arr, int pos, int len) {
int tmp = arr[pos];
int child = pos;
for (tmp = arr[pos]; 2 * pos + 1 < len; pos = child) {
child = 2 * pos + 1;
if (child + 1 < len && arr[child] < arr[child + 1]) {
child++;
}
if (tmp < arr[child]) {
arr[pos] = arr[child];
}
else {
break;
}
}
arr[pos] = tmp;
}
void heap_sort(int *arr, int arr_len) {
// step 1
int i = 0;
for (i = arr_len / 2 - 1; i >= 0; i--) {
adjust_min_heap(arr, i, arr_len - 1);
}
// step 2 - 3
for (i = arr_len - 1; i >= 0; i--) {
swap_heap(&arr[0], &arr[i]);
adjust_min_heap(arr, 0, i - 1);
}
}
测试main函数
int main() {
int nums[] = { 8, 2, 2, 2, 5, 3, 6, 7, 1, 9,0, 0, 0 };
int nums_length = 13;
int i = 0;
printf("before sort_insert : ");
for (i = 0; i < nums_length; i++) {
printf(" %d ", nums[i]);
}
printf("\n");
// sort_insert
heap_sort(nums, nums_length);
printf("after sort_insert : ");
for (i = 0; i < nums_length; i++) {
printf(" %d ", nums[i]);
}
printf("\n");
stop;
return 0;
}