文章目录

  • 十大排序算法(Java)
    • 一、冒泡排序(Bubble Sort)
    • 二、选择排序(Selection Sort)
    • 三、堆排序(Heap Sort)
    • 四、插入排序(Insertion Sort)
    • 五、归并排序(Merge Sort)
    • 六、快速排序(Quick Sort)
    • 七、希尔排序(Shell Sort)
    • 八、计数排序(Counting Sort)
    • 九、基数排序(Radix Sort)
    • 十、桶排序(Bucket Sort)
    • 扩展:十一、史上“最强”排序-休眠排序666(仅供参考,不要用!!)

十大排序算法(Java)

小猴子自定义口诀(瞎编的,哈哈):冒泡两个两个对比,选择最大的排在最后,插入前面有序列表,归并先分区后合并,快速将一列数划分小于pivot在左边大于pivot在右边再依次递归左右子列,希尔分列排序每列排序算法借用插入;以上是基于比较的排序算法

以下不是基于比较的排序算法,(以空间换时间),计数计算每个数出现的次数然后从小到大排序,基数非常适合非负整数个十百分别比较,桶是把每个数分到相应的桶再排序

各个排序图片归纳:

一、冒泡排序(Bubble Sort)

冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

//原始排序(无优化)
public void bubbleSort(Integer[] array){for(int end=array.length-1;end>0;end--){for(int begin=1;begin<=end;begin++){if(array[begin] < array[begin-1]){int temp = array[begin];array[begin] = array[begin-1];array[begin-1] = temp;}}}
}//优化方案1(当数组完全有序或者数组在循环少量次数后就有序时)
public void bubbleSort1(Integer[] array){for(int end=array.length-1;end>0;end--){boolean sorted = true;for(int begin=1;begin<=end;begin++){if(array[begin] < array[begin-1]){int temp = array[begin];array[begin] = array[begin-1];array[begin-1] = temp;sorted = false;}}if(sorted){break;}}
}//优化方案2(当数组中后面部分完全有序)
public void bubbleSort2(Integer[] array){for(int end=array.length-1;end>0;end--){//sortedIndex的初始值在数组完全有序的时候有用int sortedIndex = 1;for(int begin=1;begin<=end;begin++){if(array[begin] < array[begin-1]){int temp = array[begin];array[begin] = array[begin-1];array[begin-1] = temp;sortedIndex = begin;}}end = sortedIndex;}
}

二、选择排序(Selection Sort)

选择排序(Selection-sort)是一种简单直观的排序算法。它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

public void selectionSort(Integer[] arr){for(int end=arr.length-1;end>0;end--){int maxIndex = 0;for(int begin=1;begin<=end;begin++){if(arr[maxIndex] <= arr[begin]){ //增加其稳定性(=)maxIndex = begin;}}int temp = arr[maxIndex];arr[maxIndex] = arr[end];arr[end] = temp;}
}

三、堆排序(Heap Sort)

(可以看做对选择排序的优化)

堆排序(Heap-sort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

//重构代码,写一个父类,其他排序都继承这个抽象类,重写sort方法
public abstract class Sort{protected Integer[] arr;protected int cmpCount; //比较的次数 protected int swapCount; //交换的次数 private long time;public void sort(Integer[] arr){if(arr == null || arr.length < 2) return;this.arr = arr;long begin = System.currentTimeMillis();sort();time = System.currentTimeMillis() - begin;//运行时间}protected abstract void sort();//比较:等于0 arr[i] == arr[j]//小于0 arr[i] < arr[j]//大于0 arr[i] > arr[j]protected int cmp(int i,int j){cmpCount++;return arr[i] - arr[j];}//比较元素大小protected int compare(Integer v1,Integer v2){return v1 - v2;}//交换protected void swap(int i,int j){swapCount++;int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}@Overridepublic String toString(){String string = getClass().getSimpleName()+" "+"耗时:"+(time/1000.0)+"s("+time+"ms)";return string;}
}
//注:上面两个排序的代码可重写,这里我就不写了
//交换堆顶元素与尾元素
//堆的元素数量减1
//对0位置进行1次shiftDown操作
public class HeapSort extends Sort{private int heapSize;@Overrideprotected void sort(){heapSize = arr.length; //原地建堆//heapSize>>1表示把heapSize右移1位,相当于heapSize/2for(int i = (heapSize >> 1)-1;i >= 0;i--){ shiftDown(i);}while(heapSize > 1){//交换堆顶元素与尾元素//swap(0,heapSize-1);//heapSize--;swap(0,--heapSize);//合并以上两步//对0位置进行1次shiftDown操作(恢复堆的性质)shiftDown(0);}}private void shiftDown(int index){Integer element = arr[index];int half = heapSize >> 1;while(index < half){ //index必须是非叶子节点//默认是左边跟父节点比int childIndex = (index << 1)+1;Integer child = arr[childIndex];//右子节点比左子节点大int rightIndex = childIndex + 1;if(rightIndex < heapSize && compare(arr[rightIndex],child) > 0){child = arr[childIndex = rightIndex];}//大于等于子节点if(compare(element,child) >= 0) break;arr[index] = child;index = childIndex;}arr[index] = element;}
}

四、插入排序(Insertion Sort)

类似扑克牌的排序

插入排序(Insertion-Sort)的算法描述是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。

public class InsertionSort extends Sort{@Overrideprotected void sort(){for(int begin=1;begin<arr.length;begin++){int cur = begin;//要把当前begin记录下来,不能改变,所以用cur来代替begin变化while(cur > 0 && cmp(cur,cur-1) < 0){swap(cur,cur-1);cur--;}}}//优化后的代码1@Overrideprotected void sort(){for(int begin=1;begin<arr.length;begin++){int cur = begin;//要把当前begin记录下来,不能改变,所以用cur来代替begin变化Integer v = arr[cur];while(cur > 0 && cmp(cur,cur-1) < 0){arr[cur] = arr[cur-1]; //逐个往右移一个位置cur--;}arr[cur] = v; //最后前面空出来的那个位置,v直接插入进去}}  //利用二分搜索优化代码2(见下面方法search)@Overrideprotected void sort(){for(int begin=1;begin<arr.length;begin++){int v = arr[begin];int searchIndex = search(begin);//将searchIndex到begin位置的元素往右边挪动一位//for(int i=begin-1;i>=searchIndex;i--){//  arr[i+1] = arr[i];//}for(int i=begin;i>searchIndex;i--){arr[i] = arr[i-1];}arr[searchIndex] = v;}}  //利用二分搜索找到index位置元素的待插入位置//已经排好序数组的区间范围值[0,index)private int search(int index){int v = arr[index];int begin = 0;int end = index-1; //左闭右开区间 while(begin < end){int mid = (begin+end) >>1;if(v <arr[mid]){ //compare(v,arr[mid])<0end = mid;}else{begin = mid+1;}}return begin;}}//写一下二分搜索(可参考学习)
public class BinarySearch{//查找v在有序数组array中的位置public static int indexOf(int[] array,int v){ //返回索引if(array == null ||array.length == 0){return -1;}int begin = 0;int end = array.length; //左闭右开区间 while(begin < end){int mid = (begin+end)/2;if(v<array[mid]){end=mid;}else if(v>array[mid]){begin=mid+1;}else{return mid;}}return -1;}//查找v在有序数组array中的插入位置,第一个比v大的位置的索引public static int search(int[] array,int v){if(array == null ||array.length == 0){return -1;}int begin = 0;int end = array.length; //左闭右开区间 while(begin < end){int mid = (begin+end) >>1;if(v <array[mid]){end = mid;}else{begin = mid+1;}}return begin;}}

五、归并排序(Merge Sort)

归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。

public class MergeSort extends Sort{private Integer[] leftArray;@Overrideprotected void sort(){leftArray = new Integer[arr.length >> 1];sort(0,arr.length);}//对[begin,end)范围内的数据进行归并排序private void sort(int begin,int end){if(end - begin < 2) return;//只有一个元素的情况int mid = (begin+end) >> 1;sort(begin,mid); //都是左闭右开区间sort(mid,end); //都是左闭右开区间merge(begin,mid,end);}//合并//将[begin,end)与[mid,end)范围内的序列合并成一个有序的序列private void merge(int begin,int mid,int end){int li = 0,le = mid -begin;int ri = mid,re = end;int ai = begin;//备份左边数组for(int i=li;i<le;i++){leftArray[i] = arr[begin+i];}while(li<le){ //如果左边还没有结束if(ri<re && leftArray[li] > arr[ri]){arr[ai] = arr[ri];ri++;ai++;}else{arr[ai++] = leftArray[li++];}}}}

六、快速排序(Quick Sort)

快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。

/*快速排序的本质:逐渐将每一个元素都转换成轴点元素(递归的过程)*/public class QuickSort extends Sort{@Overrideprotected void sort(){//sort(0,arr.length);sort2(0,arr.length-1);}//对[begin,end)范围的元素进行快速排序private void sort2(int begin,int end){if(end-begin<2) return;//确定轴点位置int mid = partition(begin,end);//对子序列进行快速排序sort(begin,mid-1);sort(mid+1,end);}private int partition(int begin,int end){int privot = begin,index = privot+1;for(int i=index;i<=end;i++){if(arr[privot] > arr[i]){swap(i,index);index++;}}swap(privot,index-1);return index-1;}private void swap(int a,int b){int temp = arr[a];arr[a] = arr[b];arr[b] = temp;}//对[begin,end)范围的元素进行快速排序private void sort(int begin,int end){if(end-begin<2) return;//确定轴点位置int mid = pivotIndex(begin,end);//对子序列进行快速排序sort(begin,mid);sort(mid+1,end);}//确定[begin,end)范围的轴点位置,return begin=end的位置pivotprivate int pivotIndex(int begin,int end){//备份begin位置的元素Integer v = arr[begin];  //arr[pivot] = v//end指向最后一个元素end--;while(begin < end){while(begin < end){if(arr[end] > v){end--;}else{arr[begin] = arr[end];begin++;break; //只退出当前循环,掉头了(本来是从右到左查找对比,只要arr[end]<v了就掉头,从begin方向往end方向查找)}}while(begin < end){if(arr[begin] < v){begin++;}else{arr[end] = arr[begin];end--;break;}}}//将轴点元素放入最终的位置arr[begin] = v;return begin;//或者end,因为begin=end=pivot轴点元素的位置}
}

七、希尔排序(Shell Sort)

1959年Shell发明,第一个突破O(n2)的排序算法,是简单插入排序的改进版。它与插入排序的不同之处在于,它会优先比较距离较远的元素。希尔排序又叫缩小增量排序

public class ShellSort extends Sort{@Overrideprotected void sort(){List<Integer> stepSequence = myStepSequence(); //步长序列{8,4,2,1}    for(Integer step:stepSequence){sort(step);}}//分成step列进行排序private void sort(int step){//col:第几列   //对第col列进行排序for(int col = 0;col < step;col++){//col,col+step,col+2*step,col+3*stepfor(int begin=col+step;begin<arr.length;begin+=step){int cur = begin;//要把当前begin记录下来,不能改变,所以用cur来代替begin变化while(cur > 0 && cmp(cur,cur-step) < 0){swap(cur,cur-step);cur-=step;}}}}private List<Integer> myStepSequence(){List<Integer> stepSequence = new ArrayList<>();int step = arr.length;while((step >> 1) > 0){stepSequence.add(step);}return stepSequence;}
}

八、计数排序(Counting Sort)

计数排序不是基于比较的排序算法,其核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。 作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数

public class CountingSort extends Sort{@Overrideprotected void sort(){//找出最大值int max = arr[0];for(int i=1;i<arr.length;i++){if(arr[i] > max){max = arr[i];}}//开辟内存空间,存储每个整数出现的次数int[] counts = new int[1+max];//统计每个整数出现的次数for(int i=0;i<arr.length;i++){counts[arr[i]]++;}//根据整数的出现次数,对整数进行排序int index=0;for(int i=0;i<counts.length;i++){while(conuts[i]-- >0){arr[index++] = i;}}}
}//优化(内存浪费,无负数,不稳定)
public class CountingSort extends Sort{@Overrideprotected void sort(){//找出最大值、最小值int max = arr[0];int min = arr[0];for(int i=1;i<arr.length;i++){if(arr[i] > max){max = arr[i];}for(int i=1;i<arr.length;i++){if(arr[i] < min){min = arr[i];}//开辟内存空间 存储次数int[] counts = new int[max-min+1];//统计每个整数出现的次数for(int i=0;i<arr.length;i++){counts[arr[i] - min]++;}//累加次数  for(int i=1;i<counts.length;i++){counts[i] += counts[i-1];}//从后往前遍历元素,将其放到有序数组中的合适位置int[] newArr = new int[arr.length];for(int i=arr.length;i>0;i--){//--counts[arr[i]-min] arr[i]-min就是这个数,counts[arr[i]-min]就是次数(前面次数和)要先减一才是新数组的索引newArr[--counts[arr[i]-min]] = arr[i]; //理解} //将有序数组赋值到arrfor(int i=0;i<arr.length;i++){arr[i]=newArr[i];}}
}

九、基数排序(Radix Sort)

基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序。最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前。(非常适合非负整数)

public class RadixSort extends Sort{@Overrideprotected void sort(){//找出最大值int max = arr[0];for(int i=1;i<arr.length;i++){if(arr[i] > max){max = arr[i];}}//max=593  593%10=3  593/10%10=9 593/100%10=5for(int divider = 1;divider <= max;divider *= 10){countingSort(divider);}}//基于计数排序protected void countingSort(int divider){ //divider=1、10、100、1000、... //开辟内存空间 存储次数int[] counts = new int[10];  //0-9//统计每个整数出现的次数for(int i=0;i<arr.length;i++){counts[arr[i] / divider % 10]++;}//累加次数  for(int i=1;i<counts.length;i++){counts[i] += counts[i-1];}//从后往前遍历元素,将其放到有序数组中的合适位置int[] newArr = new int[arr.length];for(int i=arr.length;i>0;i--){//--counts[arr[i]-min] arr[i]-min就是这个数,counts[arr[i]-min]就是次数(前面次数和)要先减一才是新数组的索引newArr[--counts[arr[i] / divider % 10] = arr[i]; //理解} //将有序数组赋值到arrfor(int i=0;i<arr.length;i++){arr[i]=newArr[i];}}
}

十、桶排序(Bucket Sort)

桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。桶排序 (Bucket sort)的工作的原理:假设输入数据服从均匀分布,将数据分到有限数量的桶里,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排)。(当数是小数时)

public class BucketSort extends Sort{@Overrideprotected void sort(){//桶数组List<Double>[] buckets = new List[arr.length];for(int i=0;i<arr.length;i++){int bucketIndex = (int) (arr[i] * arr.length);List<Double> bucket = buckets[bucketIndex];if(bucket == null){bucket = new LinkedList<>();buckets[bucketIndex] = bucket;}bucket.add(arr[i]);}//对每个桶进行排序int index = 0;for(int i=0;i<buckets;i++){if(buckets[i] == null) continue;buckets[i].sort(null);//java内部的排序方法for(Double d:buckets[i]){arr[index++] = d;}}}
}

扩展:十一、史上“最强”排序-休眠排序666(仅供参考,不要用!!)

private static class SortThread extends Thread{private int value;public SortThread(int value){this.value = value;}public void run(){try{Thread.sleep(value);System.out.println(value);}catch(IntereuptedException e){e.printStackTrace();}}
}public class SortThreadTest{public static void main(String[] args){int[] array = [10,100,50,60,30];for(int i=0;i<array.length;i++){new SortThread(array[i]).start();}}
}

主要是理解某个算法本身的意义和思想,再根据代码联系思考。

这篇博客是自己在学习的时候跟着老师一起敲的,如有错误或不足之处还请多指教,以下是几个参考学习的链接。

可视化算法结构

前端JS实现十大排序算法可参见博文

学习视频bilibili

十大排序算法(Java)相关推荐

  1. 经典十大排序算法(含升序降序,基数排序含负数排序)【Java版完整代码】【建议收藏系列】

    经典十大排序算法[Java版完整代码] 写在前面的话 十大排序算法对比 冒泡排序 快速排序 直接选择排序 堆排序 归并排序 插入排序 希尔排序 计数排序 桶排序 基数排序 完整测试类 写在前面的话   ...

  2. JAVA十大排序算法动画_十大排序算法(java实现)

    [前言]最近在重新研究算法,此篇博文供自己复习使用也为方便广大程序员同学!此文代码均为自己实现,通过对比经典解法校验,若有错请读者及时提出! - [对比分析图]首先,我们先来对比分析一下这十大排序算法 ...

  3. 这或许是东半球分析十大排序算法最好的一篇文章

    作者 | 不该相遇在秋天 转载自五分钟学算法(ID:CXYxiaowu) 前言 本文全长 14237 字,配有 70 张图片和动画,和你一起一步步看懂排序算法的运行过程. 预计阅读时间 47 分钟,强 ...

  4. 「干货总结」程序员必知必会的十大排序算法

    点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:硬刚一周,3W字总结,一年的经验告诉你如何准备校招! 个人原创100W+访问量博客:点击前往,查看更多 绪论 身 ...

  5. 「归纳|总结」程序员必知必会的十大排序算法

    微信搜一搜「bigsai」关注这个有趣的程序员 新人原创公众号,求支持一下!你的点赞三连肯定对我至关重要! 文章已收录在 我的Github bigsai-algorithm 欢迎star 本文目录 绪 ...

  6. 八十八、Python | 十大排序算法系列(下篇)

    @Author:Runsen @Date:2020/7/10 人生最重要的不是所站的位置,而是内心所朝的方向.只要我在每篇博文中写得自己体会,修炼身心:在每天的不断重复学习中,耐住寂寞,练就真功,不畏 ...

  7. 八十七、Python | 十大排序算法系列(上篇)

    @Author:Runsen @Date:2020/7/10 人生最重要的不是所站的位置,而是内心所朝的方向.只要我在每篇博文中写得自己体会,修炼身心:在每天的不断重复学习中,耐住寂寞,练就真功,不畏 ...

  8. 十大排序算法之堆排序

    十大排序算法之堆排序 本文采用Java书写选择排序,其他语言类似可以借鉴着写 思想:所谓堆排序就是通过构造最大堆(升序)或者最小堆(降序)来进行排列的方法.可能有些童鞋不知道何为最大堆,何为最小堆.这 ...

  9. 十大排序算法之快速排序(两种方法)

    十大排序算法之快速排序 本文采用Java书写选择排序,其他语言类似可以借鉴着写 思想:在待排序序列中选择一个分割元素,将待排序序列中所有比分割元素关键字小的元素移动到分割元素左侧位置:将待排序序列中所 ...

最新文章

  1. 腾讯首位17级杰出科学家诞生:腾讯AI Lab负责人张正友
  2. 深入浅出 Redis client/server交互流程
  3. BusinessObject Port 配置
  4. mybatis 联查
  5. 160809308周子济第7次作业
  6. 如何使用GZip和Jersey压缩Java REST API中的响应
  7. matlab 符号 约束,非线性优化 问题约束函数带有符号的条件函数怎么写?
  8. python2/3 模块gmpy2在linux下安装
  9. 27、简述redis的有哪几种持久化策略及比较?
  10. android wear 同步应用,Android Wear发布 突出语音及同步功能
  11. 快学Scala习题解答—第四章 映射和元组
  12. 对象tostring后怎么转成对象_和女生相亲后怎么联系对方?和相亲对象该如何聊天...
  13. IoU实现 python
  14. Nagios 分布式
  15. 风之大陆互通服务器账号,风之大陆有几个服务器?服务器互通吗?
  16. golang 安全的tcp server_化繁为简,写一个简单好用的server
  17. 智能网联汽车——传感器与驾驶辅助
  18. SpringAOP简单案例
  19. [渝粤教育】陕西师范大学《教育社会学》作业
  20. 思科模拟器配置静态路由(下一跳使用IP)

热门文章

  1. Spring Security学习(二)
  2. 侧输出流简单应用-打印的完整流程
  3. raft中集群成员变更
  4. CSS盒子模型的使用及其注意事项——响应式Web系列学习笔记
  5. 1.使用适配器模式设计一个仿生机器人:要求机器人可以模拟各种动物行为,在机器人中定义了一系列方法,如机器人发声方法talk(),机器人移动方法move()等。如果希望在不改变已有Bird类代码的基础上
  6. oracle 存储过程挂起,library cache pin与PROCEDURE的重建
  7. feign 序列化_Spring Cloud Feign 配置 FastJson
  8. [java][工具类][Arrays]
  9. python笔记之for循环
  10. java与jquery的选择器区别_java day44【JQuery 基础:概念,快速入门,JQuery对象和JS对象区别与转换,选择器,DOM操作,案例】...