image

前言

好久没复习基础了,写个冒泡排序都要想一会。感觉自己好像老了好多,今天手痒总结一下排序算法。目前网上博客普遍都有详细介绍,写的很清楚。说实话我是没必要再写一遍的,感觉就是在啰嗦、还是重复性的,但是如果只是单纯看的话,不到3分钟我就忘记了(可能是健忘症晚期)。所以还是自己亲手“教训”一下印象比较深刻。

一、简介

排序(Sorting) 是计算机程序设计中的一种重要操作,它的功能是将一个数据元素(或记录)的任意序列,重新排列成一个关键字有序的序列。

排序算法在很多领域得到相当地重视,尤其是在大量数据的处理方面。一个优秀的算法可以节省大量的资源。在各个领域中考虑到数据的各种限制和规范,要得到一个符合实际的优秀算法,得经过大量的推理和分析。

那么怎么对比哪个排序算法更好呢? 这时候就是要看谁运行的比较快。 哈哈 真是一句废话,谁不知道呢

timg (1).gif

所以我们需要了解一下

二、算法复杂度

时间复杂度是指执行算法所需要的计算工作量;而空间复杂度是指执行这个算法所需要的内存空间

(1)时间复杂度

时间复杂度可以认为是对排序数据的总的操作次数。反映当n变化时,操作次数呈现什么规律。

常见的时间复杂度有:常数阶O(1),对数阶O(log2n),线性阶O(n), 线性对数阶O(nlog2n),平方阶O(n2)。

时间复杂度O(1):算法中语句执行次数为一个常数,则时间复杂度为O(1)。

(2)空间复杂度

空间复杂度是指算法在计算机内执行时所需存储空间的度量,它也是问题规模n的函数。

空间复杂度O(1):当一个算法的空间复杂度为一个常量,即不随被处理数据量n的大小而改变时,可表示为O(1)。

空间复杂度O(log2N):当一个算法的空间复杂度与以2为底的n的对数成正比时,可表示为O(log2n) , ax=N,则x=logaN。

空间复杂度O(n):当一个算法的空间复杂度与n成线性比例关系时,可表示为0(n)。

(3)排序算法稳定性

假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。

稳定性的意义

1、如果只是简单的进行数字的排序,那么稳定性将毫无意义。

2、如果排序的内容仅仅是一个复杂对象的某一个数字属性,那么稳定性依旧将毫无意义

3、如果要排序的内容是一个复杂对象的多个数字属性,但是其原本的初始顺序毫无意义,那么稳定性依旧将毫无意义。

4、除非要排序的内容是一个复杂对象的多个数字属性,且其原本的初始顺序存在意义,那么我们需要在二次排序的基础上保持原有排序的意义,才需要使用到稳定性的算法,例如要排序的内容是一组原本按照价格高低排序的对象,如今需要按照销量高低排序,使用稳定性算法,可以使得想同销量的对象依旧保持着价格高低的排序展现,只有销量不同的才会重新排序。

image

太复杂了,我也只了解了点皮毛。就简单介绍这些,要详细了解的同学们还是自己看书吧!!!

download.jpg

三、常见算法

(1)冒泡排序

1、简介:

重复地走访过要排序的元素列,依次比较两个相邻的元素,如果他们的顺序(如从大到小、首字母从A到Z)错误就把他们交换过来

2、步骤:

比较相邻的元素。如果第一个比第二个大,就交换他们两个。

对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。

针对所有的元素重复以上的步骤,除了最后一个。

持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较

3、动图:

image

4、代码:

public static void order1(int[] a) {

for(int x=0;x

for (int y = 0; y < a.length-1-x; y++) {

if(a[y]>a[y+1]) {

int t = a[y];

a[y] = a[y+1];

a[y+1] = t;

}

}

}

}

image.gif

(2)选择排序

1、简介:

每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到全部待排序的数据元素排完。 选择排序是不稳定的排序方法

2、步骤:

首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。

再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。

重复第二步,直到所有元素均排序完毕。

3、动图:

image

4、代码:

public static void order2(int[] a) {

for (int i = 0; i < a.length-1; i++) {

for (int j = i + 1; j < a.length; j++) {

if (a[i] > a[j]) {

int t = a[i];

a[i] = a[j];

a[j] = t;

}

}

}

}

image.gif

(3)插入排序

1、简介:

