- 引自百度百科
快速排序由C. A. R. Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
- 算法介绍
设要排序的数组是Array[0]……Array[N-1],首先任意选取一个数据(通常选用数组的第一个数)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序。值得注意的是,快速排序不是一种稳定的排序算法,也就是说,多个相同的值的相对位置也许会在算法结束时产生变动。
一趟快速排序的步骤:
1)设置两个变量i、j,排序开始的时候:i=0,j=N-1;
2)以第一个数组元素作为关键数据,赋值给key,即key=Array[0];
3)从j开始向前搜索,即由后开始向前搜索(j--),找到第一个小于等于key的值Array[j],将Array[j]的值赋给Array[i];
4)从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于等于key的Array[i],将Array[i]的值赋给Array[j];
5)重复第3、4步,直到i=j; (3,4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值,使得j=j-1,i=i+1,直至找到为止。找到符合条件的值,进行交换的时候i, j指针位置不变。另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束)。
过程演示
下标 | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|
数据 | 6 | 2 | 7 | 3 | 8 | 9 |
i=0, j=5, k=6
创建变量i=0(指向第一个数据), j=5(指向最后一个数据), k=6(赋值为第一个数据的值)。
我们要把所有比k小的数移动到k的左面,所以我们可以开始寻找比6小的数,从j开始,从右往左找,不断递减变量j的值,我们找到第一个下标3的数据比6小,于是把数据3移到下标0的位置,把下标0的数据6移到下标3,完成第一次比较:
下标 | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|
数据 | 3 | 2 | 7 | 6 | 8 | 9 |
i=0, j=3, k=6
接着,开始第二次比较,这次要变成找比k大的了,而且要从前往后找了。递加变量i,发现下标2的数据是第一个比k大的,于是用下标2的数据7和j指向的下标3的数据的6做交换,数据状态变成下表:
下标 | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|
数据 | 3 | 2 | 6 | 7 | 8 | 9 |
i=2, j=3, k=6
称上面两次比较为一个循环。
接着,再递减变量j,不断重复进行上面的循环比较。
本例中进行一次循环后,j--,得到i==j,一次快排结束
注意:第一遍快速排序不会直接得到最终结果,只会把比k大和比k小的数分到k的两边。为了得到最后结果,需要再次对k值两边的数组分别执行此步骤,然后再分解数组,直到数组不能再分解为止(只有一个数据),才能得到正确结果。
- C语言实现
void quickSort(int *array, int leftIndex, int rightIndex) {
if(leftIndex >= rightIndex) {/*如果左边索引大于或者等于右边的索引就代表已经整理完成一个组了*/
return ;
}
int i = leftIndex;
int j = rightIndex;
int key = array[leftIndex];
while(i < j) {/*控制在当组内寻找一遍*/
while(i < j && array[j] >= key) {
/*而寻找结束的条件就是,1、找到一个小于或者大于key的数(大于或小于取决于你想升
序还是降序)2、没有符合条件1的,并且i与j的大小没有反转*/
j--;/*向前寻找*/
}
array[i] = array[j];
/*找到一个这样的数后就把它赋给前面的被拿走的i的值(如果第一次循环且key是
array[left],那么就是给key)*/
while(i < j && array[i] <= key) {
/*这是i在当组内向前寻找,同上,不过注意与key的大小关系停止循环和上面相反,
因为排序思想是把数往两边扔,所以左右两边的数大小与key的关系相反*/
i++;
}
array[j] = array[i];
}
array[i] = key;/*当在当组内找完一遍以后就把中间数key回归*/
quickSort(array, leftIndex, i - 1);/*最后用同样的方式对分出来的左边的小组进行同上的做法*/
quickSort(array, i + 1, rightIndex);/*用同样的方式对分出来的右边的小组进行同上的做法*/
/*当然最后可能会出现很多分左右,直到每一组的i = j 为止*/
}
- OC实现
- (void)quickSortArray:(NSMutableArray *)array withLeftIndex:(NSInteger)leftIndex andRightIndex:(NSInteger)rightIndex {
if (leftIndex >= rightIndex) {//如果数组长度为0或1时返回
return ;
}
NSInteger i = leftIndex;
NSInteger j = rightIndex;
//记录比较基准数
NSInteger key = [array[i] integerValue];
while (i < j) {
/**** 首先从右边j开始查找比基准数小的值 ***/
while (i < j && [array[j] integerValue] >= key) {//如果比基准数大,继续查找
j--;
}
//如果比基准数小,则将查找到的小值调换到i的位置
array[i] = array[j];
/**** 当在右边查找到一个比基准数小的值时,就从i开始往后找比基准数大的值 ***/
while (i < j && [array[i] integerValue] <= key) {//如果比基准数小,继续查找
i++;
}
//如果比基准数大,则将查找到的大值调换到j的位置
array[j] = array[i];
}
//将基准数放到正确位置
array[i] = @(key);
/**** 递归排序 ***/
//排序基准数左边的
[self quickSortArray:array withLeftIndex:leftIndex andRightIndex:i - 1];
//排序基准数右边的
[self quickSortArray:array withLeftIndex:i + 1 andRightIndex:rightIndex];
}
- 时间复杂度
最好和平均的时间复杂度为O(nlogn)
最坏的时间复杂度为O(n^2)