算法笔记六:使用分治策略执行快速排序
2014-10-17 17:41
232 查看
算法思想:
//采用分治策略,将原数组,分解为三部分:左边的 + 已最终定位的节点位置 + 右边的
//分解:取任意一个位置的数,将数组划分为3部分:左边+该数的最终位置+右边,继续对左右两边递归执行分解操作
//解决:求出给定位置数的最终位置,即保证左边都比它小,右边都比它大
//合并:在分解的过程中,就已经将元素的最终位置给计算好了,不需要任何操作
分解—>解决—>合并
在分解的步骤中,什么条件下是阻止其继续分解的终止阀呢?:
分解的只有一个元素了
解决:
找出给定元素应该在该数组出现的最终位置,这里只要做一次数组的遍历就可以计算出来了,具体实现方式请参见实现代码的注释部分
合并:
不需要执行任何动作,解决的过程中就已经将要解决的数子的位置给计算好了
最好情况:
O(n*log2n)
最坏情况:
O(n^2)
下面我们来分析下这里的时间代价:
假设数组是一个已经排好序的数组,那么在分解的过程中,每个元素的初始化位置就是其最终位置,则如果每次选择数组中的第一个元素执行分解的话,那么就会导致每次都分解成只有右边一侧的子数组,而由于每次解决的代价都是数组大小n,则总的代价为:n + (n-1) + (n-2) + … + 1 = O(n^2)
如果每次分解都能将数组分割为两部分(假定为平均的2个部分,有利于分析),则有:
T(n) = T(n/2) + T(n/2) + O(n)
使用带入法:
T(n) = T(n/4) + T(n/4)+ T(n/4)+ T(n/4) + O(n) + O(n/2)
使用递归树的分析不难得出:T(n) = O(n*lgn)
这里需要理解的是,即使是每次分解后的数组不是均衡的,比如左边是9/10,右边是1/10,依然不影响这个这个递归树的高度,所以无论是否均衡,其代价都是O(n*lgn),而如果每次分解后只产生一颗子树,那么树的高度将大大增加,导致的时间代价就是上面分析的最坏情况n^2
空间代价上,只是两个元素交换时需要开辟一个元素的额外空间,基本忽略不计!
算法实现:
算法总结:
由于一般待排序的记录都是无序的,所以该算法很少会出现最坏情况,又因为其无论是在时间代价上和空间代价上,其解都是最优的,所以其广泛的运用于各种排序算法中
//采用分治策略,将原数组,分解为三部分:左边的 + 已最终定位的节点位置 + 右边的
//分解:取任意一个位置的数,将数组划分为3部分:左边+该数的最终位置+右边,继续对左右两边递归执行分解操作
//解决:求出给定位置数的最终位置,即保证左边都比它小,右边都比它大
//合并:在分解的过程中,就已经将元素的最终位置给计算好了,不需要任何操作
分解—>解决—>合并
在分解的步骤中,什么条件下是阻止其继续分解的终止阀呢?:
分解的只有一个元素了
解决:
找出给定元素应该在该数组出现的最终位置,这里只要做一次数组的遍历就可以计算出来了,具体实现方式请参见实现代码的注释部分
合并:
不需要执行任何动作,解决的过程中就已经将要解决的数子的位置给计算好了
最好情况:
O(n*log2n)
最坏情况:
O(n^2)
下面我们来分析下这里的时间代价:
假设数组是一个已经排好序的数组,那么在分解的过程中,每个元素的初始化位置就是其最终位置,则如果每次选择数组中的第一个元素执行分解的话,那么就会导致每次都分解成只有右边一侧的子数组,而由于每次解决的代价都是数组大小n,则总的代价为:n + (n-1) + (n-2) + … + 1 = O(n^2)
如果每次分解都能将数组分割为两部分(假定为平均的2个部分,有利于分析),则有:
T(n) = T(n/2) + T(n/2) + O(n)
使用带入法:
T(n) = T(n/4) + T(n/4)+ T(n/4)+ T(n/4) + O(n) + O(n/2)
使用递归树的分析不难得出:T(n) = O(n*lgn)
这里需要理解的是,即使是每次分解后的数组不是均衡的,比如左边是9/10,右边是1/10,依然不影响这个这个递归树的高度,所以无论是否均衡,其代价都是O(n*lgn),而如果每次分解后只产生一颗子树,那么树的高度将大大增加,导致的时间代价就是上面分析的最坏情况n^2
空间代价上,只是两个元素交换时需要开辟一个元素的额外空间,基本忽略不计!
算法实现:
// // QuickSort.h // p1 // // Created by MinerGuo on 14-10-17. // Copyright (c) 2014年 MinerGuo. All rights reserved. // #ifndef __p1__QuickSort__ #define __p1__QuickSort__ #include <stdio.h> //采用分治策略,将原数组,分解为三部分:左边的 + 已最终定位的节点位置 + 右边的 //分解:取任意一个位置的数,将数组划分为3部分:左边+该数的最终位置+右边,继续对左右两边递归执行分解操作 //解决:求出给定位置数的最终位置,即保证左边都比它小,右边都比它大 //合并:在分解的过程中,就已经将元素的最终位置给计算好了,不需要任何操作 class QuickSort { void changeTwoItems(int * data,int i,int j){ int tmp = *(data + i); *(data + i) = *(data + j); *(data + j) = tmp; } public: //分解 void split(int * data,int left,int right){ //只有一个元素时终止 if(left >= right){ return; } //这里选取参考数组的位置是可以随机的 int referenceDataPosition = left; //解决 int finalPosition = solve(data,left,right,referenceDataPosition); //fianlPosition 元素已经定位完毕 //分解左半部分 split(data,left,finalPosition -1); //分解右半部分 split(data,finalPosition + 1,right); } //给定数组的区间,以及要找出数组最终位置的那个数据 //返回该数据的最终位置, //这里的方法是:先从后往前找,发现第一个比它小的,调换,从前往后找,这样保证了后面都比他大 //然后从前往后找,找到第一个大于等于它的,调换,再从后往前找,直到左右相等 int solve(int * data,int left,int right,int referenceDataPosition){ int finalDataPosition = referenceDataPosition; int referencDataValue = *(data + referenceDataPosition); int lp = left,rp=right,direction = -1; while(lp < rp){ if(direction == -1){ //从后往前 for(;rp>=lp;rp--){ if(*(data + rp) < referencDataValue){ changeTwoItems(data,rp,finalDataPosition); finalDataPosition = rp; direction = 1; break; } } }else{ //从前往后 for(;lp<=rp;lp++){ if(*(data + lp) >= referencDataValue){ changeTwoItems(data,lp,finalDataPosition); finalDataPosition = lp; direction = -1; break; } } } } return finalDataPosition; } //排序入口 void do_sorting(int * data,int size){ split(data, 0, size - 1); } }; #endif /* defined(__p1__QuickSort__) */
算法总结:
由于一般待排序的记录都是无序的,所以该算法很少会出现最坏情况,又因为其无论是在时间代价上和空间代价上,其解都是最优的,所以其广泛的运用于各种排序算法中
相关文章推荐
- 递归与分治策略之快速排序
- C语言实现的快速排序,采用分治策略,递归实现
- 使用企业库在某些站点会报试图执行安全策略不允许的操作异常的解决方法。
- Spring中正确使用Quartz和CronExpression 执行策略
- 递归与分治策略之快速排序
- Java使用分治递归的思想实现快速排序
- 算法基础(3)分治策略之快速排序
- 基于分治策略的排序算法:合并排序和快速排序
- 算法分析与设计实验 分治策略 两路合并排序和快速排序
- 递归与分治策略-----快速排序(C++)
- 分治策略(快速排序)
- 使用ant执行xsl转换
- (示例)使用快速排序例程进行排序
- 使用链接服务器执行远程数据库上的存储过程
- 在 ASP.NET 中使用计时器执行用户代码(原创代码)
- 使用 SqlCommand 执行SQL命令示例
- Workshop8.1中使用ANT自动执行Sql
- J2EE 探索者:使用 Java Servlets 2.4 来执行过滤
- 使用struts 怎么才能在执行完js校验页面的信息,发现不全的情况下,不让页面提交到Action中
- J2EE 探索者:使用 Java Servlets 2.4 来执行过滤