算法回顾——快排
今天再复习一下快排:
当初看左神的算法课,受益匪浅。
他是先讲解了荷兰国旗问题,然后再引出的快排,如下:
荷兰国旗问题:
给定一个数组arr,和一个数num,请把小于num的数放在数组的左边,等于num的数放在数组的中间,大于num的数放在数组的右边。
要求时间复杂度为O(N)、额外空间复杂度为O(1)。
分析:三个指针法:一个指向前头less,一个指向尾部more,一个是当前下标cur。当前下标由指向前面的指针推着前进。
public static int[] partition(int[] arr, int L, int R, int num) { int less = L-1; //小于 int more = R+1; //大于【特别注意+1】 int cur = L; //等于 while (cur<more) { if (arr[cur]<num) { swap(arr,++less,cur++); }else if (arr[cur]>num) { swap(arr,--more,cur);//【特别注意cur】 }else { cur++; } } return arr; } private static void swap(int[] arr, int i, int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; }
快排
根据荷兰国旗问题,变形,让num=arr[arr.length-1],即是将比较的基准值变成数组arr的末尾值;
另外使得 R= arr.length-2; 将R变成数组 arr 中的倒数第二个值;
这样就形成了快排;
在这里,引入了一个“分治”的思想,以及求分治的边界点;
//根据荷兰国旗问题改进 public int[] quickSort3(int arr, int left, int right){ if(left<right){ int[] p = partition3(arr,left,right);//获得大小区间的临界 quickQort3(arr,left,p[0]);//递归小区间 quickQort3(arr,p[1],right);//递归大区间 return arr; } } public int[] partition3(int[] arr, int L,int R){ int left = L-1; int right = R;//这里和荷兰国旗不一样 int cur = L; while(cur<right){ if(arr[cur] < arr[R]){ swap(arr,++left,cur++); }else if(arr[cur] > arr[R]){ swap(arr,cur,--right); }else{ cur++; } } swap(arr,R,right);//① :这里和荷兰国旗不一样:交换当前比对值到中间相等区; return new int[]{left+1,right};//②:这里和荷兰国旗不一样:返回小区间的右临界和大区间的左临界; }
注:
在① 处:其实是把当前的比对基准值arr[R] 和大区间的左侧边界进行交换,这样 [L, left+1)就是小区间,(right,R]就是大区间【注意区间开闭,对应 ② 步】;
常学常乐
Over......