快速排序的分治法的一个典型应用,其时间复杂度是O(logN)。
比如将6,12,1,4,7,15,3这7给元素进行排序。首先选出一个基准值,一般是选用第一个元素,这里也就是6。然后开始从最右边开始寻找比基准值小的元素放到基准值的左边,然后从左开始寻找比基准值大的元素放大基准值的右边。
其执行过程:
第一趟:基准值6 用一个变量来保存。
设置两个哨兵,i=0,j=6。从右开始找比基准值小的元素,也就是不断的j–来判断下标为j的元素是否比基准值小,注意到3比6小,将3放到下标为i的位置(此时j的值为6),然后i++。从左开始找比基准值大的元素,也就是不断的i++来判断下标为i 的怨谁呢是否比基准值大,注意到12比6大,将12放到j所指向的位置(此时i的值为1),然后j–。
就变成了i=1,j=5。
接着从有开始寻找比6小的元素,注意到4比6小,将4放到下标为i的元素(此时i已经变成1了,j变成3了)。然后找比6大的元素,注意此时j为3,i为1,一直把i++来寻找比6大的数,一直寻找到i为3的时候,此时i已经不小于j了,都没有找到比基准值6小的数,所以此轮结束。然后将基准值填入i的位置也就是下标为3的位置。
下轮以这次的基准值6为界,将整个序列分为两个部分,分别对左半部分和右半部分分别进行快速排序。
第二轮:
对左半部分排序:
取基准值3,i=0,j=2。
从右开始寻找比3小的数注意到是1,将1放到下标为i(0)的位置,然后i++,变为1。然后从左开始寻找比3的数注意到是4,将4放到下标为j的位置(2),然后j–,j变成了1,此时i已经不小于j,这一趟排序也结束了,将基准值3放到下标为i(1)的位置。
对右半部分排序:
基准值为7,i=4,j=6。
从右开始寻找比7小的数,j一直自减到4也没有发现比7小的数,此时i已经不小于j了,此时这一趟排序结束,注意到这一趟排序只做了比较并没有交换任何一组数据。
对左右两部分都做了排序,此时这一轮已经排序结束了。
第三轮:
注意到上一轮对左半部分的排序,以3为基准时,3的左边只有1,右边只有4,都只有一个元素,说明这一部分已经全部排序完毕了。
上一轮对右半部分的排序,以7为基准时,7的左边没有元素,只用对7右边的元素进行排序。
此时以15为基准,i=5,j=6。
从右开始寻找比15小的元素,此时为12,将12放到i的位置,然后i++。此时i变成6了,i不再小于j,将基准值放到i的位置。这一轮结束。
这个时候已经全部有序了。
实现代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define N 10
void sort(int a[], int left, int right);
int main()
{
int a[N];
srand((unsigned) time(NULL));
//随机生成数组的值
for (int i = 0; i < N ; i++)
a[i] = rand();
printf("排序前\n");
for (int i = 0; i < N; i++)
{
printf("%d\n", a[i]);
}
sort(a, 0, N - 1);
printf("排序后\n");
for (int i = 0; i < N; i++)
{
printf("%d\n", a[i]);
}
return 0;
}
void sort(int a[], int left, int right)
{
if (left < right)
{
int i = left, j = right;
//每次将待排序序列的最左边一个元素作为基准数
int temp = a[left];
while (i < j)
{
//从右开始寻找比基准数小的元素
while (a[j] >= temp && j > i)
{
j--;
}
if (j > i)
{
a[i] = a[j];
i++;
}
//从左开始寻找比基准数大的元素
while (a[i] <= temp && j > i)
{
i++;
}
if (j > i)
{
a[j] = a[i];
j--;
}
}
//将基准数放到他的位置
a[i] = temp;
//进行左半部分的排序
sort(a, left, i - 1);
//进行右半部分的排序
sort(a, i + 1, right);
}
}
实现效果: