总结一下Java排序算法,以便记忆。算法
各种排序的时间复杂度:数组
排序方法 | 时间复杂度(平均) | 时间复杂度(最坏) | 时间复杂度(最好) | 空间复杂度 | 稳定性 | 复杂性 |
---|---|---|---|---|---|---|
直接插入排序 | O(n2)O(n2) | O(n2)O(n2) | O(n)O(n) | O(1)O(1) | 稳定 | 简单 |
希尔排序 | O(nlog2n)O(nlog2n) | O(n2)O(n2) | O(n)O(n) | O(1)O(1) | 不稳定 | 较复杂 |
直接选择排序 | O(n2)O(n2) | O(n2)O(n2) | O(n2)O(n2) | O(1)O(1) | 不稳定 | 简单 |
堆排序 | O(nlog2n)O(nlog2n) | O(nlog2n)O(nlog2n) | O(nlog2n)O(nlog2n) | O(1)O(1) | 不稳定 | 较复杂 |
冒泡排序 | O(n2)O(n2) | O(n2)O(n2) | O(n)O(n) | O(1)O(1) | 稳定 | 简单 |
快速排序 | O(nlog2n)O(nlog2n) | O(n2)O(n2) | O(nlog2n)O(nlog2n) | O(nlog2n)O(nlog2n) | 不稳定 | 较复杂 |
归并排序 | O(nlog2n)O(nlog2n) | O(nlog2n)O(nlog2n) | O(nlog2n)O(nlog2n) | O(n)O(n) | 稳定 | 较复杂 |
基数排序 | O(d(n+r))O(d(n+r)) | O(d(n+r))O(d(n+r)) | O(d(n+r))O(d(n+r)) | O(n+r)O(n+r) | 稳定 | 较复杂 |
冒泡排序(Bubble Sort)是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,若是他们的顺序错误就把他们交换过来。走访数列的工做是重复地进行直到没有再须要交换,也就是说该数列已经排序完成。这个算法的名字由来是由于越小的元素会经由交换慢慢“浮”到数列的顶端。ui
冒泡排序算法的运做以下:atom
①. 比较相邻的元素。若是第一个比第二个大,就交换他们两个。
②. 对每一对相邻元素做一样的工做,从开始第一对到结尾的最后一对。这步作完后,最后的元素会是最大的数。
③. 针对全部的元素重复以上的步骤,除了最后一个。
④. 持续每次对愈来愈少的元素重复上面的步骤①~③,直到没有任何一对数字须要比较spa
冒泡排序须要两个嵌套的循环. 其中, 外层循环移动游标; 内层循环遍历游标及以后(或以前)的元素, 经过两两交换的方式, 每次只确保该内循环结束位置排序正确, 而后内层循环周期结束, 交由外层循环日后(或前)移动游标, 随即开始下一轮内层循环, 以此类推, 直至循环结束.code
public static void bubbleSort(int[] arr){ for (int i = arr.length - 1; i > 0; i--) { //外层循环移动游标 for(int j = 0; j < i; j++){ //内层循环遍历游标及以后(或以前)的元素 if(arr[j] > arr[j+1]){ int temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; System.out.println("Sorting: " + Arrays.toString(arr)); } } } }
快速排序的基本思想:挖坑填数+分治法。xml
首先选一个轴值(pivot,也有叫基准的),经过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另外一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。blog
快速排序使用分治策略来把一个序列(list)分为两个子序列(sub-lists)。步骤为:排序
①. 从数列中挑出一个元素,称为”基准”(pivot)。递归
②. 从新排序数列,全部比基准值小的元素摆放在基准前面,全部比基准值大的元素摆在基准后面(相同的数能够到任一边)。在这个分区结束以后,该基准就处于数列的中间位置。这个称为分区(partition)操做。
③. 递归地(recursively)把小于基准值元素的子数列和大于基准值元素的子数列排序。
递归到最底部时,数列的大小是零或一,也就是已经排序好了。这个算法必定会结束,由于在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。
用伪代码描述以下:
①. i = L; j = R;
将基准数挖出造成第一个坑a[i]
。
②.j--
,由后向前找比它小的数,找到后挖出此数填前一个坑a[i]
中。
③.i++
,由前向后找比它大的数,找到后也挖出此数填到前一个坑a[j]
中。
④.再重复执行②,③二步,直到i==j
,将基准数填入a[i]
中
/** * 快速排序(递归) * * ①. 从数列中挑出一个元素,称为"基准"(pivot)。 * ②. 从新排序数列,全部比基准值小的元素摆放在基准前面,全部比基准值大的元素摆在基准后面(相同的数能够到任一边)。在这个分区结束以后,该基准就处于数列的中间位置。这个称为分区(partition)操做。 * ③. 递归地(recursively)把小于基准值元素的子数列和大于基准值元素的子数列排序。 * @param arr 待排序数组 * @param low 左边界 * @param high 右边界 */ public static void quickSort(int[] arr, int low, int high){ if(arr.length <= 0) return; if(low >= high) return; int left = low; int right = high; int temp = arr[left]; //挖坑1:保存基准的值 while (left < right){ while(left < right && arr[right] >= temp){ //坑2:从后向前找到比基准小的元素,插入到基准位置坑1中 right--; } arr[left] = arr[right]; while(left < right && arr[left] <= temp){ //坑3:从前日后找到比基准大的元素,放到刚才挖的坑2中 left++; } arr[right] = arr[left]; } arr[left] = temp; //基准值填补到坑3中,准备分治递归快排 System.out.println("Sorting: " + Arrays.toString(arr)); quickSort(arr, low, left-1); quickSort(arr, left+1, high); }
说明:快速排序每次交换的元素都有可能不是相邻的, 所以它有可能打破原来值为相同的元素之间的顺序. 所以, 快速排序并不稳定.