插入算法把要排序的数组分成两部分:第一部分包含了这个数组的所有元素,但将最后一个元素除外(让数组多一个空间才有插入的位置),而第二部分就只包含这一个元素(即待插入元素)。在第一部分排序完成后,再将这个最后元素插入到已排好序的第一部分中。

2、步骤:

从第一个元素开始,该元素可以认为已经被排序

取出下一个元素,在已经排序的元素序列中从后向前扫描

如果该元素(已排序)大于新元素,将该元素移到下一位置

重复步骤3,直到找到已排序的元素小于或者等于新元素的位置

将新元素插入到下一位置中

重复步骤2~5

3、动图:

image

4、代码:

public static void order3(int[] a) {

for (int i = 1; i < a.length; i++) {

int get = a[i];

int j = i-1;

while (j >= 0 && a[j] > get) {

a[j + 1] = a[j];

j--;

}

a[j + 1] = get;

}

}

(4)归并排序

1、简介:

将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。

2、步骤:

把长度为n的输入序列分成两个长度为n/2的子序列。

对这两个子序列分别采用归并排序。

将两个排序好的子序列合并成一个最终的排序序列。

3、动图:

4、代码:

/**

* 归并排序

*/

public static void order4(int[] a) {

sort(a,0,a.length-1);

}

public static void sort(int[] data,int left,int right) {

if(left >= right) return;

//找出中间索引

int center = (left + right)/2;

//对左边数组进行递归

sort(data, left, center);

//对右边数组进行递归

sort(data, center+1, right);

//合并

merge(data,left,center,right);

}

public static void merge(int[] data,int left, int center,int right) {

//临时数组

int[] tmpArr = new int[data.length];

//右数组第一个元素索引

int mid = center + 1;

//third 记录临时数组的索引

int third = left;

//缓存左数组第一个元素的索引

int tmp = left;

while (left <= center && mid <=right) {

//从两个数组中取出最小的放入临时数组

if (data[left] <= data[mid]) {

tmpArr[third++] = data[left++];

} else {

tmpArr[third++] = data[mid++];

}

}

//剩余部分依次放入临时数组(实际上两个while只会执行其中一个)

while(mid <= right) {

tmpArr[third++] = data[mid++];

}

while(left <= center) {

tmpArr[third++] = data[left++];

}

//将临时数组中的内容拷贝回原数组中

while (tmp <= right) {

data[tmp] = tmpArr[tmp++];

}

}

(5)快速排序

1、简介:

在数组中随机选一个数(默认数组首个元素),数组中小于等于此数的放在左边,大于此数的放在右边,再对数组两边递归调用快速排序,重复这个过程。

2、步骤:

先从数列中取出一个数作为key值;

将比这个数小的数全部放在它的左边,大于或等于它的数全部放在它的右边;

对左右两个小数列重复第二步,直至各区间只有1个数。

3、动图:

image

4、代码:

/**

* 快速排序

*/

public static void order5(int[] a) {

quickSort(a,0,a.length-1);

}

private static void quickSort(int[] a, int left, int right) {

if(left < right) {

int i = getMiddle(a,left,right);

quickSort(a, left, i - 1);

quickSort(a, i + 1,right);

}

}

private static int getMiddle(int[] a, int low, int high) {

int pivot = a[low];

int i = low;

int j = high;

while(i < j) {

while(pivot <= a[j] && i < j) j--;

while(pivot >= a[i] && i < j) i++;

if(i < j) {

int temp = a[i];

a[i] = a[j];

a[j] = temp;

}

}

a[low] = a[i];

a[i] = pivot;

return i;

}

(6)希尔排序

1、简介:

希尔排序是插入排序改良的算法,希尔排序步长从大到小调整,第一次循环后面元素逐个和前面元素按间隔步长进行比较并交换,直至步长为1,步长选择是关键。

2、步骤:

先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,具体算法描述:

选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;

按增量序列个数k,对序列进行k 趟排序;

每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。

3、动图:

image

4、代码:

/**

* 希尔排序

*/

public static void order6(int[] a) {

int len = a.length;//单独把数组长度拿出来,提高效率。

while(len != 0) {

len = len/2;

for (int i = 0; i < len; i++) {//分组

for (int j = i + 1; j < a.length; j+=len) {//元素从第二个开始

int k = j - len;//k为有序序列最后一位的位数

int temp = a[j];//要插入的元素

while (k >= 0 && temp < a[k]) {//从后往前遍历

a[k + len] = a[k];

k -= len;//向后移动len位

}

a[k + len] = temp;

}

}

}

}

