算法笔记-快速排序
最近准备将算法捡起来,感觉又痛苦又很爽,很多时候一个小细节错了要找半天问题,明明思路对了,但是就是和自己想的有一些差别,我想这是很多小伙伴学习的时候都会有的感受吧(绝对不是我太菜了)。
今天研究了一下快排算法,快排的思路其实也不是很复杂,首先尽量找到数组中一个相对居中的数,然后将大的数放在右边,小的数放在数组左边(这种指的是按从小到大排序,也可以根据自身需求改变),然后无限递归直到可以保证数组有序(一般是子数组只有一个元素),不理解的可以看下图帮助理解:
标注颜色的就是选中的相对居中的数,但是我们在写代码的时候如何直到哪个是相对居中的数呢,那就只能先随机找一个数了(保证算法复杂度尽量不受数据状况影响),接下来我们看代码实现:
我们已经知道快排的核心思想是将数组调整为选中数左边右边相对有序,我们首先看这块的实现方式:
/** * 这里使用r作为对比数, * 先将所有比r小的数放左边相等的数放中间,大于的数放右边 * 最后将r与大数最左边交换,最终得到完整小等大三个区域,下面用low和high分割 */ private static void partition(int[] arr, int l, int r){ int low = l-1; int high = r; while(l < high){ //当前数比 if(arr[l] < arr[r]){ swap(arr, l++, ++low); }else if(arr[l] < arr[r]){ swap(arr, l, --high); }else{ l++; } } swap(arr, high++,r); }
这个方法可以将一个数组切割为三部分相对有序,那么我们如何实现数组中所有数都有序呢: 如果左右两部分都只有一个数,那么是不是就一点是有序的,要做到这个我们就必须要递归循环,直到只有一个数,代码如下:
private static void quickSort(int[] arr, int l, int r) { //此处是为了校验数组中是否只有一个数 if(l < r){ //随机一个数,保证数据随机性 swap(arr, (int)(Math.random() * (r-l+1))+l, r); int[] p = partition(arr, l, r); //递归左右继续排序 quickSort(arr,l,p[0]); quickSort(arr,p[1],r); } }
这里partition方法做了一点改动:返回了切割的两个点下标。
private static int[] partition(int[] arr, int l, int r){ int low = l-1; int high = r; while(l < high){ //当前数比 if(arr[l] < arr[r]){ swap(arr, l++, ++low); }else if(arr[l] > arr[r]){ swap(arr, l, --high); }else{ l++; } } swap(arr, high++,r); return new int[]{low,high}; }
快排就写这么多,后面继续分享学习经验。