快速排序

  • 快速排序也是分治的,但不同于分治的一点是,它有分隔的概念,把一个序列按照p分为两份,左边的小于等于p,右边的大于等于p,再对两边的序列重复这个过程,直到序列只有一个元素为止。
  • 快速排序的最坏运行时间是O(n^2),证明如下:

  • 快速排序的平均运行时间能达到O(nlg(n)),比较排序不能突破这个极限,可以把比较排序算法理解为决策树模型,决策树是一种满二叉树,注意这里的二叉树是国际定义的满二叉树,也就是说,所有的节点,要么是叶子节点,要么度为2,不存在度为1的节点:


    以上就是一棵满二叉树,表示了对3,2,1进行排序的过程。可以看到,对于排列而言,n个元素对应n!个排列,也就对应树的n!个叶子节点,这里的n指的是待排序的元素的个数。最坏情况下的排序也就是最终到达高度最大的叶子节点,比较次数和树的高度相同。下面要证明的是,一棵对应n个元素组成的比较排序的决策树,它的高度的渐近下确界为nlg(n),也就是证明,高度h=Θ(nlg(n)):

  • 快速排序有一个演化,就是内省式快速排序,它能够控制递归次数以及序列划分的质量,当划分的恨不均衡,算法时间复杂度向O(n^2)恶化时,能自动转换为堆排序。这个算法会在最后和三点中值快速排序合并在一起给出。
  • 下面是快速排序的子程序,partition:
    int partition(int* arr, int first, int last)
    	{
    	const int pivot = arr[last - 1];
    	int i = first - 1;
    	for(int j = first; j < last - 1; ++j)
    		{
    		if(arr[j] <= pivot)
    			std::swap(arr[++i], arr[j]);
    		}
    	std::swap(arr[++i], arr[last - 1]);
    	return i;
    	}
    
  • 下面是快速排序的主函数:
    void Quicksort(int *arr, int first, int last)
    {
    	if(first < last)
    	{
    		int r = partition(arr, first, last);
    		Quicksort(arr, first, r);
    		Quicksort(arr, r + 1, last);
    	}
    }
    

    需要注意的是,partition的方法不只一种。最常用的是三点中值法,结合上面所说的对递归层次的限制,有下面这个内省式快速排序算法:

    const int cThreshold = 32;
    const int cDeepthLmt = 10;	//deepth limit.deepth limit. <span>2*lg(n) in SGI-STL
    
    int __xpartition(int *arr, int first, int last, int val)
    	{
    	//the same as std::partition.
    	for(; ; ++first)
    		{
    		for(; first != last && arr[first] <= val; ++first)
    			;
    		if(first == last)
    			break;
    
    		for(; first != (--last) && arr[last] > val;)
    			;
    		if(first == last)
    			break;
    		std::swap(arr[first], arr[last]);
    		}
    	
    	return first;
    	}
    
    int __median3(int x1, int x2, int x3)
    	{	//median of 3 numbers.
    	if(x1 > x2)
    		std::swap(x1, x2);
    	if(x1 > x3)
    		std::swap(x1, x3);
    	return std::min(x2, x3);
    	}
    
    int __mean(int *arr, int first, int last)
    	{	//median 3 partition.
    	int p = __median3(arr[first], arr[(last + first - 1) / 2], arr[last - 1]);
    	return __xpartition(arr, first, last, p);
    	}
    
    void __introsort_loop(int* arr, int first, int last, int m)
    	{
    	//main loop.
    	while(last - first > cThreshold)
    		{
    		if((m--) == 0)
    			{
    			make_heap(arr + first, arr + last);
    			sort_heap(arr + first, arr + last);
    			//or std::partial_sort.
    			return;
    			}
    		int povit = __mean(arr, first, last);
    		//loop on the first half.
    		__introsort_loop(arr, first, povit, m);
    		//loop on the second half.
    		first = povit + 1; //IntroSortLoop(arr, povit + 1, last);
    		}
    	// insertion_sort here, or in Introsort().
    	}
    
    void __insertion_sort(int*arr, int first, int last)
    	{
    	for(size_t i = 1; i != last; ++i)
    		{
    		int key = arr[i];
    		int j = (int)(i - 1);
    		for(; j >= 0 && key < arr[j]; --j)
    			arr[j + 1] = arr[j];
    
    		arr[j + 1] = key;
    		}
    	}
    
    void Introsort(int *arr, int first, int last)
    	{
    	__introsort_loop(arr, first, last, cDeepthLmt);
    	__insertion_sort(arr, first, last);
    	}
    

     

     

     

     

     

     

posted @ 2012-09-03 21:51  Gallagher  阅读(192)  评论(0)    收藏  举报