中位数和顺序统计量(第9章)
2016-03-03 16:36
239 查看
学习由n个不同的树的集合中选择第i个顺序统计量的问题。
输入:一个包含n个(互异的)数的集合A,1≤i≤n的整数i。
输出:元素x∈A,并且 A中恰好有i个元素小于它。
求解第i小的元素的算法设计
同时找到最大值和最小值,我们只需要最多3⌊n/2⌋次比较就可以确定。具体的方法是对输入的元素成对的处理,首先我们将一对输入元素进行比较,然后将较小的与最小值比较,较大的与最大值比较。这样每两个元素仅需要三次比较。
如上 RANDOMIZED−SELECT(A,p,q,i)所示,在算法中首先检查数组仅包含一个元素的情况,i=1.其他的情况,我们调用随机划分函数RANDOMIZED−PARTITION(A,p,q),类似于快速排序中的思路,将数组A划分为A[p....r−1]和A[r+1...q],A[r]称为主元.然后计算前面部分的元素个数k=r−p+1;//小于A[r]的元素的个数的计算 ,后面进行检查和递归求解。
类似于RANDOMIZED-SELECT算法,SELECT通过对输入数组的递归划分来找出所需元素,但是该算法能够保证对数组的一个好的划分。核心就是在划分主元的确定上,将PARTITION中的主元也作为输入参数进行输入。
具体算法的文字描述:
分析算法:
整个过程中,第1,2,4步所需时间为O(n), 注意第2步的复杂度不为O(n^2),第3步的复杂度为 T(n/5),第五步的复杂度为 T(7n/10)。注意这里第2步虽然我们使用的是插入排序,但是待排的序列长度为常数5,所以对一组的排序时间花费为O(1),对于n/5个组,其时间预期是O(n/5),即O(n)。
时间预期为T(n)<=T(n/5)+T(7n/10+6)+O(n)
算法伪代码描述:
输入:一个包含n个(互异的)数的集合A,1≤i≤n的整数i。
输出:元素x∈A,并且 A中恰好有i个元素小于它。
求解第i小的元素的算法设计
1. Max 和 Min
在一个有n个元素的集合中,确定Max 和 Min的方法是遍历。同时找到最大值和最小值,我们只需要最多3⌊n/2⌋次比较就可以确定。具体的方法是对输入的元素成对的处理,首先我们将一对输入元素进行比较,然后将较小的与最小值比较,较大的与最大值比较。这样每两个元素仅需要三次比较。
2. 期望时间是线性时间的选择算法
//划分算法 A[q]作为划分数组的主元 PARTITION(A,p,q){ x=A[q] i=p-1 for j=p to q-1 if(A[j]<=x){//将比A[q]小的数值统一按照顺序移动到前面 i=i+1 exchange A[i] with A[j] } exchange A[i+1] with A[q] return i+1; } //随机划分算法 随机选择主元 RANDOMIZED-PARTITION(A,p,q){ i=Random(p,q) exchange A[q] with A[i]; return PARTITION(A,p,q) } //Algorithms //这里不是从整个数组中找,而是从其中的一段中找 递归的算法设计如下 RANDOMIZED-SELECT(A,p,q,i){ if(p==q)//检查递归的基本情况,A中仅仅包括一个元素这种情况下 i=1. return A[p] r=RANDOMIZED-PARTITION(A,p,q)//随机划分函数 k=r-p+1;//小于A[r]的元素的个数的计算 if(i==k){ return A[r] else if(i<k) RANDOMIZED-SELECT(A,p,r-1,i) else RANDOMIZED-SELECT(A,r+1,q,i) } }
如上 RANDOMIZED−SELECT(A,p,q,i)所示,在算法中首先检查数组仅包含一个元素的情况,i=1.其他的情况,我们调用随机划分函数RANDOMIZED−PARTITION(A,p,q),类似于快速排序中的思路,将数组A划分为A[p....r−1]和A[r+1...q],A[r]称为主元.然后计算前面部分的元素个数k=r−p+1;//小于A[r]的元素的个数的计算 ,后面进行检查和递归求解。
3. 最坏情况为线性的选择算法
指示器随机变量(indicator random variable):给定一个样本空间S和 事件A,那么事件A对应的指示器随机变量I{A}=1(如果A发生),0(如果A不发生);显而易见,事件A对应的指示器随机变量的期望等于事件A发生的概率。实例分析见指示器随机变量类似于RANDOMIZED-SELECT算法,SELECT通过对输入数组的递归划分来找出所需元素,但是该算法能够保证对数组的一个好的划分。核心就是在划分主元的确定上,将PARTITION中的主元也作为输入参数进行输入。
具体算法的文字描述:
Step 1:把数组划分为若干个子数组,每个子数组里包含5个数,因为会有无法整除的可能,所以最后一个子数组可能会小于5. Step 2:用插入排序把每个组的5个数排序,然后找出中位数。 Step 3:把获得的中位数又排序,找出中位数的中位数x。如果中位数的个数是偶数,那么取排好序的第 m/2 个数,m指的是中位数的个数。 Step 4:把原来的数组使用类似快排的方法,分成两个部分。一部分比x大,一部分比x小。我们可以假设左边的数小,右边的数大。然后我们可以得到“中位数的中位数”的位置i. //这个地方是调用修改后的PARTITION,返回当前x的位置。 假设下标从1开始。 Step 5:如果i = k, 那么那个“中位数的中位数”就是第小的数。如果 i < k, 则在低区递归调用SELECT来找出第i小的元素,如果i > k, 则在高区递归查找第i-k大的元素。
分析算法:
整个过程中,第1,2,4步所需时间为O(n), 注意第2步的复杂度不为O(n^2),第3步的复杂度为 T(n/5),第五步的复杂度为 T(7n/10)。注意这里第2步虽然我们使用的是插入排序,但是待排的序列长度为常数5,所以对一组的排序时间花费为O(1),对于n/5个组,其时间预期是O(n/5),即O(n)。
时间预期为T(n)<=T(n/5)+T(7n/10+6)+O(n)
算法伪代码描述:
//设定主元参数的划分函数 PARTITION(A,p,q,key){ i=p-1; for j=p to q-1{ if(A[j]<=key){//将比A[q]小的数值统一按照顺序移动到前面 i=i+1 exchange A[i] with A[j] } } return i+1; } //--------------------------------- SELECT(A,p,q,i){ if(A.length<5){ InsertSort(A,p,q); return A[i]; } groups=A.length/5; midValues[groups]=0;//声明初始化一个中位数数组 for(int t=0;t<groups;t++){ InsertSort(A,t*5,t*5+5); midvalues[t] = A[t*5+3];//中 } InsertSort(midvalues,0,groups); if(groups/2==0){ x=midvalues[groups/2];//中位数的中位数作为主元 }else{ x=midvalues[groups/2+1];//中位数的中位数作为主元 } r=PARTITION(A,p,q,x)//设定主元的划分函数 k=r-p+1;//小于A[r]的元素的个数的计算 if(i==k){ return A[r] else if(i<k) SELECT(A,p,r-1,i) else SELECT(A,r+1,q,i) } }
相关文章推荐
- 期望为线性时间的选择算法randomizedSelect
- 第K顺序统计量的求解
- 中位数和顺序统计学之求解顺序统计量
- Python实现返回数组第i小的元素
- 选择算法
- 《算法导论》读书笔记之第9章 中位数和顺序统计学
- 查找算法、选择算法——LeetCode
- 第 9 章 中位数和顺序统计量
- 算法导论学习(二)——排序和顺序统计量
- 漫步数理统计三十四——顺序统计量
- 算法导论之中位数与顺序统计量(2)
- 分治算法:线性时间选择第k大小的数字 && STL函数:nth_element()
- 算法导论读书笔记(9)中位数和顺序统计量
- 算法导论第九章-中位数和顺序统计量-Cpp代码实现
- 顺序统计量
- 算法导论(4) 顺序统计量
- 初识遗传算法(一): 基本概念
- Android提供的LruCache类简介
- 什么是友元类
- 日期控件如何显示出时分秒