

- 稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面。
- 不稳定:如果a原本在b的前面,而a=b,排序之后 a 可能会出现在 b 的后面。
1. 冒泡排序(已经会了,就不做笔记了)
时间复杂度分析:
- 最坏的情况是每一个元素都要从前面交换到最后面,每排好一个元素就要遍历一遍数组,一共要排好n个元素,需要O(n^2)的时间复杂度
- 最好的情况是遍历一遍数组就可排好,O(n)
空间复杂度:不需要额外的空间,O(1)
2. 快速排序
思想:找一个基准值,保证每递归一次基准值的左边都小于等于基准值,右边都大于等于基准值
算法描述:
- 用数组的最左边的值作为基准值
- 右指针从数组的最右边开始找第一个小于基准值的数(说明这个数的右边都大于等于基准值)
- 左指针再从数组的最左边开始找第一个大于基准值的数(说明这个数的左边都小于等于基准值)
- 交换这两个数
- 直到左右两个指针重合,此时指向的数是小于基准值的数(因为是右指针先动的),交换基准值和当前左右指针指向的元素
- 以当前左右指针的位置为分界点递归调用快排方法(递归退出条件是没有要排序的元素时,即左指针大于等于右指针)
1 public class Solution { 2 3 public static void main(String[] args){ 4 int[] nums = {23,46,0,8,11,18}; 5 Solution sol = new Solution(); 6 sol.quickSort(nums, 0, nums.length-1); 7 for(int i = 0; i < nums.length; i++){ 8 System.out.println(nums[i]); 9 } 10 } 11 12 //快速排序算法 13 private void quickSort(int[] nums, int low, int high){ 14 if(low >= high) return;//注意这里是>=而不是== 15 int pivot = nums[low];//用第一个元素作为基准值 16 int left = low; 17 int right = high; 18 while(left < right){ 19 //必须先找右边的第一个小于基准值的数,如果先从左边开始找第一个大于基准值的数的话, 20 //最后合基准值交换位置的就会是比基准值大的数了。 21 while(left < right && nums[right] >= pivot) 22 right--; 23 while(left < right && nums[left] <= pivot) 24 left++; 25 if(left < right) 26 swap(nums, left, right); 27 } 28 swap(nums, low, left); 29 quickSort(nums, low, left-1); 30 quickSort(nums, left+1, high); 31 } 32 33 private void swap(int[] nums, int i, int j){ 34 int tmp = nums[i]; 35 nums[i] = nums[j]; 36 nums[j] = tmp; 37 } 38 }
时间复杂度分析:
T(1) = 1;
T(n) = 2*T(n/2) + a*n;(a为常数,每次合并时,复杂度为O(n))
= 2*(2*T(n/4)+a*n/2) + a*n
= 4*T(n/4) + 2*a*n
= 4*(2*T(n/8)+a*n/4) + 2*a*n
= 8*T(n/8) + 3*a*n
=......
= 2^k*T(1) + k*a*n (其中n==2^k,即k=log2(n))
= n + a*n*log2(n);
所以平均和最好的时间复杂度是每次都能对半分,是O(nlogn)
最坏的情况是每次其中一边的元素个数为0的时候,是O(n^2)
非递归快排https://blog.csdn.net/mine_song/article/details/64121553
快排升级版,快速选择算法https://zhuanlan.zhihu.com/p/64627590,http://www.noteanddata.com/classic-algorithm-quick-select.html
3. 归并排序
算法描述:
- 把长度为n的输入序列分成两个长度为n/2的子序列;
- 对这两个子序列分别采用归并排序;
- 将两个排序好的子序列合并成一个最终的排序序列。
1 public class Solution { 2 3 public static void main(String[] args){ 4 int[] nums = {23,46,0,8,11,18}; 5 Solution sol = new Solution(); 6 sol.mergeSort(nums, 0, nums.length-1); 7 for(int i = 0; i < nums.length; i++){ 8 System.out.println(nums[i]); 9 } 10 } 11 12 //归并排序算法 13 private void mergeSort(int[] nums, int start, int end){ 14 if(start >= end) 15 return; 16 int mid = start + (end - start)/2; 17 mergeSort(nums, start, mid); 18 mergeSort(nums, mid+1, end); 19 merge(nums, start, mid, end); 20 } 21 22 private void merge(int[] nums, int start, int mid, int end){ 23 int[] tmp = new int[end-start+1]; 24 int p1 = start; 25 int p2 = mid+1; 26 int k = 0; 27 //2路归并,将两个排好序的数组排成一个有序的数组 28 while(p1 <= mid && p2 <= end){ 29 if(nums[p1] <= nums[p2]) 30 tmp[k++] = nums[p1++]; 31 else 32 tmp[k++] = nums[p2++]; 33 } 34 while(p1 <= mid) 35 tmp[k++] = nums[p1++]; 36 while(p2 <= end) 37 tmp[k++] = nums[p2++]; 38 39 //把排好序的子数组复制到原数组 40 for(int i = start; i <= end; i++) 41 nums[i] = tmp[i-start]; 42 } 43 }
时间复杂度分析:归并排序的时间复杂度不受输入数据的影响,没有最好和最坏之分,都是O(nlogn)。
空间复杂度:需要一个额外的数组的内存空间,O(n)
4. 选择排序
选择排序(Selection-sort)是一种简单直观的排序算法。它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
时间复杂度:无论什么数据都是O(n^2)的时间复杂度。
5. 插入排序
插入排序(Insertion-Sort)的算法描述是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
算法描述:
一般来说,插入排序都采用in-place在数组上实现。具体算法描述如下:
- 从第一个元素开始,该元素可以认为已经被排序;
- 取出下一个元素,在已经排序的元素序列中从后向前扫描;
- 如果该元素(已排序)大于新元素,将该元素移到下一位置;
- 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;
- 将新元素插入到该位置后;
- 重复步骤2~5。
1 public class Solution { 2 3 public static void main(String[] args){ 4 int[] nums = {23,46,0,8,11,18}; 5 Solution sol = new Solution(); 6 sol.insertionSort(nums); 7 for(int i = 0; i < nums.length; i++){ 8 System.out.println(nums[i]); 9 } 10 } 11 12 //插入排序算法 13 private void insertionSort(int[] nums){ 14 //可以认为第一个数已经排好序 15 for(int i = 1; i < nums.length; i++){ 16 int cur = nums[i]; 17 int preindex = i - 1; 18 19 while(preindex >= 0 && nums[preindex] > cur){ 20 nums[preindex+1] = nums[preindex]; 21 preindex--; 22 } 23 nums[preindex+1] = cur; 24 } 25 } 26 }
时间复杂度分析:
最好的情况是内层循环没有循环次数,输入数据几乎是排好序的状态,O(n)
最坏的情况是内层循环要一直遍历到第一个元素,O(n^2)
6. 希尔排序
直接插入排序的升级版,以增量为分组,进行组内的插入排序,直至增量为1,即只有一个分组,再进行插入排序后排序即完成。
浙公网安备 33010602011771号