【ICPC-465】算法研究之快速排序

 

   1 快速排序的思想

      通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。 

      快速排序的思想就是通过分治策略,每次对两部分的数据进行递归排序。假设我们要排序的数组是arr,从left~right这一段,我们每次选择arr[(left+right)>>1]作为基准数字(很多地方是选择第一个或者最后一个),然后把这个子段分成两部分,再进行递归

      代码:

 

int partition(int *arr, int l, int r){
	int pos = (l+r)>>1;//选择中间的数作为基准
	swap(arr[pos], arr[r]);//把这个数交换到最后一个位置
	int leftSeqNum = l; //左子序列的结束位置

	for(int i = l; i < r; i++){
		if(arr[i] < arr[r]){
		   if(leftSeqNum < i)
			   swap(arr[leftSeqNum], arr[i]);
		   leftSeqNum++;
		}	
	}
	//再把基准的值交换到正确的位置
	swap(arr[leftSeqNum], arr[r]);
	return leftSeqNum;
}
void quickSort(int *arr, int l, int r){
    if(arr == NULL || l == r)
		return;
	int index = partition(arr, l, r);
	if(l < index)
		quickSort(arr, l, index-1);
	if(index < r)
		quickSort(arr, index+1, r);
}


    2 假设我们要排序一个数组arr[7] = {5, 1, 3, -1, 0, 7, 4}

 

      第一趟:我们排序的是left = 0,right = 6,我们的基准数字是standard = arr[3] = -1,i = 0, j = 6

                   从i开始判断有没有连续小于standard的,得到 i = 0

                   从j往下判断有没有连续大于standard的,得到 j = 3

                   于是交换 arr[i] 和 arr[j],并把i++和j--,得到i = 1, j = 2,序列为-1 1 3 5 0 7 4

 

                   然后重复上面的,得到i = 1,j =0,于是这一轮的排序结束,最终序列为

                   -11 3 5 0 7 4,分成了两部分 ,于是对着两部分进行递归排序

         

      第二趟:我们考虑序列 1 3 5 0 7 4,left = 1,right = 6,i = 1,j = 6,standard = 5                 

 

                              从i开始判断有没有连续小于standard的,得到 i = 3

                   从j往下判断有没有连续大于standard的,得到 j = 6

                   于是交换 arr[i] 和 arr[j],并把i++和j--,得到i = 4, j = 5,序列为1 3 4 0 7 5

                    

                   然后重复上面的,得到i = 5,j =4,于是这一轮的排序结束,最终序列为

                   1 3 4 07 5,分成了两部分,于是对这剩下的进行递归排序

         

      第三趟: 我们考虑序列 1 3 4 0,left = 1,right = 4,i = 1,j = 4,standard = 3

                   从i开始判断有没有连续小于standard的,得到 i = 2

                   从j往下判断有没有连续大于standard的,得到 j = 4

                   于是交换 arr[i] 和 arr[j],并把i++和j--,得到i = 3, j = 3,序列为1 0 4 3

                   这边就是为什么我们需要写成while(i <= j),而不是while(i < j)的原因了,这个时候i和j指向同一个元素,我们                      还没有分成两部分

 

                   然后重复上面的,得到i = 4,j =3,于是这一轮的排序结束,最终序列为

                   1 04 3,分成了两部分,于是对这剩下的进行递归排序

 

        第四趟:  我们考虑序列 1 0,left = 1,right = 4,i = 1,j = 2,standard = 1

                   从i开始判断有没有连续小于standard的,得到 i = 1

                   从j往下判断有没有连续大于standard的,得到 j = 2

                   于是交换 arr[i] 和 arr[j],并把i++和j--,得到i = 1, j = 1,序列为0 1

 

                   这个时候序列分成了两部分,分别只有一个数字,所以继续递归向下

 

     注意:   为什么,在while里面的交换,那边要写成if(i <= j) swap(arr[i++], arr[j--]),大家试着想下面的一个例子

                 假设我们要排序的数组是arr[] = {1, 2, 3, 4, 5, 6, 7}

                 那么我们第一轮过后最终得到i = 3,j = 3,如果我们写成if(i < j) swap(arr[i++], arr[j--]),那么将永远执行while

                 循环,所以说为了防止这个特例的发生,必须要写成if(i <= j) swap(arr[i++], arr[j--])

 

     剩下的和上面差不多,大家可以试着手动写一下。快速排序很重要,希望文章能够帮助大家,谢谢!

 

 

 

     ==================================

     ==      from:陈国林                                        ==

     ==      email:cgl1079743846@gmail.com     ==

     ==      转载请注明出处,谢谢!                        ==

     ==================================

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值