C语言快速排序算法及三种优化方式

C语言快速排序算法及三种优化方式

1. 原理

快速排序的基本思想就是从一个数组中任意挑选一个元素(通常来说会选择最左边的元素)作为中轴元素,将剩下的元素以中轴元素作为比较的标准,将小于等于中轴元素的放到中轴元素的左边,将大于中轴元素的放到中轴元素的右边,然后以当前中轴元素的位置为界,将左半部分子数组和右半部分子数组看成两个新的数组,重复上述操作,直到子数组的元素个数小于等于1。


2. 快速排序复杂度分析

2.1 时间复杂度

  • 在最好情况下,快速排序算法的时间复杂度为O(nlogn)
  • 在最坏情况下,待排序的序列为正序或者逆序,每次划分只得到一个臂上次划分少一个记录的子序列,而且另一个序列还为空。如果递归树画出来,它就是一棵斜树。此时需要执行(n-1)次递归调用,且第i次划分需要经过i-1次关键字的比较才能找到第i个记录,即中轴元素的位置,因此比较次数为:n-1+n-2+n-3+…+1 = n*(n-1)/2 时间复杂度为O(n^2)

2.2 空间复杂度

  • 在最好情况下,递归树的深度为logn,其时间复杂度为O(logn)
  • 在最坏情况下,需要进行n-1次递归调用,其空间复杂度为O(n)

3. 快速排序代码实现

3.1 普通快速排序

普通快速排序代码如下

/***************************
Author:tmw
date:2017-11-5
*************************/
#include <stdio.h>
#include <stdlib.h>

/**普通快速排序**/
//选取序列中的第一个元素作为中轴元素
int first_ele_fast_sort( int array[] , int low , int high )
{
    int target = array[low];//选取最左边元素为中轴
    while( low < high )
    {
        while( low < high && array[high] >= target )
            high--;//high为数组最右边下标
        //交换
        int temp;
        temp = array[high];
        array[high] = array[low];//当前low的位置存的是target值
        array[low] = temp;

        while( low < high && array[low] <= target )
            low++;
        //交换
        temp = array[low];
        array[low] = array[high];//经上一轮交换,当前high位置存的是target值
        array[high] = temp;
    }
    return low;//返回当前中轴元素下标值
}

int* first_ele_fast_sort_all( int array[] , int low , int high )//这里的high为array_len-1
{
    if( low < high )
    {
        int target_index;
        target_index = first_ele_fast_sort(array,0,high);//数组元素从0下标开始存

        first_ele_fast_sort(array,0,target_index-1);//对中轴元素左边快排
        first_ele_fast_sort(array,target_index+1,high);//对中轴元素的右边快排
    }
    return array;
}

3.2 快速排序优化1—-三数取中&&优化不必要的交换

优化点:
优化选取中轴元素

以上代码target 选取的位置是认定了数组元素的首位,但是若这个数值的大小不在整个数组的中间位置,会大大降低快排的性能。target = array[low] 这句就成了一个潜在的性能瓶颈。因此快速排序的速度还取决于这个target关键元素在数组中的位置。
【改进方法】
三数取中法:去三个元素先进行排序,将中间数作为中轴元素,下面的代码选取数组的左、中、右三个数;

优化交换

将上一个代码中的交换改成直接赋值,减少了多次交换数据的操作,在性能上又得到了部分提高

优化1的快速排序代码如下:

/*************************
Author:tmw
date:2017-11-5
**************************/

