QUICKSORT(快速排序)--算法导论

快速排序和归并排序一样,都使用了分治思想,下面是对一个子数组A[p,r]进行快速排序的三步分治过程:

分解:数组A通过PARTITION()算法分区为两个(可能为空)子数组A[p...q-1]和A[q+1,r]使得A[p..q-1中的每一个元素都小于(小于等于)A[q],而A[q]也小于等于(小于)A[q+1...r]中的每一个元素。

解决:通过递归调用快速排序,对子数组A[p..q-1]和A[q+1,r]进行PARTITION()

合并:因为子数组都是原址排序的,所以不需要合并操作,数组A[p...r]已经有序。

快速排序需要选择一个主元(就是上面的A[q])来充当划分的界限,这里有三种方法进行PARTITION()操作:

1.前后指针法

2.左右指针法

3.挖坑法

一,前后指针法(指针非真指针,这里是使用下标)

我们选第一个元素作主元,也可以选最后一个,代码会与下面有些点点改变,但思想不变

伪代码:

PARTITION1(A,p,r)                   

        x = A[p]                                           //选取A[p]作为主元

        i = p                                            

        for j = p+1 to r                               

                if A[j] <= x                                 //找到小于等于主元的元素

                        i = i +1

                        exchange A[i] with A[j]            //交换下标为 i 和 j 的元素

        exchange A[i] with A[p]

        return i

二,左右指针法:

取头尾位置作为主元(分区后主元左边的元素都比其小(或相等),右边的元素都比其大(或相等)),这里我们取头位置作为主元

伪代码:

PARTITION2(A,p,r)                   

        x = A[p]                                           //选取A[p]作为主元

        i = p                                            

        j  = r                           

        while( i != j )
               

                while(A[ j ] > x&&j!=i)                        //找小,遇到大的就继续                      

                         j = j - 1

                while(A[ i ] < = x &&j!=i)                             //找大,遇到小的就继续

                        i = i +1                

                 exchange A[i] with A[j]            //交换下标为 i 和 j 的元素

        exchange A[i] with A[p]

        return i

左右指针法有些要注意的方面,就是我们是先找大,还是先找小。这根据我们所选主元的位置有关,我们取第一个元素作主元,假设进行升序排,我们让 i 从前往后找 大于主元的元素,找到之后,让 j 从后往前找 小于等于主元的元素,找到了 就交换A[ i ] 和A [ j ]  ,这样进行了几轮交换之后,开始了最一轮,先找大的,i 从前往后找,找着找着和  j 相遇了  ,此时应结束循环,将主元归位 exchange A[i] with A[p],此时问题出现了,j 指针所指的元素是大于主元的,主元又位于第一个元素位置,交换之后,主元左边的元素就不是都小于等于主元。

看图:先找大

SO 我们先找小

看图:

以最后一个元素作主元,思路也是相似的,要诀定好是先找大,还是先找小

三,挖坑法:我们取第一个元素作为主元,也可以取最后一个,思想一样

挖坑法顾名思义就是挖坑

伪代码:

PARTITION2(A,p,r)                   

        x = A[p]                   //选取A[p]作为主元

        t = p                                       //坑的下标

        i = p+1                                            

        j  = r                           

        while( i != j )            

               while(A[ j ] > x&&i !=j )           //找小于等于主元的元素

                        j = j - 1

                exchange A[ t ] with A[ j ]                  //找到后填入坑中

                t = j                                                //填入元素之前的下标变为新坑

                while(A[ i ] <= x &&i !=j )                         //找大于主元的元素           

                         i = i +1        

                 exchange A[ t ] with A[ i ]                        //填入新坑中

                  t = i                                                      //填入的元素又成为新坑

        exchange A[ t ] with  x                                        // 最后将主元填入坑中

        return t

四,实现快速排序

伪代码:

QUICKSORT(A, p , r )

        if p < r

                q = PARTITION( A, p , r)

                QUICKSORT(A, p, q-1)

                QUICKSORT(A, q+1, r)

我使用的是挖坑法,看图:

五,代码实现

#include<iostream>
using namespace std;

//前后指针法
int PARTITION1(int A[], int p, int r)
{
	int x = A[p];
	int i = p;
	for (int j = p + 1; j <= r; ++j)
	{
		if (A[j] <= x)
		{
			++i;
			int temp = A[j];
			A[j] = A[i];
			A[i] = temp;
		}
	}
	A[p] = A[i];
	A[i] = x;
	return i;
}
//使用前后指针法的快速排序
void QUICKSORT1(int A[], int p, int r)
{
	if (p <r)
	{
		int q = PARTITION1(A, p, r);
		QUICKSORT1(A, p, q - 1);
		QUICKSORT1(A, q+1,r);
	}
}
//左右指针法
int PARTITION2(int A[], int p, int r)
{

	int x = A[p];
	int i = p;
	int j = r;
	while (i != j)
	{
		while (A[j] > x&&i!=j)
		{
			--j;
		}
		while (A[i] <= x&&i!=j)
		{
			++i;
		}
		int temp = A[j];
		A[j] = A[i];
		A[i] = temp;

	}
		A[p] = A[i];
		A[i] = x;
		return i;
	
	
}
//使用左右指针法的快速排序
void QUICKSORT2(int A[], int p, int r)
{
	if (p < r)
	{
		int q = PARTITION2(A, p, r);
		QUICKSORT2(A, p, q - 1);
		QUICKSORT2(A, q + 1, r);
	}
}
//挖坑法
int PARTITION3(int A[], int p, int r)
{

	int x = A[p];
	int t = p;
	int i = p;
	int j = r;
	while (i != j)
	{
		while (A[j] > x && i != j)
		{
			--j;
		}
		A[t] = A[j];
		t = j;
		while (A[i] <= x && i != j)
		{
			++i;
		}
		A[t] = A[i];
		t = i;

	}
	A[t] = x;
	return t;


}
//使用挖坑法的快速排序
void QUICKSORT3(int A[], int p, int r)
{
	if (p < r)
	{
		int q = PARTITION3(A, p, r);
		QUICKSORT3(A, p, q - 1);
		QUICKSORT3(A, q + 1, r);
	}
}

//打印
void Print(int A[], int size)
{
	for (int i = 0; i < size; ++i)
	{
		cout << A[i] << " ";
	}
	cout << endl;
}
int main()
{
	int A[] = { 13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7 };
	int B[] = { 13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7 };

	int C[] = { 13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7 };
	int size = sizeof(A) / sizeof(int);
	
	cout << "要排序的的数组为:" << endl;
	Print(A, size);
	QUICKSORT1(A, 0, size - 1);
	cout << "用前后指针法排完升序后:" << endl;
	Print(A, size);
	QUICKSORT2(B, 0, size - 1);
	cout << "用左右指针法排完升序后:" << endl;
	Print(B, size);
	QUICKSORT2(C, 0, size - 1);
	cout << "用挖坑法排完升序后:" << endl;
	Print(C, size);
}

结果

要排序的的数组为:
13 -3 -25 20 -3 -16 -23 18 20 -7 12 -5 -22 15 -4 7
用前后指针法排完升序后:
-25 -23 -22 -16 -7 -5 -4 -3 -3 7 12 13 15 18 20 20
用左右指针法排完升序后:
-25 -23 -22 -16 -7 -5 -4 -3 -3 7 12 13 15 18 20 20
用挖坑法排完升序后:
-25 -23 -22 -16 -7 -5 -4 -3 -3 7 12 13 15 18 20 20

  • 26
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值