c++ 快速排序

Posted 乘舟凉

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c++ 快速排序相关的知识,希望对你有一定的参考价值。

快速排序的思想是使某个数在它该在的位置,然后对这个数前后两部分进行递归处理即可
例子: 6 5 79 2
6该在的位置应该在第三位 5 2 6 79
那么如何使一个数在它该在的位置呢,观察上面的例子,要使一个数在它该在的地方应该要让所有小于它的数在左边,所有大于它的数在右边即可
按照上面的思想我们可以编写代码

#include <iostream>
using namespace std;

#define N 13

template<class T>
void fastSort(T *ary,size_t len);

int main()
	int ary[] = 4,5,7,2,46,41,4,45,4,56,64,6,4;
	fastSort(ary,N);

	for(int i = 0;i<N;i++)
		cout << ary[i] << " ";	
	

	return 0;



template<class T>
void fastSort(T *ary,size_t len)
	T* t  = new T[len];
	int left = 0,right = len-1;	
	for(int i=1;i<len;i++)
		if(ary[i] < ary[0]) //我们干脆每次都选定最左边的数为中心节点
			t[left] = ary[i];
			left++;
		
		else
			t[right] = ary[i];
			right--;
		

	

	t[left] = ary[0];
	memcpy(ary,t,sizeof(T)*len);

	delete[] t;

	if(left>1)
		fastSort(ary,left);
	size_t right_len = len-left-1; //计算右半部分的长度
	if(right_len>1)
		fastSort(ary+left+1,right_len);

上面fastSort函数思想很简单,首先创建一块和排序数组一样大小的内存,然后将数组内所有小于最左边的数放入内存的左边,将数组内所有大于最左边的数放入内存的右边,然后再将最左边的数放入内存的最后一个位置,这样就得到最左边的数应该放的位置。最后将这个位置的左半部分和右半部分进行递归处理,它们的长度变1就不用递归了

现在我们尝试不创建一块内存来构建算法,我们为什么要创建一块新内存呢?因为原来的数组没地方放我们比较的结果,但是上面我们观察到数组第0个位置是没有被使用的,我们可以将ary[0]暂存,然后利用这块空闲内存进行移动,由于这块内存在数组的最左边,所以我们从数组的最右边开始比较,如果该数比ary[0]大,我们就继续向前检查,这样可以保证我们检查过的数据在右边都是大于ary[0],如果该数比ary[0]小,那我们就把它移到左边空闲的位置,这样右边就有了空闲的位置,此时,我们从左边开始检查,检查到大于ary[0]的,就把它移动到右边空闲的位置,如此循环往复,从左边到右边的范围不断缩小,直至它们指向同一个位置

#include <time.h>
#include <iostream>
using namespace std;

#define N 15

//template<class T>
//void fastSort(T *ary,size_t left,size_t right);
template<class T>
void fastSort(T *ary,size_t len);

int main()
	int ary[N];
	srand((unsigned)time(NULL));
	for(int i = 0; i < N;i++ )
		ary[i] = rand() % 100;
	fastSort(ary,N);

	for(int i = 0;i<N;i++)
		cout << ary[i] << " ";	
	

	return 0;


template<class T>
void fastSort(T *ary,size_t len)
	T temp = ary[0];
	int i=0,j=len-1;
	bool turnLeft=true;
	while(i!=j)
		if(turnLeft)
			if(ary[j]>temp)
				j--;
			else
				ary[i]=ary[j];
				i++;
				turnLeft=false;
			
		
		else
			if(ary[i]<=temp)
				i++;
			else
				ary[j]=ary[i];
				j--;
				turnLeft=true;
			

		
		
	

	ary[i]=temp;
	
	if(i>1)
		fastSort(ary,i);
	size_t right_len = len-i-1;
	if(right_len>1)
		fastSort(ary+i+1,right_len);

C++ 在快速排序函数中出现 *** 错误

【中文标题】C++ 在快速排序函数中出现 *** 错误【英文标题】:C++ Getting *** error in quicksort function 【发布时间】:2014-03-09 18:05:50 【问题描述】:

当我尝试使用快速排序对一个大尺寸数组进行排序时,我遇到了 *** 错误,并且该数组按降序排列。我想使用下面的代码按升序对其进行排序:

