九大排序,Java实现
九大排序,Java实现(附代码)
今天整理了一下九大排序,分享一波,以下例子都测试过,都进行升序排序
先从简单选择排序讲起:
简单选择排序,不稳定
从待排序序列中选取一个最小的数,与当前序列最左边的数交换
如:
第一趟:在n个元素中选出最小的一个元素与数组0号索引上的元素交换,
第二趟:在剩下的 n - 1 个数中找到最小的数, 与第数组1号索引上的元素交换,
以此类推,n个元素需要选择 n - 1趟,序列全部有序
代码实现:
public static void selectSort(int[] data){int i = 0, j = 0;int index = 0;//第i小元素存放的位置, 从0开始计数for(i = 0; i < data.length - 1; i++){int min = Integer.MAX_VALUE;//找到剩余数的最小值,最小值的索引for(j = i; j < data.length; j++){if(data[j] < min){min = data[j];index = j;}}//交换data[index] =data[i];data[i] = min;}}
上述简单选择排序,每次遍历只维护一个最小值,与待排序序列的第一个位置交换,
优化:
2元选择排序, 每次遍历保存待排序数的最大值,和最小值
最小值与待排序序列最左边的元素交换, 最大值与最右边的元素交换
public static void selectSort2(int[] data){int i = 0, j = 0, min = Integer.MAX_VALUE, max = Integer.MIN_VALUE;int indexMax = 0, indexMin = 0, len = data.length - 1;//len为数组中待排序数的最后一位,即当前最大值的存放位置//i为最小值存放位置for(i = 0; i < len; i++, len--){min = Integer.MAX_VALUE;max = Integer.MIN_VALUE;for(j = i; j <= len; j++){//维护最小值if(data[j] < min){min = data[j];indexMin = j;}//维护最大值, 保证稳定性,必须 >= ,即相等的元素,靠后的元素先往后排if(data[j] >= max){max = data[j];indexMax = j;}}//交换data[indexMin] = data[i];data[i] = min;data[indexMax] = data[len];data[len] = max;}}
堆排序
堆排序,不稳定
选择排序的一种,就是每次选择一个最大(或最小)的值,
存放到正确的位置。
那么该如和选择呢:
堆排序核心思想:将待排序序列建成堆,得到最大(最小)值,存放到正确位置
首先知道使用数组存储一颗完全2叉树, 从0开始计数,
大顶堆:所有父节点元素的值 >= 两个子节点的值
那么 i 节点的左子节点为 2 * i + 1, 右子节点为 2 * i + 2;
我们把待排序序列建成一个大顶堆
从最后一个叶子节点的父节点((size - 1)/ 2)开始往前遍历,建立大顶堆,即,比较两个子节点的值,与父亲节点的值,如果子节点值大于父节点,则交换
第一趟找到 [0, data.length - 1]序列中最大的数存放到 data.length - 1
第一趟找到 [0, data.length - 2]序列中最大的数存放到 data.length - 2,
每次取得最大值,都需要从下往上交换 , 以此类推得到有序序列
代码
public static void headSort(int[] data){int i = 0, temp = 0;//每次循环找到一个第 data.length - i大的元素,存放到 i 位置上for(i = data.length - 1; i > 0; i--){createHeap(data, i);//初始化大顶堆后第一个元素必定是最大的元素, i位置就是该元素的正确位置temp = data[0];data[0] = data[i];data[i] = temp;}}//将从 0 到 size的待排序序列建立大顶堆, 待排序序列中的最大值存放在第0号元素上public static void createHeap(int[] data, int size){int i = 0, temp = 0, index = 0;//最后一个节点的父亲节点int backRoot = (size - 1) / 2;//初始化大顶堆for(i = backRoot; i >= 0; i--){int left = 2 * i +1; //左子节点int right = 2 * i + 2; //右子节点// 得到子节点更大元素的下标,注意越界,已经排好序的元素不能再访问index = right > size || data[left] > data[right] ? left : right;//如果子节点更大,则交换if(data[i] < data[index]){temp = data[i];data[i] = data[index];data[index] = temp;}}}
冒泡排序, 稳定:
交换排序的一种,比较相邻的元素,如果左边的元素大于右边的元素,就交换他们两个。
每一趟交换,都在待排序数中找到最大的元素,
存放在最待排序数中的最右边
10个元素第一趟时需比较9次,将最大的元素移动到最后一位
第2趟时,待排序数变为9个,需比较8次, 找到第2大的数,存放在倒数第2为,以此类推
代码
public static void bubbleSort(int[] data){boolean flag = true;//趟数for(int i = 1; i < data.length; i++){flag = true;//每趟需要比较的次数, 如第一趟需要比较9次// 每趟选出 [0, data.length - i)中最大的一位放在最后的位置for(int j = 0; j < data.length - i; j++){//升序排序,比较相邻的元素。如果左边的元素大于右边的元素,就交换他们两个。if(data[j] > data[j + 1]){int temp = data[j];data[j] = data[j + 1];data[j + 1] = temp;flag = false;}}//全程无交换,说明已经有序了if(flag) break;}}
快速排序, 不稳定:
使用递归分治思想, 交换排序的一种
选择一个基准数,通常选择第一个元素或者最后一个元素
经过一趟排序后,左边一部分比基准数小,右边一部分比基准数大
将基准数存放至交界位置
然后分别对这两部分进行同样的排序,直到每部分元素个数为1,则此时整个序列有序
public static void quickSort(int[] data, int start, int end){int left = start, right = end, temp = 0, index = 0;if(start >= end) return;//基准数int begin = left;left++;while(left < right){//如果该元素大于基准数将它与右边的元素交换if(data[left] > data[begin]){temp = data[left];data[left] = data[right];data[right] = temp;right--;continue;}left++;}//此时left == right, 得到data[begin]存放的位置,index = data[left] < data[begin] ? left : left - 1;//交换后在 data[begin]左边的元素都比它小,右边的都比它大temp = data[begin];data[begin] = data[index];data[index] = temp;//递归,分治quickSort(data, start, index - 1);quickSort(data, index + 1, end);}
简单插入排序,稳定
初始时,第0号元素默认有序, 从第1号元素开始,往前搜索,找到正确的位置
public static void insertSort(int[] data){int i = 0, j = 0;int temp = 0;for(i = 1; i < data.length; i++){//待排序数temp = data[i];//从后往前遍历,当前一个数小于等于待排序数时,该位置就为正确的位置,插入//保证稳定性for(j = i; j > 0; j--){//如果前一个数比当前数更大,往后移一位if(data[j - 1] > temp){data[j] = data[j - 1];}else{break;}}//插入data[j] = temp;}}
希尔排序,缩小增量排序, 不稳定
每趟排序根据增量scan, 将待排序序列分为scan组,在组内进行直接插入排序。一趟后,每个组内有序,再缩小增量继续分组排序,直至增量为1,整个序列有序
代码:
public static void shellSort(int[] data){//增量, 增量是多少,就会分成多少组int scan = data.length / 2;//增量每次缩小为一半while(scan > 0){shellInsertSort(data, scan);scan = scan / 2;}}public static void shellInsertSort(int[] data, int scan){int m = 0;//组数 == 增量for(int i = 0; i < scan; i++){//组内直接插入排序, 以每组第0号元素为基准for(int j = i + scan; j < data.length; j = j + scan){int temp = data[j];//从右往左遍历, 注意越界for(m = j; m > i; m = m - scan){//如果左边的元素大于右边的元素, 左边的元素往右移scan位if(data[m - scan] > temp) {data[m] = data[m - scan];}else{break;}}data[m] = temp;}}}
归并排序,稳定
过程分为:先拆分,再归并
拆分:即每次将待排序序列分为两部分
归并: 当每部分拆分至只有一个元素时,此时每部分都有序,两两开始归并,
归并两个有序序列的时间复杂度为 O(n)
代码:
public static void mergeSort(int[] data, int left, int right){//拆分至每个序列只有一个元素时if(left >= right){return;}int middle = (left + right) / 2;//拆分为两部分mergeSort(data, left, middle);mergeSort(data, middle + 1, right);//两两归并,归并后,得到的序列有序merge(data, left, middle, right);}//归并两个有序序列public static void merge(int[] data, int left, int middle, int right){int i = left, j = middle + 1, size = 0;//辅助空间int[] temp = new int[right - left + 1];//归并两个有序序列while(i <= middle && j <= right){temp[size++] = data[i] <= data[j] ? data[i++] : data[j++];}//说明左边的元素都加进辅助数组中了if(i > middle){while(j <= right) temp[size++] = data[j++];}else{while(i <= middle) temp[size++] = data[i++];}size = 0;//将有序的序列更新回data数组for(i = left; i <= right; i++){data[i] = temp[size++];}}
那么最后还有两个接近线性的排序算法,虽然并不是,hhhh
桶排序, 稳定
桶排序, 稳定
需要k(当前数组的最大值)个辅助空间, 将当前数组中的元素与计数数组的下标对应
即将对应下标的值加一, count[data[i]]++;
若要得到得到升序序列,从左向右遍历, 若要得到降序序列从右往左遍历即可优化:可将计数数组的长度设为 max - min + 1, 那么需要多维护一个原数组的最小值
要保证稳定性,需对计数数组,从后往前遍历
若需要降低空间复杂度可以将一组数,放入一个桶中,
再对桶中的元素(桶中可使用其他排序方法)
在当待排序数组内有大量重复的数值并且这些数值较为集中时,使用桶排序效率较好,基本达到O(n)
代码:
public static void barrelSort(int[] data){int max = Integer.MIN_VALUE, i = 0;//得到当前数组的最大值for(i = 0; i < data.length; i++){if(data[i] > max) max = data[i];}//辅助空间int[] count = new int[max + 1];//计数for(i = 0; i < data.length; i++){count[data[i]]++;}int size = 0;//从左往右遍历,for(i = 0; i < count.length; i++){while(count[i] > 0){data[size++] = i;count[i]--;}}}
基数排序:
基数排序, 桶排序的延伸
对数字的每位进行桶排序
代码:
public static void radixSort(int[] data){int exp = 1, i = 0, max = Integer.MIN_VALUE;//得到最大的数for(i = 0; i < data.length; i++){if(max < data[i]) max = data[i];}//分别对每一位(个位,十位,百位。。。)进行排序for(exp = 1; max / exp > 0; exp = exp * 10){countSort(data, exp);}}
对exp位进行桶排序(1代表个位, 10代表十位,以此类推)
public static void countSort(int[] data, int exp){int[] count = new int[10];int[] out = new int[data.length];int i = 0;//根据exp位数,将数据位数出现的次数存放在桶中for(i = 0; i < data.length; i++){count[(data[i] / exp) % 10]++;}//累加count, 使更改后的count[i]的值,是该数据在out[]中的下标 + 1for(i = 1; i < count.length; i++){count[i] += count[i - 1];}//对原数据根据exp位进行排序,存储在out中,out中存放的是原数组的整体数据//从后往前遍历for(i = data.length - 1; i >= 0; i--){out[count[(data[i] / exp) % 10] - 1] = data[i];//已经找到一个正确位置count[(data[i] / exp) % 10]--;}//将数据重新存入datafor(i = 0; i < out.length; i++){data[i] = out[i];}}
九大排序,Java实现相关推荐
- 九大排序算法Java实现
之前学习数据结构与算法时花了三天时间整理九大排序算法,并采用Java语言来实现,今天第一次写博客,刚好可以把这些东西从总结的文档中拿出来与大家分享一下,同时作为自己以后的备忘录. 1.排序算法时间复杂 ...
- python快速排序算法没看懂_你需要知道的九大排序算法【Python实现】之快速排序...
五.快速排序 基本思想: 通过一趟排序将待排序记录分割成独立的两部分,其中一部分记录的关键字均比另一部分关键字小,则分别对这两部分继续进行排序,直到整个序列有序. 算法实现: #coding: ...
- c语言折半排序的程序,C语言实现九大排序算法的实例代码
直接插入排序 将数组分为两个部分,一个是有序部分,一个是无序部分.从无序部分中依次取出元素插入到有序部分中.过程就是遍历有序部分,实现起来比较简单. #include void insertion_s ...
- 经典九大排序(1)——简单排序
本博客已弃用,当时存在一些小细节错误后期也不再修改了 欢迎来我的新博客 九大排序排序是数据结构体系中最重要的内容之一,这一块必须要非常熟练的掌握,应该做到可以立马写出每个排序的代码,有多种实现方法的必 ...
- 2021 最受欢迎的九大顶级 Java 框架
点击"开发者技术前线",选择"星标????" 让一部分开发者看到未来 作者丨Patricia Ne il 由"京东云开发者社区"公众号编辑整 ...
- JAVA 九大排序算法
1.冒泡排序 public class Bobble {private static void sort(int[] arrays) {//一次性读取到高速缓存中,避免cache missint le ...
- 九大排序算法,你会几个?
概述排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存. 我们这里说说八大排序就是内部排序. 当n较大,则 ...
- 九大排序算法-C语言实现及详解
概述 排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存. 我们这里说说八大排序就是内部排序. 当n较大, ...
- (面经总结)一篇文章带你整理面试过程中常考的九大排序算法
文章目录 一.二分插入排序 1. 原理 2. 代码 二.冒泡排序 1. 原理 2. 代码 三.插入排序算法 1. 原理 2. 代码 四.快速排序算法 1. 原理 2. 代码 五.希尔排序 1. 原理 ...
最新文章
- nyoj7——街区最短问题
- Android 音视频深入 十一 FFmpeg和AudioTrack播放声音(附源码下载)
- jar包让别人看不到代码_【求助】反编译查看jar包的源代码,出现如下问题,求解单...
- oracle的sga
- python双划线_Python中单下划线(_)和双下划线(__)的特殊用法
- HTTP 协议深入理解(一)
- sqlite的编译、练习
- 一张图看懂VnTrader的数据流
- 问题七十一:环境光遮蔽(Ambient Occlusion)
- python numpy数据类型_Python中numpy的数据类型,python,dtype
- windows32位安装MongoDB
- Thinkpad E40黑苹果驱动
- linux识别硬盘时显示gpt,Ubuntu不识别GPT硬盘已有系统的解决方案
- 4、windows与jetson tx2文件互传工具
- 无聊写着玩:解二阶线性微分方程
- 可编程中控 c 语言,可编程中控是什么?如何应用?
- python计算点到面的距离
- Emgucv类型转换
- 计算机组装兴趣小组考核,中职计算机专业课程学生成绩考核之我见
- 2020年7月1日打卡