(7)基数排序

1、简介:

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

2、步骤:

取得数组中的最大数,并取得位数;

arr为原始数组,从最低位开始取每个位组成radix数组;

对radix进行计数排序(利用计数排序适用于小范围数的特点);

3、动图:

image

4、代码:

/**

* 基数排序

*/

public static void order7(int[] a) {

int max = a[0];

for (int i = 1; i < a.length; i++) {

if (a[i] > max) {

max = a[i];

}

}

int time = 0;

while (max > 0) {

max /= 10;

time++;

}

List> queue = new ArrayList>();

for (int i = 0; i < 10; i++) {

ArrayList queue1 = new ArrayList();

queue.add(queue1);

}

for (int i = 0; i < time; i++) {

for (int j = 0; j < a.length; j++) {

int x = a[j] % (int) Math.pow(10, i+1)/(int)Math.pow(10, i);

ArrayList queue2 = queue.get(x);

queue2.add(a[j]);

queue.set(x, queue2);

}

int count = 0;

for (int k = 0; k < 10; k++) {

while (queue.get(k).size()>0) {

ArrayList queue3 = queue.get(k);

a[count] = queue3.get(0);

queue3.remove(0);

count++;

}

}

}

}

(8)堆排序

1、简介:

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

2、步骤:

将初始待排序关键字序列(R1,R2….Rn)构建成大顶堆,此堆为初始的无序区;

将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,……Rn-1)和新的有序区(Rn),且满足R[1,2…n-1]<=R[n];

由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,……Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2….Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。

3、动图:

image

4、代码:

/**

* 堆排序

*/

public static void order8(int[] a) {

int len = a.length;

for (int i = 0; i < len - 1; i++) {

buildMaxHeap(a,len - 1 - i);

swap(a,0,len - 1 - i);

}

}

private static void buildMaxHeap(int[] data, int lastIndex) {

//从lastIndex处节点(最后一个节点)的父节点开始

for (int i = (lastIndex - 1)/2; i >= 0; i--) {

//k保存正在判断的节点

int k = i ;

//如果当前K节点的子节点存在

while(k * 2 + 1 <= lastIndex) {

//k节点的左子节点的索引

int biggerIndex = 2 * k +1;

//如果biggerIndex小于lastIndex,即biggerIndex +1代表的K节点的右子节点存在

if(biggerIndex < lastIndex) {

//如果右子节点的值较大

if(data[biggerIndex] < data[biggerIndex + 1]) {

biggerIndex++;

}

}

//如果K节点的值小于其较大的子节点的值

if(data[k] < data[biggerIndex]) {

//交换他们

swap(data, k, biggerIndex);

k = biggerIndex;

} else {

break;

}

}

}

}

private static void swap(int[] a, int i, int j) {

int tmp = a[i];

a[i] = a[j];

a[j] = tmp;

}

四、总结

场景应用:

(1)若n较小(如n≤50),可采用直接插入或直接选择排序。

当记录规模较小时,直接插入排序较好;否则因为直接选择移动的记录数少于直接插人,应选直接选择排序为宜。

(2)若文件初始状态基本有序(指正序),则应选用直接插人、冒泡或随机的快速排序为宜;

(3)若n较大,则应采用时间复杂度为O(nlgn)的排序方法:快速排序、堆排序或归并排序。

快速排序是目前基于比较的内部排序中被认为是最好的方法,当待排序的关键字是随机分布时,快速排序的平均时间最短;

堆排序所需的辅助空间少于快速排序,并且不会出现快速排序可能出现的最坏情况。这两种排序都是不稳定的。

若要求排序稳定,则可选用归并排序。但本章介绍的从单个记录起进行两两归并的 排序算法并不值得提倡,通常可以将它和直接插入排序结合在一起使用。先利用直接插入排序求得较长的有序子文件,然后再两两归并之。因为直接插入排序是稳定 的,所以改进后的归并排序仍是稳定的。

果然算法很复杂,以我智商都有点不够用。分析的我脑壳有点疼,实在扯不下去。就写这么多了。见谅。。。

download.gif

五、Demo地址

六、参考文档

七、内容推荐

上一篇:

如果你觉得我写的不错或者对您有所帮助的话

不妨顶一个【微笑】,别忘了点赞、收藏、加关注哈

您的每个举动都是对我莫大的支持

image

