C++ 快速排序 Quicksort 分治法

C++快速排序的复杂度为O(nlogn)。快速排序利用了分治的思想。

分治法简介:

计算机科学中,分治法是建基于多项分支递归的一种很重要的算法范式。字面上的解释是“分而治之”,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。

这个技巧是很多高效算法的基础,如排序算法快速排序归并排序)、傅立叶变换快速傅立叶变换)。

另一方面,理解及设计分治法算法的能力需要一定时间去掌握。正如以归纳法去证明一个理论,为了使递归能够推行,很多时候需要用一个较为概括或复杂的问题去取代原有问题。而且并没有一个系统性的方法去适当地概括问题。

分治法这个名称有时亦会用于将问题简化为只有一个细问题的算法,例如用于在已排序的列中寻找其中一项的折半搜索算法(或是在数值分析中类似的勘根算法)。这些算法比一般的分治算法更能有效地执行。其中,假如算法使用尾部递归的话,便能转换成简单的回圈。但在这广义之下,所有使用递归或回圈的算法均被视作“分治算法”。因此,有些作者考虑“分治法”这个名称应只用于每个有最少两个子问题的算法。而只有一个子问题的曾被建议使用减治法这个名称。

分治算法通常以数学归纳法来验证。而它的计算成本则多数以解递回关系式来判定。

——以上来自维基百科

C++快速排序讲解——参考网址:http://wiki.jikexueyuan.com/project/easy-learn-algorithm/fast-sort.html

扫描二维码关注公众号,回复: 2784268 查看本文章

这个网页讲解得非常详细,易懂。

快速排序代码块:

template<typename T> 
void Swap(T & a, T & b) // 交换a与b的值
{
    T t;
    t = a; a = b; b = t;
}

template<class T>
void QuickSort(T * s, T * t) // 快速排序
{
    T *i, *j;
    i = s; j = t;
    T temp = *s; // temp是快排中的基准值,用于分治,将比它小的元素放到temp的左边;反之则放右边
    if (s > t) // 递归返回条件:当分治的子问题只有一个元素的时候,此时不必排序,直接返回即可
        return;
    while (i != j) // i为头指针,j为尾指针。i向后移动,j向前移动。但是i必须满足:i <= j
    {
        while (*j >= temp && i < j) j--;
        while (*i <= temp && i < j) i++;
        if (i < j) Swap<T>(*i, *j);
    }

    *s = *i; // i == j的时候,将i赋值给最左端的*s
    *i = temp; // 同时,更新基准值temp的值

    QuickSort(s, i - 1); // 递归,分治
    QuickSort(i + 1, t); // 递归,分治
}

具体代码实现如下:

// C++ 快速排序-Quicksort
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <ctime>
using namespace std;

template<typename T>
void Swap(T & a, T & b)
{
    T t;
    t = a; a = b; b = t;
}

template<class T>
void QuickSort(T * s, T * t)
{
    T *i, *j;
    i = s; j = t;
    T temp = *s; // temp是快排中的基准值,用于分治,将比它小的元素放到temp的左边;反之则放右边
    if (s > t) // 递归返回条件:当分治的子问题只有一个元素的时候,此时不必排序,直接返回即可
        return;
    while (i != j) // i为头指针,j为尾指针。i向后移动,j向前移动。但是i必须满足:i <= j
    {
        while (*j >= temp && i < j) j--;
        while (*i <= temp && i < j) i++;
        if (i < j) Swap<T>(*i, *j);
    }

    *s = *i; // i == j的时候,将i赋值给最左端的*s
    *i = temp; // 同时,更新基准值temp的值

    QuickSort(s, i - 1); // 递归,分治
    QuickSort(i + 1, t); // 递归,分治
}

const int maxn = 9731 ;
double a[maxn];
const double CLOCK_PER_SECOND((clock_t)1000); // 秒(s)
//计时器输出的时长以秒为单位(s)
const double CLOCK_PER_MILLISECOND((clock_t)1); // 毫秒(ms)
//计时器输出的时长以毫秒为单位(ms)

int main()
{
    srand((unsigned)time(0));
    
    clock_t startTime, endTime;

    for (int i = 0; i < maxn; i++) // 为数组元素随机赋值
        a[i] = rand() / (double)(RAND_MAX / 10); // 生成0~10以内的double型数据并赋值给a[i]

    startTime = clock();
    QuickSort(a, a + maxn - 1); // 快速排序
    endTime = clock();

    cout << "The element of array a after quicksort:\n\n";
    for (int i = 0; i < maxn; i++) // 输出数组元素
        cout << a[i] << " ";
    cout << endl << endl;

    cout << "The time of Quicksort is " 
         << (double)(endTime - startTime) /CLOCK_PER_MILLISECOND       
         << " ms" << endl; 

    return 0;
}

我们可以利用clock计时器比较自编的快速排序与C++ STL algorithm中的排序算法比较运行性能。

具体实现代码如下:

// C++ 快速排序-Quicksort
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <ctime>
using namespace std;

template<typename T>
void Swap(T & a, T & b)
{
	T t;
	t = a; a = b; b = t;
}

template<class T>
void QuickSort(T * s, T * t)
{
	T *i, *j;
	i = s; j = t;
	T temp = *s; // temp是快排中的基准值,用于分治,将比它小的元素放到temp的左边;反之则放右边
	if (s > t) // 递归返回条件:当分治的子问题只有一个元素的时候,此时不必排序,直接返回即可
		return;
	while (i != j) // i为头指针,j为尾指针。i向后移动,j向前移动。但是i必须满足:i <= j
	{
		while (*j >= temp && i < j) j--;
		while (*i <= temp && i < j) i++;
		if (i < j) Swap<T>(*i, *j);
	}

	*s = *i; // i == j的时候,将i赋值给最左端的*s
	*i = temp; // 同时,更新基准值temp的值

	QuickSort(s, i - 1); // 递归,分治
	QuickSort(i + 1, t); // 递归,分治
}

const int maxn = 100;
double a[maxn];
const double CLOCK_PER_SECOND((clock_t)1000); // 秒(s)
//计时器输出的时长以秒为单位(s)
const double CLOCK_PER_MILLISECOND((clock_t)1); // 毫秒(ms)
//计时器输出的时长以毫秒为单位(ms)

int main()
{
	srand((unsigned)time(0));
	clock_t startTime, endTime;

	startTime = clock();
	for (int i = 0; i < maxn; i++)
		a[i] = rand() / (double)(RAND_MAX / 10); // 生成0~10以内的double型数据并赋值给a[i]

	QuickSort(a, a + maxn - 1);
	endTime = clock();
	cout << "QuickSort: " << (double)(endTime - startTime) / CLOCK_PER_MILLISECOND << "ms";
	cout << endl;

	for (int i = 0; i < maxn; i++)
		cout << a[i] << " ";
	cout << endl;

	startTime = clock();
	sort(a, a + maxn);
	endTime = clock();
	cout << "sort: " << ((double)(endTime - startTime) / CLOCK_PER_SECOND) * 1000 << "ms";
	cout << endl;

	for (int i = 0; i < maxn; i++)
		cout << a[i] << " ";
	cout << endl;

	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41705423/article/details/81663970
今日推荐