-
2020-07-15 22:46:37
找出集合中的中位数
- 方法:递归
- 将大问题拆分成子问题
- step1:以集合的第一个元素x为基准
- step2:将集合分为两个子集,S1比x大,S2比x小
- step3:观察两个子集的元素数,若均为K-1(x为第k大数),那么x即为中位数
- step4:若子集的元素数不为K-1,则在数量大的子集里继续重复上述步骤
ElementType FindKthLatgest(ElementType S[],int K) {/*在S这个含有K个元素的集合中寻找中位数*/ ElementType S1[MAXSIZE],S2[MAXSIZE]; int i,lengthS1=0,lengthS2=0; for(i=1;i<K;i++) { if(S[i]>S[0]) { S1[lengthS1]=S[i]; lengthS1++; } else if(S[i]<S[0]) { S2[lengthS2]=S[i]; lengthS2++; } } if(lengthS1==K/2-1)return S[0]; else if(lengthS1>lengthS2)return(S1,lengthS1); else if(lengthS2>lengthS1)return(S2,lengthS2); }
更多相关内容 -
快速切分法寻找中位数的递归与非递归实现
2015-11-01 21:31:26中位数 对于有限的数集,可以通过把所有观察值高低排序后找出正中间的一个作为中位数。如果观察值有偶数个,则中位数不唯一,通常取最中间的两个数值的平均数作为中位数。 中位数寻找的快速算法 一般寻找中位数可以...- 中位数
对于有限的数集,可以通过把所有观察值高低排序后找出正中间的一个作为中位数。如果观察值有偶数个,则中位数不唯一,通常取最中间的两个数值的平均数作为中位数。
- 中位数寻找的快速算法
一般寻找中位数可以先将数组排序,按照次序将中间的数据作为中位数即可,其时间复杂度主要取决于排序算法的时间复杂度,利用快速排序可以将其控制为线性对数量级。
但是能否打破线性对数的限制呢?其中最关键的问题是,寻找中位数并不需要整个数组完全有序,如果把多余的元素排序省略掉,那么就可以超越线性对数的限制实现最快的算法。
启发来源于快速排序算法中的切分法,比如我们需要找到数组中第k
小的元素,首先将数组a[lo,hi]
切分返回整数j
,使得a[lo,j-1]
都小于等于a[j]
,而a[j+1,hi]
都大于等于a[j]
,如果j==k
,那么j
位置的元素就是我们要找的第k
小的元素,而如果j>k
,就要切分左子数组,如果j<k
,就要切分右子数组,不断缩小选定的子数组的规模直到只剩下一个元素,则它就是最终我们要找的第k
小的元素。
经过数学推导,这种快速切分法寻找中位数仅仅为线性量级,是寻找中位数最为快速的算法。- 算法实现
public class Select { // 寻找中位数 public static <T> Comparable<T> findMedium(Comparable<T>[] a) { return select1(a, a.length / 2); } // 找出数组中第k小的元素,非递归实现 public static <T> Comparable<T> select1(Comparable<T>[] a, int k) { int lo = 0, hi = a.length - 1; while (hi > lo) { int j = partition(a, lo, hi); if (j == k) { return a[k]; } else if (j > k) { hi = j - 1; } else if (j < k) { lo = j + 1; } } return a[k]; } // 找出数组中第k小的元素,递归实现 public static <T> Comparable<T> select2(Comparable<T>[] a, int k, int lo, int hi) { int j = partition(a, lo, hi); if (j == k) { return a[k]; } else if (j > k) { return select2(a, k, lo, j - 1); } else { return select2(a, k, j + 1, hi); } } public static <T> int partition(Comparable<T>[] a, int lo, int hi) { int i = lo, j = hi + 1; Comparable<T> v = a[lo];// 切分元素选为首元素 while (true) { while (less(a[++i], v)) {// 向右扫描 if (i == hi) { break; } } while (less(v, a[--j])) {// 向左扫描 if (j == lo) { break; } } if (i >= j) {// 指针相遇,切分位置确定 break; } exch(a, i, j);// 交换左右逆序元素 } exch(a, lo, j);// 将切分元素放在切分位置 return j; } @SuppressWarnings("unchecked") public static <T> boolean less(Comparable<T> v, Comparable<T> w) { return v.compareTo((T) w) < 0; } private static <T> void exch(Comparable<T>[] a, int i, int j) { Comparable<T> t = a[i]; a[i] = a[j]; a[j] = t; } public static void main(String[] args) { String[] a = "qwertyuiopasdfghjklzxcvbnm".split(""); System.out.println("Max: "+select1(a, 0)); System.out.println("Min: "+select2(a, 25, 0, a.length - 1)); System.out.println("Medium: "+findMedium(a)); } }
-
Python寻找两个有序数组的中位数实例详解
2020-12-24 06:16:492.如果我们去掉其中一个数组比中位数小的k个数,再去掉另一个数组中比中位数大的k个数,得到的合并子数组的中位数和原来的中位数相同。 eg:[1,2,3],[1,2,3] => [1,1,2,2,3,3] 根据定理去除元素[2,3],[1 -
递归与分治策略之利用中位数线性时间选择
2017-07-03 01:40:32中位数就是指将数据按大小顺序排列起来,形成一个数列,居于数列中间位置的那个数据就是中位数。 算法思路(1)将输入的n个数划分成 ⌈n5⌉\lceil \frac{n}{5} \rceil 个组,当然最后一组的数目可能是小于5的! ...前言
这一篇文章就上上一篇博文算法的进一步优化了!
这里我们就利用中位数来进行线性时间的选择算法!中位数就是指将数据按大小顺序排列起来,形成一个数列,居于数列中间位置的那个数据就是中位数。
算法思路
(1)将输入的n个数划分成 ⌈n5⌉ 个组,当然最后一组的数目可能是小于5的!
(2)用任意的排序方法对他们进行排序,并取出一共 ⌈n5⌉ 个中位数。
(3)找出该 ⌈n5⌉ 个中位数中的中位数。(如果 ⌈n5⌉ 是偶数则取相对大的那个数)
(4)将全部的数划分为两个部分,小于基准的在左边,大于等于基准的放右边。我们用小圆点表示元素,得到如下图:
说明:
图中中间白色圈表示各组数据的中位数,最中间灰色表示中位数的中位数! 箭头是从较小的数指向较大的数!故我们可以使用该数作为划分的基准(比上一个随机基准的方法会好很多)!
图中
3∗A1=3∗(n−5)10
当n≥75时,3A1大于等于 14n 。所以按此基准划分所得的左右2个子数组的长度都至少缩短 14 。代码描述
int Select(int a[],int p,int r,int k) { if(r-p<75) { //这里对数组 a[p->r] 进行排序 return a[p+k-1]; } //(r-p-4)/5相当于n-5 for(int i=0; i<=(r-p-4)/5; i++) { //这里将元素每5个分成一组,分别排序,并将该组中位数与a[p+i]交换位置 //使所有中位数都排列在数组最左侧,以便进一步查找中位数的中位数 } int x = Select(a,p,p+(r-p-4)/5,(r-p-4)/10); //找中位数的中位数 int i = Partition(a,p,r,x); //以x为基准对数组a进行划分 int j = i-p+1; if(k<=j) { return Select(a,p,i,k); } else { return Select(a,i+1,r,k-j); } }
-
C#用递归算法实现:一列数的规则如下: 1、1、2、3、5、8、13、21、34,求第30位数是多少
2020-09-02 04:25:55本文主要介绍三种方法,解决面试中常见的问题,求第30位数是多少的问题,希望能给大家一个参考。 -
32位无符号乘法/递归调用程序
2019-06-28 17:32:26微机原理课设程序设计 -
bfptr算法(即中位数的中位数算法)
2018-08-25 22:35:16BFPRT算法是解决从n个数中选择第k大或第k小的数这个经典问题的著名算法,但很多人并不了解其细节。本文将首先介绍求解这个第k小数字问题的几个思路,然后重点介绍在最坏情况下复杂度仍然为O(n)的BFPRT算法。 一 ...BFPRT算法是解决从n个数中选择第k大或第k小的数这个经典问题的著名算法,但很多人并不了解其细节。本文将首先介绍求解这个第k小数字问题的几个思路,然后重点介绍在最坏情况下复杂度仍然为O(n)的BFPRT算法。
一 基本思路
关于选择第k小的数字有许多方法,其效率和复杂度各不一样,可以根据实际情况进行选择。
- 将n个数排序(比如快速排序或归并排序),选取排序后的第k个数,时间复杂度为O(nlogn)。使用STL函数sort可以大大减少编码量。
- 将方法1中的排序方法改为线性时间排序算法(如基数排序或计数排序),时间复杂度为O(n)。但线性时间排序算法使用限制较多,不常使用。
- 维护一个k个元素的最大堆,存储当前遇到的最小的k个数,时间复杂度为O(nlogk)。这种方法同样适用于海量数据的处理。
- 部分的选择排序,即把最小的放在第1位,第二小的放在第2位,直到第k位为止,时间复杂度为O(kn)。实现非常简单。
- 部分的快速排序(快速选择算法),每次划分之后判断第k个数在左右哪个部分,然后递归对应的部分,平均时间复杂度为O(n)。但最坏情况下复杂度为O(n^2)。
- BFPRT算法,修改快速选择算法的主元选取规则,使用中位数的中位数作为主元,最坏情况下时间复杂度为O(n)。
二 快速选择算法
快速选择算法就是修改之后的快速排序算法,前面快速排序的实现与应用这篇文章中讲了它的原理和实现。
其主要思想就是在快速排序中得到划分结果之后,判断要求的第k个数是在划分结果的左边还是右边,然后只处理对应的那一部分,从而达到降低复杂度的效果。
在快速排序中,平均情况下数组被划分成相等的两部分,则时间复杂度为T(n)=2*T(n/2)+O(n),可以解得T(n)=nlogn。
在快速选择中,平均情况下数组也是分成相等的两部分,但是只处理其中一部分,于是T(n)=T(n/2)+O(n),可以解得T(n)=O(n)。但是两者在最坏情况下的时间复杂度均为O(n^2),出现在每次划分之后左右总有一边为空的情况下。为了避免这个问题,需要谨慎地选取划分的主元,一般的方法有:
- 固定选择首元素或尾元素作为主元。
- 随机选择一个元素作为主元。
- 三数取中,选择三个数的中位数作为主元。一般是首尾数,再加中间的一个数或者随机的一个数。
============================================================
通常,我们需要在一大堆数中求前K大的数,或者求前K小的。比如在搜索引擎中求当天用户点击次数排名前10000的热词;在文本特征选择中求IF-IDF值按从大到小排名前K个的等等问题,都涉及到一个核心问题,即TOP-K问题。
通常来说,TOP-K问题可以先对所有数进行快速排序,然后取前K大的即可。但是这样做有两个问题。
(1)快速排序的平均复杂度为
,但最坏时间复杂度为
,不能始终保证较好的复杂度。
(2)我们只需要前K大的,而对其余不需要的数也进行了排序,浪费了大量排序时间。
除这种方法之外,堆排序也是一个比较好的选择,可以维护一个大小为K的堆,时间复杂度为
。
我们的目的是求前K大的或者前K小的元素,实际上有一个比较好的算法,叫做BFPTR算法,又称为中位数的中位数算法,它的最坏时间复杂度为
,它是由Blum、Floyd、Pratt、Tarjan、Rivest 提出。
该算法的思想是修改快速选择算法的主元选取方法,提高算法在最坏情况下的时间复杂度。我们先来看看快速排序是如何进行的。
一趟快速排序的过程如下
(1)先从序列中选取一个数作为基准数。
(2)将比这个数大的数全部放到它的右边,把小于或者等于它的数全部放到它的左边。
一趟快速排序也叫做Partion,即将序列划分为两部分,一部分比基准数小,另一部分比基准数大,然后再进行分治过程,因为每一次Partion不一定都能保证划分得很均匀,所以最坏情况下的时间复杂度不能保证总是为
。
对于Partion过程,通常有两种方法:
(1)两个指针从首尾向中间扫描(双向扫描)
这种方法可以用挖坑填数来形容,比如
初始化:i = 0; j = 9; pivot = a[0];
现在a[0]保存到了变量pivot中了,相当于在数组a[0]处挖了个坑,那么可以将其它的数填到这里来。从j开始向前找一个小于或者等于pivot的数,即将a[8]填入a[0],但a[8]又形成了一个新坑,再从i开始向后找一个大于pivot的数,即a[3]填入a[8],那么a[3]又形成了一个新坑......
就这样,直到i==j才停止,最终得到结果如下
上述过程就是一趟快速排序。
代码:
#include <iostream> #include <string.h> #include <stdio.h> #include <algorithm> #include <time.h> using namespace std; const int N = 10005; int Partion(int a[], int l, int r) { int i = l; int j = r; int pivot = a[l]; while (i < j) { while (a[j] >= pivot && i < j) j--; a[i] = a[j]; while (a[i] <= pivot && i < j) i++; a[j] = a[i]; } a[i] = pivot; return i; } void QuickSort(int a[], int l, int r) { if (l < r) { int k = Partion(a, l, r); QuickSort(a, l, k - 1); QuickSort(a, k + 1, r); } } int a[N]; int main() { int n; while (cin >> n) { for (int i = 0; i < n; i++) cin >> a[i]; QuickSort(a, 0, n - 1); for (int i = 0; i < n; i++) cout << a[i] << " "; cout << endl; } return 0; }
(2)两个指针一前一后逐步向前扫描(单向扫描)
代码:
#include <iostream> #include <string.h> #include <stdio.h> using namespace std; const int N = 10005; int Partion(int a[], int l, int r) { int i = l - 1; int pivot = a[r]; for(int j = l; j < r; j++) { if(a[j] <= pivot) { i++; swap(a[i], a[j]); } } swap(a[i + 1], a[r]); return i + 1; } void QuickSort(int a[], int l, int r) { if(l < r) { int k = Partion(a, l, r); QuickSort(a, l, k - 1); QuickSort(a, k + 1, r); } } int a[N]; int main() { int n; while(cin >> n) { for(int i = 0; i < n; i++) cin >> a[i]; QuickSort(a, 0, n - 1); for(int i = 0; i < n; i++) cout << a[i] << " "; cout << endl; } return 0; }
实际上基于双向扫描的快速排序要比基于单向扫描的快速排序算法快很多。接下来,我们学习BFPTR算法的原理。
在BFPTR算法中,仅仅是改变了快速排序Partion中的pivot值的选取,在快速排序中,我们始终选择第一个元素或者最后一个元素作为pivot,而在BFPTR算法中,每次选择五分中位数的中位数作为pivot,这样做的目的就是使得划分比较合理,从而避免了最坏情况的发生。算法步骤如下:
(1)将输入数组的
个元素划分为
组,每组5个元素,且至多只有一个组由剩下的
个元素组成。
(2)寻找
个组中每一个组的中位数,首先对每组的元素进行插入排序,然后从排序过的序列中选出中位数。
(3)对于(2)中找出的
个中位数,递归进行步骤(1)和(2),直到只剩下一个数即为这
个元素的中位数,找到中位数后并找到对应的下标
。
(4)进行Partion划分过程,Partion划分中的pivot元素下标为
。
(5)进行高低区判断即可。
本算法的最坏时间复杂度为
,值得注意的是通过BFPTR算法将数组按第K小(大)的元素划分为两部分,而这高低两部分不一定是有序的,通常我们也不需要求出顺序,而只需要求出前K大的或者前K小的。
另外注意一点,求第K大就是求第n-K+1小,这两者等价。TOP K问题在工程中有重要应用,所以很有必要掌握。
代码:
#include <iostream> #include <string.h> #include <stdio.h> #include <time.h> #include <algorithm> using namespace std; const int N = 10005; int a[N]; //插入排序 void InsertSort(int a[], int l, int r) { for(int i = l + 1; i <= r; i++) { if(a[i - 1] > a[i]) { int t = a[i]; int j = i; while(j > l && a[j - 1] > t) { a[j] = a[j - 1]; j--; } a[j] = t; } } } //寻找中位数的中位数 int FindMid(int a[], int l, int r) { if(l == r) return a[l]; int i = 0; int n = 0; for(i = l; i < r - 5; i += 5) { InsertSort(a, i, i + 4); n = i - l; swap(a[l + n / 5], a[i + 2]); } //处理剩余元素 int num = r - i + 1; if(num > 0) { InsertSort(a, i, i + num - 1); n = i - l; swap(a[l + n / 5], a[i + num / 2]); } n /= 5; if(n == l) return a[l]; return FindMid(a, l, l + n); } //寻找中位数的所在位置 int FindId(int a[], int l, int r, int num) { for(int i = l; i <= r; i++) if(a[i] == num) return i; return -1; } //进行划分过程 int Partion(int a[], int l, int r, int p) { swap(a[p], a[l]); int i = l; int j = r; int pivot = a[l]; while(i < j) { while(a[j] >= pivot && i < j) j--; a[i] = a[j]; while(a[i] <= pivot && i < j) i++; a[j] = a[i]; } a[i] = pivot; return i; } int BFPTR(int a[], int l, int r, int k) { int num = FindMid(a, l, r); //寻找中位数的中位数 int p = FindId(a, l, r, num); //找到中位数的中位数对应的id int i = Partion(a, l, r, p); int m = i - l + 1; if(m == k) return a[i]; if(m > k) return BFPTR(a, l, i - 1, k); return BFPTR(a, i + 1, r, k - m); } int main() { int n, k; scanf("%d", &n); for(int i = 0; i < n; i++) scanf("%d", &a[i]); scanf("%d", &k); printf("The %d th number is : %d\n", k, BFPTR(a, 0, n - 1, k)); for(int i = 0; i < n; i++) printf("%d ", a[i]); puts(""); return 0; } /** 10 72 6 57 88 60 42 83 73 48 85 5 */
关于本算法最坏时间复杂度为
的证明可以参考《算法导论》9.3节,即112页,有详细分析。
原文链接:https://blog.csdn.net/wyq_tc25/article/details/51801885
-
线性时间选择中位数算法
2012-06-09 14:26:05线性时间选择,中位数算法,利用按每5个元素分组,分别找出其中位数,再递归找出 -
O(n)的时间复杂度求中位数
2020-09-26 14:45:14O(n)的时间复杂度求中位数 O(n)中位数问题是指:在O(n)的时间复杂度内找到一个无序序列的中位数。 在开始O(n)时间复杂度求中位数之前,先手写一下快速排序。 快速排序的实现 Reference: 快速排序|菜鸟教程 白话经典... -
设计一个递归函数,使用数字求和来计算位数和
2021-04-27 03:04:10要获得(正整数)数字的最后一位,可以计算模:last_digit = n % 10数字的剩余部分(不包括最后一位)为:^{pr2}$理论上这应该足够分割一个数字并加上数字:def sum_digits(n):if n < 10:return nelse:last_digit = n... -
java中实现递归计算二进制表示中1的个数
2020-09-03 18:04:38是一个很有意思的问题,是在面试中特别容易被问到的问题之一,解决这个问题第一想法肯定是一位一位的去判断,是1计数器+1,否则不操作,跳到下一位,十分容易,编程初学者就可以做得到! -
寻找两个有序数组的中位数(附上三种解法)
2019-12-06 18:23:32具体思路,中位数的概念其实可以理解为,将数组整体分为两个部分,一边大于等于中位数,一边小于等于中位数。那么在这道题目中两个有序数组,我们可以将两个数组并排画一条线,这条线能正好划分左右两个部分,而我们... -
(C语言)递归练习:递归输出一个数的各个位上的数字
2021-11-24 19:14:48//一个整数对100取余,得到十位和个位 //... //由于打印操作是在调用print_num()之后,所以会打印最后算出的n%10,也就是最高位 void print_num1(int n) { if (n > 9) print_num1(n / 10); printf("%d ", n... -
递归函数用python找到整数中的数字总和
2020-12-05 18:05:35递归函数必须终止才能在程序中使用。 通常,它会终止,如果每次递归调用,问题的解决方案都会缩小并向基本情况移动。 基本情况是一种情况,可以在没有进一步递归的情况下解决问题。 (如果调用中没有满足基本情况,则... -
Leetcode 4. 寻找两个正序数组的中位数
2020-05-31 18:42:32寻找两个正序数组的中位数1、问题分析2、问题解决3、总结 1、问题分析 题目链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays/submissions/ 具体思路是: 1、 根据两个数组的总长度计算是否是 ... -
Python 递归函数详解及实例
2020-12-24 23:19:31在这道题中,运算符%和//可以用来把一个数分成两部分:最低位和不包含最低位数字两部分. 18117的数字和为:1+8+1+1+7=18.这样我们就可以分割这个数.把这个数分割成最低位7和不包含最低位数字... -
Java实现 LeetCode 4 寻找两个有序数组的中位数
2020-02-11 18:54:06寻找两个有序数组的中位数 给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。 请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。 你可以假设 nums1 和 nums2 不会同时为空。 示例 1: ... -
计算两个有序数组的中位数
2018-09-04 11:56:01题目: ...类比一个数组的中位数,求两个数组的中位数就相当于把两个数组合并后的一个数组的中位数,例 输入: num1=[1,3,5] num2=[2,4,6] 输出:(3+4)/2=3.5 方法:二分+递归 思路: --... -
深入理解python函数递归和生成器
2021-01-20 04:51:46递归做为一种算法在程序设计语言中广泛应用,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的... -
利用递归输出一个整数的每一位数字
2019-12-19 20:42:35 -
python – 设计一个使用digit_sum计算数字总和的递归函数
2021-03-18 00:31:54要获得(正整数)数字的最后一位数,您可以计算模数:last_digit = n % 10该数字的其余部分(不包括最后一个地方)是:rest = (n - last_digit) / 10理论上这应该足以分割数字并添加数字:def sum_digits(n):if n <... -
BFPRT(中位数的中位数)算法
2017-10-09 16:05:05BFPRT 算法又称为 “中位数的中位数算法”,该算法由 Blum、Floyd、Pratt、Rivest、Tarjan 在1973年提出,最坏时间复杂度为 O(n) TOP-K问题 -
100亿个整数,找出中位数
2017-07-26 10:50:51100亿个整数,内存足够,如何找到中位数?内存不足,如何找到中位数?... • 如果小于它的数超过一半,那么中位数一定在左半边,递归到左边处理(还是第几大) • 否则中位数一定在右半边,根据左半边的元素个数 -
Labview实现递归:斐波那契数列
2020-10-23 15:44:07在数学上它以递归的方式进行定义,指这样的一个数列:0、1、1、2、3、5、8、13、21、34、55、89、144……,即前两个数为分别为0和1,从第3项开始,每项的值都等于其前两项之和。斐波那契数列Fib(n)用公式表示为: ... -
为什么你学不会递归?告别递归,谈谈我的经验
2019-10-27 16:01:40可能也有一大部分人知道递归,也能看的懂递归,但在实际做题过程中,却不知道怎么使用,有时候还容易被递归给搞晕。也有好几个人来问我有没有快速掌握递归的捷径啊。说实话,哪来那么多捷径啊,不过,我还是想写一篇... -
从数据流中获取中位数
2020-02-29 11:55:55从数据流中获取中位数需求描述需求分析C++代码如下python代码 需求描述 有一个动态的数据流,如何比较快的获得数据流的中位数。这个过程中,数据流可能会有新的数据加入。中位数定义为元素个数为奇数的序列的... -
递归
2020-11-03 23:35:25递归的意思就是不停的调用自己,但是我们要知道的是我们的计算机资源是有限的,一般来说递归的层数不能太深(特别是自己写的程序有问题容易资源耗尽!)。递归通常来说是程序写着简洁但是人的思维量比较大同时... -
算法分析与设计实验-中位数问题
2020-07-18 15:53:21分治法解决中位数问题实验 问题描述 设X[ 0 : n - 1]和Y[ 0 : n – 1 ]为两个数组,每个数组中含有n个已排好序的数。找出X和Y的2n个数的中位数。利用分治策略试设计一个O (log n)时间的算法求出这2n个数的中位数。 ... -
C语言计算一个数的每位之和(递归实现)
2020-09-13 19:31:30写一个递归函数DigitSum(n),输入一个非负整数,返回组成它的数字之和 例如,调用DigitSum(1729),则应该返回1+7+2+9,它的和是19 输入:1729,输出:19 #include<stdio.h> //写一个递归函数DigitSum(n),... -
快速排序和寻找中位数复杂度分析
2019-02-20 09:45:10之所以,起“快速排序和寻找中位数”这个题目,并不是因为寻找中位数的时候使用了快速排序,而是这两个算法使用了一个同一个预处理结构 —— 划分,然后都是递归解决!中位数的也是根据一个数把原来的数划分一下,...