int partition_lastElementPivot(int * arr, int lo, int hi)

    int x = arr[hi];
    int i = lo - 1;
    for (int j = lo; j < hi; j++)
    
        if (arr[j] <= x)
        
            i++;
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        
    
    int temp = arr[hi];
    arr[hi] = arr[i + 1];
    arr[i + 1] = temp;

    return i + 1;


void quicksortLastElementPivot(int*arr, int lo, int hi)

    if (lo<hi)
    
        int mid = partition_lastElementPivot(arr, lo, hi);
        quicksortLastElementPivot(arr, lo, mid - 1);
        quicksortLastElementPivot(arr, mid + 1, hi);
    

当我随机生成一个任意大小的数组(假设大小为 5000)时,此代码工作正常。但是当我生成一个按降序排序的大小为 5000 的数组,然后尝试使用此代码进行排序时,我得到一个 *** 错误。 C++ 是否限制堆栈可用的内存以及为什么会发生这种情况。

int arr[5000];
int count = 5001;
for(int i=0; i<5000; i++)

    arr[i] = count;
    count--;


quicksortLastElementPivot(arr, 0, 4999)

谢谢

【问题讨论】:

是的,C++ 确实限制了堆栈大小。 ***.com/questions/1825964/… 另请参阅有关快速排序和枢轴以及堆栈空间的讨论。 ***.com/questions/12970688/… 【参考方案1】:

正如您在此处所发现的那样,Quicksort 的最坏情况性能非常糟糕。它以 5000 的堆栈深度调用自己。This Wikipedia article 对此主题进行了很好的讨论。特别是,它提到了tail recursion 作为堆栈溢出问题的解决方案。

简而言之,这意味着不是最后一次调用quicksortLastElementPivot,然后立即返回,而是循环回到函数的开头。这具有相同的效果,但尾递归不会增加堆栈大小。为此,您必须确保使用传统递归对两个分区中较小的分区进行排序,而对较大的分区进行尾递归排序。像这样的东西(未经测试!):

void quicksortLastElementPivot(int*arr, int lo, int hi)

TailRecurse:
    if (lo<hi)
    
        int mid = partition_lastElementPivot(arr, lo, hi);
        if (mid < (lo + hi) / 2)
             // First partition is smaller
            quicksortLastElementPivot(arr, lo, mid - 1); // Sort first partition
            lo = mid + 1; goto TailRecurse;              // Sort second partition
            
        else
             // Second partition is smaller
            quicksortLastElementPivot(arr, mid + 1, hi); // Sort second partition
            hi = mid - 1; goto TailRecurse;              // Sort first partition
            
    

【讨论】:

感谢您的回答。【参考方案2】:

C++ 标准没有定义可执行程序的堆栈大小。

此限制通常在项目的 make 文件或链接器命令文件中定义。

根据您的 IDE,您可能还会在项目设置中找到它(在链接器配置下)。

TonyK 给出的答案在解释最坏情况下快速排序的堆栈使用方面做得很好(这正是您的代码中的情况,其中arr倒序排列)。

【讨论】:

【参考方案3】:
#include <iostream>
using namespace std;

void QuickSort(int *arr, int left, int right)

int i = left;
int j = right;
int pivot = arr[rand() % (right - left) + left];
while (i < j)

    while (arr[i] < pivot)
    
        i++;
    
    while (arr[j] > pivot)
    
        j--;
    
    if (i <= j)
    
        swap(arr[i], arr[j]);
        i++;
        j--;
    

if (left < j)

    QuickSort(arr, left, j);

if (i < right)

    QuickSort(arr, i, right);

  
  int main()
 
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int n;
cin >> n;
int *arr = new int[n];

for (int i = 0; i < n; i++)

    cin >> arr[i];

QuickSort(arr, 0, n - 1);
for (int i = 0; i < n; i++)

    cout << arr[i] << " ";


delete arr;

【讨论】:

以上是关于c++ 快速排序的主要内容,如果未能解决你的问题,请参考以下文章

C++ 快速排序算法

C++ 快速排序枢轴优化

C++中的快速排序

排序算法的c++实现——快速排序

C++ 快速排序段错误

快速排序(QuickSort),归并排序(MergeSort),堆排序(HeapSort)典型C++代码实现总结