快速排序:
快速排序也属于交换排序,它是对冒泡排序的改进。它的基本思想:
(1)从当前序列中选择一个元素作为分界元素,称为支点。定义两个指针i,j,让j指针从后往前找,找到第一个比支点小的元素和支点交换。让i指针从前往后找,找到第一个比支点大的元素与支点交换。这样,最终找到支点的位置k.
(2)以支点的位置为中心,把序列分为左右两个部分,分别对左右两个部分进行上述过程。直到子序列的长度为1,从而整个序列有序。
快速排序算法的JAVA实现:
第一种:双向交换,选择最左边的端点为轴,从j向前找时,把轴元素与比它小的元素交换,然后从i向后找时,把轴元素与比它大的元素交换。
第二种:单向交换,选择最左边的端点为轴,从j向前找时,把比它小的元素r[i]=r[j].然后i从前向后找。把比轴大的元素r[j]=r[i].
第三种:中心交换。选择中间的端点为轴,从j向前找到比轴的小的元素,从i向后找到比轴大的元素,然后把它们交换。这样,轴左边的元素始终比轴小,轴右边的元素始终比轴大。
下面是这三种算法的JAVA实现:
public class QuickSort {
/**
*
* 快速排序算法:先找到一个基准,然后分别从左右进行寻找,从左边找到第一个比这个轴大的元素
* 从右边找到第一个比这个轴小的元素进行交换,直到右边的指针大于左边的指针为止.然后在左右两边 在选择轴进行递归的进行上述操作.
*
* @param args
*/
public static void main(String[] args) {
int[] s = { 13, 15, 7, 10, 20, 4, 8, 19 };
// s = quicksort(s, 0, s.length - 1);
s = quicks(s, 0, s.length - 1);
for (int i : s) {
System.out.print(i + " ");
}
}
public static int[] quickd(int[] num, int left, int right) {
if (left < right) {
int k = doublequick(num, left, right);
System.out.println("k=" + k);
quickd(num, left, k - 1);
quickd(num, k + 1, right);
}
return num;
}
public static int[] quicks(int[] num, int left, int right) {
if (left < right) {
int k = singlequick(num, left, right);
System.out.println("k=" + k);
quicks(num, left, k - 1);
quicks(num, k + 1, right);
}
return num;
}
//双向交换
public static int doublequick(int[] s, int left, int right) {
int i = left;
int j = right;
int temp;
int x = s[i];// 左边第一个元素为轴,进行交换,从而得到x的正确位置
while (i < j) {
while (i < j && s[j] >= x)
j--;// 首先从右向左找,找到第一个比x小的,然后和x交换
temp = s[j];
s[j] = s[i];
s[i] = temp;
while (i < j && s[i] <= x)
i++;// 然后从左向右找,找到第一个比x大的,然后和x交换
temp = s[j];
s[j] = s[i];
s[i] = temp;
}
return i;
}
//单向交换
public static int singlequick(int[] s, int left, int right) {
int i = left;
int j = right;
int x = s[left];
while (i < j) {
while (i < j && s[j] >= x)
j--;
s[i] = s[j];
while (i < j && s[i] <= x)
i++;
s[j] = s[i];
}
s[i] = x;
System.out.println("i=" + i);
return i;
}
//中间为轴,左右交换
public static int[] quicksort(int[] s, int left, int right) {
// 关键字的先取
int i = left;
int j = right;
int middle = s[(i + j) / 2];
System.out.println(middle);
do {
while (i <= right && middle > s[i])
i++;// 找到第一个大小等于middle的元素
while (j >= left && middle < s[j])
j--;// 找到第一个小于middle元素
if (i <= j) {// 表示找到此元素
// 进行交换
int temp = s[j];
s[j] = s[i];
s[i] = temp;
i++;
j--;
}
} while (i <= j);
for (int k : s) {
System.out.print(k + " ");
}
if (left < j) {
// 左部分递归调用
System.out.println("j=" + j);
quicksort(s, left, j);
}
if (right > i) {
// 右部分递归调用
System.out.println("i=" + i);
quicksort(s, i, right);
}
return s;
}
}
性能分析:
时间复杂度:
快速排序的采用递归,其深度为logn,由于每一次划分元素交换n次,所以时间复杂度为nlogn.
空间复杂度:
递归的深度为logn,每一次递归需要一个单元的辅助空间用于交换,因此,空间复杂度为logn.
稳定性:
由于划分轴过程中存在着交换,所以快速排序不稳定。
快速排序的空间复杂度与归并排序空间复杂度的区别:
我们知道,快速排序与归并排序都采用递归,然而快速排序是从上向下进行递归的,即从上向下交换。所以所需要的最大辅助空间为logn.
而归并排序是从上向上递归,即从下向上合并的,最先是两个元素合并,逐渐合并到n个元素的有序序列。因此,归并排序的所需要的最大辅助空间为O(n). 这与快速排序是有区别的。
至于快速排序的实例,可参考http://www.cnitblog.com/liaoqingshan/archive/2008/03/19/41163.html。