归并排序改良 java_Java 八种排序算法总结相关推荐

  1. Java常用的八种排序算法与代码实现

    在Java的时候,对于排序的应用需要熟练的掌握,这样才能够确保Java学习时候能够有扎实的基础能力.那Java有哪些排序算法呢?本文小千就来详细说说Java经典的8种排序算法. 经典的排序算法有八种, ...

  2. Java 八种排序算法比较实践

    写这篇文章是因为面试时经常会问这个问题,但是工作中也没用到过,所以一直是一知半解.但是我是属于比较较真的人,这次下定决心要把它们搞明白.知识在于积累,多点知识对自己总是有好处的. 我比较好奇的是,这几 ...

  3. 八种排序算法动画讲解

    思维导图 前言 算法和数据结构是一个程序员的内功,所以经常在一些笔试中都会要求手写一些简单的排序算法,以此考验面试者的编程水平!动图来源于今日头条.动图来源于今日头条.动图来源于今日头条! 1.冒泡排 ...

  4. 八种排序算法的时间复杂度复杂度

    https://www.cnblogs.com/dll-ft/p/5861210.html 转载 1.稳定性 归并排序.冒泡排序.插入排序.基数排序是稳定的 选择排序.快速排序.希尔排序.堆排序是不稳 ...

  5. java排序算法代码_Java实现八种排序算法(代码详细解释)

    package八大排序算法;importjava.util.Arrays;importorg.junit.Test;/*** 1.插入排序 直接插入排序.希尔排序 折半插入排序 * 2.交换排序 冒泡 ...

  6. java八种排序算法---直接插入排序

    在学习算法的过程中,我们难免会接触很多和排序相关的算法.总而言之,对于任何编程人员来说,基本的排序算法是必须要掌握的. 从今天开始,我们将要进行基本的排序算法的讲解.Are you ready?Let ...

  7. java实现八种排序算法并测试速度(详细)

    算法代码: /*** Created by CLY on 2017/3/17.*/ package pers.cly.sorting; /*** 排序工具类,里面包含各种排序方法*/ public c ...

  8. 算法 | 快速搞定八种排序算法与代码实现

    点击上方"阿拉奇学Java",选择"置顶或者星标"  每天早晨00点00分,与你相约! 往日回顾:不敢相信,相同 SQL 下 Mybatis 查询结果和数据库竟 ...

  9. 【基础不牢地动山摇】一遍记住 Java 面试中常用的八种排序算法与代码实现!...

    作者:KaelQ www.jianshu.com/p/5e171281a387 1.直接插入排序 经常碰到这样一类排序问题:把新的数据插入到已经排好的数据列中. 将第一个数和第二个数排序,然后构成一个 ...

最新文章

  1. mysql基础之视图
  2. [置顶] 贝叶斯分类(一)
  3. 150m虚拟主机容量不足
  4. [转]MongoDB c++驱动安装与使用
  5. SpringBoot中Profile配置和加载配置文件
  6. python爬取考研成绩什么时候出来_用Python爬取了考研吧1000条帖子,原来他们都在讨论这些!...
  7. POJ 1852 Ants O(n)
  8. pdo mysql fedora_在Fedora 23 Server和Workstation上安装LAMP(Linux, Apache, MariaDB和PHP)
  9. python数据库操作实例
  10. Linux运维学习历程-第五天-Linux文件系统与管理
  11. mysql介质故障_pciessd异常readonly致mysql反复crash
  12. Sencha touch 开发系列:容器组件:tabpanel,carousels
  13. Linux IO系统分析(scsi篇)
  14. Oracle DUL/AUL/ODU 工具说明
  15. Unity 官方标准资源下载(standard assets)2种方式
  16. 全民免费吃鸡,驱动人生带你玩转PUBG
  17. 实时渲染技术和DLSS 2.0技术
  18. java poi word 复制_java poi如何复制word中的table
  19. 松翰单片机数码管c语言,松翰单片机数码管程序
  20. UE4设置场景摄像机视角

热门文章

  1. 有意思的前端函数面试题
  2. [转载]为什么使用 SLF4J 而不是Log4J来做Java 日志
  3. Bzoj4503 两个串
  4. 孙钟秀--《操作系统教程》注释(陈怀临)-- 读书笔记
  5. 浏览器窗口的高度和宽度
  6. 使用Xmodem恢复交换机IOS
  7. dreamweaver 疑问
  8. 【财务思维】上市定价
  9. 采购定价过程字段解析
  10. LSMW批处理使用方法(07)_步骤6、7