【原文】https://www.toutiao.com/i6591634652274885128/

常见排序算法总结与实现

本文使用Java实现这几种排序。

以下是对排序算法总体的介绍。

冒泡排序

  1. 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
  2. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
  3. 针对所有的元素重复以上的步骤,除了最后一个。
  4. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

时间复杂度:O(n^2),最优时间复杂度:O(n),平均时间复杂度:O(n^2)

1public static void bubbleSort(Comparable[] a) {

2 int j, flag;

3 Comparable temp;

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

5 flag = 0;

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

7 if (a[j].compareTo(a[j - 1]) < 0) {

8 temp = a[j];

9 a[j] = a[j - 1];

10 a[j - 1] = temp;

11 flag = 1;

12 }

13 }

14 // 如果没有交换,代表已经排序完毕,直接返回

15 if (flag == 0) {

16 return;

17 }

18 }

19}

插入排序

  1. 从第一个元素开始,该元素可以认为已经被排序
  2. 取出下一个元素,在已经排序的元素序列中从后向前扫描
  3. 如果该元素(已排序)大于新元素,将该元素移到下一位置
  4. 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
  5. 将新元素插入到该位置后
  6. 重复步骤2~5

时间复杂度:O(n^2),最优时间复杂度:O(n),平均时间复杂度:O(n^2)

下面展示了三种插入排序的实现,第二种方法减少了交换次数,第三种采用二分查找法查到插入点。

1public static void insertionSort(Comparable[] a) {

2 int length = a.length;

3 Comparable temp;

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

5 for (int j = i; j > 0 && a[j].compareTo(a[j - 1]) < 0; j--) {

6 temp = a[j];

7 a[j] = a[j - 1];

8 a[j - 1] = temp;

9 }

10 }

11}

12

13// 对实现Comparable的类型进行排序,先将大的元素都向右移动,减少一半交换次数

14public static void insertionSort(Comparable[] a) {

15 int length = a.length;

16 Comparable temp;

17 int j;

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

19 temp = a[i];

20 for (j = i; j > 0 && temp.compareTo(a[j - 1]) < 0; j--) {

21 a[j] = a[j - 1];

22 }

23 a[j] = temp;

24 }

25}

26

27// 二分插入排序,使用二分查找找到插入点,然后进行移位

28public static void insertionSort(Comparable[] a) {

29 int length = a.length;

30 Comparable temp;

31 int j;

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

33 if (a[i].compareTo(a[i - 1]) < 0) {

34 temp = a[i];

35 int index = binarySearch(a, a[i], 0, i - 1);

36 for (j = i - 1; j >= index; j--) {

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

38 }

39 a[index] = temp;

40 }

41 }

42}

43

44private static int binarySearch(Comparable[] a, Comparable target, int start, int end) {

45 int mid;

46 while (start <= end) {

47 mid = (start + end) >> 1;

48 if (target.compareTo(a[mid]) < 0) {

49 end = mid - 1;

50 } else {

51 start = mid + 1;

52 }

53 }

54 return start;

55}

选择排序

首先在未排序序列中找到最小元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小元素,然后放到已排序序列的末尾。

时间复杂度:O(n^2),最优时间复杂度:O(n^2),平均时间复杂度:O(n^2)

1public static void selectionSort1(Comparable[] a) {

2 int length = a.length;

3 int min;

4 Comparable temp;

5 for (int i = 0; i < length; i++) {

6 min = i;

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

8 if (a[j].compareTo(a[min]) < 0) {

9 min = j;

10 }

11 }

12 temp = a[min];

13 a[min] = a[i];

14 a[i] = temp;

15 }

16}

希尔排序

希尔排序通过将比较的全部元素分为几个区域来提升插入排序的性能。这样可以让一个元素可以一次性地朝最终位置前进一大步。然后算法再取越来越小的步长进行排序,算法的最后一步就是普通的插入排序,但是到了这步,需排序的数据几乎是已排好的了(此时插入排序较快)。

时间复杂度:根据步长而不同,最优时间复杂度:O(n),平均时间复杂度:根据步长而不同

1public static void shellSort(Comparable[] a) {

2 int length = a.length;

3 int h = 1;

4 Comparable temp;

5 while (h < length / 3) {

6 h = 3 * h + 1;

7 }

8 while (h >= 1) {

9 for (int i = h; i < length; i++) {

10 for (int j = i; j >= h && a[j].compareTo(a[j - h]) < 0; j -= h) {

11 temp = a[j];

12 a[j] = a[j - h];

13 a[j - h] = temp;

14 }

15 }

16 h /= 3;

17 }

18}

堆排序

  1. 创建最大堆(Build_Max_Heap):将堆所有数据重新排序
  2. 堆排序(HeapSort):移除位在第一个数据的根节点,并做最大堆调整的递归运算

时间复杂度:O(nlogn),最优时间复杂度:O(nlogn),平均时间复杂度:O(nlogn)

1public static void heapSort(Comparable[] a) {

2 int length = a.length;

3 Comparable temp;

4 for (int k = length / 2; k >= 1; k--) {

5 sink(a, k, length);

6 }

7 while (length > 0) {

8 temp = a[0];

9 a[0] = a[length - 1];

10 a[length - 1] = temp;

11 length--;

12 sink(a, 1, length);

13 }

14}

