目录

插入排序

直接插入排序

希尔排序

选择排序

直接选择排序

堆排序

交换排序

冒泡排序

快速排序(递归)

三数取中

快速排序(hoera版)

快速排序(挖坑版)

快速排序(前后指针版)

快速排序非递归

归并排序

归并(递归)

归并(非递归)

计数排序

总结

插入排序

直接插入排序

void InsertSort(int* a, int n) {for (int i = 0; i < n - 1; i++) {int end = i;int tmp = a[end + 1];while (end >= 0) {if (a[end] > tmp) {a[end + 1] = a[end];end--;}else {break;}}a[end + 1] = tmp;}
}

希尔排序

void ShellSort(int* a, int n) {int gap = n;while (gap > 1) {gap = gap / 3 + 1;for (int i = 0; i < n - gap; i++) {int end = i;int tmp = a[end + gap];while (end >= 0) {if (a[end] > tmp) {a[end + gap] = a[end];end -= gap;}else {break;}}a[end + gap] = tmp;}}
}

选择排序

直接选择排序

void SelectSort(int* a, int n) {int begin = 0;int end = n - 1;while (begin < end) {int mini = begin;int maxi = begin;for (int i = begin + 1; i <= end; i++) {if (a[i] < a[mini]){mini = i;}if (a[i] > a[maxi]) {maxi = i;}}Swap(&a[begin], & a[mini]);if (begin==maxi) {maxi = mini;}//假如初始数组的最大值在最开始,最小值交换与最开始的值交换位置后,最大的值在原先最小值的位置Swap(&a[end], &a[maxi]);begin++;end--;}
}

堆排序

// 堆排序(升序建大堆)
void AdjustDown(int* a, int n, int root) {int child = root * 2 + 1;while (child < n) {if (child + 1 < n && a[child + 1] > a[child]) {child++;}if (a[child] > a[root]) {Swap(&a[child], &a[root]);root = child;child = root * 2 + 1;}else {break;}}
}
void Swap(int* num1, int* num2) {int tmp = *num1;*num1 = *num2;*num2 = tmp;
}
void HeapSort(int* a, int n) {//升序建大堆for (int i = (n - 1 - 1) / 2; i >= 0; i--) {AdjustDown(a, n, i);}int end = n - 1;while (end > 0) {Swap(&a[0], &a[end]);AdjustDown(a, end, 0);end--;}
}

交换排序

冒泡排序

void BubbleSort(int* a, int n) {for (int i = 0; i < n - 1; i++) {int exchange = 0;for (int j = 0; j < n - i - 1; j++) {if (a[j + 1] < a[j]) {exchange = 1;int tmp = a[j + 1];a[j + 1] = a[j];a[j] = tmp;}}if (exchange == 0) {break;//如果这一轮没有数字交换,说明本次开始数组是有序的,没有交换}}
}

快速排序(递归)

三数取中

假如每次的key都是在数组的最左边,就会出现每次递归为单链的情况,时间复杂度为O(N^2),数据量较大的时候,可能出现栈溢出。所以尽量把key设在偏中间,可以减少地递归深度。

三数取中后,递归深度明显减少。

//为了避免栈溢出,要让a[keyi]的数尽量在中间,选出不是最大,也不是最小的数
//选用三数取中
int GetMidIndex(int* a,int left, int right) {int mid = (left + right) / 2;if (a[left] < a[mid]) {if (a[right] > a[mid]) {return mid;}//走到这一步,a[mid]>a[right],a[mid]最大,中间数在a[left]和a[right]中的一个else if (a[left] > a[right]) {return left;}else {return right;}}//走到这一步,a[left]>a[mid]else {if (a[mid] > a[right]) {return mid;}//走到这一步,a[mid]<a[right], a[mid]最小,中间数在a[left]和a[right]中的一个else if (a[left] > a[right]) {return right;}else {return left;}}
}

快速排序(hoera版)

int PartSort1(int* a, int left, int right) {int mid=GetMidIndex(a, left, right);Swap(&a[mid], &a[left]);int keyi = left;while (left < right) {//当左边的数做key时,要让右边的数先走while (left<right && a[right] >= a[keyi]) {//右边找小,注意当数组所有值相等时,right可能会越界,所以在这层循环要设置left<rightright--;}while (left<right && a[left] <= a[keyi]) {//左边找大left++;}Swap(&a[left], &a[right]);}Swap(&a[left], &a[keyi]);keyi = left;return keyi;
}

快速排序(挖坑版)

int PartSort2(int* a, int left, int right) {if (left >= right) {return -1;}int mid = GetMidIndex(a, left, right);Swap(&a[mid], &a[left]);int key = a[left];int piti = left;while (left < right) {while (left < right && a[right] >= key) {right--;}//找到小的数a[piti] = a[right];piti = right;while (left < right && a[left] <= key) {left++;}//找到大的数a[piti] = a[left];piti = left;}a[left] = key;piti = left;return piti;
}

快速排序(前后指针版)

int PartSort3(int* a, int left, int right) {int prev = left;int cur = left + 1;int keyi = left;/*int mid = GetMidIndex(a, left, right);Swap(&a[mid], &a[keyi]);*/while (cur <= right) {//找小,判断a[cur]是否小于key,若小于,prev后移一位,a[prev]与a[cur]交换位置,cur++if (a[cur] < a[keyi] && ++prev != cur) {Swap(&a[prev], &a[cur]);}cur++;}Swap(&a[keyi], &a[prev]);keyi = prev;return keyi;
}

快速排序适用于处理大量数据,但是越往深处递归,可能会出现栈溢出,后面的区间越分越小,递归次数占比总次数较多,为减少递归次数,可以在数据量较小时使用插入排序。

void QuickSort(int* a, int left, int right) {if (left >= right) {return;}if (right - left+1 > 20) {hoare版本//int keyi = PartSort1(a, left, right);//QuickSort(a, left, keyi - 1);//QuickSort(a, keyi+1, right);挖坑法//int piti = PartSort2(a, left, right);//QuickSort(a, left, piti - 1);//QuickSort(a, piti+1, right);//前后指针法int keyi = PartSort3(a, left, right);QuickSort(a, left, keyi - 1);QuickSort(a, keyi + 1, right);}else {InsertSort(a + left, right - left + 1);}
}

快速排序非递归

用栈模拟快速排序递归过程,类似于二叉树的前序遍历。

void QuickSortNonR(int* a, int left, int right) {Stack st;InitStack(&st);StackPush(&st, right);StackPush(&st, left);while (!StackEmpty(&st)){int begin = StackTop(&st);StackPop(&st);int end = StackTop(&st);StackPop(&st);int keyi=PartSort3(a, begin, end);if (keyi + 1 < end) {StackPush(&st, end);StackPush(&st, keyi + 1);}if (keyi - 1 >begin) {StackPush(&st, keyi-1);StackPush(&st, begin);}}StackDestroy(&st);return;
}

归并排序

归并(递归)

void _MergeSort(int* a, int left, int right,int* tmp) {if (left >= right) {return;}int mid = (left + right)/2;_MergeSort(a, left, mid, tmp);_MergeSort(a, mid+1, right, tmp);int begin1 = left, end1 = mid;int begin2 = mid + 1, end2 = right;int i = begin1;while (begin1 <= end1 && begin2 <= end2) {if (a[begin1] < a[begin2]) {tmp[i++] = a[begin1++];}else {tmp[i++] = a[begin2++];}}while (begin1 <= end1) {tmp[i++] = a[begin1++];}while (begin2 <= end2) {tmp[i++] = a[begin2++];}int m = right - left + 1;memcpy(a + left, tmp + left, m*sizeof(int));}// 归并排序递归实现
void MergeSort(int* a, int n) {int* tmp = (int*)malloc(sizeof(int) * n);assert(tmp);_MergeSort(a, 0, n - 1, tmp);free(tmp);tmp = NULL;
}

归并(非递归)

// 归并排序非递归实现
void MergeSortNonR(int* a, int n) {int* tmp = (int*)malloc(sizeof(int) * n);assert(tmp);int gap =1;//分组while (gap < n) {for (int i = 0; i < n; i += 2 * gap){int begin1 = i, end1 = i + gap - 1;//[i,i+gap-1]  [i+gap,i+2*gap-1]int begin2 = i + gap, end2 = i + 2 * gap - 1;//如果n不是2次方的数,需要修正//如果end1越界,第二区间修正为不存在的范围,就不用归并if (end1 >= n) {end1 = n - 1;begin2 = n;end2 = n - 1;}//begin2开始越界else if (begin2 >= n) {begin2 = n;end2 = n - 1;}//end2开始越界else if (end2 >= n) {end2 = n - 1;}int j = begin1;while (begin1 <= end1 && begin2 <= end2) {if (a[begin1] < a[begin2]) {tmp[j++] = a[begin1++];}else {tmp[j++] = a[begin2++];}}while (begin1 <= end1) {tmp[j++] = a[begin1++];}while (begin2 <= end2) {tmp[j++] = a[begin2++];}}memcpy(a, tmp, sizeof(int) * n);gap *= 2;}free(tmp);tmp = NULL;
}

计数排序

先遍历一边数组,找出最大值和最小值,数组a对应的数据采用相对映射到tmp中,例如

tmp数组对应下标的值,就是待排序数组每个数据出现的次数。

void CountSort(int* a, int n) {int min = a[0], max =a[0];int i = 0;for (int i = 0; i < n; i++) {if (a[i] < min)min = a[i];if (a[i] > max)max = a[i];}int m = max - min + 1;int* tmp = (int*)calloc(m,sizeof(int));assert(tmp);for (i = 0; i < n; i++) {tmp[a[i] - min]++;}int j = 0;for (i = 0; i < m; i++) {while (tmp[i]--) {a[j++] = min+i;}}
}

这种排序方法局限性较大,不能堆浮点数和字符排序,且数据要相对集中,如果数据范围较大,空间开销很大。

总结

排序算法 最好时间复杂度 平均时间复杂度 最坏时间复杂度 空间复杂度 稳定性
直接插入排序 O(N)(有序) O(N^2) O(N^2) O(1) 稳定
希尔排序 O(NlogN)~O(N^2) O(N^1.3) O(N^2) O(1) 不稳定
直接选择排序 O(N^2) O(N^2) O(N^2) O(1) 不稳定
堆排序 O(NlogN) O(NlogN) O(NlogN) O(1) 不稳定
冒泡排序 O(N) O(N^2) O(N^2) O(1) 稳定
快速排序 O(NlogN) O(NlogN) O(N^2)(有序) O(logN)~O(N) 不稳定
归并排序 O(NlogN) O(NlogN) O(NlogN)

O(N+logN)

->O(N)

稳定

内部排序算法的实现(插入排序、选择排序、交换排序、归并排序、计数排序)相关推荐

  1. 十一大排序算法的实现

    十一大排序算法的实现 前言 终于写完了,九大排序算法亲自打一遍,给自己加深印象,算是一种模板,留给自己以后用,也分享给大家. U p d a t e : Update: Update: 2020.12 ...

  2. 排序算法的实现。用C语言编程实现冒泡排序、选择排序、插入排序、shell排序、快速排序、堆排序算法、归并排序。利用随机函数产生N个随机整数(10000以上)。

    #include<stdio.h> #include <time.h> #include<stdlib.h> #define N 10000 double T, T ...

  3. 插入排序和希维尔排序算法的实现

    直接插入排序: 当插入第i(i>=1)个元素时,前面的array[0],array[1],-,array[i-1]已经排好序,此时用array[i]的排序码与array[i-1],array[i ...

  4. Python之十大经典排序算法的实现和原理

    一.冒泡排序 冒泡排序(Bubble Sort)是一种比较简单的排序算法,它重复地走访过要排序的元素,依次比较相邻两个元素,如果它们的顺序错误就把它们调换过来,直到没有元素再需要交换,排序完成. 冒泡 ...

  5. 数组的几种排序算法的实现(1)

    数据结构中的排序算法,各有用处,比如: 1,直接插入排序,在序列基本有序的情况下,移动的次数比较少,但是比较次数是一样的 复杂度O(n*n); 2,冒泡排序,这个不用说了吧,刚学C的人都懂了 3,希尔 ...

  6. java 排序算法面试题_面试题: java中常见的排序算法的实现及比较

    1.冒泡排序 1.1 冒泡排序普通版 每次冒泡过程都是从数列的第一个元素开始,然后依次和剩余的元素进行比较,若小于相邻元素,则交换两者位置,同时将较大元素作为下一个比较的基准元素,继续将该元素与其相邻 ...

  7. 【八大排序详解~C语言版】直接插入排序-希尔排序- 直接选择排序-堆排序-冒泡排序-快速排序-归并排序-计数排序

    八大排序 1.直接插入排序 2.希尔排序 3.直接选择排序 直接选择排序改进 4.堆排序 1.建堆 2.利用堆删除思想来进行排序 5.冒泡排序 6.快速排序 递归实现 非递归实现 7.归并排序 递归实 ...

  8. 数据结构实验四 排序算法的实现

    广州大学学生实验报告 开课实验室:计算机科学与工程实验(电子楼416)     2019年6月4日 学院 计算机科学与教育软件学院 年级.专业.班 姓名 学号 实验课程名称 数据结构实验 成绩 实验项 ...

  9. Java语言基础(常见对象3(数组排序(冒泡排序、选择排序、直接插入排序、快速排序、归并排序)、Arrays、基本数据类型包装类、Integer类、自动拆箱、自动装箱))

    Java语言基础 常见对象 数组排序 冒泡排序 相邻元素两两比较,大的往后放,第一次完毕,最大值的元素就会出现在最大索引处:以此循环 //冒泡排序:public static void main(St ...

最新文章

  1. Keras快速上手:基于Python的深度学习
  2. 笔记本电脑下载python视频教程-Python的Jupyter Notebook入门教程
  3. urllib使用cookies(下载,提取)
  4. sql 精读(六)获取每个类别中最受欢迎的商品
  5. .Net中DataTable的保存
  6. 20172326 《程序设计与数据结构》第六周学习总结
  7. idea 单独引入jar_Intellij IDEA 添加jar包的三种方式
  8. 图论 —— 网络流 —— 基本概念与建模技巧
  9. js跟php增加删除信息,浅谈JavaScript数组的添加和删除
  10. 【codevs1074】食物链
  11. dubbo 负载均衡中策略决策
  12. Halcon 4点单标相机外参
  13. Word排版打印1寸照片
  14. php 动态生成网站地图,DedeCMS网站地图动态生成方法
  15. 为磁盘更换好看的ico图标
  16. 淘宝信用等级|淘宝买家信用等级|淘宝卖家信用等级(图片介绍更清晰)
  17. android 崩溃原因,Android中导致小米系列手机直接崩溃的主要原因。
  18. QQ安装包内置UE4是什么意义呢?会不会是奔着元宇宙,搭载了虚幻引擎的QQ在渲染数字孪生上表现更强劲?
  19. PC制做gif动图超简单教程
  20. C51简易计算器微机课设

热门文章

  1. 如何在 Linux 中安装 Microsoft OneDrive
  2. 计算机网络数据链路层测试
  3. 数控编程的具体步骤与要求
  4. Android-跳转高德地图并导航地址(所有地图均可以)
  5. Win10 C盘突然爆满,怎么清理
  6. Logstash:使用 aggregation filter 把事件流聚合为一个事件
  7. 压缩感知重构算法之迭代硬阈值(IHT)
  8. app检测android模拟器代码
  9. 生产无线充线圈要选好设备
  10. 7200套非标机械设计自动化设备运行工厂工作流水生产线视频实拍