内部排序算法的实现(插入排序、选择排序、交换排序、归并排序、计数排序)
目录
插入排序
直接插入排序
希尔排序
选择排序
直接选择排序
堆排序
交换排序
冒泡排序
快速排序(递归)
三数取中
快速排序(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) |
稳定 |
内部排序算法的实现(插入排序、选择排序、交换排序、归并排序、计数排序)相关推荐
- 十一大排序算法的实现
十一大排序算法的实现 前言 终于写完了,九大排序算法亲自打一遍,给自己加深印象,算是一种模板,留给自己以后用,也分享给大家. U p d a t e : Update: Update: 2020.12 ...
- 排序算法的实现。用C语言编程实现冒泡排序、选择排序、插入排序、shell排序、快速排序、堆排序算法、归并排序。利用随机函数产生N个随机整数(10000以上)。
#include<stdio.h> #include <time.h> #include<stdlib.h> #define N 10000 double T, T ...
- 插入排序和希维尔排序算法的实现
直接插入排序: 当插入第i(i>=1)个元素时,前面的array[0],array[1],-,array[i-1]已经排好序,此时用array[i]的排序码与array[i-1],array[i ...
- Python之十大经典排序算法的实现和原理
一.冒泡排序 冒泡排序(Bubble Sort)是一种比较简单的排序算法,它重复地走访过要排序的元素,依次比较相邻两个元素,如果它们的顺序错误就把它们调换过来,直到没有元素再需要交换,排序完成. 冒泡 ...
- 数组的几种排序算法的实现(1)
数据结构中的排序算法,各有用处,比如: 1,直接插入排序,在序列基本有序的情况下,移动的次数比较少,但是比较次数是一样的 复杂度O(n*n); 2,冒泡排序,这个不用说了吧,刚学C的人都懂了 3,希尔 ...
- java 排序算法面试题_面试题: java中常见的排序算法的实现及比较
1.冒泡排序 1.1 冒泡排序普通版 每次冒泡过程都是从数列的第一个元素开始,然后依次和剩余的元素进行比较,若小于相邻元素,则交换两者位置,同时将较大元素作为下一个比较的基准元素,继续将该元素与其相邻 ...
- 【八大排序详解~C语言版】直接插入排序-希尔排序- 直接选择排序-堆排序-冒泡排序-快速排序-归并排序-计数排序
八大排序 1.直接插入排序 2.希尔排序 3.直接选择排序 直接选择排序改进 4.堆排序 1.建堆 2.利用堆删除思想来进行排序 5.冒泡排序 6.快速排序 递归实现 非递归实现 7.归并排序 递归实 ...
- 数据结构实验四 排序算法的实现
广州大学学生实验报告 开课实验室:计算机科学与工程实验(电子楼416) 2019年6月4日 学院 计算机科学与教育软件学院 年级.专业.班 姓名 学号 实验课程名称 数据结构实验 成绩 实验项 ...
- Java语言基础(常见对象3(数组排序(冒泡排序、选择排序、直接插入排序、快速排序、归并排序)、Arrays、基本数据类型包装类、Integer类、自动拆箱、自动装箱))
Java语言基础 常见对象 数组排序 冒泡排序 相邻元素两两比较,大的往后放,第一次完毕,最大值的元素就会出现在最大索引处:以此循环 //冒泡排序:public static void main(St ...
最新文章
- Keras快速上手:基于Python的深度学习
- 笔记本电脑下载python视频教程-Python的Jupyter Notebook入门教程
- urllib使用cookies(下载,提取)
- sql 精读(六)获取每个类别中最受欢迎的商品
- .Net中DataTable的保存
- 20172326 《程序设计与数据结构》第六周学习总结
- idea 单独引入jar_Intellij IDEA 添加jar包的三种方式
- 图论 —— 网络流 —— 基本概念与建模技巧
- js跟php增加删除信息,浅谈JavaScript数组的添加和删除
- 【codevs1074】食物链
- dubbo 负载均衡中策略决策
- Halcon 4点单标相机外参
- Word排版打印1寸照片
- php 动态生成网站地图,DedeCMS网站地图动态生成方法
- 为磁盘更换好看的ico图标
- 淘宝信用等级|淘宝买家信用等级|淘宝卖家信用等级(图片介绍更清晰)
- android 崩溃原因,Android中导致小米系列手机直接崩溃的主要原因。
- QQ安装包内置UE4是什么意义呢?会不会是奔着元宇宙,搭载了虚幻引擎的QQ在渲染数字孪生上表现更强劲?
- PC制做gif动图超简单教程
- C51简易计算器微机课设