快速排序

快速排序的描述

        快速排序是一种基于分治(+递归)技术的重要排序算法,广泛认为它是解决一般问题的最佳排序算法,属于比较排序的一种,而且不需要额外的存储空间。在处理中到大型数据集时,快速排序是一个比较好的选择。

        快速排序按照元素的值对它们进行划分。具体来说,它对给定的数组中的元素进行重新排列,以得到一个快速排序的分区。一个分区中,所有在s下标之前的元素都小于等于A[s],所有在s下标之后的元素都大于等于A[s]。

                                                                 

        选择中轴(A[s])的一种行之有效的方法是通过随机选择来选取。通过随机数的统计特性,从而保证快速排序的整体性能,因此快速排序是随机算法的一个好例子。

        显然,建立一个分区以后,A[s]已经位于它在有序数组中的最终位置,接下来我们可以继续对A[s]前和A[s]后的子数组使用同样的方法分别进行排序。

 

         算法:

 

QuickSort(A[l...r])
 //用QuickSort对子数组排序
 //输入:数组A[0...n-1]中的子数组A[l...r],由左右下标l和r定义。
 //输出:非降序排列的子数组A[l...r]
 if l < r
	 s <- Partition(A[l...r]) //s为中轴的位置
 QuickSort(A[l...s-1])
 QuickSort(A[s+1...r])

 

 

 

 

 

        为了建立一个分区,也有许多不同的方法对元素重新排列。在这里,我们使用一种基于两次扫描子数组的高效方法:一次是从左到右,另一次是从右到左,每次都把子数组的元素和中轴进行比较。从左到右的扫描(下面用索引 i 表示)从第二个元素开始。因为我们希望小于中轴的元素都位于子数组的第一部分,扫描会忽略小于中轴的元素,直到遇到第一个大于等于中轴的元素才会停止。从右到左的扫描(下面用索引 j 表示)从最后一个元素开始。因为我们希望大于中轴的元素位于子数组的第二部分,扫描会忽略大于中轴的元素,直到遇到第一个小于等于中轴的元素才会停止。两次扫描全部停止以后,取决于扫描的指针是否相交,会发生3种不同的情况:

        如果扫描指针i 和 j 不相交,也就是说 i < j ,我们简单的交换A[i]和A[j],再分别对i加一,j减一,然后继续扫描。 

 

                                               

 

        如果扫描指针相交,也就是说 i > j,把中轴和A[j]交换以后,我们得到了该数组的一个分区。

 

                                                       

 

        最后,如果扫描指针停下来时指向同一个元素,也就是说i = j,被指向的元素值一定等于p(为什么?),因此,我们建立了该数组的一个分区,中轴的位置s=i=j。

 

                                                                

 

        我们可以把第三种情况和指针相交的情况(i > j)结合起来,只要i >= j,就交换中轴和A[j]的位置。

 

            算法:

 

Partition(A[l...r])
 //对子数组进行分区
 //输入:数组A[0...n-1]中的子数组A[l...r],由左右下标l和r定义。
 //输出:A[l...r]的一个分区,中轴的位置作为函数的返回值
 p <- A[l]
 i <- l; j <- r+1;
 
 repeat
	 repeat i <- i+1 until A[i] >= p
	 repeat j <- j-1 until A[j] <= p

	 if i < j
		 swap(A[i], A[j])
	 else
	     swap(A[l], A[j]) // 交换中轴和A[j]的位置
		 break

 return j

 

 

 

 

 

 

 

 

快速排序的实现

 

// QuickSort.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include "typedef.h"

/*
*函数名:Compare_uint
*参数:pKey1  指向第一个比较元素的地址
*      pKey2  指向第二个比较元素的地址
*功能:比较两个元素的大小
*返回值:1 表示Key1 大于 Key2
*        -1 表示Key1 小于 Key2
*        0 表示Key1 等于 Key2
*作者:AlbertoNo1
*日期:2016-03-15
*/
INT32 Compare_uint(VOID *pKey1, VOID *pKey2)
{
	/*对两个无符号整型数进行比较*/
	if (*((UINT32*)pKey1) > *((UINT32*)pKey2))
	{
		return 1;
	}
	else if (*((UINT32*)pKey1) < *((UINT32*)pKey2))
	{
		return -1;
	}
	else
	{
		return 0;
	}
}

