浅谈快速排序的二三应用
大家都知道快排算法,快速排序算法的应用是非常广泛的,这里举出几个例子,谈一谈快速排序算法的应用。快速排序的思想不仅用于单纯的排序问题,对于很多查找类问题,快排算法能达到最小的时间复杂度,是最优解法之一。
首先先java实现一个快速排序函数:
1 private int partition(int[] arr, int l, int h){ 2 int p = arr[l]; 3 int i=l; int j = h+1; 4 while(true){ 5 while(i!=h && arr[++i]<p); 6 while(j!=l && arr[--j]>p); 7 8 if(i >= j){ 9 swap(arr, i, j); 10 break; 11 } 12 } 13 swap(arr, l, j); 14 return j; 15 }
1. 求一个数组里面最小的k个数
通过调用快速排序的 partition() 方法,会返回一个整数 j ,要让得 a[l..j-1] 小于等于 a[j],且 a[j+1..h] 大于等于 a[j],此时 a[j] 就是数组的第 j 大元素。可以利用这个特性找出数组的第 K 个元素,这种找第 K 个元素的算法称为快速选择算法。这种算法时间复杂度为O(N) + O(1)。使用最小堆求解的话时间复杂度不变。代码如下:
1 public List<Integer> GetLeastNumbers(int[] nums, int k){ 2 List<Integer> ret = new ArrayList<>(); 3 if(nums.length == 0 || k>nums.length || k<0) 4 return new ArrayList<Integer>(); 5 6 findKthSmallest(nums, k-1); 7 8 for (int i = 0; i < k; i++) 9 ret.add(nums[i]); 10 return ret; 11 } 12 13 private void findKthSmallest(int[] nums, int k) { 14 int l = 0; 15 int h = nums.length-1; 16 17 while(l<h){ 18 int res = partition(nums, l, h); 19 20 if(res == k){ 21 return; 22 23 }else if(res<k){ 24 l= res+1; 25 }else{ 26 h=res-1; 27 } 28 } 29 } 30 31 private int partition(int[] arr, int l, int h){ 32 int p = arr[l]; 33 int i=l; int j = h+1; 34 while(true){ 35 while(i!=h && arr[++i]<p); 36 while(j!=l && arr[--j]>p); 37 38 if(i >= j){ 39 swap(arr, i, j); 40 break; 41 } 42 } 43 swap(arr, l, j); 44 return j; 45 } 46 47 private void swap(int[] arr, int i, int j) { 48 int temp = arr[i]; 49 arr[i] = arr[j]; 50 arr[j] = temp; 51 52 }
2 求数组中出现次数超过一半的数
容易理解次数超过一半的那个数必然是这个数组的中位数,依次可以使用快排来寻找数组的中位数,时间复杂度为O(n),java代码如下所示
1 public int MoreThanHalfNum(int[] nums){ 2 3 if(nums.length == 0 || nums == null) 4 return 0; 5 6 int ret = 0; 7 int end = nums.length-1; 8 int start = 0; 9 int middle = end/2; 10 11 int index = partition(nums, start, end); 12 13 while(index != middle){ 14 if(index < middle) index=partition(nums, index+1, end); 15 if(index > middle) index=partition(nums, start, index-1); 16 } 17 18 ret = nums[middle]; 19 20 return ret; 21 } 22 23 private int partition(int[] arr, int l, int h){ 24 int p = arr[l]; 25 int i=l; int j = h+1; 26 while(true){ 27 while(i!=h && arr[++i]<p); 28 while(j!=l && arr[--j]>p); 29 30 if(i >= j) 31 break; 32 33 swap(arr, i, j); 34 35 } 36 swap(arr, l, j); 37 return j; 38 } 39 40 private void swap(int[] arr, int i, int j) { 41 int temp = arr[i]; 42 arr[i] = arr[j]; 43 arr[j] = temp; 44 45 }
时间复杂度为o(n)。
永远不要忘记过去,永远不要放弃未来。