Java 排序算法 - 冒泡、快速,选择、插入
2018-01-29 14:45
260 查看
冒泡排序
依次比较相邻的两个数,将小数放在前面,大数放在后面。即首先比较第1个和第2个数,将小数放前,大数放后。然后比较第2个数和第3个数,将小数放前,大数放后,如此继续,直至比较最后两个数,将小数放前,大数放后。重复以上过程,仍从第一对数开始比较(因为可能由于第2个数和第3个数的交换,使得第1个数不再大于第2个数),将小数放前,大数放后,一直比较到最小数前的一对相邻数,将小数放前,大数放后,第二趟结束,在倒数第二个数中得到一个新的最小数。如此下去,直至最终完成排序。
由于在排序过程中总是小数往前放,大数往后放,相当于气泡往上升,所以称作冒泡排序。
冒泡排序动态图:
![](https://img-blog.csdn.net/20180312231615413)
冒泡排序核心思路代码:
全部代码:
控制台打印结果:
快速排序
快速排序由
借一张大佬的图,传送门:http://blog.csdn.net/it_zjyang/article/details/53406764
初始数组:[3, 7, 2, 9, 1, 4, 6, 8, 10, 5]
![](https://img-blog.csdn.net/20180307191943208)
流程模拟:
初始数组
选定数组的最后一个元素
从左边开始,寻找比
从右边开始,由于
从左边开始,由于
从右边开始,从
这个时候,
快速排序核心之一:
快速排序核心之二:
完整代码如下:
控制台:
算法优缺点
快速排序最“快”的地方在于左右两边能够快速同时递归排序下去,所以最优的情况是基准值刚好取在无序区的中间,这样能够最大效率地让两边排序,同时最大地减少递归划分的次数。此时的时间复杂度仅为
快速排序也有存在不足的情况,当每次划分基准值时,得到的基准值总是当前无序区域里最大或最小的那个元素,这种情况下基准值的一边为空,另一边则依然存在着很多元素(仅仅比排序前少了一个),此时时间复杂度为
选择排序
动图:
![](https://img-blog.csdn.net/20180312232102182)
插入排序
动图:
依次比较相邻的两个数,将小数放在前面,大数放在后面。即首先比较第1个和第2个数,将小数放前,大数放后。然后比较第2个数和第3个数,将小数放前,大数放后,如此继续,直至比较最后两个数,将小数放前,大数放后。重复以上过程,仍从第一对数开始比较(因为可能由于第2个数和第3个数的交换,使得第1个数不再大于第2个数),将小数放前,大数放后,一直比较到最小数前的一对相邻数,将小数放前,大数放后,第二趟结束,在倒数第二个数中得到一个新的最小数。如此下去,直至最终完成排序。
由于在排序过程中总是小数往前放,大数往后放,相当于气泡往上升,所以称作冒泡排序。
冒泡排序动态图:
冒泡排序核心思路代码:
public static void sort(int[] arr) { for (int i = 0; i < arr.length - 1; i++) { for (int j = 0; j < arr.length - 1 - i; j++) { if (arr[j] > arr[j + 1]) { int minVal = arr[j + 1]; arr[j + 1] = arr[j]; arr[j] = minVal; } } } }
全部代码:
package com.ggsddu.domain.sort; import java.util.Arrays; import java.util.Random; import java.util.Scanner; public class BubbleSort { public static void main(String[] args) { System.out.print("输入数组长度:"); Scanner scanner = new Scanner(System.in); int n = scanner.nextInt(); int[] arr = new int ; Random random = new Random(); for (int i = 0; i < arr.length; i++) { arr[i] = random.nextInt(100); } scanner.close(); System.out.println("排序前:" + Arrays.toString(arr)); System.out.println("--------------------- 排序结束 ---------------------"); sort(arr); System.out.println("--------------------- 排序结束 ---------------------"); System.out.println("排序后:" + Arrays.toString(arr)); } public static void sort(int[] arr) { /** * 假设数组有10个元素,外层循环9次,每轮排序将此轮参与比较元素的最大值“冒泡”出去 * ----- 排序开始 * 第一轮排序:从10个元素中比较出最大值,将最大值“冒泡”到数组arr[9]的位置 * 第二轮排序:从9个元素中(已“冒泡”元素不参与后续排序)比较出最大值,“冒泡”到数组arr[8]的位置 * 第三轮排序:从8个元素中比较出最大值,“冒泡”到最后数组arr[7]的位置 * ... * 第八轮排序:从3个元素中比较出最大值,“冒泡”到最后数组arr[2]的位置 * 第九轮排序:从2个元素中比较最大值,“冒泡”到数组arr[1]的位置,则arr[0]最小不动,排在arr[0] * ----- 排序结束 */ for (int i = 0; i < arr.length - 1; i++) { /** * 内层循环控制当前轮排序的参与比较的元素(已“冒泡”元素不再参与后续排序) * 第一轮排序,参与排序的元素个数为arr.length - 1 - 0 * 第二轮排序,参与排序的元素个数为arr.length - 1 - 1 * 第三轮排序,参与排序的元素个数为arr.length - 1 - 2 * ... * 第i轮排序,参与排序的元素个数为arr.length - 1 - i */ for (int j = 0; j < arr.length - 1 - i; j++) { if (arr[j] > arr[j + 1]) { int minVal = arr[j + 1]; arr[j + 1] = arr[j]; arr[j] = minVal; } } System.out.println("第 " + (i + 1) + " 次排序:" + Arrays.toString(arr)); } } }
控制台打印结果:
输入数组长度:10 排序前:[64, 89, 36, 57, 82, 70, 40, 61, 81, 15] --------------------- 排序开始 --------------------- 第 1 次排序:[64, 36, 57, 82, 70, 40, 61, 81, 15, 89] 第 2 次排序:[36, 57, 64, 70, 40, 61, 81, 15, 82, 89] 第 3 次排序:[36, 57, 64, 40, 61, 70, 15, 81, 82, 89] 第 4 次排序:[36, 57, 40, 61, 64, 15, 70, 81, 82, 89] 第 5 次排序:[36, 40, 57, 61, 15, 64, 70, 81, 82, 89] 第 6 次排序:[36, 40, 57, 15, 61, 64, 70, 81, 82, 89] 第 7 次排序:[36, 40, 15, 57, 61, 64, 70, 81, 82, 89] 第 8 次排序:[36, 15, 40, 57, 61, 64, 70, 81, 82, 89] 第 9 次排序:[15, 36, 40, 57, 61, 64, 70, 81, 82, 89] --------------------- 排序结束 --------------------- 排序后:[15, 36, 40, 57, 61, 64, 70, 81, 82, 89] Process finished with exit code 0
快速排序
快速排序由
C. A. R. Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
借一张大佬的图,传送门:http://blog.csdn.net/it_zjyang/article/details/53406764
初始数组:[3, 7, 2, 9, 1, 4, 6, 8, 10, 5]
流程模拟:
初始数组
arr:[3, 7, 2, 9, 1, 4, 6, 8, 10, 5],期望结果:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
选定数组的最后一个元素
5作为基准值,也就是
最终排序结果应该是以
5为界限划分为左右两边且有序
从左边开始,寻找比
5大的值,然后与
5进行调换(比
5小的值保持原状,排在
5前面,比
5大的值与
5调换位置排
5的后面),此轮找到
7,将
7与
5调换,结束此次遍历。
从右边开始,由于
7已经是上一轮排好序的便不再动它,此轮从
10开始,向左遍历,寻找比
5小的值,然后与
5进行调换(比
5大的值保持原状,排在
5后面,比
5小的值与
5调换位置排
5的后前面),此轮找到
4,将
4与
5调换,结束此次遍历。
从左边开始,由于
3和
4都是前两轮已经排好序的便不再动它,从
2开始,向右遍历,寻找比
5大的值,然后与
5进行调换(道理同步骤
1),此轮找到
9,将
9与
5调换位置,结束此次遍历。
从右边开始,从
1开始,向右遍历,寻找比
5小的值,然后与
5进行调换(道理同步骤
2),此轮找到
1,将
1与
5调换,结束此次遍历。
这个时候,
5的左右两侧符合左侧值
<=5,右侧值
>=5,所以结束此轮排序。
5的左右两侧继续抽出来各自进行下一轮的排序,规则同上,直到无法再拆分下去,即完成了整体的快速排序。
快速排序核心之一:
public static int divide(int[] arr, int start, int end) { int base = arr[end]; while (start < end) { while (start < end && arr[start] <= base) { start++; } if (start < end) { int temp = arr[start]; arr[start] = arr[end]; arr[end] = temp; end--; } while (start < end && arr[end] >= base) { end--; } if (start < end) { int temp = arr[start]; arr[start] = arr[end]; arr[end] = temp; start++; } } int borderPostion = start == end ? start : -1; return borderPostion; }
快速排序核心之二:
public static void sort(int[] arr, int start, int end) { if (start > end) { return; } else { int borderPostion = divide(arr, start, end); sort(arr, start, borderPostion - 1); sort(arr, borderPostion + 1, end); } }
完整代码如下:
package com.ggsddu.domain.sort; import java.util.Arrays; import java.util.Random; import java.util.Scanner; public class QuickSort { public static void main(String[] args) { int[] arr = new int[]{3, 7, 2, 9, 1, 4, 6, 8, 10, 5}; System.out.println("排序前:" + Arrays.toString(arr)); sort(arr, 0, arr.length - 1); System.out.println("排序后:" + Arrays.toString(arr)); } /** * 快速排序 * * @param arr * @param start * @param end */ public static void sort(int[] arr, int start, int end) { if (start > end) { return; } else { // 如果不止一个元素,继续划分两边递归排序下去 int borderPostion = divide(arr, start, end); System.out.print(borderPostion + " ");// 以某个基准值为界每一次划分元素排序后,此基准值所在位置 System.out.println(Arrays.toString(arr)); sort(arr, start, borderPostion - 1);// 基准值左侧元素递归排序 sort(arr, borderPostion + 1, end);// 基准值右侧元素递归排序 } } /** * 对数组某一段元素进行划分 * 以基准值为界,左侧数都大于基准值,右侧数都大于基准值 * 形象表示为:[{A|num<=基准值} 基准值 {B|num>=基准值}] * * @param arr * @param start 开始遍历的位置 * @param end 基准值的初始位置 * @return 每一次划分元素,基准值所在位置 */ public static int divide(int[] arr, int start, int end) { int base = arr[end];// 默认以最右边的元素作为基准值 // 一旦start等于end,就说明左右两个指针合并到了同一位置,可以结束此轮循环 while (start < end) { while (start < end && arr[start] <= base) { start++;// 从左边开始向右遍历,如果如果遍历的值比基准值小,下标start就继续向右走 } // 上面的while循环结束时,就说明当前的arr[start]的值比基准值大,应与基准值位置进行交换 if (start < end) { //交换 int temp = arr[start]; arr[start] = arr[end]; arr[end] = temp; // 此值与基准值交换位置后,被“排序”,并且“占领”了原end的位置,排序范围缩小,end向前移动一位 end--; } while (start < end && arr[end] >= base) { end--;// 从右边开始遍历,如果遍历的值比基准值大,下标end就继续向左走 } // 上面的while循环结束时,就说明当前的arr[end]的值比基准值小,应与基准值进行交换 if (start < end) { // 交换 int temp = arr[start]; arr[start] = arr[end]; arr[end] = temp; // 此值与基准值交换后,被“排序”,并且“占领”原start的位置,排序范围缩小,所以start同时向后移动一位 start++; } } // 返回start或end皆可,因为此时start和end都为基准值所在的位置 int borderPostion = start == end ? start : -1; return borderPostion; } }
控制台:
排序前:[3, 7, 2, 9, 1, 4, 6, 8, 10, 5] 4 [3, 4, 2, 1, 5, 9, 6, 8, 10, 7] 0 [1, 4, 2, 3, 5, 9, 6, 8, 10, 7] 2 [1, 2, 3, 4, 5, 9, 6, 8, 10, 7] 1 [1, 2, 3, 4, 5, 9, 6, 8, 10, 7] 3 [1, 2, 3, 4, 5, 9, 6, 8, 10, 7] 6 [1, 2, 3, 4, 5, 6, 7, 8, 10, 9] 5 [1, 2, 3, 4, 5, 6, 7, 8, 10, 9] 8 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 7 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 9 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 排序后:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] Process finished with exit code 0
算法优缺点
快速排序最“快”的地方在于左右两边能够快速同时递归排序下去,所以最优的情况是基准值刚好取在无序区的中间,这样能够最大效率地让两边排序,同时最大地减少递归划分的次数。此时的时间复杂度仅为
O(NlogN)。
快速排序也有存在不足的情况,当每次划分基准值时,得到的基准值总是当前无序区域里最大或最小的那个元素,这种情况下基准值的一边为空,另一边则依然存在着很多元素(仅仅比排序前少了一个),此时时间复杂度为
O(N*N)。
选择排序
动图:
插入排序
动图:
相关文章推荐
- 七大排序算法(冒泡,选择,插入,二分法排序,希尔,快速,合并,堆排序)的java实现
- 六大经典排序算法(Java版):冒泡、选择、插入、希尔、快速、归并
- 《冒泡,选择,插入,归并,希尔,快速》排序算法java实现一览
- java 排序算法总结(冒泡,选择,插入,快速)
- java排序之冒泡、插入、选择、快速等排序算法
- 【转】排序算法复习(Java实现)(一): 插入,冒泡,选择,Shell,快速排序
- 排序算法复习(Java实现)(一): 插入,冒泡,选择,Shell,快速排序
- 001-简单的java代码实现几种排序算法(插入,快速,冒泡,选择)
- 排序算法Java描述:选择、冒泡、插入、希尔、归并、快速及三向切分快速排序
- 各种排序算法-Java-冒泡、选择、插入、快速、归并排序
- 冒泡、快速、直接插入、选择排序算法(Java语言实现)
- 排序算法复习(Java实现)(一): 插入,冒泡,选择,Shell,快速排序
- 排序算法复习(Java实现)(一): 插入,冒泡,选择,Shell,快速排序
- 排序算法复习(Java实现)(二): 插入,冒泡,选择,Shell,快速排序
- 排序算法复习(Java实现):插入,冒泡,选择,Shell,快速排序, 归并排序,堆排序,桶式排序,基数排序
- 排序算法复习(Java实现)(一): 插入,冒泡,选择,快速排序
- 基础排序算法,java实现(快速,冒泡,选择,堆排序,插入)
- 排序算法复习(Java实现): 插入,冒泡,选择,Shell,快速排序
- 常见的排序算法(Java实现):冒泡、插入、选择、快速排序
- Java之美[从菜鸟到高手演变]之常见的几种排序算法-插入、选择、冒泡、快排、堆排等