快速排序的思想巧秒,利用分治的思想,可以极快排序数组。其基本思想分两步:
1. 给你一个数组,让你选择数组中的任意一个数作为基数,然后让数组中所有比基数小的数都放在放在基数的左边,所有比基数大的数放在基数的右边。
2. 将刚才基数的位置作为中点,将数组中基数左边的所有元素做1操作,将基数右边的所有元素做1操作。
看到步骤2,就很容易想到这里面是递归调用的。所以我们的关键任务就是如何让第一步高效快速实现。
// 选n为基准, 使左边的数都比它下, 右边的数都比它大
// 返回基准在数组中的位置
int insertToMid(int arr[], int left, int right, int n)
{
int i = left;
int j = right;
while (i < j)
{
for (; i < j; --j)
{
if (arr[j] < n)
{
arr[i] = arr[j];
++i;
break;
}
}
for (; i<j; ++i)
{
if (arr[i] > n)
{
arr[j] = arr[i];
--j;
break;
}
}
}
arr[i] = n;
return i;
}
解释一下:选取的基数是n,是外部传入的(后面可以看到其实是数组中的第一个元素)。然后让i和j分别指向数组的开头和结尾。从数组的最后开始向前找第一个比n小的数,将这个数与赋值到i位置上(比n小的数放到n的左边)。然后又从i+1位置往后找第一个比n大的数,将这个数赋值到j位置上(比n大的数放到n的右边)。(由于第一路找第一个比n小的数的时候,是总末尾开始找的,所以可以保证现在赋值的位置的右边都是比n大的数。),直到i=j的时候,就是n该放到的中间位置。然后返回i的索引位置。
看看图解:
到这里我们完成了步骤1(选取基数,排序后使基数左边的数都小于基数,让基数右边的数都大于基数,当然这里的排序不是严格的从低到高,而是一个范围大小的归类。这样基数右边的所有数都大于基数左边的数了)
//快速排序
void quickSort(int arr[], int left, int right)
{
if (left < right)
{
int mid = insertToMid(arr, left, right, arr[left]);
quickSort(arr, left, mid - 1);
quickSort(arr, mid + 1, right);
}
}
解释:这里之所以让insertToMid()
返回中间值就是为了进行递归调用,将基数左边的所有数执行步骤1,右边的所有数也执行步骤1。到最后只剩两个数的时候就,就一定为有序数列了。
图解:
快速排序的时间辅助读为 O(nlog2(n)),其快慢主要区别就是在步骤1上,当然是先步骤1可以采取自己的方法,只要能达到要求就行了。这种分治的思想还是非常先进的,感觉自己明白的又多了。
原文地址:http://blog.csdn.net/u013647382/article/details/45600647