快速排序的算法思路:
快速排序中,算法先对数组进行重新整理分割成两个子数组,再对两个子数组进行排序,当两个子数组是有序时,整个数组即为有序的。
下面给出具体代码:
package javastudy;
public class QuickSort {
public void quickSort(int[] A, int n) {
// 快速排序
qSort(A, 0, n - 1);
}
public void qSort(int[] A, int left, int right) {
// 枢轴
int pivot;
if (left < right) {
/**
* pivot的初值:为切割点(第一次排完序后切割点的位置)
*/
pivot = partition(A, left, right);
/**
* 以此切割点为基础 左边的比切割点小 右边的比切割点大 进行递归排序
*/
qSort(A, left, pivot - 1);
qSort(A, pivot + 1, right);
}
}
/**partition是寻找到第一次排序后的被当做切割点元素的位置(这个元素的位置也就是最后排完序的位置)
* 需要注意到:这个元素的选取通过median3函数来确定
* 当确定这个元素的位置后,我们仅仅只是排完一次序,并没有达到我们最后的效果
*/
public int partition(int[] A, int left, int right) {
/** 优化选取元素,采用三数取中的方法来确定开始要选取的那个元素
* 也就是被当做切割点的元素的值
*/
int pivotKey = median3(A, left, right);
/**
* while(left<right)这是个大的前提,当low等于high的时候,证明一次的排序结束
*/
while (left < right) {
/**
* 这里的low<high一定要加 不然就超出整个数组范围,程序会标报错
*/
while (left < right && A[right] >= pivotKey) {
right--;
}
/**
* 条件:A[hight]< pivotKey
*/
A[left] = A[right];
while (left < right && A[left] <= pivotKey) {
left++;
}
/**
* 条件:A[left]> pivotKey
*/
A[right] = A[left];
}
/**
* 循环结束的时候:low一定和high是相等的,然后把切割点val的值赋给循环跳出来的a[low]或者a[high]都行
*/
A[left] = pivotKey;
/**
* 返回此时这个切割点元素的下标
*/
return left;
}
// 通过三数取中来确定基数(切割点的元素)
public int median3(int[] A, int left, int right) {
int mid = (right - left) / 2;
if (A[left] > A[right]) {
swap(A, left, right);
}
if (A[mid] > A[left]) {
swap(A, mid, left);
}
if (A[mid] > A[right]) {
swap(A, mid, right);
}
return A[left];
}
public void swap(int[] A, int i, int j) {
int temp = A[i];
A[i] = A[j];
A[j] = temp;
}
}
主函数测试一下:
package javastudy;
public class MainTest {
public static void main(String[] args) {
QuickSort sort = new QuickSort();
int A[] = { -2, -5, -1, -88, 9 };
sort.qSort(A, 0, A.length - 1);
for (int i : A) {
System.out.print(i + " ");
}
}
}
快速排序
时间性能取决于递归的深度,可以用递归树来描述递归算法的执行情况!最优情况下,partition每次划分均匀,排序n个数值,则递归树的深度为[logn]+1,第一次partition需要对整个数组扫描一遍,做n次比较,第二次对一半扫描。所以最优时间复杂度 Ο(n log n) ,最差时间复杂度 Ο(n^2) ,平均时间复杂度Ο(n log n) 。
递归导致栈空间的使用,最好空间复杂度为Ο(log n),最差空间复杂度Ο(n)。