Java实现各大经典排序算法(插入、希尔、简单选择、冒泡、快速、归并)
2018-05-20 23:58
399 查看
1.插入排序
基本思想:数组中有n个元素,那么我们先把第一个元素看成一个有序数列,将第2个元素插入到前面的有序数列中,直至将第n个元素插入到前面长度为n-1的有序数列中就实现了排序。时间复杂度为O(n^2);
2.希尔排序(递减增量排序算法)
基本思想:针对直接插入排序的效率问题(1.插入 排序在对几乎已经排好序的数据 操作时,效率高,即可以达到线性排序的效率;2.一般来说插入排序是低效的,每次只能将数据移动一位。),提出的改进与升级,希尔排序是非稳定排序算法。思想如下,数组中有n个元素,首先求出k=n/2,将下标差值为k的元素利用插入排序变为有序序列,再次求出k=k/2,将下标差值为k的元素利用插入排序变为有序序列,重复上述做法,直至k=1时,执行简单插入排序,这时数组的排序完成。3.简单选择排序
基本思想:将数组分为两个部分,第一部分为已排序数组(初始为空),第二部分为待排序数组(初始为整个数组),那么排序的过程为:第一次在待排序数组中找到最小(最大)的元素,放在已排序数组中,直至待排序数组为空,排序完成。尽管与冒泡排序同为O(n^2),但简单选择排序的性能要略优于冒泡排序。4.冒泡排序
基本思想:将数组中的元素两两比较,找出最大的放到最右边(或者找出最小的放在最左边),也就是一次冒泡,下一次冒泡开始的时候,对已经找到位置的元素(已经确定顺序位置的元素)不参与本次的冒泡,直到参与冒泡的元素为0,则整个数组有序。改进思路:设置标志位,明显如果有一趟没有发生交换(flag = false),说明排序已经完成。
5.快速排序
基本思想:在待排序数组中找到一个基准值(一般为数组的首元素),第一趟扫描,将比基准值小的放在基准值的左边,将比基准值大的放在基准值右边,这样基准值的位置就正确了,再用同样的方法递归基准值左右两个部分,直至整个数组有序。时间复杂度为O(nlogn) 。
6.归并排序(二路归并)
基本思想 :首先将原始的无序序列划分成两个子序列,然后分别对每个子序列递归进行排序,最后再将有序子列合并。二路归并排序是首先将初始序列的n个记录看成是n个有序的子序列,每个子序列的长度为1,然后两两归并,得到[n/2]个长度为2(n为奇数时,最后一个序列的长度为1)的有序子序列。在此基础上,在对长度为2的有序子序列进行两两归并,得到若干个长度为4的有序子序列。以此类推,直至得到长度为n的有序序列。 时间复杂度为O(nlogn),空间复杂度为O(n+logn),如果非递归实现归并,则避免了递归时深度为logn的栈空间,那么空间复杂度为O(n)。各类排序算法的时间复杂度与空间复杂度对比表
7.代码实现
- 生成乱序数组的工具类
package com.norte.util; import java.util.Random; public class ArrayUtil { /** * @author Norte * Date:2018-5-18 * * 功能: * 利用随机函数生成一个指定大小的随机数组 * */ public ArrayUtil() { } public int[] MakeArray(int n) { int[] a = new int ; for(int i = 0; i < a.length; i++) { Random random = new Random(); //产生一个Random实例,调用nextInt(int n)生成的随机数是介于0到n的int类型整数。 a[i] = random.nextInt(100); // a[i] = (int) (Math.random() * 100); //Math.random()生成的随机数是介于0.0到1.0的double类型数值。 } return a; } public static void main(String[] args) { ArrayUtil arrayUtil = new ArrayUtil(); int[] a = arrayUtil.MakeArray(10); for(int i = 0; i < a.length; i++) { System.out.println("a[" + i +"]:" + a[i]); } } }
- 实现各种排序算法的排序类
package com.norte.sort; public class Sort { /** * @author Norte * Date:2018-5-18 * * 功能:直接插入排序 * * 基本思想:数组中有n个元素,那么我们先把第一个元素看成一个有序数列,将第2个元素插入 * 到前面的有序数列中,直至将第n个元素插入到前面长度为n-1的有序数列中就实现了排序。 * * */ public void insertSort(int[] arr) { int len = arr.length; //单独拿出数组长度,提高效率 int tmp; //要插入有序数列的数 for(int i = 1; i < len; i++) { //第一个元素不需要插入,从第二个开始 tmp = arr[i]; int j = i - 1; //有序数列的元素个数 while(j >= 0 && tmp <= arr[j]) { //将有序数列的元素从后向前,将大于tmp的依次后移 arr[j+1] = arr[j]; j--; } arr[j+1] = tmp; //找到tmp的插入位置 } } /** * @author Norte * Date:2018-5-18 * * 功能:希尔排序(递减增量排序算法) * * 基本思想:针对直接插入排序的效率问题(1.插入 排序在对几乎已经排好序的数据 操作时,效率高,即可以达到线性排序的效率; * 2.一般来说插入排序是低效的,每次只能将数据移动一位。),提出的改进与升级,希尔排序是非稳定排序算法。思想如下,数组 * 中有n个元素,首先求出k=n/2,将下标差值为k的元素利用插入排序变为有序序列,再次求出k=k/2,将下标差值为k的元素利用插 * 入排序变为有序序列,重复上述做法,直至k=1时,执行简单插入排序,这时数组的排序完成。 * */ public void sheelSort(int[] arr) { int len = arr.length; while(len != 0) { len = len >> 1; for(int i = 0; i < len; i++) { //分组,就是整个数组从0开始到结束,符合下标差值为len的子序列组数 for(int j = i + len; j < arr.length; j += len) { //子序列进行插入排序,直至len=0 int k = j - len; int tmp = arr[j]; while(k >= 0&&arr[k] >= tmp) { arr[k+len] = arr[k]; k -= len; } arr[k+len] = tmp; } } } } /** * @author Norte * Date:2018-5-18 * * 功能:简单选择排序 * * 基本思想:将数组分为两个部分,第一部分为已排序数组(初始为空),第二部分为待排序数组(初始为整个数组),那么排序的过程 * 如下:第一次在待排序数组中找到最小(最大)的元素,放在已排序数组中,直至待排序数组为空,排序完成。 * * */ public void selectSort(int[] arr) { int len = arr.length; int minIndex; for(int i = 0; i < len - 1; i++) { //控制选择的次数 minIndex = i; for(int j = i + 1; j < len; j++) { //找出待排序数组中的最小元素的下标minIndex if(arr[minIndex] > arr[j]) { minIndex = j; } } if(minIndex != i) { //下标比已排序数组的最后一位小,则进行交换 arr[minIndex] = arr[minIndex] ^ arr[i]; //利用位运算交换提高效率 arr[i] = arr[minIndex] ^ arr[i]; arr[minIndex] = arr[minIndex] ^ arr[i]; } } } /** * @author Norte * Date:2018-5-20 * * 功能:冒泡排序 * * 基本思想:将数组中的元素两两比较,找出最大的放到最右边(或者找出最小的放在最左边),也就是一次冒泡, * 下一次冒泡开始的时候,对已经找到位置的元素(已经确定顺序位置的元素)不参与本次的冒泡,直到参与冒泡 * 的元素为0,则整个数组有序。 * * */ public void bubbleSort(int[] arr) { int len = arr.length; for(int i = 0; i < len; i++) { //控制循环次数 for(int j = 0; j < len - i - 1; j++) { //len - i - 1为未排序的元素个数 if(arr[j] > arr[j + 1]) { //前数比后数大则进行交换 arr[j] = arr[j] ^ arr[j + 1]; arr[j + 1] = arr[j] ^ arr[j + 1]; arr[j] = arr[j] ^ arr[j + 1]; } } } } /** * @author Norte * Date:2018-5-20 * * 功能:快速排序 * * 基本思想:在待排序数组中找到一个基准值(一般为数组的首元素),第一趟扫描,将比基准值小的放在基准值的左边, * 将比基准值大的放在基准值右边,这样基准值的位置就正确了,再用同样的方法递归基准值左右两个部分,直至整个 * 数组有序。 * */ public int getMiddle(int[] arr, int start, int end) { int tmp = arr[start]; //数组的第一个作为基准值 while(start < end) { while(end > start && arr[end] >= tmp) { //从后向前比较,不小于基准值则向前移动(end--) end --; } arr[start] = arr[end]; //小于基准值,则把该值移动到低端 while(end > start && arr[start] < tmp) { //从前向后比较,小于基准值则向后移动(start++) start++; } arr[end] = arr[start]; //不小于基准值,则把该值移动到高端 } arr[start] = tmp; //基准值到位(此时的start = end) return start; //返回基准值的下标 } public void quickSort(int[] arr, int start, int end) { if(start < end) { int middle = getMiddle(arr, start, end); //获取基准值的位置下标,将数组一分为二 quickSort(arr, start, middle - 1); //对低端序列递归排序 quickSort(arr, middle + 1, end); //对高端序列递归排序 } } /** * @author Norte * Date:2018-5-20 * * 功能:归并排序(二路归并排序) * * 基本思想 :首先将原始的无序序列划分成两个子序列,然后分别对每个子序列递归进行排序,最后再将有序子列合并。 * 二路归并排序是首先将初始序列的n个记录看成是n个有序的子序列,每个子序列的长度为1,然后两两归并,得到[n/2] * 个长度为2(n为奇数时,最后一个序列的长度为1)的有序子序列。在此基础上,在对长度为2的有序子序列进行两两归并, * 得到若干个长度为4的有序子序列。以此类推,直至得到长度为n的有序序列。 * */ public void merge(int[] arr, int start, int middle, int end) { int[] temp = new int[end - start + 1]; //临时数组,两个序列合并后存储于此 int i = start; //第一个序列的指针 int j = middle + 1; //第二个序列的指针 int k = 0; //临时数组的指针 while(i <= middle && j <= end) { //终止条件:某个序列已经全部比较完毕,代表已经有序列全部移入到临时数组中 if(arr[i] < arr[j]) { //第一个序列中较小的元素放到临时数组中 temp[k++] = arr[i++]; } else { //第二个序列中较小的元素放到临时数组中 temp[k++] = arr[j++]; } } while(i <= middle) { //如果第一个序列没有移完,则将剩下的移到临时数组中 temp[k++] = arr[i++]; } while(j <= end) { //如果第二个序列没有移完,则将剩下的移到临时数组中 temp[k++] = arr[j++]; } for(int index = 0; index < temp.length; index++) { //将临时数组的值赋给原始数组 arr[index + start] = temp[index]; } } public void mergeSort(int[] arr, int start, int end) { int middle = (end + start) / 2; if(start < end) { mergeSort(arr, start, middle); //左半边 mergeSort(arr, middle + 1, end); //右半边 merge(arr, start, middle, end); //左右合并 } } }
- 测试类
package com.norte.test; import java.util.Arrays; import com.norte.sort.Sort; import com.norte.util.ArrayUtil; public class SortTest { public static void main(String[] args) { ArrayUtil arrayUtil = new ArrayUtil(); Sort sort = new Sort(); int[] array = arrayUtil.MakeArray(10); System.out.println("排序前:" + Arrays.toString(array)); // sort.insertSort(array); //插入排序 // sort.sheelSort(array); //希尔排序 // sort.selectSort(array); //简单选择排序 // sort.bubbleSort(array); //冒泡排序 // sort.quickSort(array, 0, array.length - 1); //快速排序 sort.mergeSort(array, 0, array.length - 1); //归并排序 System.out.println("排序后:" + Arrays.toString(array)); } }
- 测试结果
相关文章推荐
- 常见内部排序算法 简单数组实现与分析(快速(偶原创partition函数,望众高手指正)、归并、希尔、插入、选择、冒泡)
- 《冒泡,选择,插入,归并,希尔,快速》排序算法java实现一览
- 六大经典排序算法(Java版):冒泡、选择、插入、希尔、快速、归并
- Java-十种内部排序实现(选择,冒泡,插入,希尔,堆,归并,快速,基数,计数,桶)及代码下载
- 排序算法总结与C++实现(冒泡、简单选择、直接插入、堆、归并、快速)
- java实现七大排序(插入,冒泡,选择,快速,堆,希尔,归并)
- Java语言实现九大排序算法(快速、归并、堆、选择、插入、计数、基数、希尔、冒泡)
- 常见排序算法C++实现(冒泡,直接插入,希尔,堆,归并,简单选择,快排)
- 001-简单的java代码实现几种排序算法(插入,快速,冒泡,选择)
- 排序算法Java描述:选择、冒泡、插入、希尔、归并、快速及三向切分快速排序
- 七大排序算法(冒泡,选择,插入,二分法排序,希尔,快速,合并,堆排序)的java实现
- 6种排序算法的简洁实现:冒泡、选择、插入、归并、快速、堆
- 排序算法复习(Java实现)(一): 插入,冒泡,选择,Shell,快速排序
- C语言实现 排序源程序(包括直接插入、希尔、冒泡、快速、简单选择、堆排序)
- 10种排序算法总结(冒泡、选择、插入、希尔、归并、快速、堆、拓扑、锦标赛、基数)
- 排序算法复习(Java实现)(二): 插入,冒泡,选择,Shell,快速排序
- 6种排序算法的简洁实现:冒泡、选择、插入、归并、快速、堆
- 排序算法复习(Java实现):插入,冒泡,选择,Shell,快速排序, 归并排序,堆排序,桶式排序,基数排序
- 排序算法大集合,插入、选择、冒泡、希尔、堆、归并、快速排序,总有一款适合你
- 排序算法复习(Java实现)(一): 插入,冒泡,选择,快速排序