快速排序

来源:互联网 发布:集线器端口的电涌 编辑:程序博客网 时间:2024/06/03 19:10

快速排序

思想:

快速排序的思想巧秒,利用分治的思想,可以极快排序数组。其基本思想分两步:
1. 给你一个数组,让你选择数组中的任意一个数作为基数,然后让数组中所有比基数小的数都放在放在基数的左边,所有比基数大的数放在基数的右边。
2. 将刚才基数的位置作为中点,将数组中基数左边的所有元素做1操作,将基数右边的所有元素做1操作。
看到步骤2,就很容易想到这里面是递归调用的。所以我们的关键任务就是如何让第一步高效快速实现。

代码:

先看代码,我们来实现步骤1:

// 选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(选取基数,排序后使基数左边的数都小于基数,让基数右边的数都大于基数,当然这里的排序不是严格的从低到高,而是一个范围大小的归类。这样基数右边的所有数都大于基数左边的数了

然后再完成步骤2就简单了,看看代码:

//快速排序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可以采取自己的方法,只要能达到要求就行了。这种分治的思想还是非常先进的,感觉自己明白的又多了。

提供另外一种将讲数插入中间, 使左边数都比它小, 右边数都比它大的方法, 自己琢磨一下, 代码很简洁

int partion(int A[], int left, int right){    int point = A[right];    int index = left;    for(int i=index; i<=right; ++i){        if(A[i] <= point){            swap(A[i], A[index]);            index++;        }    }    return index-1;}
0 0
原创粉丝点击