/*
*函数名:Swap
*参数:pKey1  指向第一个交换元素的地址
*      pKey2  指向第二个交换元素的地址
*      uiKeySize 交换元素所占内存大小(Byte)
*功能:交换两个元素的位置
*返回值:无
*作者:AlbertoNo1
*日期:2016-03-15
*/
VOID Swap(VOID *pKey1, VOID *pKey2, UINT32 uiKeySize)
{
	VOID *pTemp = NULL;

	if (NULL == (pTemp = malloc(uiKeySize)))
	{
		return;
	}

	memcpy(pTemp, pKey1, uiKeySize);
	memcpy(pKey1, pKey2, uiKeySize);
	memcpy(pKey2, pTemp, uiKeySize);
}

/*
*函数名:Partition
*参数:pData  待分区数组数据的首地址
*      uiElmSize  数据元素所占内存大小(Byte)
*      iLeft  数组的开始下标
*      iRight 数组的结束下标
*      compare  两个元素的比较函数
*功能:对子数组进行分区划分,并返回中轴位置
*返回值:中轴元素所在位置
*作者:AlbertoNo1
*日期:2016-03-15
*/
INT32 Partition(VOID *pData,UINT32 uiElmSize, INT32 iLeft, INT32 iRight, INT32 (*compare)(void *key1, void *key2))
{
	INT32 i,j;
	CHAR *pucData = NULL;

	INT32 uiRand = 0;

	pucData = (CHAR*)pData;

	/*选择中轴位置*/
	uiRand = (rand()%(iRight-iLeft+1)) + iLeft;

	/*中轴值和第一个元素交换*/
	Swap(&pucData[iLeft*uiElmSize], &pucData[uiRand*uiElmSize], uiElmSize);

	i = iLeft;
	j = iRight+1;

	while(1)
	{
		/*向右侧移动,直到找到一个大于等于中轴值的元素*/
		do 
		{
			i = i+1;
		}while((i<=iRight)&&(compare(&pucData[i*uiElmSize], &pucData[iLeft*uiElmSize])<0));
		
	        /*向左侧移动,直到找到一个小于等于中轴值的元素*/
		do 
		{
			j = j-1;
		}while((compare(&pucData[j*uiElmSize], &pucData[iLeft*uiElmSize])>0));


		if (i < j)
		{
			/*交换元素位置*/
			Swap(&pucData[i*uiElmSize], &pucData[j*uiElmSize], uiElmSize);
		} 
		else
		{/* i >= j */
			/*中轴元素和A[j]交换,一次分区结束*/
			Swap(&pucData[iLeft*uiElmSize], &pucData[j*uiElmSize], uiElmSize);
			break;
		}
	}

	/*返回两个分区的分割位置*/
	return j;
}

/*
*函数名:QuickSort
*参数:pData  待分区数组数据的首地址
*      uiSize 数据的元素个数
*      uiElmSize  数据元素所占内存大小(Byte)
*      iLeft  数组的开始下标
*      iRight 数组的结束下标
*      compare  两个元素的比较函数
*功能:对子数组进行快速排序
*返回值:无
*作者:AlbertoNo1
*日期:2016-03-15
*/
VOID QuickSort(VOID *pData, UINT32 uiSize, UINT32 uiElmSize, INT32 iLeft, INT32 iRight, INT32 (*compare)(void *key1, void *key2))
{
	INT32   iPivotPos = 0;

    if (iLeft < iRight)
    {
		/*分区划分,j为最后划分分区的位置*/
		iPivotPos = Partition(pData, uiElmSize, iLeft, iRight, compare);
	
		/*对左侧分区继续快速排序*/
		QuickSort(pData,uiSize, uiElmSize, iLeft, iPivotPos-1, compare);
		/*对右侧分区继续快速排序*/
		QuickSort(pData,uiSize, uiElmSize, iPivotPos+1, iRight, compare);
    }
	
	return;
}


int _tmain(int argc, _TCHAR* argv[])
{
	INT32 iRet = 0;
	UINT32 uiLoop = 0;

	UINT32 auiData[] = {10,15,15,18,20,20,20,36,48,51,51,77,77};
	//UINT32 auiData[] = {77,77,51,51,48,36,20,20,20,18,15,15,10};
	//UINT32 auiData[] = {77,15,20,18,51,51,36,10,77,15,20,20,48};
	//UINT32 auiData[] = {77,77};
	//UINT32 auiData[] = {77};

	QuickSort(auiData, sizeof(auiData)/sizeof(auiData[0]), sizeof(auiData[0]), 0, ((sizeof(auiData)/sizeof(auiData[0]))-1),Compare_uint);

	printf("Quick Sort Success.\n");
	printf("Result:\n");

	for (uiLoop = 0; uiLoop < sizeof(auiData)/sizeof(auiData[0]); uiLoop++)
	{
		printf("%d  ", auiData[uiLoop]);
	}

	getchar();

	return 0;
}

 

 

 

 

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值