参考来源:
官方描述
在待排席表L[1..n]中任取一个元素pivot作为枢轴(或基准,通常取首元素),通过一趟排序将待排序表划分为独立的两部分L[1..k-1]和Lk+1..n],使得L[1..k-1]中的所有元素小于pivot,L[k+1..n]中的所有元素大于等于pivot,则pivot放在了其最终位置L(k)上,这个过程称为一次“划分”。然后分别递归地对两个子表重复上述过程,直至每部分内只有一个元素或空为止,即所有元素放在了其最终位置上。
图解
个人理解:(以上图举例)
第一个元素49为基准(并拿出来)0号位成为待交换位,high指针(从右向左找小的)依次比较小于基准49的,发现27符合,便与基准位交换位置(准确来说是基准位置的元素替换成了27,是赋值操作),此时high位成为待交换位(待替换位)。low指针同理...(high指针找到(并替换)一个后便由low指针去进行同样操作,两个轮起来)
当high和low相同时,表示该基准点已经确定了位置,第一轮结束
后面几轮便以前一轮基准作划分点,继续划分表,(不考虑前一轮基的基准点,再分别定义新的:基准、high指针、low指针)。当划分到左、右子表中元素个数小于等于1时,表示子表排序完成
效率分析
每次划分越平均(基准越接近平均值)效率越高 时间复杂度:O(nlong2^n) 空间复杂度:O(long2^n)
初始表越有序(每次比较都找不到目标交换元素),递归越深,越接近最坏情况,效率越低 时间复杂度:O(n^2) 空间复杂度:O(n)
代码实现
public static int sort(int a[], int low, int high) { //这里的参数low、high可理解为每次划分后的值
int pivot = a[low]; // 通常用表的第一个记录做基准
while (low< high) { // 用low、high从表的两端交替向中间扫描(一旦low==high此轮排序结束)
while ( a[high] >= pivot && low< high) {
high--; // 从右向左到小于基准的,没找到便继续移动(忽略掉大于基准的)
}
a[low] = a[high]; // (不满足循环条件即找到了)该元素移动到左端
while ( a[low] < pivot && low< high) {
low++; // 从左向右找大于基准的,没找到便继续移动(忽略掉小于基准的)
}
a[high] = a[low]; // (不满足循环条件即找到了)该元素移动到右端
}
a[low] = pivot; // 将基准数安放到最终位置(便确定了该元素位置,此时low==high)
// a[high] = pivot; // 效果一样
return low; // 返回基准点
}
public static void quickSort(int a[], int low, int high) {
if (low < high) { // 递归条件
int pivotPos = sort(a,low,high); // 将该方法返回的基准点作为划分点
quickSort(a, low, pivotPos- 1); // 划分左子表进行排序(递归调用)
quickSort(a, pivotPos+ 1, high); // 划分右子表进行排序(递归调用)
}
}
//再封装一层,主程序直接传数组就行(封装思想)(自个想法可省略)
public static int[] QuickSort(int[] array) {
quickSort(array, 0, array.length - 1);
return array;
}
public static void main(String[] args) {
int a[] = { 49, 38, 65, 97, 76, 13, 27, 49,-45 };
QuickSort(a);
System.out.println(Arrays.toString(a)); //输出结果
}