写在前面
快速排序在排序算法中算是效率较高的算法之一,快排也经常被采用,在工作面试、考研都有可能会遇到。我在初学快排的时候基本是复制粘贴别人的代码,不能理解快排是怎么实现的,最近重新看了看快排算法的思想,尝试写了快排算法,虽然碰到几个问题,但是最后基本能写出来了。在这里把我碰到的问题和我的想法写一写。
快排基本思想
快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序。它采用了一种分治的策略,通常称其为分治法(Divide-and-ConquerMethod)。
该方法的基本思想是:
-
先从数列中取出一个数作为基准数。
-
分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
-
再对左右区间重复第二步,直到各区间只有一个数。
快排算法实现
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MAXSIZE 100
void quicksort(int *, int, int);
int main()
{
int data[MAXSIZE];
time_t t;
srand((unsigned)time(&t));
// 随机生成20个数
for(int i=1;i<=20;i++)
{
data[i] = rand() % 100;
}
for(int i=1;i<=20;i++)
{
printf("%d ", data[i]);
}
printf("\n");
// 快排
quicksort(data, 1, 20);
for(int i=1;i<=20;i++)
{
printf("%d ", data[i]);
}
printf("\n");
return 0;
}
void quicksort(int *data, int start, int end)
{
// 其实快排中不必要每次取start和end的中间值,这样做增加理解难度,而且容易忘掉data[mid] = data[start];这句代码
int mid = (start + end) / 2;
int temp = data[mid]; // 如果比较的基准值使用数组中间位置的数,那么必须要有下面的一句
data[mid] = data[start]; // 没有这一句会出现数组中数值错乱
int i = start, j = end;
while(i < j)
{
// 下面的data[j]必须要写成>=temp,不能写成>,如果写>会发生死循环,会出现在data[j]==temp时
// >=也是导致快排不稳定的原因
while(i < j && data[j] >= temp)
j--;
data[i] = data[j];
while(i < j && data[i] <= temp)
i ++;
data[j] = data[i];
}
data[i] = temp;
if(start < i - 1)
quicksort(data, start, i-1);
if (i + 1 < end)
quicksort(data, i+1, end);
}
碰到的问题和我的一些想法
- 我设置了基准值为start和end的中点的数据,但是在排完序之后出现很多数据被替换掉。对应的错误写法。
void quicksort(int *data, int start, int end)
{
int mid = (start + end) / 2;
int temp = data[mid]; // 如果比较的基准值使用数组中间位置的数,那么必须要有下面的一句
int i = start, j = end;
while(i < j)
{
// 下面的data[j]必须要写成>=temp,不能写成>,如果写>会发生死循环,会出现在data[j]==temp时
// >=也是导致快排不稳定的原因
while(i < j && data[j] >= temp)
j--;
data[mid] = data[j];
while(i < j && data[i] <= temp)
i ++;
data[j] = data[i];
}
data[i] = temp;
if(start < i - 1)
quicksort(data, start, i-1);
if (i + 1 < end)
quicksort(data, i+1, end);
}
首先,代码12行就会造成数据丢失。循环里面每次都会修改data[mid]的值,而没有保存data[mid]的数据,导致出现丢失。实际应该做的是每次修改的都是下标为 i 和 j 位置的值,除了第一次修改data[i],每次修改data[i]时,data[j]会保存住data[i]的值,同理修改data[j]的值时,data[i]会保存住data[j]的值。
- 虽然设置了基准值为start和end的中点的数据,while循环内的复制也只涉及到data[i]和data[j],但是会造成数据丢失。错误写法为:
void quicksort(int *data, int start, int end)
{
int mid = (start + end) / 2;
int temp = data[mid]; // 如果比较的基准值使用数组中间位置的数,那么必须要有下面的一句
int i = start, j = end;
while(i < j)
{
// 下面的data[j]必须要写成>=temp,不能写成>,如果写>会发生死循环,会出现在data[j]==temp时
// >=也是导致快排不稳定的原因
while(i < j && data[j] >= temp)
j--;
data[i] = data[j];
while(i < j && data[i] <= temp)
i ++;
data[j] = data[i];
}
data[i] = temp;
if(start < i - 1)
quicksort(data, start, i-1);
if (i + 1 < end)
quicksort(data, i+1, end);
}
还是第12行导致的错误。每次调用quicksort函数的时候,第一次要修改的data[i]的值没有保存住,都会丢失。
文中都是我个人的理解,如有错误的地方欢迎下方评论告诉我,我及时更正,大家共同进步