1 头文件
1.1 vector函数
C++ 数据结构学习 ---- 向量_孤城寻欢的博客-CSDN博客
2 相关算法
2.1 暴力算法
// 中位数算法蛮力版:效率低,仅适用于max(n1, n2)较小的情况
//子向量S1[lo1, lo1 + n1)和S2[lo2, lo2 + n2)分别有序,数据项可能重复
template <typename T> T trivialMedian(Vector<T>& S1, int lo1, int n1, Vector<T>& S2, int lo2, int n2) {
cout<<endl << "平凡中位数" ; //printf("trivial median\n");
int hi1 = lo1 + n1, hi2 = lo2 + n2;
Vector<T> S; //将两个有序子向量归并为一个有序向量
while ((lo1 < hi1) && (lo2 < hi2))
S.insert(S1[lo1] <= S2[lo2] ? S1[lo1++] : S2[lo2++]);
while (lo1 < hi1) S.insert(S1[lo1++]);
while (lo2 < hi2) S.insert(S2[lo2++]);
//print(S);
return S[(n1 + n2) / 2]; //直接返回归并向量的中位数
}
2.2 低效版中位数算法
//中位数算法(低效版)
//向量S1[lo1, lo1 + n1)和S2[lo2, lo2 + n2)分别有序,数据项可能重复
template <typename T> T median(Vector<T>& S1, int lo1, int n1, Vector<T>& S2, int lo2, int n2) {
if (n1 > n2) return median(S2, lo2, n2, S1, lo1, n1); //确保n1 <= n2
for (int i = 0; i < lo1; i++)cout << " .";// printf(" .");
for (int i = 0; i < n1; i++)
cout << S1[lo1 + i] <<" ";// print(S1[lo1 + i]);
cout << endl;
for (int i = lo1 + n1; i < S1.size(); i++)
cout << " ."<< endl;// printf(" ."); printf("\n");
for (int i = 0; i < lo2; i++) cout << " ."; //printf(" .");
for (int i = 0; i < n2; i++) cout << S2[lo2 + i] << " ";//print(S2[lo2 + i]);
cout << endl;
for (int i = lo2 + n2; i < S2.size(); i++) cout << " ."<<endl<<endl; //printf(" ."); printf("\n--\n");
if (n2 < 6) //递归基:1 <= n1 <= n2 <= 5
return trivialMedian(S1, lo1, n1, S2, lo2, n2);
///
// lo1 lo1 + n1/2 lo1 + n1 - 1
// | | |
// X >>>>>>>>>>>>>>> X >>>>>>>>>>>>>>> X
// Y .. trimmed .. Y >>>>>>>>>>>>>>> Y >>>>>>>>>>>>>>> Y .. trimmed .. Y
// | | | | |
// lo2 lo2 + (n2-n1)/2 lo2 + n2/2 lo2 + (n2+n1)/2 lo2 + n2 -1
///
if (2 * n1 < n2) //若两个向量的长度相差悬殊,则长者(S2)的两翼可直接截除
return median(S1, lo1, n1, S2, lo2 + (n2 - n1 - 1) / 2, n1 + 2 - (n2 - n1) % 2);
///
// lo1 lo1 + n1/2 lo1 + n1 - 1
// | | |
// X >>>>>>>>>>>>>>>>>>>>> X >>>>>>>>>>>>>>>>>>>>> X
// |
// m1
///
// mi2b
// |
// lo2 + n2 - 1 lo2 + n2 - 1 - n1/2
// | |
// Y <<<<<<<<<<<<<<<<<<<<< Y ...
// .
// .
// .
// .
// .
// .
// .
// ... Y <<<<<<<<<<<<<<<<<<<<< Y
// | |
// lo2 + (n1-1)/2 lo2
// |
// mi2a
///
int mi1 = lo1 + n1 / 2;
int mi2a = lo2 + (n1 - 1) / 2;
int mi2b = lo2 + n2 - 1 - n1 / 2;
if (S1[mi1] > S2[mi2b]) //取S1左半、S2右半
return median(S1, lo1, n1 / 2 + 1, S2, mi2a, n2 - (n1 - 1) / 2);
else if (S1[mi1] < S2[mi2a]) //取S1右半、S2左半
return median(S1, mi1, (n1 + 1) / 2, S2, lo2, n2 - n1 / 2);
else //S1保留,S2左右同时缩短
return median(S1, lo1, n1, S2, mi2a, n2 - (n1 - 1) / 2 * 2);
}
2.3 高效版中位数算法
//序列S1[lo1, lo1 + n)和S2[lo2, lo2 + n)分别有序,n > 0,数据项可能重复
//中位数算法(高效版)
template <typename T> T median(Vector<T>& S1, int lo1, Vector<T>& S2, int lo2, int n) {
cout << "中位数" << endl;// printf("median\n");
for (int i = 0; i < lo1; i++)
cout << " .";//printf(" .");
for (int i = 0; i < n; i++)
cout << S1[lo1 + i] << " ";// print(S1[lo1 + i]);
cout << endl;
for (int i = lo1 + n; i < S1.size(); i++)
cout << " ." << endl;// printf(" ."); printf("\n");
for (int i = 0; i < lo2; i++)
cout << " .";// printf(" .");
for (int i = 0; i < n; i++)
cout << S2[lo2 + i] << " ";//print(S2[lo2 + i]);
cout << endl;
for (int i = lo2 + n; i < S2.size(); i++)
cout << " ." << endl << endl; //printf(" ."); printf("\n--\n");
if (n < 3) return trivialMedian(S1, lo1, n, S2, lo2, n); //递归基
int mi1 = lo1 + n / 2, mi2 = lo2 + (n - 1) / 2; //长度(接近)减半
if (S1[mi1] < S2[mi2])
return median(S1, mi1, S2, lo2, n + lo1 - mi1); //取S1右半、S2左半
else if (S1[mi1] > S2[mi2])
return median(S1, lo1, S2, mi2, n + lo2 - mi2); //取S1左半、S2右半
else
return S1[mi1];
}
3 完整代码
//生成长度为n的随机有序向量,元素取值来自[min, max]
Vector<int> randomSortedVector(int n, int min, int max) { //ACP, Vol.2, Algorithm S
cout << "创造一个长度为" << n << "的任意有序向量!" << endl; // printf("creating a random sorted vector of size %d...\n", n);
Vector<int> A;
for (int i = min; i <= max; i++)
if (rand() % (max - i + 1) < n)
{
cout << i << " ";
A.insert(i); n--;
}
cout << endl;
return A;
}
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include "Median.h"
using namespace std;
int main() {
int nTest = 1; //测试轮数
int n = 8; //向量长度
int min1 = 0, max1 =100; //数值范围
int min2 =2, max2 = 9; //数值范围
if ((nTest < 1) || (n < 1) || (max1 + 1 < min1 + n) || (max2 + 1 < min2 + n))
{
cout << "错误!" << endl; //printf("arguments error\a\a\n");
return -1;
}
// 随机种子
srand((unsigned int)time(NULL));
// 每次测试100组
for (int i = 0; i < nTest; i++) {
// 随机生成向量
Vector<int> A1 = randomSortedVector(n, min1, max1);// print(A1);
Vector<int> A2 = randomSortedVector(n, min2, max2); //print(A2);
// 计算中位数,并与蛮力算法(更不易出错)的结果对比
int m1 = median(A1, 0, A2, 0, n);
int m2 = trivialMedian(A1, 0, n, A2, 0, n);
if (m1 == m2) {
cout << endl << "中位数:" << m1 << "=" << m2 << endl << endl;// printf("\nmedian: %d = %d\a\n\n\n", m1, m2);
}
else {
cout << "错误!" << endl << endl;
// printf("\nmedian: %d <Error> %d\a\a\n\n\n", m1, m2);
getchar();
}
}
int n1 = 10; //向量1长度、取值范围
int n2 = 8; //向量2长度、取值范围
for (int i = 0; i < nTest; i++) {
// 随机生成向量
Vector<int> A1 = randomSortedVector(n1, min1, max1);
Vector<int> A2 = randomSortedVector(n2, min2, max2); cout << endl;// printf("--\n");
// 计算中位数,并与蛮力算法(更不易出错)的结果对比
int m1 = median(A1, 0, n1, A2, 0, n2);
int m2 = trivialMedian(A1, 0, n1, A2, 0, n2);
if (m1 == m2) {
cout << endl << "中位数:" << m1 << "=" << m2 << endl << endl;// printf("\nmedian: %d = %d\a\n\n\n", m1, m2);
}
else {
cout << "错误!" << endl << endl;
// printf("\nmedian: %d <Error> %d\a\a\n\n\n", m1, m2);
getchar();
}
}
system("pause");
return 0;// 返回
}