荷兰国旗问题

给定一个数组arr,和一个数num,请把小于num的数放数组的左边,等于num的数放在数组的中间,大于num的数放在数组的右边。要求额外空间复杂度O(1),时间复杂度O(N)。

这个问题的解决思路是这样的,首先划定一个小于区域,其右边界为less,划定一个大于区域,其左边界为more。从数组的第一个元素开始进行遍历,如果当前小于num,那么将这个数与小于区域外的第一个元素进行交换,并对当前位置的下一个元素进行判断;如果当前值大于num,那么将当前值与大于区域外的第一个元素进行交换,并且对交换来的元素进行判断;如果当前值等于num,那么对当前值的下一个元素进行判断。

void Netherlandsflag(vector<int> arr, int num)
{
vector<int> res;
int more = arr.size() ; //大于区域左边界
int less = -1; //小于区域右边界
int current = 0;
while (current < more)
{
if (arr[current] < num)
{
swap(arr[current++], arr[++less]); //将当前值与小于区域下一个值进行交换,小于区域扩大
}
else if (arr[current]>num)
{
swap(arr[current], arr[--more]); //将当前值与大于区域下一个值进行交换,大于区域扩大,并对
} //交换来的数继续进行判断
else //当前值等于num时,对下一个值进行判断
{
current++;
}
}
}

快排

快排的思路类似于荷兰国旗问题,挑选一个比较值,将小于比较值的放左边,大于比较值的放右边,等于比较值的放中间。并对大于区域和小于区域进行同样的操作。

void Quicksort(vector<int> &arr, int start, int end)
{
if (start < end)
{
vector<int> edge = partition(arr, start, end);
Quicksort(arr, start, edge[0]);
Quicksort(arr, edge[1], end);
}
} vector<int> partition(vector<int> &arr, int start, int end) //类似于荷兰国旗问题
{
int index = start;
int less = start - 1;
int more = end + 1;
int num = arr[rand() % (end - start + 1) + start]; //随机选取数组中元素作为比较值
while (index < more)
{
if (arr[index] < num)
{
swap(arr[index++], arr[++less]);
}
else if (arr[index]>num)
{
swap(arr[index], arr[--more]);
}
else
{
index++;
}
}
vector<int> res{less, more}; //存储边界
return res;
}

经典快排将每次的比较值都选择为arr[end],这种方法的弊端在于它的时间复杂度是与数据状况有关。举个例子,如果我们需要处理的数组为{1,2,3,4,5,6},选择arr[end]作为比较值时,每次partition仅能将问题的规模减少一个,这样使得时间复杂度变为了O(N^2)。而随机快排可以使得问题的期望达到O(N*logN),其做法仅需要在经典快排的基础上,将数组中随机的一个数与arr[end]进行交换。

BFPRT算法

BFPRT算法是对上述的快排进行优化的,可以利用BFPRT算法求一个数组中第k大的值或第k小的值。BFPRT对于随机快排的优化在于,随机选取一个元素变为选取中位数,它的步骤可以分为以下几步:

  1. 将数组分为5个一组的多个数组,不足五个的形成一组。
  2. 组内进行排序。
  3. 每个组中位数取出构成新的数组。
  4. 递归调用BFPRT直到得到一个数组只剩下一个数,返回这个数作为比较值。
int selectnum(vector<int> arr, int start, int end)
{
if (start == end)
{
return arr[start];
}
int offset = (end - start + 1) % 5 == 0 ? 0 : 1; //不足5个数的形成一组
int length = (end - start + 1) / 5 + offset;
vector<int> median(length);
for (int i = 0; i < median.size(); i++)
{
int startI = start + i * 5;
int endI = startI + 4 < end ? (startI + 4) : end;//最后一组的endI为end
median[i] = getmedian(arr, startI, endI); //可以选择插入排序选择排序等,数据规模不大于5
}
return select(median, 0, median.size() - 1); //递归调用
}

接下来解决求数组中第k小的值的问题:

  1. 小于中位数的放左边,等于中位数的放中间,大于中位数的放右边
  2. 如果k小于小于区域的右边界,那么在小于区域递归partition过程。如果k大于大于区域的左边界,那么在大于区域递归partition过程。如果刚好k处于等于区域中,返回中位数的值。
int MinKthbyBFPRT(vector<int> &arr, int start, int end, int k)
{
if (start == end)
return arr[start];
int num = selectnum(arr, start, end);
vector<int> edge = partition(arr, start, end, num);
if (k > edge[0] && k < edge[1])
{
return num;
}
else if (k <= edge[0])
{
return BFPRT(arr, start, edge[0], k);
}
else
{
return BFPRT(arr, edge[1], end, k);
}
}

