快速排序算法:
对于一个待排序列,确认出一个基准值key,将将序列分为小于基准值和大于等于基准值的两个序列,然后再将这两个序列再进行之前的操作分成新的两列,不断往下循环操作使数组分到的数组越来越小,如果分到的新序列里的元素为1或者为0,那么这个序列就是有序的了。
key值可以定为待排序列的第一个元素或者最后一个元素,对待排序列的分组操作有三种实现思想。
1.按基准值互划分左右区间:
- huver法
- 挖坑法
- 前后指针法
1. 1hover法(前后指针法)
定义两个指针,begin指向待排序列的第一个元素,end指向待排序列的倒数第二个元素,将最后一个元素定位基准值key。
begin向后移动,当begin所指向的元素小于key时向后移动一个元素,当begin指向的元素大于等于key时begin停止后移,开始移动end,当end指向的元素大于等于key时,end向前移动一位,当end指向元素小于key时停止移动。交换begin和end指向元素,然后继续向后移动begin,大于key停止,向前移动end,小于key停止,begin和end交换所指向元素的值。重复指向这个操作,直至end和begin指向同一个元素。这是将这个元素和基准值进行交换。此时的序列就分为了小于begin指向的基准值的左边序列,和大于等于基准值的右边序列。
int hover(int array[], int left, int right){
int begin = left;
int end = right - 1;
int key = array[right];
while (begin < end){
while (begin<end&&array[begin] < key)
begin++;
while (begin<end&&array[end] >= key)
end--;
Swap(array + begin, array + end);
}
Swap(array + begin, array + right);
return begin;
}
1.2挖坑法
“挖坑法”听名字就是要从待排序列中取出一个元素,让序列中“空”出一个元素出来。第一步确定基准值key,将待排序列的最后一个元素定为基准值,将这个基准值“挖”出来,定义两个指针分别指向待排序列的第一个元素和倒二个元素分别为begin和end,begin所指向的元素小于key,begin向后移动,当begin指向元素大于key时,将这个元素“挖”出来将之前“挖”出的空填起来,然后移动end指针,当end指向的元素大于等于key时,向前移动一位,否则将end指向的元素“挖”起来,去“填”前面的坑,然后又开始向后移动begin,大于key就“挖”起来填后面的坑,向前移动end指针重复上面的操作,依次移动两个指针,直至两个指针指向同一个位置,而且这个位置是个“坑”,用key“填”这个“坑”,此时待排序列就被分为左边小于key的左序列,和右边大于等于key的右序列。
int potholing(int array[], int left, int right){
int key = array[right];
int begin = left;
int end = right;
while(begin < end){
while (begin < end&&array[begin] < key)
begin++;
array[end] = array[begin];
while (begin < end&&array[end] >= key)
end--;
array[begin] = array[end];
}
array[begin] = key;
return begin;
}
1.3前后指针法
老规矩先确定基准值key为待排序列的最后一个元素,定义两个指针begin(初始化为待排序列的第一个位置),prev(初始化为待排序列的第一个位置之前的位置),分别指向右区间最后一个元素(大于等于基准值),左区间最后一个元素(小于基准值),begin,prev为元素的数组下标。两个指针都是先后移动。
先移动begin,当begin指向的元素大于key时begin向后移动,否则prev向后移动一位,交换两个指针指向元素的值,继续向后移动begin,循环以上操作,当begin遍历过待排序列的最后一个元素之后,循环结束,prev指向的元素的值就是key的值。此时待排序列就被分为左边小于key的左序列,和右边大于等于key的右序列。
int PartSort(int array[], int left, int right){
int key = array[right];
int begin = left;
int prev = left - 1;
while (begin <= right){
if (array[begin] <= key){
prev++;
if (prev != begin)
Swap(array + begin, array + prev);
}
begin++;
}
return prev;
}
2.快排实现
按照基准值将待排序列分为左区间后还需继续对两个区间在进行以上三种方法的划分,直至得到的子区间只有一个元素或者没有元素
void _QuickSort(int array[], int left, int right) {
// 终止条件 size == 0 || size == 1
// left == right 区间内还剩一个数
// left > right 区间内没有数
if (left == right) {
return;
}
if (left > right) {
return;
}
int div; // 比基准值小的放基准值左边,大的放右边后,基准值所在的下标
div = PartSort(array, left, right); // 遍历 array[left, right],把小的放左,大的放右
//div=hover(array,left,right);
//div=potholing(array, left, right);
_QuickSort(array, left, div - 1); // 分治解决左边的小区间
_QuickSort(array, div + 1, right); // 分治解决右边的小区间
}
总结:
快速排序整体的综合性能和使用场景都是比较好的,所以才敢叫快速排序
时间复杂度:O(N*logN)
稳定性:不稳定