[转]Java学习---7大经典的排序算法总结实现
【原文】https://www.toutiao.com/i6591634652274885128/
常见排序算法总结与实现
本文使用Java实现这几种排序。
以下是对排序算法总体的介绍。
冒泡排序
- 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
- 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
- 针对所有的元素重复以上的步骤,除了最后一个。
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
时间复杂度: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}
插入排序
- 从第一个元素开始,该元素可以认为已经被排序
- 取出下一个元素,在已经排序的元素序列中从后向前扫描
- 如果该元素(已排序)大于新元素,将该元素移到下一位置
- 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
- 将新元素插入到该位置后
- 重复步骤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}
堆排序
- 创建最大堆(Build_Max_Heap):将堆所有数据重新排序
- 堆排序(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}
快速排序
- 从数列中挑出一个元素,称为"基准"(pivot),
- 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的 摆在基准的后面(相同的数可以到任一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
- 递归地(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大经典的排序算法总结实现的更多相关文章
- Java 实现的各种经典的排序算法小Demo
由于有上机作业,所以就对数据结构中常用的各种排序算法都写了个Demo,有如下几个: 直接插入排序 折半插入排序 希尔排序 冒泡排序 快速排序 选择排序 桶排序 Demo下载地址 下面谈一谈我对这几个排 ...
- JAVA学习笔记(4)—— 排序算法
排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作.排序算法,就是如何使得记录按照要求排列的方法. 排序算法大体可分为两种: 一种是比较排序,时间复杂度O(nlogn) ...
- 深度实战玩转算法, Java语言7个经典应用诠释算法精髓
深度实战玩转算法,以Java语言主讲,通过7款经典好玩游戏,真正将算法用于实际开发,由算法大牛ACM亚洲区奖牌获得者liuyubobobo主讲,看得见的算法,带领你进入一个不一样的算法世界,本套课程共 ...
- 我们一起来排序——使用Java语言优雅地实现常用排序算法
破阵子·春景 燕子来时新社,梨花落后清明. 池上碧苔三四点,叶底黄鹂一两声.日长飞絮轻. 巧笑同桌伙伴,上学径里逢迎. 疑怪昨宵春梦好,元是今朝Offer拿.笑从双脸生. 排序算法--最基础的算法,互 ...
- java讲讲几种常见的排序算法(二)
java讲讲几种常见的排序算法(二) 目录 java讲讲几种常见的排序算法(一) java讲讲几种常见的排序算法(二) 堆排序 思路:构建一个小顶堆,小顶堆就是棵二叉树,他的左右孩子均大于他的根节点( ...
- java讲讲几种常见的排序算法
java讲讲几种常见的排序算法(一) 目录 java讲讲几种常见的排序算法(一) java讲讲几种常见的排序算法(二) 以数组array={6,3,20,8,15,1}为例 冒泡排序 思路:从第0个到 ...
- Java中常用的6种排序算法详细分解
排序算法很多地方都会用到,近期又重新看了一遍算法,并自己简单地实现了一遍,特此记录下来,为以后复习留点材料. 废话不多说,下面逐一看看经典的排序算法: 1. 选择排序 选择排序的基本思想是遍历数组的过 ...
- Java面试宝典系列之基础排序算法
本文就是介绍一些常见的排序算法.排序是一个非常常见的应用场景,很多时候,我们需要根据自己需要排序的数据类型,来自定义排序算法,但是,在这里,我们只介绍这些基础排序算法,包括:插入排序.选择排序.冒泡排 ...
- 用 Java 实现的八种常用排序算法
八种排序算法可以按照如图分类 交换排序 所谓交换,就是序列中任意两个元素进行比较,根据比较结果来交换各自在序列中的位置,以此达到排序的目的. 1. 冒泡排序 冒泡排序是一种简单的交换排序算法,以升序排 ...
随机推荐
- [Python] 震惊, 我居然用Python干这种事ꈍ .̮ ꈍ
阅读本文只需花费你两分钟, 两分钟你买不了吃亏,你也买不了上当. 那么, 为何不静下心来看看呢? Python 海龟创意绘画, Turtle库创作精美图画 Author:Amd794 E-ma ...
- Python模块: 命令行解析optionparser
Python 有两个内建的模块用于处理命令行参数:一个是 getopt,<Deep in python>一书中也有提到,只能简单处理 命令行参数:另一个是 optparse,它功能强大,而 ...
- 精读JavaScript模式(二)
我在想知识点怎么去分类,原本计划一章节一篇,但这样会会显得长短不一.更主要的是看到哪写的哪更为随意.那么这一篇还是紧接第一篇进行知识梳理,上篇说到了更优化的for循环,现在继续聊聊其它的循环方式. 1 ...
- Re:从零开始的Spring Session(一)
Session和Cookie这两个概念,在学习java web开发之初,大多数人就已经接触过了.最近在研究跨域单点登录的实现时,发现对于Session和Cookie的了解,并不是很深入,所以打算写两篇 ...
- org.hibernate.HibernateException: Wrong column type
这个问题一般出现在我们使用定长的字符串作为主键(其它字段也可能)的时候,如数据库中的ID为char(16).虽然很多资料上都说不推荐这样做,但实际上我们在做很多小case的时候自己为了方便也顾不得那么 ...
- IDEA中上传项目到GIt
一.先创建一个git仓库 二.然后在右键项目pull 三.add 最后提交: 完成
- 判断ArryaList有没有重复对象的方法
ArrayList类是List类下一种常用的子类,如果要判断容器里面的对象是否有相等,有两种方法. 下面是自定义的一个Student类,假设容器里重复是按照对象的两个属性都相等. /** * @aut ...
- Java面试题阶段汇总
初级面试题 Java面试题-基础篇一 Java面试题-基础篇二 Java面试题-集合框架篇三 Java面试题-基础篇四 Java面试题-基础篇五 Java面试题-javaweb篇六 Java面试题 ...
- 1.Strategy Pattern(策略模式)
策略模式(Strategy Pattern): 我的理解,将代码中每个变化之处抽出,提炼成一个一个的接口或者抽象类,让这些变化实现接口或继承抽象类成为具体的变化类.再利用多态的功能,可将变化之处用接口 ...
- 如何在SpringMVC中使用REST风格的url
如何在SpringMVC中使用REST风格的url 1.url写法: get:/restUrl/{id} post:/restUrl delete:/restUrl/{id} put:/restUrl ...