感觉在网上查找到的有关quickSort的资料都不是很详细或简洁,特把自己的理解做个总结,记录,以待分享。
1、时间复杂度及推导思想:
快排的平均时间复杂度为O(nlog(n)),最差为O(n*n)。
其时间复杂度的推到可利用二叉树的思想:切分的次数是树高n,查找的次数为logn,总的时间复杂度为nlog(n)。
数学推导思想:首先我们请注意到,所有实际的排序操作都在partition中做完的,因为排序从根本上来讲还是元素的交换,那么在partition函数中进行了多少次比较就是整个算法复杂度的关键。
如果将A中的元素排列成S (z1,z2,…,zn),zi表示第i小元素。在整个排序过程中,任意两个元素最多比较一次。如果我们定义一个变量Xij,当zi和zj发生比较时为1,否则为0。那么
把对所有可ij求和Xij就得到全部的比较次数。我们对这个和求期望,根据期望的线性性,也就是zi和zj发生比较的概率的总和。
那么zi和zj发生比较的概率是多少呢?在Sij这个子集合里,只有zi或zj被选为pivot的时候他们才会有比较,而平均来讲,这个概率是2/(j-i+1)。这就是S中任意两个元素发生比较的概
率。如果不在这个集合里呢?
因此所有比较次数的表达式是Sum(2/(j-i+1)), i从1到n-1,j从i+1到n。
他可以变形为n个Sum(2/k)k从1到n。
最终得到n*lg(n)。
2、实现的原理及思路
快排的整体思想是随机挑选一个元素,对数组进行分割,以将所有比它小的元素排在前面,比它大的元素排在后面。分割反复执行,直到有序。
1)给定一个数组arr[ ],定义数组首元素的索引和尾元素的索引分别为left和right。
2)以中间位置arr[(left+right)/2]为基准点pivot。
3)从左面第一个元素开始向右搜索,即由左向右(left++),找到第一个大于pivot的值arr[left],则停止,与同样停止的arr[right]进行交换,swap(arr,left,right)。
4)从右面第一个元素开始向左搜索,即由右向左(right--),找到第一个小于pivot的值arr[right],则停止,与同样停止的arr[left]进行交换,swap(arr,left,right)。
5)重复3)、4)步操作,直到满足left==right,这时arr[left]=arr[right]=pivot,而pivot的位置就是在数组中的正确位置。
6)递归调用,对pivot的左右部分分别进行2)~ 5)的操作,最后解出问题。
核心思想代码:
void quickSort(int arr[],int left, int right){
int index = partition(arr, left, right);
if (left < index-1){//对左半部分进行切分,递归排序
quickSort(arr, left, index-1);
}
if (right > index){//对右半部分进行切分,递归排序
quickSort(arr, index, right);
}
}
int partition(int arr[],int left, int right){
int pivot = arr[(left+right)/2];//选取一个基准点
while(left <= right){
while (arr[left] < pivot) left++;//指针从左面开始向基准点移动,直到不满足条件停止
while (arr[right] > pivot) right--;//指针从右面开始向基准点移动,直到不满足条件停止
//对停止的左右两个元素进行换位,调整左右索引值,然后继续循环
if(left <= right){
swap(arr, left, right);
left++;
right--;
}
}
return left;//返回的位置满足arr[left]=arr[right]=pivot
}
void swap(int arr[],int left,int right){
int temp;
temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
}
java可测试执行代码:
package com.company;
/**
* Created by zu on 14-10-4.
*/
public class QuickSortTest {
public static void quickSort(int arr[],int left, int right){
int index = partition(arr, left, right);
if (left < index-1){//对左半部分进行切分,递归排序
quickSort(arr, left, index-1);
}
if (right > index){//对右半部分进行切分,递归排序
quickSort(arr, index, right);
}
}
public static int partition(int arr[],int left, int right){
int pivot = arr[(left+right)/2];//选取一个基准点
while(left <= right){
while (arr[left] < pivot) left++;//指针从左面开始向基准点移动,直到不满足条件停止
while (arr[right] > pivot) right--;//指针从右面开始向基准点移动,直到不满足条件停止
//对停止的左右两个元素进行换位,调整左右索引值,然后继续循环
if(left <= right){
swap(arr, left, right);
left++;
right--;
}
}
return left;//返回的位置满足arr[left]=arr[right]=pivot
}
public static void swap(int arr[],int left,int right){
int temp;
temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
}
//打印数组
public static void print(int arry[])
{
for(int i:arry)
{
System.out.print(i+" ");
}
System.out.println();
}
public static void main(String args[]){
int arr[] = {1,43,5454,33,4,33,6,66,23,22,45,2,3,35};
int len = arr.length;
System.out.print("快速排序前数组元素为:");
print(arr);
quickSort(arr,0,len-1);
System.out.print("快速排序后数组元素为:");
print(arr);
}
}
执行结果输出:
快速排序前数组元素为:1 43 5454 33 4 33 6 66 23 22 45 2 3 35
快速排序后数组元素为:1 2 3 4 6 22 23 33 33 35 43 45 66 5454