什么是快速排序
通冒泡排序一样,快速排序也属于叫唤排序,通过元素之间的比较和交换来达到目的。不同的是,冒泡排序在每一轮中只把1个元素冒泡到数列另一端,而快排则在每一轮挑选一个基准元素,并让其他比他大的元素移到数列一边,比它小的移到另一边,相当是把数列拆成了两个部分。这种思路其实叫分治法。
选定基准元素(pivot)
在分治过程中,以基准元素为中心,把其它元素移动到它的左右两边。那么怎么选基准元素呢?最简单的就是选数列第一个元素。还有就是随机选择数列中一个元素。不过都存在一个问题就是选的基准元素会是数列中最小的或者最大的值,在这种极端情况下,快速排序需要进行N轮,时间复杂度就退化成了O(n^2),不过平均时间复杂度还是保持在O(nlogn)。
元素交换排序过程
一、双边循环法:数组两边交换遍历元素。
选出基准元素pivot,确定2个指针left跟right
- right指针开始,right指向元素跟基准元素比较,如果大于或等于pivot,指针向左移动。小于基准则停止移动,切换到left指针。
- left指针移动,跟基准元素比较,如果小于等于pivot,指针向右移动,如果大于pivot,指针停止移动。
- 由于6>3,left在元素6的位置停下,让left与right指针所指向的元素进行交换。
按照此方法,一直循环比交换。
当循环到right指针和left指针重合的时候跟pivot基准元素交换。进行下一轮循环交换。
代码递归实现:
private static void quickSort(int[] arr,int startIndex,int endIndex){
//递归结束条件
if (startIndex >= endIndex){
return;
}
//得到基准元素
int pivotIndex = partition(arr,startIndex,endIndex);
//根基基准元素,分成两部分进行递归排序
quickSort(arr,startIndex,pivotIndex-1);
quickSort(arr,pivotIndex+1,endIndex);
}
/**
* 双边循环法
* @param arr 待交换数组
* @param startIndex 起始下标
* @param endIndex 结束下标
* @return left
*/
private static int partition(int[] arr, int startIndex, int endIndex) {
//取第一个元素也可以随机取作为基准元素
int pivot = arr[startIndex];
int left = startIndex;
int right = endIndex;
while (left != right){
//控制right指针比较并左移
while (left<right && arr[right]> pivot){
right--;
}
//控制left指针比较并右移
while (left<right && arr[left] <= pivot){
left++;
}
//交换left和right指针指向的元素
if (left<right){
int temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
}
}
//pivot和指针重复交换
arr[startIndex] = arr[left];
arr[left] = pivot;
return left;
}
public static void main(String[] args) {
int[] arr = {4,7,2,5,6,1,8};
quickSort(arr,0,arr.length-1);
System.out.println(Arrays.toString(arr));
}
二、单边循环法:从数组一边对元素遍历交换元素。
选定基准元素pivot,设置mark指针指向数组起始位置,mark指针代表小于基准元素的区域边界。
1、从基准元素的下一个位置开始遍历数组。如果遍历到的大于基准,就继续向后遍历。
2、如果遍历到的小于基准,需要做两件事:
- 把mark指针右移一位。
- 最近遍历到的与mark指针所在位置元素交换位置。
如图遍历到的是2>3,所以mark右移一位到2元素上面。在跟3元素交换位置得到下图。
接下来依照以上方法一直交换到顺序排列位置。
代码递归实现:
private static void quickSort(int[] arr,int startIndex,int endIndex){
//递归结束条件
if (startIndex >= endIndex){
return;
}
//得到基准元素
int pivotIndex = partition(arr,startIndex,endIndex);
//根基基准元素,分成两部分进行递归排序
quickSort(arr,startIndex,pivotIndex-1);
quickSort(arr,pivotIndex+1,endIndex);
}
/**
* 单边循环法
* @param arr 待交换数组
* @param startIndex 起始下标
* @param endIndex 结束下标
* @return left
*/
private static int partition(int[] arr, int startIndex, int endIndex) {
//取第一个元素也可以随机取作为基准元素
int pivot = arr[startIndex];
int mark = startIndex;
for (int i = startIndex+1; i < endIndex; i++) {
if (arr[i]<pivot){
mark ++;
int temp = arr[mark];
arr[mark] = arr[i];
arr[i] = temp;
}
}
//pivot和指针重复交换
arr[startIndex] = arr[mark];
arr[mark] = pivot;
return mark;
}
public static void main(String[] args) {
int[] arr = {4,7,2,5,6,1,8};
quickSort(arr,0,arr.length-1);
System.out.println(Arrays.toString(arr));
}