纯手撸——快速排序

运用递归思想:

  • 随机找主元(一般为第一个、中间、最后一个元素)
  • 对数组进行分割处理,小的元素放在主元前面,大的放在后面
  • 在对小的元素部分再取主元再分割,递归下去(同理大的元素部分)
  • 建议:下拉看图~

一张图归纳我的上述思想:

重难点操作:分割 图片参考美文——不要在问我快速排序,写的实在太好了!

1️⃣单向调整

选一个主元,如选最后一个为主元。假设数组arr的范围为[left, right],即起始下标为left,末尾下标为right。源数组如下:

然后可以用一个下标 i 指向 left,即 i = left ;用一个下标 j 也指向left,即j = left

接下来 j 从左向右遍历,遍历的范围为 [left, right-1] ,遍历的过程中,如果遇到比主元小的元素,则把该元素与 i 指向的元素交换,并且 i = i +1

如:当j指向1时,1比4小,此时把i和j指向的元素交换,之后 i++

就这样让j一直向右遍历,直到 j = right

遍历完成之后,把 i 指向的元素与主元进行交换,交换之后,i 左边的元素一定小于主元,而 i 右边的元素一定大于或等于主元。这样,就 i 完成了一次分割了

有了上面的引导,一切真的非常简单了,直接开写吧:

int partition(int a[],int left,int right)
{
    int tmp,pivot; //tmp作为临时存储,pivot指向主元
    int i,j; 
    pivot=a[right]; //照着图片写的,主元取最后一个元素
    for(j=left;j<right;j++)
    {
    	if(a[j]<pivot)
    	{
    		//swap
    		tmp=a[i];
    		a[i]=a[j];
    		a[j]=tmp;
    		i++; //记得i要移一下哟
    	}
    }
    //i指向的元素与主元元素交换
    a[right]=a[i];
    a[i]=pivot;
    return i;
}
void QuickSort(int a[],int left ,int right)
{
 	int center;
 	//至少存在两个元素
 	if(left<right)
 	{
 		center=partition(a,left,right);
 		QuickSort(a,left,center-1); //左区间递归
 		QuickSort(a,center+1,right); //右区间递归
 	}
}

2️⃣双向调整

还是用我的第一个元素充当主元吧。哈哈,源数组如下:

然后用令变量i = left + 1,j = right。然后让 i 和 j 从数组的两边向中间扫描

i 向右遍历的过程中,如果遇到大于或等于主元的元素时,则停止移动,j向左遍历的过程中,如果遇到小于或等于主元的元素则停止移动

当i和j都停止移动时,如果这时i < j,则交换 i, j 所指向的元素。此时 i < j,交换8和3

然后继续向中间遍历,直到i >= j

此时i >= j,分割结束。

最后在把主元与 j 指向的元素交换(当然,与i指向的交换也行)

这个时候,j 左边的元素一定小于或等于主元,而右边则大于或等于主元。

到此,分割调整完毕

有了上面的引导,一切又非常简单了,直接开写吧:

int partition(int a[],int left,int right)
{
	int pivot=a[left]; //这次把主元定在第一个元素
	int i=left+1; //i指向主元旁第一个元素
	int j=right;
	while(i<j) //从两端向中间扫描,直到i=j为止
	{
		//从左向右扫描
		while(i<j&&a[i]<=pivot) i++;
		//从右向左扫描
		while(i<j&&a[j]>=pivot) j--;
		if(i>=j)
			break;
		//swap
		int tmp=a[i];
		a[i]=a[j];
		a[j]=tmp;
	}
	//a[j]或a[i]与主元交换
	a[left]=a[j];
	a[j]=pivot;
	return j;
}

void QuickSort(int a[],int left ,int right)
{
 	int center;
 	//至少存在两个元素
 	if(left<right)
 	{
 		center=partition(a,left,right);
 		QuickSort(a,left,center-1); //左区间递归
 		QuickSort(a,center+1,right); //右区间递归
 	}
}

一点心得:对于这种算法,其实如果直接读书看代码或记忆真的还挺有难度,不妨记住实现的步骤图,跟着图自行拟出代码即可。

posted @ 2020-08-12 11:08  我在吃大西瓜呢  阅读(215)  评论(0编辑  收藏  举报