15

16private static void sink(Comparable[] a, int k, int n) {

17 Comparable temp;

18 while (2 * k <= n) {

19 int j = 2 * k;

20 if (j < n && a[j - 1].compareTo(a[j]) < 0) {

21 j++;

22 }

23 if (a[k - 1].compareTo(a[j - 1]) >= 0) {

24 break;

25 }

26 temp = a[k - 1];

27 a[k - 1] = a[j - 1];

28 a[j - 1] = temp;

29 k = j;

30 }

31}

归并排序

归并操作(merge),也叫归并算法,指的是将两个已经排序的序列合并成一个序列的操作。归并排序算法依赖归并操作。

时间复杂度:O(nlogn),最优时间复杂度:O(n),平均时间复杂度:O(nlogn),空间复杂度O(n)

自顶向下的归并排序

1private static Comparable[] aux;

2// 自顶向下

3public static void mergeSort(Comparable[] a) {

4 aux = new Comparable[a.length];

5 mergeSort(a, 0, a.length - 1);

6}

7

8public static void mergeSort(Comparable[] a, int lo, int hi) {

9 if (hi <= lo) {

10 return;

11 }

12 int mid = (lo + hi) >>> 1;

13 mergeSort(a, lo, mid);

14 mergeSort(a, mid + 1, hi);

15 merge(a, lo, mid, hi);

16}

17

18public static void merge(Comparable[] a, int lo, int mid, int hi) {

19 int i = lo, j = mid + 1;

20

21 for (int k = lo; k <= hi; k++) {

22 aux[k] = a[k];

23 }

24

25 for (int k = lo; k <= hi; k++) {

26 if (i > mid) {

27 a[k] = aux[j++];

28 } else if (j > hi) {

29 a[k] = aux[i++];

30 } else if (aux[j].compareTo(aux[i]) < 0) {

31 a[k] = aux[j++];

32 } else {

33 a[k] = aux[i++];

34 }

35 }

36}

自底向上的归并排序

1private static Comparable[] aux;

2

3// 自底向上

4public static void mergeSort(Comparable[] a) {

5 int length = a.length;

6 aux = new Comparable[length];

7 for (int sz = 1; sz < length; sz = sz + sz) {

8 for (int lo = 0; lo < length - sz; lo += sz + sz) {

9 merge(a, lo, lo + sz - 1, Math.min(lo + sz + sz - 1, length - 1));

10 }

11 }

12}

13

14public static void merge(Comparable[] a, int lo, int mid, int hi) {

15 int i = lo, j = mid + 1;

16

17 for (int k = lo; k <= hi; k++) {

18 aux[k] = a[k];

19 }

20

21 for (int k = lo; k <= hi; k++) {

22 if (i > mid) {

23 a[k] = aux[j++];

24 } else if (j > hi) {

25 a[k] = aux[i++];

26 } else if (aux[j].compareTo(aux[i]) < 0) {

27 a[k] = aux[j++];

28 } else {

29 a[k] = aux[i++];

30 }

31 }

32}