#include <stdio.h>
#include <stdlib.h>
/**快速排序优化----三数取中&&优化不必要的交换**/
//取三个元素先进行排序,将中间值作为中轴元素,选取左端、右端、中间三个数,也可以随机选取
int Three_choose_one_optimize_fastSort( int array[] , int low , int high )
{
    int mid = ( low + high ) / 2;
    if( array[high] < array[low] )
    {
        int temp1;
        temp1 = array[high];
        array[high] = array[low];
        array[low] = temp1;
    }
    if( array[high] < array[mid] )
    {
        int temp2;
        temp2 = array[high];
        array[high] = array[mid];
        array[mid] = temp2;
    }//以上,保证high为三个值当中最大值的下标
    if( array[mid] > array[low] )//将low作为中间值的下标
    {
        int temp3;
        temp3 = array[low];
        array[low] = array[mid];
        array[mid] = temp3;
    }//以上,完成了三数取中,此时array[low]即可作为快排优化后的中轴元素

    int target = 0;
    target = array[low];

    while( low < high )
    {
        while( low < high && array[high] >= target  )
            high--;
        array[low] = array[high];//此时high位置上的元素为待处理元素

        while( low < high && array[low] <= target   )
            low++;
        array[high] = array[low];//将大于target值的元素放到待处理的high位置上,那么此时,low位置变为待处理
    }
    array[low] = target; //以上,省去交换,变为“挖坑赋值”,降低时间复杂度
    return low;
}
void fast_sort( int array[] , int low , int high )
{
    if( low < high )
    {
        int index;
        index = Three_choose_one_optimize_fastSort(array,low,high);
        fast_sort(array,low,index-1);
        fast_sort(array,index+1,high);
    }
}

3.3 快速排序优化2—-优化递归操作:

递归对性能是有一定影响的,快排在其尾部有两次递归操作,如果待排序的序列划分极端不平衡,递归深度将趋近于n,而不是平衡时的logn。这就不仅仅是速度快慢的问题了,栈的大小是有限的,每次递归调用都会耗费一定的栈空间,函数的参数越多,每次递归耗费的空间也越多,因此,减少递归会大大提高性能

  • 下面是用一次迭代来换取一次递归的代码,此代码主要对快排的递归部分修改,中轴元素的选取和排序部分代码沿用优化1方案的。
/*************************
Author:tmw
date:2017-11-5
**************************/

#include <stdio.h>
#include <stdlib.h>

int Three_choose_one_optimize_fastSort( int array[] , int low , int high )
{
    int mid = ( low + high ) / 2;
    int temp;
    if( array[low] > array[high] )
    {
        temp = array[low];
        array[low] = array[high];
        array[high] = temp;
    }
    if( array[mid] > array[high] )
    {
        temp = array[high];
        array[high] = array[mid];
        array[mid] = temp;
    }//以上,high位置的元素为三者中的最大
    if( array[low] < array[mid] )
    {
        temp = array[low];
        array[low] = array[mid];
        array[mid] = temp;
    }//以上,low位置的元素为三者中第二大元素

    int target = array[low];
    while( low < high )
    {
        while( low < high && array[high] > target )
            high--;
        array[low] = array[high];

        while( low < high && array[low] < target )
            low++;
        array[high] = array[low];
    }
    array[low] = target;
    return low;
}

void interate_replace_one_recursion_fastSort( int array[] , int low , int high )
{
    int index;
    while( low < high )//迭代换递归,这里从if换成while
    {
        index = Three_choose_one_optimize_fastSort(array,low,high);

        interate_replace_one_recursion_fastSort(array,low,index-1);
        low = index+1;
    }
}

3.4 快速排序优化3—-优化小数组时的排序方案

以上两种优化方法是充分利用了快速排序解决大数组排序强大的功能,那么相反的情况,当数组非常小,其实快速排序不如直接插入排序来的好。
本质原因还是因为快速排序用到了递归,在大量数据排序时,这点性能影响可以通过上面的优化方法忽略掉,但是对于一个只有几个元素的数组需要排序时,用快排就像“大炮打蚊子”。

解决方案就是设定一个判断分支:
当数组长度大于7,则使用优化2的快排
当数组长度小于7,则使用直接插入排序

