排序算法_快速排序(算法设计与C代码实现)

快速排序算法

快速排序算法简单来说就是在用一种“二分”的思想去挪数字,先找一个数,然后所有比它大的数放其右边,所有比它小的数放其左边,重复此过程直到排序完成。

一、问题描述

       将一个数组中的数字进行排序处理,并返回一个排好序的新数组。

二、问题分析

算法:排序算法_快速排序
步骤:
(1)需要先找一个数作为基准数,那么这个基准数如何设定?
假设目标序列是target_list,因为每次挪动数字后序列都会发生改变,所以我们可以直接设定每次的基准数都是target_list[0]。

(2)如何实现“比它大的放右边,比它小的放左边”?
这里可以设定两个哨兵 i 和 j,分别从序列头和序列尾相向而行,i 遇到比基准数大的数字就停下,j 遇到比基准数小的数字就停下,然后交换目标序列中 i 和 j 的数字,重复这个过程,直到i 和 j 碰面。

(3)需要设置几个变量?
首先需要两个哨兵变量: i 和 j,需要他们从两端向中间移动,从而实现数字交换;
其次需要两个边界变量:left 和 right,因为目标序列会被分成一段一段,没有边界变量就没法进行下一次二分;
最后需要一个中间变量:交换数字时用来存放中间变量。

这里有一个序列:6 1 2 7 9 3 4 2 5 10 8 的二分流程图,可以参考一下:
在这里插入图片描述

三、代码实现

main.c

#include <stdio.h>
#include "quickSort.h"

int main() {
    int target_list[5] = {2,4,5,6,2};
    quickSort(target_list, 0 , 4);
    //输出结果
    for (int i = 0; i < 5; ++i) {
        printf("%d ", target_list[i]);
    }
    return 0;
}

quickSort.h

#ifndef SORTINGALGORITHM_QUICKSORT_H
#define SORTINGALGORITHM_QUICKSORT_H


void quickSort(int target_list[], int left, int right){
    if(left > right)    //嵌套终止条件
        return;

    int i = left, j = right;
    int t;                             //用于交换
    int temp = target_list[left];      //设置基准数
    while (i != j){
        while ((target_list[j] >= temp) && (i < j))
            j--;
        while ((target_list[i] <= temp) && (i < j))
            i++;

        //没有相遇时的交换
        if(i < j) {
            t = target_list[i];
            target_list[i] = target_list[j];
            target_list[j] = t;
        }
    }

    //相遇后的交换
    target_list[left] = target_list[j];		//右边哨兵先行,以右边哨兵为主,原因见算法解析
    target_list[j] = temp;

    //递归
    quickSort(target_list,left, i -1);
    quickSort(target_list,j+1, right);
}

#endif //SORTINGALGORITHM_QUICKSORT_H

四、运行结果

在这里插入图片描述

五、算法解析

  1. 快速排序之所以比较快,是因为相比冒泡排序,每次交换是跳跃式的。每次排序的时候
    设置一个基准点,将小于等于基准点的数全部放到基准点的左边,将大于等于基准点的数全
    部放到基准点的右边。这样在每次交换的时候就不会像冒泡排序一样只能在相邻的数之间进
    行交换,交换的距离就大得多了。因此总的比较和交换次数就少了,速度自然就提高了。当
    然在最坏的情况下,仍可能是相邻的两个数进行了交换。因此快速排序的最差时间复杂度和
    冒泡排序是一样的,都是 O(N2),它的平均时间复杂度为 O (NlogN)。
  2. 因为这个算法不断进行二分,所以必须使用递归的方式进行。
  3. 设定的基准数是序列中左边第一个数,因此右边的哨兵需要先走,为什么必须是基准数对面的哨兵先走呢?
    (1)比如4 1 2 3 5,这一步是以4为基准数,要是从右边开始就会定位到3,而3在第四个位置,的确就是4应该在的位置,但要是从左边开始,找到第一个比4大的数就会找到5,停住了,右边的也只能到5,换完以后是5 1 2 3 4,而4应该放在第四个位置上,而不是第五个位置,这就出错了;
    (2)以左边第一个数为基准数,那么最后要和基准数交换的数一定是比基准数小,因为右边的哨兵找的是比基准数小的数,所以右边先行可以确保最终要去和基准数交换的数一定比基准数小,若左边哨兵先行,最终要和基准数交换的数有可能比基准数大,这样算法就失效了;
    (3)所以一般情况下:
    快速排序若是从小到大排序,基准数在左,右边哨兵先行;
    快速排序若是从大到小排序,基准数在右,左边哨兵先行;
    (不用记忆,理解就好)

六、BUG记录

  1. 两个哨兵没有相遇时的交换和相遇后的交换是不一样的,注意区分情况。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值