[算法] 关于快速排序的四种写法

news/2024/7/1 10:53:12

前序

说到排序算法,应该算是家喻户晓,人人皆知的大路货了。但是往往这些为人所熟知的东西中,也存在一些可以令人琢磨的细节。

这不,某天深夜,无所事事,大概是太寂寞,在思念了一番妹子以后,脑子里突然闪过了快速排序,遂在脑子中模拟了一遍快速排序的运行过程,以前只是死记硬背代码,没有去探究其运作的流程,于是在一些细节处陷入了沉思和迷惑,导致脑回路短路,当场打开斗鱼看了会球。

首先大家都知道,快排主要有两部分,分段(Partition)和递归(Recursive)。分段既将一组数据相对一个参考值分为两段,左段比参考值小,右端比参考值大,然后再递归对这两段进行分段。那么快排的关键部分自然就是这个分段算法,有了分段算法,加上递归,一个快排算法就写好了。

当然别小看了这个分段算法,是需要好好琢磨一番的。主要是一些临界值和极端情况的考虑,我的迷惑便是于此。于是查找了一些书籍和网络资源,加上自己的思路,总结了四种不同的分段算法。细节控可以来好好感受一下。

一. 填坑法

之所以叫填坑法,是其运作过程就像填坑一样。而且一点都不坑,代码形式非常好理解。

图片描述

代码如下:

int partition(int a[], int start, int end){
    int p = a[start];
    while(start < end){
        while(a[end] >= p && start < end) end--;
        a[start] = a[end];
        while(a[start] < p && start < end) start++;
        a[end] = a[start];
    }
    a[start] = p;
    return start;
}

void qs(int a[], int start, int end){
    if(start >= end){
        return;
    }
    int mid = partition(a, start, end);
    qs(a, start, mid-1);
    qs(a, mid+1, end);
}

二. 交换法

交换法,顾名思义就是要对两边的元素进行交换,再代码形式中用到swap函数。其流程如下:

图片描述

代码如下:

void swap(int* a, int* b){
    int temp = *a;
    *a = *b;
    *b = temp;
}

int partition(int a[], int start, int end){
    int pivot = a[start];
    int p = start+1;
    int q = end;
    while(p <= q){
        while(a[p] < pivot && p <= q) p++;
        while(a[q] >= pivot && p <= q) q--;
        if(p < q){
            swap(&a[p], &a[q]);
        }
    }
    swap(&a[start], &a[q]);
    return q;
}

void qs(int a[], int start, int end){
    if(start >= end){
        return;
    }
    int mid = partition(a, start, end);
    qs(a, start, mid-1);
    qs(a, mid+1, end);
}

可以看出这个方法和第二个方法有什么不同的地方,为什么要选第二个元素为start

三. 顺序遍历法

上面两种方法是维护了一个start,一个end指针,逐步向中间趋近的过程。而顺序遍历用一次遍历完成对数据的分段。

图片描述

代码如下:

void swap(int* a, int* b){
    int temp = *a;
    *a = *b;
    *b = temp;
}

int partition(int a[], int start, int end){
    int pivot = a[end];
    int storeIndex = start;
    for(int i = start; i < end; i++){
        if(a[i] < pivot){
            swap(&a[storeIndex], &a[i]);
            storeIndex++;
        }
    }
    swap(&a[storeIndex], &a[end]);
    return storeIndex;
}

void qs(int a[], int start, int end){
    if(start >= end){
        return;
    }
    int mid = partition(a, start, end);
    qs(a, start, mid-1);
    qs(a, mid+1, end);
}

四. 另类交换法

这个方法和之前的交换法的思路相同,但是它不返回mid值,所以索性称之为另类交换法吧。运作的流程就不做解释,直接上代码,各位客官姑且一看。

void qs(int a[], int start, int end){
    if(start >= end){
        return;
    }
    int pivot = a[start];
    int p = start;
    int q = end;
    while(1){
        while(a[p] < pivot) p++;
        while(a[q] > pivot) q--;
        if(p >= q){
            break;
        }
        swap(&a[p], &a[q]);
        p++;
        q--;
    }
    qs(a, start, p-1);
    qs(a, q+1, end);
}

后记

这四种算法用了四种不同的解决问题的思路,虽然都是细节上的不同,但是细细去想一下也能领会其中到奥妙。第一次在sf上发文章,也是为了巩固和牢记自己这么多天琢磨的东西。如果有什么错误和不足,也请各位看客多多指正和补充。


http://www.niftyadmin.cn/n/2525907.html

相关文章

delete this 需要注意呀

delete this 需要注意呀 2011-07-11 21:32 715人阅读 评论(2) 收藏 举报首先转载一下牛人的文章,我觉得写得不错&#xff1a;http://www.cppblog.com/lovedday/archive/2008/06/03/52060.html 内容如下&#xff1a; In order to understand "delete this" : First St…

百度知道发帖的一点经验分享及留网址技巧

首先感谢逆袭会vip里帮我提问以及回答问题的会友&#xff0c;因为在12月初&#xff0c;我在逆袭会群里组织了一次小范围的百度知道互助推广&#xff0c;现在初见效果。如图&#xff1a;虽然是没有指数的关键词以及多数问答排名目前都在第二页&#xff0c;但对公司项目是很有意义…

关于static函数的用法和全局变量在工程中的引用

就像我们熟知的那样&#xff0c;变量可以分全局的和局部的&#xff0c;函数也可以分全局的和局部的。比如说&#xff0c;在一个工程的common.h中定义了一个全局变量 int test;那么在整个工程的作用范围内&#xff0c;该变量都是存在的&#xff0c;在编译的时候会将其保存在整个…

JAVA连接各种数据库详解

Java数据库连接&#xff08;JDBC&#xff09;由一组用 Java 编程语言编写的类和接口组成。JDBC 为工具/数据库开发人员提供了一个标准的 API&#xff0c;使他们能够用纯Java API 来编写数据库应用程序。然而各个开发商的接口并不完全相同&#xff0c;所以开发环境的变化会带来一…

leetcode 241. Different Ways to Add Parentheses (Python版)

题目&#xff1a;Given a string of numbers and operators, return all possible results from computing all the different possible ways to group numbers and operators. The valid operators are, - and *.大意是给定一个运算&#xff0c;求解所有运算序列的解例如Input…

SVN 相关

转在声明&#xff1a;http://blog.csdn.net/linjf520/article/details/77985423 —————————————————————dos下svn api获取当前执行目录的所有资源版本信息并且存保存到指定文件 echo of svn ls -R -v>[PathName]/saveFileName.extecho refresh asset_…

static函数

static函数 (2008-07-10 15:05:19) 转载▼标签&#xff1a; it 分类&#xff1a; c static修饰符是一个能够减少此类命名冲突的有用工具。例如&#xff0c;以下声明语句 static int a; 其含义与下面的语句相同 int a; 只不过&#xff0c;a的作用域限制在一个源文件内&#…

成都Uber优步司机奖励政策(2月7日)

滴快车单单2.5倍&#xff0c;注册地址&#xff1a;http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单&#xff1a;http://www.cnblogs.com/mfryf/p/4612609.html 优步奖励低/不挣钱/怎么办?看这里&#xff1a;http://www.cnblogs.com/mfry…