Max2: 迭代1
在给定的数组区间 中找出最大的两个元素 和 。元素比较的次数,要求尽可能得少。
中包含的元素是......
void max2(int A[], int lo, int hi, int & x1, int & x2){ // 1 < n = hi - lo
for (x1 = lo, int i = lo + 1; i < hi; i ++) //扫描A[lo,hi), 找出A[x1]
if (A[x1] < A[i]) x1 = i; // hi - lo - 1 = n - 1
for (x2 = lo, int i = lo + 1; i < x1; i ++) //扫描A[lo, x1)
if (A[x2] < A[i]) x2 = i; // x1 - lo - 1
for (int i = x1 + 1; i < hi; i++) //再扫描A(x1, hi),找出A[x2]
if (A[x2] < A[i]) x2 = i; // hi - x1 - 1
}
比较次数是:
Max2: 迭代2
void max2(int A[], int lo, int hi, int & x1, int & x2){ // 1 < n = hi - lo
if (A[x1 = lo] < A[x2 = lo + 1]) swap(x1, x2);
for (int i = lo + 2; i < hi; i++)
if (A[x2] < A[i])
if (A[x1] < A[x2 = i])
swap(x1, x2)
\\ else continue;
}
首先确认和是扫描范围内的最大者和次大者。然后利用循环,从第三个元素开始逐一递增,第一步和作比较,只有当它大于时,才将更新为。第二步与作比较,如果大于,则交换位置。从而实现当前最大元素和次大元素的更新。
最好的情况是循环中是实行一次比较 ;
最坏的情况是实行两次比较 。
递归 + 分治
这里我们递归求解两个子问题:分别求出左侧的最大元素和次大元素,以及右侧的最大元素和次大元素。全局的最大元是,有两种情况,左侧胜出和右侧胜出。
先考虑左侧胜出。那么全局最大元素是。
void max2(int A[], int lo, int hi, int & x1, int & x2){
if (lo + 2 == hi) {; return;} // T(2) = 1
if (lo + 3 == hi) {; return;} // T(3) <= 3
int mi = (lo + hi) / 2; //divide
int x1L, x2L; max2(A, lo, mi, x1L, x2L);
int x1R, x2R; max2(A, mi, hi, x1R, x2R);
if (A[x1L] > A[x1R]){ // 对子区间的最大值进行比较(左图)
x1 = x1L; // 第一层比较
x2 = (A[x2L] > A[x1R]) ? x2L : x1R; // 第二层比较
}
else{
x1 = x1R;
x2 = (A[x1L] > A[x2R]) ? x1L : x2R;
} // 1 + 1 = 2
} // T(n) = 2*T(n/2) + 2 <= 5n / 3 -2 实现下降
首先递归树的叶子节点都在同一层,然后整个算法的复杂度是从叶子向根节点这样综合上去的,因此既然层数一定,唯一影响复杂度的就是叶子节点所代表的递归基的复杂度。递归基有两种T(3)和T(2),这两种都是不可再分的。前者复杂度为3,后者复杂度为2,因此最好的情况是递归树的叶子节点都是T(2),最差的情况是叶子节点都是T(3)。[ref 评论区]
下界:
上界: