C++快速排序超详细讲解

 更新时间:2025年03月17日 08:26:23   作者:你干码,哎哟  
快速排序是一种高效的排序算法,通过分治法将数组划分为两部分,递归排序,直到整个数组有序,通过代码解析和示例,详细解释了快速排序的工作原理和实现过程,需要的朋友可以参考下

一、快速排序原理

快速排序(QuickSort)是一种基于分治法的高效排序算法。它的基本思想是通过一个称为“基准”(pivot)的元素将数组划分为两部分,一部分的所有元素都比基准小,另一部分所有元素都比基准大,然后递归地对这两部分进行同样的操作,直到整个数组有序。 

二、快速排序标准代码

void quick_sort(int q[], int l, int r)
{
	if (l >= r) return; //递归停止条件
	int i = l - 1, j = r + 1, x = q[l + r >> 1]; //设定指针,基准
	while (i < j)
	{
		do i++; while (q[i] < x); //q[i]大于等于基准时,指针i停止
		do j--; while (q[j] > x); //q[j]小于等于基准时,指针j停止
		if (i < j) swap(q[i], q[j]); //判断是否i<j,交换i,j对应的数组元素
	} // 结束时数组被分为 >=x,<=x 的两部分
	quick_sort(q, l, j); //继续分直到分到一到两个元素此时数组有序
	quick_sort(q, j + 1, r);
}

三、代码解析

我们以一个简单的例子帮助我们了解快速排序

53412

1.排序的数组以及需要排序元素的范围,无返回值

void quick_sort(int q[], int l, int r)

 2.递归结束的条件:元素剩一个或空

if (l >= r) return;

3.设定变量,其中 i, j 为两个指针分别减 1 加 1 是为了下一步的 do while 循环,x 即为“基准”(pivot) 用来将列表分为 <=x 和 >=x 的两部分,x 是随机的,这里取了数组中间的一个元素,l + r >> 1相当于 (l + r)/2 (pivot:q[2] = 4)向下取整(提高了效率)

int i = l - 1, j = r + 1, x = q[l + r >> 1];
53412
\rightarrow01234\leftarrow j

4.while循环实现了遍历、比较、交换的功能,先使 i 指针递增直到 i 所对应的元素 >=x 停止,接下来使 j 指针递减直到其对应的元素 <=x 停止

while (i < j)
{
	do i++; while (q[i] < x);
	do j--; while (q[j] > x);
	if (i < j) swap(q[i], q[j]);
}
53412
i(>=4停止)j(<=4停止)

交换之后开启下一次循环

23415
<4<4i(>=4停止)j(<=4停止)>4

满足 i<j 交换

23145
<4<4j(<=4停止)i(>=4停止)

>4

不满足 i<j 不交换,此时整个 while 循环结束,注意此时 j(包含)往左为 <=4 部分,j + 1 及其往右为 >=4部分 

5.接下来就是递归了,每次运行分将数组为左<=右的两部分,我们只需将左右两部分分别执行函数程序得到直到剩两个或一个元素,此时数组便有序了

quick_sort(q, 0, 2); 
23145
<4<4j(<=4停止)i(>=4停止)

>4

x(pivot)=3

231
<3i(>=3停止)j(<=3停止)
213
<3j(<=3停止)i(>=3停止)
quick_sort(q, 0, 1); 

x(pivot)=2

2

1
i(>=2停止)j(<=2停止)

1

2
j(<=2停止)i(>=2停止)

剩一个元素时,执行递归停止程序:

if (l >= r) return;

 数组中最初的“左”部分就变为

123

而最初的“右”部分:x(pivot)=4

45
i(>=4停止)j(<=4停止)>5
if (i < j) swap(q[i], q[j]);

不满足 if 条件以及 while 条件,while 循环停止,依旧选择了 j 为分界点分到一个元素时结束递归

此时代码全部有序

12345
quick_sort(q, l, j); 
quick_sort(q, j + 1, r);

6.总结

快速排序利用两个指针对数组的元素进行比较交换进行部分排序,再利用递归整体排序

四、使用while循环的快速排序

1.代码

代码1.由快排代码等价转化而来

void quick_sort(int q[], int l, int r)
{
    if (l >= r) return;
    int i = l, j = r, x = q[l + r >> 1];
    while (i < j)
    {
        while (q[i] < x) i++;
        while (q[j] > x) j--;
        if (i < j)
        {
            swap(q[i], q[j]);
            if (i + 1 < j - 1)
            {
                i++;
                j--;
            }
            else
            {
                i++;
                j--;
                while (q[i] < x) i++;
                while (q[j] > x) j--;
                break;
            }
        }
    }
    quick_sort(q, l, j);
    quick_sort(q, j + 1, r);
}

代码2.效率提高版