(有资料认为7这个设定比较合理,也有人认为50合理,不论多少,有个这个思想就行啦~~~)

  • 21
    点赞
  • 85
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: 好的,以下是用C语言编写快速排序算法的示例代码: ```c #include <stdio.h> void quickSort(int arr[], int left, int right); int main() { int arr[] = { 10, 7, 8, 9, 1, 5 }; int n = sizeof(arr) / sizeof(arr[0]); quickSort(arr, 0, n - 1); printf("Sorted array: \n"); for (int i = 0; i < n; i++) { printf("%d ", arr[i]); } return 0; } void quickSort(int arr[], int left, int right) { int i = left, j = right; int temp; int pivot = arr[(left + right) / 2]; while (i <= j) { while (arr[i] < pivot) { i++; } while (arr[j] > pivot) { j--; } if (i <= j) { temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; i++; j--; } } if (left < j) { quickSort(arr, left, j); } if (i < right) { quickSort(arr, i, right); } } ``` 这个快速排序算法使用了递归的方式对整个数组进行排序。在排序过程中,我们首先选择数组中间的数作为枢纽元,然后将小于枢纽元的数移到数组的左边,大于枢纽元的数移到数组的右边。最后,我们使用递归对左右两个子数组分别进行快速排序,直到所有子数组都排好序为止。 注意:这只是一个示例代码,实际使用时需要考虑到边界条件和优化问题。 ### 回答2: 快速排序是一种常用的排序算法,基于分治的思想。它通过选择一个基准值将数组划分为小于基准值和大于基准值的两个子数组,然后递归地对两个子数组进行排序,最终将整个数组排序完成。 下面是用C语言实现的快速排序算法: ``` #include <stdio.h> void swap(int *a, int *b) { int tmp = *a; *a = *b; *b = tmp; } int partition(int arr[], int low, int high) { int pivot = arr[high]; // 选择最后一个元素作为基准值 int i = low - 1; for (int j = low; j <= high - 1; j++) { if (arr[j] < pivot) { i++; swap(&arr[i], &arr[j]); } } swap(&arr[i + 1], &arr[high]); return (i + 1); } void quickSort(int arr[], int low, int high) { if (low < high) { int pivot = partition(arr, low, high); quickSort(arr, low, pivot - 1); quickSort(arr, pivot + 1, high); } } int main() { int arr[] = {9, 2, 5, 3, 7, 6, 8, 1, 4}; int n = sizeof(arr) / sizeof(arr[0]); quickSort(arr, 0, n - 1); printf("排序后的数组:"); for (int i = 0; i < n; i++) { printf("%d ", arr[i]); } return 0; } ``` 以上代码先定义了两个辅助函数:`swap` 用于交换两个元素的位置,`partition` 用于划分数组。然后定义了主函数 `quickSort`,其中通过递归的方式对划分后的子数组进行快速排序。在 `main` 函数中定义了一个示例数组,使用 `quickSort` 对其进行排序,并打印结果。 ### 回答3: 快速排序(Quicksort)是一种常用的排序算法,也被称为分治法排序。以下是用C语言实现快速排序的代码: ``` #include <stdio.h> // 交换两个元素的函数 void swap(int* a, int* b) { int temp = *a; *a = *b; *b = temp; } // 选择一个基准元素,将大于基准的元素移到右边,小于基准的元素移到左边 int partition(int arr[], int low, int high) { int pivot = arr[high]; // 选择最后一个元素为基准 int i = low - 1; for (int j = low; j <= high - 1; j++) { if (arr[j] < pivot) { i++; swap(&arr[i], &arr[j]); } } swap(&arr[i + 1], &arr[high]); return i + 1; } // 递归地进行快速排序 void quickSort(int arr[], int low, int high) { if (low < high) { int pivot = partition(arr, low, high); quickSort(arr, low, pivot - 1); quickSort(arr, pivot + 1, high); } } // 打印数组元素 void printArray(int arr[], int size) { for (int i = 0; i < size; i++) { printf("%d ", arr[i]); } printf("\n"); } int main() { int arr[] = { 10, 7, 8, 9, 1, 5 }; int size = sizeof(arr) / sizeof(arr[0]); printf("原数组:"); printArray(arr, size); quickSort(arr, 0, size - 1); printf("排序后的数组:"); printArray(arr, size); return 0; } ``` 以上代码首先定义了一个`swap()`函数,用于交换两个元素的值。然后定义了一个`partition()`函数,用于选择基准元素,并将小于基准的元素放置在基准的左边,大于基准的元素放置在基准的右边,并返回基准的位置。接下来定义了`quickSort()`函数,该函数使用递归地对子数组进行快速排序。最后,我们在`main()`函数中定义了一个测试数组,调用`quickSort()`函数对数组进行排序,并使用`printArray()`函数打印排序后的数组。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值