author: i.sshe
email: i.sshe@foxmail.com
github: https://github.com/isshe
1.快速排序
是一种分治的排序算法。切分元素的选择关系到算法的性能,因此在排序前,应先把数据打乱。
2.快速排序的过程:
1). 选择切分元素(一般选择切分区域第一个位置 k )。
2). i 指向第二个元素(第一个 k ),j指向最后一个元素。
3). i 向右移动,遇到大于等于切分元素 k 的元素时,停下。
4). j 向左移动,遇到小于等于 k 的元素时,停下。
5). 如果i < j,交换 i 和 j 两个位置的值。
6). 循环2-5过程,直到 i >= j.
7). 交换 k 位置和 i/j 位置的值。(i和j的选择,和先从左开始扫描 或 先从右开始扫描有关系)
3.1 概观:
3.2 排序过程示意图:
3.3 代码:
//这份代码是先从左边开始扫描
void quick_sort(int *array, int left, int right)
{
int i = 0;
int j = 0;
int select = 0;
int temp = 0;
if (left >= right)
{
return;
}
i = left; //or left+1
j = right;
select = array[left];
while(1)
{
while(array[i] <= select)
{
i++;
if (i == right) break;
}
while(array[j] >= select)
{
j--;
if (j == left) break;
}
if (i >= j)
{
break;
}
temp = array[i];
array[i] = array[j];
array[j] = temp;
}
temp = array[j];
array[j] = array[left];
array[left] = temp;
quick_sort(array, left, j-1);
quick_sort(array, j+1, right);
}
4. 需要注意的细节:
1). 原地切分:不要使用辅助数组,【更不要在递归的切分方法中创建空数组(不是很理解)】。
2). 别越界: 主要是切分元素是最大或最小的情况.
3). 保持随机性: 在排序前把数据打乱.
4). 终止循环: 同时注意越界问题.
5). 有元素和切分元素相同的情况: 左扫描时,>=; 右扫描时,<=;(等于是关键)
6). 终止递归: 常见错误是没有把切分元素放在正确位置.
5. 快速排序优点:
1). 内循环简洁;
2). 比较的次数少.
6.算法改进:
1). 切换到插入排序.(if (hi <= lo + M) {InsertSort(); return }), 这里的M一般取5~15, 最佳值和系统有关.
2). 三取样切分: 选择数组中一小部分元素的中位数来切分数组.(一小部分一般取3!)[代价是需要计算中位数]
3). 熵最优的排序: 实际应用中,一般都有大量重复元素, 这时候采用三向切分能提高性能.
4). 三向切分: 把数据分三部分,左边小于切分元素,中间等于,右边大于. (lt标记小于部分,i标记等于,gt标记大于)
7. 三向切分
三向切分概观:
三向切分排序过程示意图:
三向切分代码:
void quick_sort3way(int *array, int left, int right)
{
int lt = 0;
int i = 0;
int gt = 0;
int v = 0;
if (left >= right)
{
return ;
}
v = array[left]; //选择的元素
lt = left;
i = left + 1;
gt = right;
while (i <= gt)
{
if (array[i] < v)
{
exchange(array, lt, i);
lt++;
i++;
}
else if (array[i] > v) //注意这里,i不用++
{
exchange(array, i, gt);
gt--;
// i++;
}
else
{
i++;
}
}
quick_sort3way(array, left, lt - 1);
quick_sort3way(array, gt + 1, right);
}
参考资料:
- <<算法 第四版>>