void quick_sort(int q[], int l, int r) {
	if (l >= r) return;
	int x = q[l + r >> 1];
	int i = l, j = r;
	while (i <= j) { // 注意:这里应该是 i <= j 而不是 i < j
		while (q[i] < x) i++;
		while (q[j] > x) j--;
		if (i <= j) {
			swap(q[i], q[j]);
			i++;
			j--;
		}
	}
	quick_sort(q, l, j);   
	quick_sort(q, i, r);   
}

2.代码2解析

1.因为没有 do 过程,所以指针起始位置直接设在了 0 和 -1 的位置,

if (l >= r) return;
int x = q[l + r >> 1];
int i = l, j = r;
53412
i\rightarrow\leftarrowj

2. while 循环中的 while 循环先判断是否满足条件,满足的话指针加/减 1,这样停止时依旧是对应元素 >=x 或 <=x 时的指针,

while (i <= j) 
{ 
	while (q[i] < x) i++;
	while (q[j] > x) j--;
	if (i <= j)
    {
		swap(q[i], q[j]);
		i++;
		j--;
	}
}
53412
i(停)j(停)

换过之后+=或--

23415
<4i(停)j(停)

交换,++/--

23145
ji

不满足 i<=j while 循环结束.

关于 i<=j 的条件判断,我们给出新的案例

321
i(停)j(停)

交换之后 ++/--

123
i(停) j(停)

注意此时并没有返回(return),

递归代码:分别以 j 和 i 作为分界点

quick_sort(q, l, j);   
quick_sort(q, i, r);   

而如果条件判断为 < 的话 i=j 时就会造成下一次递归多了一个元素,

而标准代码的运行过程到此处后结束,以 j 和 j+1 为分界点不会造成此问题.

因此再进行一次循环

123
ji

而此时元素 2 的位置是 i,j同时停过的位置即为基准 x,而i,j也会再下一次++/--后停止,所以我们可以直接将元素 2 所对应的数组位置固定不动,将元素 2 左右的数组递归处理. 

quick_sort(q, l, j);   
quick_sort(q, i, r);   

五、总结

使用 while 循环会比 do while 多一层内层循环,所以 do while 循环效率更高,建议只用 do while 循环.

到此这篇关于C++快速排序的文章就介绍到这了,更多相关C++快速排序内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C语言三种函数调用约定_cdecl与_stdcall及_fastcall详细讲解

    C语言三种函数调用约定_cdecl与_stdcall及_fastcall详细讲解

    本篇文章使用的工具是vs2010,内容可能涉及到汇编的知识,建议有一些汇编基础的再来看,不过没有汇编基础也没有关系,了解一下这三种调用约定即可
    2022-10-10
  • 详解如何使用openssl创建自签名证书

    详解如何使用openssl创建自签名证书

    这篇文章主要为大家介绍了详解如何使用openssl创建自签名证书示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-04-04
  • 深入C/C++浮点数在内存中的存储方式详解

    深入C/C++浮点数在内存中的存储方式详解

    本篇文章是对C/C++浮点数在内存中的存储方式进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • Visual Studio Code配置C、C++环境并编写运行的方法

    Visual Studio Code配置C、C++环境并编写运行的方法

    这篇文章主要介绍了Visual Studio Code配置C、C++环境并编写运行的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-08-08
  • QT实现秒表项目

    QT实现秒表项目

    这篇文章主要为大家详细介绍了QT实现秒表项目,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-08-08
  • C语言实现修改文本文件中特定行的实现代码

    C语言实现修改文本文件中特定行的实现代码

    最近由于项目需要实现修改文件的功能,所以,博主认真查阅了一些资料,但是,很遗憾,并没有太多的收获
    2013-06-06
  • C语言深入探索数据类型的存储

    C语言深入探索数据类型的存储

    使用编程语言进行编程时,需要用到各种变量来存储各种信息。变量保留的是它所存储的值的内存位置。这意味着,当您创建一个变量时,就会在内存中保留一些空间。您可能需要存储各种数据类型的信息,操作系统会根据变量的数据类型,来分配内存和决定在保留内存中存储什么
    2022-07-07
  • 深入理解C语言的new[]和delete[]

    深入理解C语言的new[]和delete[]

    new和delete既是C++中的关键字也是一种特殊的运算符。这篇文章主要介绍了C++的new和delete详解,需要的朋友可以参考下
    2021-09-09
  • C语言深入分析整形数据存储

    C语言深入分析整形数据存储

    C语言中,我们经常使用数据类型,那么整形数据在内存中如何存储?存储方式是什么?如果你对这些内容不太了解的话,相信看完这篇博客后,你会对整形数据的存储有一个新的认识。话不多说,我们进入正题
    2022-08-08
  • C语言中send()函数和sendto()函数的使用方法

    C语言中send()函数和sendto()函数的使用方法

    这篇文章主要介绍了C语言中send()函数和sendto()函数的使用方法,是C语言入门学习中的基础知识,需要的朋友可以参考下
    2015-09-09

最新评论