快速排序

  1. 从数列中挑出一个元素,称为"基准"(pivot),
  2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的 摆在基准的后面(相同的数可以到任一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
  3. 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

时间复杂度:O(n^2),最优时间复杂度:O(nlogn),平均时间复杂度:O(nlogn)

快排的时间复杂度跟选取基准的方法有关,一下是默认选择了第一个元素作为基准,随机性较大。

可以在序列中选取开始中间结尾三个数的中位数作为基准,进行优化。

1public static void quickSort(Comparable[] a) {

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

3}

4

5public static void quickSort(Comparable[] a, int lo, int hi) {

6 if (hi <= lo) {

7 return;

8 }

9 int j = partition(a, lo, hi);

10 quickSort(a, lo, j - 1);

11 quickSort(a, j + 1, hi);

12}

13

14public static int partition(Comparable[] a, int lo, int hi) {

15 int i = lo, j = hi + 1;

16 Comparable temp;

17 Comparable v = a[lo];

18 while (true) {

19 while (a[++i].compareTo(v) < 0) {

20 if (i == hi) {

21 break;

22 }

23 }

24 while (v.compareTo(a[--j]) < 0) {

25 if (j == lo) {

26 break;

27 }

28 }

29 if (i >= j) {

30 break;

31 }

32 temp = a[i];

33 a[i] = a[j];

34 a[j] = temp;

35 }

36 temp = a[lo];

37 a[lo] = a[j];

38 a[j] = temp;

39 return j;

40}

[转]Java学习---7大经典的排序算法总结实现的更多相关文章

  1. Java 实现的各种经典的排序算法小Demo

    由于有上机作业,所以就对数据结构中常用的各种排序算法都写了个Demo,有如下几个: 直接插入排序 折半插入排序 希尔排序 冒泡排序 快速排序 选择排序 桶排序 Demo下载地址 下面谈一谈我对这几个排 ...

  2. JAVA学习笔记(4)—— 排序算法

    排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作.排序算法,就是如何使得记录按照要求排列的方法. 排序算法大体可分为两种: 一种是比较排序,时间复杂度O(nlogn) ...

  3. 深度实战玩转算法, Java语言7个经典应用诠释算法精髓

    深度实战玩转算法,以Java语言主讲,通过7款经典好玩游戏,真正将算法用于实际开发,由算法大牛ACM亚洲区奖牌获得者liuyubobobo主讲,看得见的算法,带领你进入一个不一样的算法世界,本套课程共 ...

  4. 我们一起来排序——使用Java语言优雅地实现常用排序算法

    破阵子·春景 燕子来时新社,梨花落后清明. 池上碧苔三四点,叶底黄鹂一两声.日长飞絮轻. 巧笑同桌伙伴,上学径里逢迎. 疑怪昨宵春梦好,元是今朝Offer拿.笑从双脸生. 排序算法--最基础的算法,互 ...

  5. java讲讲几种常见的排序算法(二)

    java讲讲几种常见的排序算法(二) 目录 java讲讲几种常见的排序算法(一) java讲讲几种常见的排序算法(二) 堆排序 思路:构建一个小顶堆,小顶堆就是棵二叉树,他的左右孩子均大于他的根节点( ...

  6. java讲讲几种常见的排序算法

    java讲讲几种常见的排序算法(一) 目录 java讲讲几种常见的排序算法(一) java讲讲几种常见的排序算法(二) 以数组array={6,3,20,8,15,1}为例 冒泡排序 思路:从第0个到 ...

  7. Java中常用的6种排序算法详细分解

    排序算法很多地方都会用到,近期又重新看了一遍算法,并自己简单地实现了一遍,特此记录下来,为以后复习留点材料. 废话不多说,下面逐一看看经典的排序算法: 1. 选择排序 选择排序的基本思想是遍历数组的过 ...

  8. Java面试宝典系列之基础排序算法

    本文就是介绍一些常见的排序算法.排序是一个非常常见的应用场景,很多时候,我们需要根据自己需要排序的数据类型,来自定义排序算法,但是,在这里,我们只介绍这些基础排序算法,包括:插入排序.选择排序.冒泡排 ...

  9. 用 Java 实现的八种常用排序算法

    八种排序算法可以按照如图分类 交换排序 所谓交换,就是序列中任意两个元素进行比较,根据比较结果来交换各自在序列中的位置,以此达到排序的目的. 1. 冒泡排序 冒泡排序是一种简单的交换排序算法,以升序排 ...

随机推荐

  1. spring StopWatch用法

    背景 有时我们在做开发的时候需要记录每个任务执行时间,或者记录一段代码执行时间,最简单的方法就是打印当前时间与执行完时间的差值,然后这样如果执行大量测试的话就很麻烦,并且不直观,如果想对执行的时间做进 ...

  2. Apriori算法进行关联分析

    设全集U = {a, b, c, d, e},其元素a,b, c, d, e称为项. 数据集: D = [ {a, b}, {b, c, d}, {d, e}, {b, c, e}, {a,b, c, ...

  3. 如何使SpringBoot作为Maven构建的项目的一个子模块

    1.问题 一般使用springboot都会引用springboot作为parent,在实际项目中web只是系统模块的一个子集.当然你可以做两个项目来管理,一个项目用来做各种支持包,一个项目专门做web ...

  4. karma + jasmine 构建前端自动化测试

    http://blog.fens.me/nodejs-karma-jasmine/   很全的文档 执行karma init时报错如下: $ karma init > readline.js:5 ...

  5. 将ABP的数据库从SQLSERVER迁移到MySql

    摘要:之前跟着网上的一些教程,学习了一点ABP的知识.最近想说把默认的SQLSERVER数据迁移到mysql吧 首先网上搜一波 安装MySql.Data.Entity 然后你需要安装 MySql.Da ...

  6. mysql 中int类型字段unsigned和signed的探索

    转自:http://www.0791quanquan.com/news_keji/topic_816453/ 探索一:正负数问题 拿tinyint字段来举例,unsigned后,字段的取值范围是0-2 ...

  7. git撤销提交(commit)

    我们知道Git有三大区(工作区.暂存区.版本库)以及几个状态(untracked.unstaged.uncommited) 一.简介 Git 保存的不是文件的变化或者差异,而是一系列不同时刻的文件快照 ...

  8. intellij idea 2016.3.5 控制台取消行数限制

    有时候我们要输出大量的信息放到控制台显示,但是多了之后就出现最上面的信息被覆盖删除, 因此就需要设置控制台的显示行数,但在idea7之后的版本中,取消了对控制台行数设置选项, 只能通过更改配置文件进行 ...

  9. spring 3.2.2后springjdbc中不用queryforInt了

    今天才发现,原来spring 3.2.2之后,jdbctemplate中的queryForInt已经被取消了! 参考博客:http://jackyrong.iteye.com/blog/2086255

  10. C# Newtonsoft.Json反序列化为dynamic对象之后的使用

    通过Newtonsoft.Json将一个json类型的字符串反序列化为dynamic后直接使用报错 源代码: namespace ConsoleApplication1 { class Program ...