荷兰国旗问题、快排以及BFPRT算法的更多相关文章

  1. BFPRT 算法 (TOP-K 问题)——本质就是在利用分组中位数的中位数来找到较快排更合适的pivot元素

    先说快排最坏情况下的时间复杂度为n^2. 正常情况:   最坏的情况下,待排序的记录序列正序或逆序,每次划分只能得到一个比上一次划分少一个记录的子序列,(另一个子序列为空).此时,必须经过n-1次递归 ...

  2. 算法笔记_051:荷兰国旗问题(Java)

    目录 1 问题描述 2 解决方案   1 问题描述 现有n个红白蓝三种不同颜色的小球,乱序排列在一起,请通过两两交换任意两个球,使得从左至右的球依次为红球.白球.蓝球.这个问题之所以叫荷兰国旗,是因为 ...

  3. Java常见的几种排序算法-插入、选择、冒泡、快排、堆排等

    本文就是介绍一些常见的排序算法.排序是一个非常常见的应用场景,很多时候,我们需要根据自己需要排序的数据类型,来自定义排序算法,但是,在这里,我们只介绍这些基础排序算法,包括:插入排序.选择排序.冒泡排 ...

  4. 冒泡,快排算法之javascript初体验

    引子:javascript实际使用的排序算法在标准中没有定义,可能是冒泡或快排.不用数组原生的 sort() 方法来实现冒泡和快排. Part 1:冒泡排序(Bubble Sort) 原理:临近的两数 ...

  5. scala写算法-快排

    快排算法很经典,今天用scala的函数式思维来整理一下并实现: def qsort(list: List[Int]):List[Int]=list match { case Nil=>Nil c ...

  6. javascript高级排序算法之快速排序(快排)

    javascript高级排序算法之快速排序(快排)我们之前讨论了javascript基本排序算法 冒泡排序 选择排序 插入排序 简单复习: 冒泡排序: 比较相邻的两个元素,如果前一个比后一个大,则交换 ...

  7. 《算法导论》——重复元素的随机化快排Optimization For RandomizedQuickSort

    昨天讨论的随机化快排对有重复元素的数组会陷入无限循环.今天带来对其的优化,使其支持重复元素. 只需修改partition函数即可: int partition(int *numArray,int he ...

  8. 《算法导论》——随机化快排RandomizedQuickSort

    今日算法:随机化快排RandomizedQuickSort 基础工作swap交换和partition分治 /* *交换数组的两个元素 *fromIndex和toIndex为要交换的两个元素的索引 */ ...

  9. 回忆Partition算法及利用Partition进行快排

    一.Partiton算法 Partiton算法的主要内容就是随机选出一个数,将这个数作为中间数,将大于它的排在它右边,小于的排在左边(无序的). int partition (int arr[],in ...

随机推荐

  1. 图像处理之基础---滤波器之高斯低通滤波器的高斯模板生成c实现

    ()代码实现 对原图进行高斯平滑,去除图像中的计算噪声void Bmp::MakeGauss(double sigma,double **pdKernel,int *pnWindowSize){ // ...

  2. Linux/Android——usb触摸屏驱动 - usbtouchscreen (一)【转】

    本文转载自:http://blog.csdn.net/jscese/article/details/41827495 最近需要往TV上装一个触摸屏设备,现在比较常见的就是使用usb接口的触摸框,适用于 ...

  3. bzoj 1826 缓存交换

    题目大意: 一些数,需要将他们依次取入一个集合中 集合的容量有限 若该数已经在集合中则不用再取 每次取的时候可以将集合中与元素替换为另一个,也可以不换,直接加入前提是不超过集合容量 求最后最小的取数次 ...

  4. [POI2012]FES-Festival

    https://www.zybuluo.com/ysner/note/1252538 题面 有一个数列\(\{a\}\).现给定多组限制,限制分成\(2\)类,第一类是\(a_x+1=a_y\),有\ ...

  5. Left Join 时筛选条件在on后与where后的区别

    a left join  b 时限制条件在on后, 相当于先筛选右连接表b的数据后,再进行数据连接.形成最终的集合. 这时不影响a表中相关字段的显示. SELECT T001W~WERKS, LGOR ...

  6. 洛谷2019 3月月赛 T1

    题干 2019第一次月赛 我只有255pts T1还是比较水的... 海星 T1一道简单的模拟(就是有坑..导致很多人不能一次性AC 比如说我) _3个坑点 1.位数问题 2.-0 3.0... #i ...

  7. [SHOI2013]超级跳马

    题目描述 现有一个n 行m 列的棋盘,一只马欲从棋盘的左上角跳到右下角.每一步它向右跳奇数列,且跳到本行或相邻行.跳越期间,马不能离开棋盘.试求跳法种数mod 30011. 输入输出格式 输入格式: ...

  8. [TJOI2012]桥

    Description 有n个岛屿,m座桥,每座桥连通两座岛屿,桥上会有一些敌人,玩家只有消灭了桥上的敌人才能通过,与此同时桥上的敌人会对玩家造成一定伤害.而且会有一个大Boss镇守一座桥,以玩家目前 ...

  9. Poj 3694 Network (连通图缩点+LCA+并查集)

    题目链接: Poj 3694 Network 题目描述: 给出一个无向连通图,加入一系列边指定的后,问还剩下多少个桥? 解题思路: 先求出图的双连通分支,然后缩点重新建图,加入一个指定的边后,求出这条 ...

  10. GIt学习之路 第二天 创建版本库

    本文参考廖雪峰老师的博客进行总结,完整学习请转廖雪峰博客 创建版本库 阅读: 1859216 什么是版本库呢?版本库又名仓库,英文名repository,你可以简单理解成一个目录,这个目录里面的所有文 ...