Partition算法记录
来源:互联网 发布:淘宝电脑客户端 编辑:程序博客网 时间:2024/06/06 01:58
转自:被忽视的 partition 算法:http://blog.jobbole.com/105219/
版权归原作者所有 如有侵权请联系作者予以删除。
算法介绍
首先以无序数组中的元素为枢轴点 pivot,经过一次遍历,将数组中其他元素分为以 pivot 为分界线的两部分,使得左边部分的数小于等于pivot,右边部分的数大于等于pivot(左部分或者右部分都可能为空),最后返回pivot在新的数组中的位置。
算法原理
指针单向遍历
以数列的第一个元素为轴点,单向遍历
arr[begin, end)
// Do partition in arr[begin, end), with the first element as the pivot.int partition(vector<int>&arr, int begin, int end){ int pivot = arr[begin]; // Last position where puts the no_larger element. int pos = begin; for(int i=begin+1; i!=end; i++){ if(arr[i] <= pivot){ pos++; if(i!=pos){ swap(arr[pos], arr[i]); } } } swap(arr[begin], arr[pos]); return pos;}
如果原始数组为[5,9,2,1,4,7,5,8,3,6],那么整个处理的过程如下图所示:
指针双向遍历
Two Pointers 的思想,保持头尾两个指针向中间扫描,每次在头部找到大于pivot的值,同时在尾部找到小于pivot的值,然后将它们做一个交换,就可以一次把这两个数字放到最终的位置。一种比较明智的写法如下:
int partition(vector<int>&arr, int begin, int end){ int pivot = arr[begin]; while(begin < end) { while(begin < end && arr[--end] >= pivot); arr[begin] = arr[end]; while(begin < end && arr[++begin] <= pivot); arr[end] = arr[begin]; } arr[begin] = pivot; return begin;}
同样以原始数组[5,9,2,1,4,7,5,8,3,6]为例,处理流程为:
直观上来看,赋值操作的次数不多,比前面单向扫描的swap次数都少,效率应该会更高。
但是直觉上总是感觉如果将双向遍历等同于两次单向遍历,效率应该差不多啊。。。
应用1:快速排序
首先用 partition 将数组分为两部分,然后分别对左右两部分递归进行快速排序,过程如下:
void quick_sort(vector<int> &arr, int begin, int end){ if(begin >= end - 1){ return; } int pos = partition(arr, begin, end); quick_sort(arr, begin, pos); quick_sort(arr, pos+1, end);}
应用2:从无序数组中寻找从小到大第k个值
首先用 partition 将数组分为两部分,得到分界点下标 pos,然后分三种情况:
pos == k-1,则找到第 K 大的值,arr[pos];
pos > k-1,则第 K 大的值在左边部分的数组。
pos < k-1,则第 K 大的值在右边部分的数组。
int find_kth_number(vector<int> &arr, int k){ int begin = 0, end = arr.size(); assert(k>0 && k<=end); int target_num = 0; while (begin < end){ int pos = partition(arr, begin, end); if(pos == k-1){ target_num = arr[pos]; break; } else if(pos > k-1){ end = pos; } else{ begin = pos + 1; } } return target_num;}
应用3:三色旗问题
问题描述:
给定红、白、蓝三种颜色的小球若干个,将其排成一列,使相同颜色的小球相邻,三种颜色先后顺序为红,白,蓝。
最直接的想法是对红,蓝,白三种颜色的球分别计数,然后根据计数结果来重新放球。
不过如果我们将问题进一步抽象,也就是说将一个数组按照某个target值分为三部分,使得左边部分的值小于 target,中间部分等于 target,右边部分大于 target,这样就不能再用简单的计数来确定排序后的结果。
- next_less_pos 指向左边部分的边界,等待存放下一个小于target的值
- next_bigger_pos指向右边部分的边界,等待存放下一个大于target的值
- next_scan_pos 为移动遍历指针
思想:不断减少未知区域的元素 当scan指针和bigger指针重合,表示未知区域减小为0, 结束遍历。
// Assume target is in the arr.void three_way_partition(vector<int> &arr, int target){ int next_less_pos = 0, next_bigger_pos = arr.size()-1; int next_scan_pos = 0; while (next_scan_pos <= next_bigger_pos){ if(arr[next_scan_pos] < target){ swap(arr[next_scan_pos++], arr[next_less_pos++]); } else if(arr[next_scan_pos] > target){ swap(arr[next_scan_pos], arr[next_bigger_pos--]); } else{ next_scan_pos++; } }}
- Partition算法记录
- Partition算法
- Spark Partition 分区记录
- 【算法】划分 partition
- 基本算法-partition函数
- 算法<Array Partition I>
- hive partition 使用记录1
- 快速排序partition算法修正
- 排序算法nth_element()和partition()
- 快速排序中的partition算法
- partition算法思想的应用
- 被忽视的 partition 算法
- 知其所以然-- partition 算法
- LeetCode算法题目:Partition List
- 编写 kafka Partition 分配算法
- 用Oracle rank partition 筛选记录
- 个人记录-LeetCode 86. Partition List
- Partition
- 笔记—自定义Veiw之Paint详解
- C++3
- 一道面试题引发的关于c语言中文件操作的总结
- 数据结构思维 第八章 索引器
- 大数阶乘(万进制)(HDU 1402)
- Partition算法记录
- 二分图匹配模板
- EasyDSS高性能流媒体服务器前端重构(五): webpack + vue-router 开发单页面前端实现按需加载
- Putty连接Linux服务器
- Appium移动自动化测试(一)--安装Appium
- Keycode对照表。
- java实现学生信息统计系统
- 理解范式NF
- 2017超星尔雅周易的奥秘答案