九大排序,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实现相关推荐

  1. 九大排序算法Java实现

    之前学习数据结构与算法时花了三天时间整理九大排序算法,并采用Java语言来实现,今天第一次写博客,刚好可以把这些东西从总结的文档中拿出来与大家分享一下,同时作为自己以后的备忘录. 1.排序算法时间复杂 ...

  2. python快速排序算法没看懂_你需要知道的九大排序算法【Python实现】之快速排序...

    五.快速排序 基本思想:  通过一趟排序将待排序记录分割成独立的两部分,其中一部分记录的关键字均比另一部分关键字小,则分别对这两部分继续进行排序,直到整个序列有序. 算法实现: ​ #coding: ...

  3. c语言折半排序的程序,C语言实现九大排序算法的实例代码

    直接插入排序 将数组分为两个部分,一个是有序部分,一个是无序部分.从无序部分中依次取出元素插入到有序部分中.过程就是遍历有序部分,实现起来比较简单. #include void insertion_s ...

  4. 经典九大排序(1)——简单排序

    本博客已弃用,当时存在一些小细节错误后期也不再修改了 欢迎来我的新博客 九大排序排序是数据结构体系中最重要的内容之一,这一块必须要非常熟练的掌握,应该做到可以立马写出每个排序的代码,有多种实现方法的必 ...

  5. 2021 最受欢迎的九大顶级 Java 框架

    点击"开发者技术前线",选择"星标????" 让一部分开发者看到未来 作者丨Patricia Ne il 由"京东云开发者社区"公众号编辑整 ...

  6. JAVA 九大排序算法

    1.冒泡排序 public class Bobble {private static void sort(int[] arrays) {//一次性读取到高速缓存中,避免cache missint le ...

  7. 九大排序算法,你会几个?

    概述排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存. 我们这里说说八大排序就是内部排序. 当n较大,则 ...

  8. 九大排序算法-C语言实现及详解

    概述 排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存. 我们这里说说八大排序就是内部排序. 当n较大, ...

  9. (面经总结)一篇文章带你整理面试过程中常考的九大排序算法

    文章目录 一.二分插入排序 1. 原理 2. 代码 二.冒泡排序 1. 原理 2. 代码 三.插入排序算法 1. 原理 2. 代码 四.快速排序算法 1. 原理 2. 代码 五.希尔排序 1. 原理 ...

最新文章

  1. nyoj7——街区最短问题
  2. Android 音视频深入 十一 FFmpeg和AudioTrack播放声音(附源码下载)
  3. jar包让别人看不到代码_【求助】反编译查看jar包的源代码,出现如下问题,求解单...
  4. oracle的sga
  5. python双划线_Python中单下划线(_)和双下划线(__)的特殊用法
  6. HTTP 协议深入理解(一)
  7. sqlite的编译、练习
  8. 一张图看懂VnTrader的数据流
  9. 问题七十一:环境光遮蔽(Ambient Occlusion)
  10. python numpy数据类型_Python中numpy的数据类型,python,dtype
  11. windows32位安装MongoDB
  12. Thinkpad E40黑苹果驱动
  13. linux识别硬盘时显示gpt,Ubuntu不识别GPT硬盘已有系统的解决方案
  14. 4、windows与jetson tx2文件互传工具
  15. 无聊写着玩:解二阶线性微分方程
  16. 可编程中控 c 语言,可编程中控是什么?如何应用?
  17. python计算点到面的距离
  18. Emgucv类型转换
  19. 计算机组装兴趣小组考核,中职计算机专业课程学生成绩考核之我见
  20. 2020年7月1日打卡

热门文章

  1. 我用DW也有几年了,真不知道你说的这些代码是什么?不是快捷键吧?
  2. 使用MHDD修护硬盘坏道教程(3)
  3. 区块链 | “抢人”大战,外部高薪挖人,员工“坐地起价”
  4. 不用相机也能随手拍大片:三款旗舰手机拍照横评
  5. 敏捷管理(3)- 建立敏捷团队、常见的敏捷问题
  6. Ubuntu解决华硕x550C的WiFi问题
  7. 小牛客户管理软件 下载
  8. smack 多人聊天获取聊天室列表
  9. Go语言初级使用学习笔记1
  10. 应该知道的速卖通站内引流方法