算法笔记六:使用分治策略执行快速排序
来源:互联网 发布:当前非涉密网络是 编辑:程序博客网 时间:2024/06/06 01:48
算法思想:
//采用分治策略,将原数组,分解为三部分:左边的 + 已最终定位的节点位置 + 右边的
//分解:取任意一个位置的数,将数组划分为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__) */
算法总结:
由于一般待排序的记录都是无序的,所以该算法很少会出现最坏情况,又因为其无论是在时间代价上和空间代价上,其解都是最优的,所以其广泛的运用于各种排序算法中
- 算法笔记六:使用分治策略执行快速排序
- 算法中分治策略实现快速排序
- 分治策略----快速排序
- 算法基础(3)分治策略之快速排序
- 算法学习(5)分治策略(快速排序)
- 分治算法-快速排序
- 分治算法----快速排序
- 快速排序-分治算法
- 分治算法---快速排序
- 分治算法 快速排序
- 基于分治策略的排序算法:合并排序和快速排序
- 0005算法笔记——【分治法】快速排序
- 0005算法笔记——【分治法】快速排序
- 算法笔记——【分治法】快速排序
- 算法笔记0005——【分治法】快速排序
- 0005算法笔记——【分治法】快速排序
- 分治算法之快速排序
- 分治算法之快速排序
- static静态变量的理解
- ios中的几种指令集(armv6、armv7、armv7s、arm64)
- sqlserver 表复制
- WeakHashMap
- 批处理xcopy 命令 局域网备份文件道另台主机
- 算法笔记六:使用分治策略执行快速排序
- HTML中select的option设置selected="selected"无效的解决方案
- C# 以JSON数组形式返回数据
- Preference元素和监听事件
- Node.js v0.10.31API手册-DNS
- android使用viewPager和Fragment实现滑动切换activity!
- php mysql PDO使用
- CPU很高分析
- UVA11248 网络扩容(枚举割边扩充)