Partition算法剖析
- 博文链接:http://haoyuanliu.github.io/2016/12/18/Partition算法剖析/
- 对,我是来骗访问量的!O(∩_∩)O~~
partition算法从字面上就非常好理解,就是分割算法嘛!简单讲就是可以把数组按照一定的分成几个部分,其中最常见的就是快速排序中使用的partition算法,这是一个二分partition算法,将整个数组分解为小于某个数和大于某个数的两个部分,然后递归进行排序算法。
上述只是二分partition算法,我们还会使用三分partition算法,三分partition也有这非常重要的应用。往往我们更多的关注点是快速排序算法等各种算法,以及时间复杂度等这些东西,今天我们专门讨论一下partition分割算法的一些应用。
二分 Partition算法
二分partition算法是我们最常使用的,尤其在快速排序中使用最为常见。常见的partition算法有如下两种实现思路:
思路I
算法思路
- 使用第一个数组元素作为枢轴点,即为pivot;
- 使用一个指针去扫描整个数组,凡是小于pivot的全部放到数组左端;
- 最后讲pivot放到数组中间的位置,pivot左边全部都是小于他的数字,右边反之,最后返回pivot的位置信息;
代码
int partition(vector<int> &nums, int begin, int end)
{
int pivot = nums[begin];
int pos = begin;
for(int i = begin+1; i < end; ++i)
{
if(nums[i] <= pivot)
swap(nums[++pos],nums[i]);
}
swap(nums[pos], nums[begin]);
return pos;
}
思路II
算法思路
- 就如快速排序中最常使用的那样,使用两个指针分别从头部和尾部进行扫描,头部遇到大于pivot的数和尾部遇到小于pivot的数进行交换;
- 使用了两个指针,效率更高一点;
代码
int partition(vector<int> &nums, int begin, int end)
{
int pivot = nums[begin];
while(begin < end)
{
while(begin < end && nums[--end] >= pivot);
nums[begin] = nums[end];
while(begin < end && nums[++begin] <= pivot);
nums[end] = nums[begin];
}
nums[begin] = pivot;
return begin;
}
二分partition算法应用
快速排序算法
经典的快速排序算法,直接上代码:
代码
void quickSort(vector<int> &nums, int begin, int end)
{
if(end - begin <= 1)
return;
int mid = partition(nums, begin, end);
quickSort(nums, begin, mid);
quickSort(nums, mid, end);
}
数组第K大数值查询
这也是LeetCode中的一道例题,非常适合使用partition算法进行解决,问题链接215. Kth Largest Element in an Array!
解题思路
- 首先可以通过排序进行求解,简单暴力;
- 不断使用partition算法进行迭代查找;
代码
class Solution
{
public:
int findKthLargest(vector<int> &nums, int k)
{
int len = nums.size();
int res = 0;
int left = 0;
int right = len;
while(left < right)
{
int pos = partition(nums, left, right);
if(pos == len-k)
{
res = nums[pos];
break;
}
else if(pos < len-k)
left = pos+1;
else
right = pos;
}
return res;
}
int partition(vector<int> &nums, int begin, int end)
{
int pivot = nums[begin];
while(begin < end)
{
while(begin < end && nums[--end] >= pivot);
nums[begin] = nums[end];
while(begin < end && nums[++begin] <= pivot);
nums[end] = nums[begin];
}
nums[begin] = pivot;
return begin;
}
};
三分paitition算法
三分partition算法,顾名思义,也就是将数组按照规则分为三个部分,比如非常经典的国旗问题Dutch national flag problem,就是要给定的红、白、蓝三色随机颜色小球按照红、白、蓝的顺序进行排序,利用partition算法,使用一个指针进行扫描,红色的小球就用swap()放到左边,白色的保持位置不变,蓝色的同样使用swap()放到右边,最后就得到要求的序列了。
Dutch National Flag Problem
LeetCode中有恰好有这么一个题:75. Sort Colors!
解题思路
- 就使用三分partition算法进行求解就可以了!
代码
class Solution
{
public:
void sortColors(vector<int> &nums)
{
int len = nums.size();
int left = 0;
int right = len - 1;
for(int i = 0; i < len; ++i)
{
if(i > right)
break;
if(nums[i] == 1)
continue;
else if(nums[i] == 0)
{
swap(nums[i], nums[left]);
left++;
}
else
{
swap(nums[i], nums[right]);
right--;
i--;
}
}
}
};
进阶应用
LeetCode 324. Wiggle Sort II
LeetCode中的第324题中也同样可以使用三分partition算法,该题的discuss中,StefanPochmann大神提出一种O(n)+O(1)复杂度的高效算法,原链接为:
324. Wiggle Sort II
Discuss!
解题思路
- 使用partition算法获取数组的中位数,这个思路同找第k大的数,这里作者用了c++中的nth_element()函数;
- 使用宏定义的方式
#define A(i) nums[(1+2*(i)) % (n|1)]
,A()
的前半部分对应nums中下标为奇数的元素,后半部分为偶数,即奇数
+偶数
;- 使用三分partition算法对A()进行排序,使其前半部分大于后半部分,即在nums中
奇数部分
>偶数部分
;- 最终达到的效果为
0
<1
>2
<3
>4
<5
...- 注意这里需要的是
奇数
>偶数
,所以进行partition的时候大于pivot枢轴值的要放到前面;
#define A(i) nums[(1+2*(i)) % (n|1)]
的作用如下所示:
假设有0, 1, 2, 3, 4, 5, 6, 7, 8, 9共10个数据,则使用A()
进行映射之后的结果为:
A(0)
-> nums[1]
.
A(1)
-> nums[3]
.
A(2)
-> nums[5]
.
A(3)
-> nums[7]
.
A(4)
-> nums[9]
.
A(5)
-> nums[0]
.
A(6)
-> nums[2]
.
A(7)
-> nums[4]
.
A(8)
-> nums[6]
.
A(9)
-> nums[8]
.
代码
class Solution
{
public:
void wiggleSort(vector<int>& nums)
{
int n = nums.size();
// Find a median.
auto midptr = nums.begin() + n / 2;
nth_element(nums.begin(), midptr, nums.end());
int mid = *midptr;
// Index-rewiring.
#define A(i) nums[(1+2*(i)) % (n|1)]
// 3-way-partition-to-wiggly in O(n) time with O(1) space.
int i = 0, j = 0, k = n - 1;
while (j <= k)
{
if (A(j) > mid)
swap(A(i++), A(j++));
else if (A(j) < mid)
swap(A(j), A(k--));
else
j++;
}
}
};
Github: https://github.com/haoyuanliu
个人博客: http://haoyuanliu.github.io/
个人站点,欢迎访问,欢迎评论!
Partition算法剖析的更多相关文章
- 二分partition算法应用
一个二分partition算法,将整个数组分解为小于某个数和大于某个数的两个部分,然后递归进行排序算法. 法一: int partition(vector<int>&arr, in ...
- Partition算法以及其应用详解下(Golang实现)
接前文,除了广泛使用在快速排序中.Partition算法还可以很容易的实现在无序序列中使用O(n)的时间复杂度查找kth(第k大(小)的数). 同样根据二分的思想,每完成一次Partition我们可以 ...
- Partition算法以及其应用详解上(Golang实现)
最近像在看闲书一样在看一本<啊哈!算法> 当时在amazon上面闲逛挑书,看到巨多人推荐这本算法书,说深入浅出简单易懂便买来阅读.实际上作者描述算法的能力的确令人佩服.就当复习常用算法吧. ...
- 回忆Partition算法及利用Partition进行快排
一.Partiton算法 Partiton算法的主要内容就是随机选出一个数,将这个数作为中间数,将大于它的排在它右边,小于的排在左边(无序的). int partition (int arr[],in ...
- 【机器学习详解】SMO算法剖析(转载)
[机器学习详解]SMO算法剖析 转载请注明出处:http://blog.csdn.net/luoshixian099/article/details/51227754 CSDN−勿在浮沙筑高台 本文力 ...
- Partition算法及Partition算法用于快速排序
JavaScript简单方便,所以用JavaScript实现,可以在Chrome控制台下观察运行结果.主要实现Partition算法,比如输入为 var array = [4, 2, 1, 3, ...
- SWATS算法剖析(自动切换adam与sgd)
SWATS算法剖析(自动切换adam与sgd) 战歌指挥官 搬砖.码砖.代查水表.... 27 人赞同了该文章 SWATS是ICLR在2018的高分论文,提出的一种自动由Adam切换为SGD而实现更好 ...
- 唯一ID生成算法剖析
https://mp.weixin.qq.com/s/E3PGP6FDBFUcghYfpe6vsg 唯一ID生成算法剖析 原创 cloudoxou 腾讯技术工程 2019-10-08
- 请读下面的这句绕口令:ResourceManager中的Resource Estimator框架介绍与算法剖析
欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由宋超发表于云+社区专栏 本文首先介绍了Hadoop中的ResourceManager中的estimator service的框架与运行 ...
随机推荐
- 24种设计模式--抽象工厂模式【Abstract Factory Pattern】
女娲造人,人是造出来了,世界是热闹了,可是低头一看,都是清一色的类型,缺少关爱.仇恨.喜怒哀乐等情绪,人类的生命太平淡了,女娲一想,猛然一拍脑袋,忘记给人类定义性别了,那怎么办?抹掉重来,然后就把人类 ...
- c#配置文件appStrings配置节的读取、添加和修改
程序开发中经常会用到应用程序配置文件,好处就是维护人员可以直接修改配置文件进行维护,而不用修改程序.好,切入主题. 给项目添加应用程序配置文件App.config,先在里面写几句: <?xml ...
- new Image()的用途
new Image()用途总结: 1.图片预加载 在做游戏时,为了使图片能快打开可以做预加载. 原理:创建image对象,将image对象的src分别指向需加载的图片地址,图片被请 ...
- Spring面试笔记
1. Spring工作机制及为什么要用?Spring 是一个开源框架,是为了解决企业应用程序开发复杂性而创建的.Spring既是一个AOP框架,也是一IOC容器.SpringFramework的组成: ...
- yii2源码学习笔记(十五)
这几天有点忙今天好些了,继续上次的module来吧 /** * Returns the directory that contains the controller classes according ...
- PHP函数补完:preg_match()
preg_match — 进行正则表达式匹配. 语法:int preg_match ( string $pattern , string $subject [, array $matches [, i ...
- ART模式和Dalvik模式的异同
Dalvik模式 如果要解释清楚什么是ART模式,我们就需要从Android系统的应用编译模式说起,我们都知道Android系统是以Linux系统为底层构建的,Android系统是开源(源代码公开)的 ...
- Python函数式编程初级学习
函数式编程即函数可以作为参数传入函数,也可以返回函数. 1.高阶函数 函数可以作为参数传入函数. def add(x,y,f): return f(x)+f(y) ...
- Cinder-2 窗口的创建过程
通过TinderBox生成的代码很简单,整个代码如下: #include "cinder/app/AppNative.h" #include "cinder/gl/gl. ...
- 2015_WEB页面前端工程师_远程测题_东方蜘蛛_1
请使用HTML+CSS实现如下效果: 1. 使用CSS Sprites,实现如图1效果,素材图片为: icons.png: 2. 使用脚本语言验证邮箱.密码的必填以及邮箱的合法性: 若验证失败,则出现 ...