真实项目中使用 std::vector,用得最少的操作,就是 insert 或 erase,即:几乎不对一个向量对象做插入和删除操作。那么,std::vector 用得最多的操作是什么呢?
1. 课堂视频
2. 完整代码
#include <cassert>
#include <cmath> // 求绝对值等
#include <iostream>
#include <iomanip>
#include <string>
#include <string_view>
#include <vector>
// 取号机
class NumberMachine
{
public:
int Inc() { return ++no; /*前置自增*/ }
private:
int no = 0; // 成员数据默认初始化
};
// 普通人
class Person
{
public:
explicit Person(int no);
Person(Person const& o) // 拷贝构造
: no(o.no), name(o.name),
gender(o.gender), age(o.age),
height(o.height), weight(o.weight)
{}
virtual ~Person() = default; // 默认析构实现
public:
// 获取各项基本信息的数据
int GetNo() const { return no; }
std::string GetName() const { return name; }
int GetGender() const { return gender; }
int GetAge() const { return age; }
int GetHeight() const { return height; }
int GetWeight() const { return weight; }
// 赛后感言(落选感言)
void virtual Speech(std::string_view desc) const
{
std::cout << AboutMe()
<< "\n遗憾落选,因为我" << desc
<< "\n感谢大赛,我将越活越美\n";
}
protected:
virtual std::string AboutMe() const // 关于
{
std::string s = "我是";
s += name + " " + std::to_string(age) + "岁\n"
+ "高 " + std::to_string(height) + " 重 "
+ std::to_string(weight);
return s;
}
private:
int no; // 编号
std::string name; // 姓名
int gender; // 性别(0女,1男)
int age; // 年龄
int height; // 身高(cm)
int weight; // 体重(kg)
};
Person::Person(int no)
: no(no)
{
std::cout << "\t姓名:";
std::getline(std::cin, name);
std::cout << "\t性别(0女 1男):";
std::cin >> gender;
std::cout << "\t年龄:";
std::cin >> age;
std::cout << "\t身高(cm):";
std::cin >> height;
std::cout << "\t体重(kg):";
std::cin >> weight;
}
// 美女
class Beauty : public Person
{
public:
explicit Beauty(Person const& p)
: Person(p)
{
std::cout << "\t胸腰臀三围数据(cm,空格间隔):";
std::cin >> bust >> waist >> hip;
}
public:
int GetBust() const { return bust; }
int GetWaist() const { return waist; }
int GetHip() const { return hip; }
public:
// 美女的赛后演讲
void Speech(std::string_view desc) const override
{
std::cout << AboutMe()
<< "\n\n很开心通过海选"
<< "\n评委评价我:" << desc << "!"
<< "\n感谢认可!"
<< "\n感谢父母给了我好基因!\n";
}
protected:
// 美女的自我介绍内容
std::string AboutMe() const override
{
std::string s = Person::AboutMe(); // 继承的应用
s += "\n我的三围:"
+ std::to_string(bust) + " "
+ std::to_string(waist) + " "
+ std::to_string(hip);
return s;
}
private:
int bust, waist, hip; // 胸围,腰围,臀围
};
// 报名
Person* SignUp()
{
// 取号机
static NumberMachine nm;
std::cout << "【报名】\n";
int no = nm.Inc(); // 取号
return new Person(no); // 构造Person对象,需填写基本信息
}
// 评测结果
struct Result
{
bool lost; // 为真表示落选
Person const * contestant; // 选手(普通人或美女)
std::string desc; // 说明(落选原因或胜选评价)
};
// 生成落选结果
Result OnLost(Person const* p, std::string_view desc)
{
std::cout << "\t" << p->GetNo() << " 号选手落选\n";
Result r;
r.lost = true; // 落选
r.contestant = p;
r.desc = desc;
return r;
}
// 生成胜选结果(包括完成选手的升级操作)
Result OnWin(Person const* p, std::string_view desc)
{
std::cout << "\t" << p->GetNo() << " 号选手胜选\n";
std::cout << "\n【升级】\n";
Beauty* beauty = new Beauty(*p);
delete p; // 重要:释放海选选手身份
return { false, beauty, std::string(desc)}; // 聚合初始化
}
// 生成胜选评价 (利用选手的编号,生成变化的评价)
std::string MakePraise(int no)
{
int index = no % 5; // 求余,故为: 0~4
if (index == 0) { return "天生丽质"; }
if (index == 1) { return "貌若天仙"; }
if (index == 2) { return "倾国倾城"; }
if (index == 3) { return "国色天香"; }
return "秀外慧中";
}
// 海选检测函数(通过的选手将升级)
Result Check(Person const * p)
{
std::cout << "\n【检测】\n";
std::cout << p->GetNo() << " 号选手正在接受检测……\n";
if (p->GetGender() != 0) { return OnLost(p, "不是女性"); }
std::cout << "\t>性别合规\n";
if (p->GetAge() < 18) { return OnLost(p, "未满十八"); }
if (p->GetAge() > 38) { return OnLost(p, "年龄超标"); }
std::cout << "\t>年龄合规\n";
if (p->GetHeight() < 151){ return OnLost(p, "身高略逊"); }
if (p->GetHeight() > 189) { return OnLost(p, "身高超标"); }
std::cout << "\t>身高合规\n";
if (p->GetWeight() < 35) { return OnLost(p, "体重过轻"); }
if (p->GetWeight() > 85) {return OnLost(p, "过于丰盈"); }
std::cout << "\t>体重合规\n";
double m = p->GetHeight() / 100.0, bmi = p->GetWeight() / (m * m);
if (bmi < 18.5) { return OnLost(p, "BMI指数过低"); }
if (bmi > 24) { return OnLost(p, "BMI指数过高"); }
std::cout << "\t>BMI达标\n";
std::string desc = MakePraise(p->GetNo()); // 生成评价(客套话)
return OnWin(p, desc);
}
// 打广告
void Advertising(std::string_view sponsor, std::string_view slogan)
{
std::cout << "\n#*************#\n"
<< "\t" << slogan << "\n"
<< "\t" << sponsor << "(宣)\n"
<< "#*************#\n\n";
}
// 第一场(海选)
std::vector<Result> FirstRound()
{
std::cout << "~~~~~~~~~~~~第2学堂网校选美大赛报名~~~~~~~~~~~~\n";
std::vector<Result> results;
while(true)
{
results.push_back(Check(SignUp()));
std::cin.ignore(99, '\n');
if (results.size() % 3 == 0)
{
Advertising("第2学堂", "让学习回归兴趣,让兴趣创造价值!");
}
std::cout << "\n继续录入?(y/n):";
char c;
std::cin >> c;
if (c != 'y' && c != 'Y')
{
break;
}
std::cin.ignore(99, '\n');
}
return results;
}
// 海选结果处理
std::vector<Beauty const*> HandOpenRoundResult (std::vector<Result> const & results)
{
std::cout << "~~~~~~~~~~~~第2学堂网校选美大赛报名~~~~~~~~~~~~\n";
std::vector<Beauty const*> beauties;
std::cout << "\n====海选结果公告====\n";
std::cout << "报名人数:" << results.size() << "\n";
int lostCount = 0;
for (auto const& r : results)
{
if (r.lost)
{
++lostCount;
}
}
std::cout << "\t其中有 " << lostCount << " 名选手遗憾落选\n";
std::cout << "下面有请各位选手上场并发表赛后感言!\n";
std::cout << "====================================\n\n";
for (auto const& r : results)
{
std::cout << "#" << r.contestant->GetNo() << "号选手感言:\n";
r.contestant->Speech(r.desc);
if (r.lost)
{
std::cout << "\t请给 " << r.contestant->GetNo() << " 号选手最后的掌声!\n";
delete r.contestant;
}
else
{
std::cout << "\t有请 " << r.contestant->GetNo() << " 号选手落座胜选席!\n";
beauties.push_back(dynamic_cast<Beauty const*> (r.contestant));
}
std::cout << std::endl;
}
std::cout << "====================================\n";
if (!beauties.empty())
{
std::cout << "恭喜" << beauties.size() << "位选手进入决赛!\n";
}
else
{
std::cout << "遗憾!本次海选无一人入选!\n(麦克风隐约传来:来的都是什么歪瓜裂枣哪!)\n";
}
return beauties;
}
// 计算身高得分 (入选范围:[151, 189],理想身高:170)
// 得分范围:[0, 80]
double calculateHeightScore(int height)
{
// 海选过关条件
if (height < 151 || height > 189)
{
return 0.0;
}
// 选美赛中国女性理想身高标准值, 取中国年轻女性平均身高:162cm + 8cm
double const ideal = 170.0; // 理想身高(cm)
double diff = height - ideal;
if (diff<=0.0)
{
return 50.0 + diff * 2.6316; // 每低 1cm 约减 2.63分
}
else
{
return 80.0 - diff * 1.5789; // 每高 1cm 减约 1.58分
}
}
// 计算胸围得分 (理想胸围: 身高*0.53)
// 得分范围:[0, 100]
double calculateBustScore(int bust, int height)
{
double ideal = height * 0.53; // 理想胸围(cm)
double diff = std::abs(bust-ideal);
if (diff > 15.0) // 相差太多不得分
{
return 0.0;
}
return 100.0 - diff * (100.0/15.0); // 每超出1cm 减 6.67分
}
// 计算腰围得分 (理想腰围: 身高*0.37)
// 得分范围:[0, 100]
double calculateWaistScore(int waist, int height)
{
double ideal = height * 0.37; // 理想腰围(cm)
double diff = std::abs(waist-ideal);
if (diff > 12.0) // 相差太多不得分
{
return 0.0;
}
return 100.0 - diff * (100.0/12.0); // 每超出1cm 减 8.33分
}
// 计算臀围得分 (理想臀围: 身高*0.542)
// 得分范围: [0, 100]
double calculateHipScore(int hip, int height)
{
double ideal = height * 0.542; // 理想臀围(cm)
double diff = std::abs(hip-ideal);
if (diff > 15.0)
{
return 0.0;
}
return 100.0 - diff * (100.0/15.0);
}
// 腰臀比得分详情
struct WHRScore
{
double value; // 腰围 ÷ 臀围
double score; // 得分 [0, 90]
std::string type; // 腰臀比类型描述
};
// 计算腰臀比得分 (理想腰臀比范围: 0.67-0.80)
// 得分范围: [0, 90]
WHRScore calculateWHRScore(int waist, int hip)
{
assert(waist > 0 && hip > 0);
// 理想腰臀比范围
double const ideal_min=0.67, ideal_max=0.70;
double whr = static_cast<double> (waist) / hip;
// “楚宫腰”:太细,不健康,得分范围:[0, 40)
if (whr < 0.60)
{
return {whr, 40.0+(whr-0.60)*500.0, "楚宫腰"};
}
// “飞燕腰”:趋向健康,得分范围:[40, 90)
if (whr < ideal_min) // 0.67
{
return {whr, 40.0+(whr-0.60)*500.0, "飞燕腰"};
}
// “沙漏腰”:黄金比例,健康、美丽,得分 90 分(本项满分)
if (whr <= ideal_max) // 0.70
{
return {whr, 90.0, "沙漏腰"};
}
// “贵妃腰” :仍然健康,但逐渐偏离理想值,得分范围: [60, 90)
if (whr <= 0.80)
{
return {whr, 90.0-(whr-0.70)*(30.0/0.10), "贵妃腰"};
}
// “直筒腰”:腰臀比过大,健康风险增加,得分范围 :[0, 60)
return {
whr,
std::max(0.0, 60.0-(whr-0.80)*200.0),
"直筒腰"
};
} // calculateWHRScore
// 计算BMI得分(入选范围: 18.5-24,理想指数:21.5)
// 得分范围:[0, 80],二选实际可得分:[50, 80]
double calculateBMIScore(double bmi)
{
double const ideal = 21.5; // 理想BMI指数
if (bmi<=16.0) return 0.0; // 极低体重,不健康,不得分
if (bmi<=18.5) return (bmi-16.0) * 20.0; // 流行的苗条: 0→50分
if (bmi<=ideal) return 50.0 + (bmi-18.5) * 10.0; // 健康上升,50→80分
if (bmi<=24.0) return 80.0 - (bmi-ideal) * 12.0; // 健康下降,80→50分
if (bmi<=27.0) return 50.0 - (bmi-24.0) * (20.0/3.0); // 过重 50→30分
if (bmi<=30.0) return 30.0 - (bmi-27.0) * 5.0; // 肥胖: 30→15分
return std::max(0.0, 15.0- (bmi-30.0) * 1.5); // 严重肥胖:15→0分
}
// 决赛分数详情
struct FinalScore
{
double bmi; //BMI指数
double bmiScore; //BMI得分
double heightScore; //身高得分
double bustScore,waistScore,hipScore; //三围得分
double bwhScore; //三围综合得分
WHRScore whrScore; //腰臀比得分
double overallScore; //综合得分
};
// 计算决赛身材总分
FinalScore calculateFinalScore (Beauty const* b)
{
FinalScore fs;
int h = b->GetHeight();
fs.bmi = b->GetWeight() / ((h/100.0) * (h/100.0));
fs.bmiScore = calculateBMIScore(fs.bmi);
fs.heightScore = calculateHeightScore(h);
fs.bustScore = calculateBustScore(b->GetBust(), h);
fs.waistScore = calculateWaistScore(b->GetWaist(), h);
fs.hipScore = calculateHipScore(b->GetHip(), h);
fs.whrScore = calculateWHRScore(b->GetWaist(), b->GetHip()); // 腰臀比
// 三围综合得分
fs.bwhScore = fs.bustScore * 0.4 + fs.waistScore * 0.3 + fs.hipScore * 0.3;
// 最终得分
fs.overallScore = fs.bmiScore * 0.14 + fs.heightScore * 0.08
+ fs.bwhScore * 0.62 + fs.whrScore.score * 0.16;
return fs;
}
// 冠军
struct Champion
{
Beauty const * beauty; //选手
FinalScore const score; //成绩
Champion(Beauty const * b, FinalScore const& s)
: beauty(b), score(s)
{}
};
// 二选(终赛),可能有多个并列第一
std::vector<Champion> FinalRound (std::vector<Beauty const*> const& beauties)
{
std::cout << "\n~~~~~~~~~~~~第2学堂选美决赛~~~~~~~~~~~~\n";
std::vector<Champion> campions;
double overallScoreTop = 0.0;
for (Beauty const* b : beauties)
{
// 当前选手得分
FinalScore fs = calculateFinalScore(b);
if (static_cast<int>(overallScoreTop * 100) == static_cast<int>(fs.overallScore * 100))
{
campions.emplace_back(b, fs); // 就地构造
}
else if (fs.overallScore > overallScoreTop)
{
campions.clear();
campions.emplace_back(b, fs); // 就地构造
overallScoreTop = fs.overallScore; // 重要哦!
}
}
return campions;
}
// 公布指定冠军详情
void OuputChampion(Champion const& c)
{
using std::cout;
cout << "\t" << c.beauty->GetNo() << " 号选手!\n";
cout << "\t" << c.beauty->GetName() << " !\n";
cout << "以下是她的得分详情:";
cout << std::fixed << std::setprecision(2); // 避免显示成科学计算法,显示两位小数
cout << "\n\t身高:" << c.beauty->GetHeight() << "厘米,得分:"
<< c.score.heightScore;
cout << "\n\t体重:" << c.beauty->GetWeight() << "公斤";
cout << "\n\tBMI指数:" << c.score.bmi << ",得分:" << c.score.bmiScore;
cout << "\n\t三围数据:";
cout << "\n\t胸围:" << c.beauty->GetBust() << ", 得分:" << c.score.bustScore;
cout << "\n\t腰围:" << c.beauty->GetWaist() << ", 得分:" << c.score.waistScore;
cout << "\n\t臀围:" << c.beauty->GetHip() << ", 得分:" << c.score.hipScore;
cout << "\n\tWHR:" << c.score.whrScore.value
<< " [" << c.score.whrScore.type << "],得分:" << c.score.whrScore.score;
cout << "\n\t---------------";
cout << "\n\t综合得分:" << c.score.overallScore;
cout << "\n--------------------------\n\n";
}
// 公布所有冠军详情
void OuputChampions(std::vector<Champion> const& champions)
{
std::cout << "\n\n=============================\n\n"
<< "本次选美大奖得主";
auto count = champions.size();
if (count > 1)
{
std::cout << "共 " << count << " 位!她们是:\n";
}
else
{
std::cout << "她是:\n";
}
for (auto const& champion : champions)
{
OuputChampion(champion);
}
}
int main()
{
auto results = FirstRound();
Advertising("作者:南郁",
"语言语法是功,标准库三方库是武!\n\t练武不练功,到老一场空\n\t练功不练武,到老白辛苦\n"
"\t学C++就用《白话C++》\n\t又练功来又练武!");
auto beauties = HandOpenRoundResult(results);
if (beauties.empty())
{
std::cout << "本次选美失败!" << std::endl;
return -1;
}
Advertising("d2school", "只用浏览器,搞定 C++ 半壁江山!\n《C++ 快速感受与探索之旅》");
auto champions = FinalRound(beauties);
Advertising("www.d2school.com", "第2学堂——关学习,我们不制造焦虑");
OuputChampions(champions);
for (auto b : beauties) // 并不需要 auto* ,b 就是指针
{
delete b;
}
}
3. 测试数据
以下数据(身高、体重、三围)非真实,仅为方便程序员测试。
表格:测试数据
姓名 | 身高(cm) | 体重(kg) | 三围 (胸 腰 臀 cm) |
---|---|---|---|
杨觅 | 166 | 55 | 85, 63, 85 |
杨引 | 166 | 55 | 85, 63, 85 |
羊紫 | 167 | 55 | 81, 60, 83 |
沈梦成 | 171 | 58 | 91, 64, 90 |
高原原 | 165 | 56 | 83, 60, 87 |
古力 | 172 | 60 | 84, 60, 89 |
张添爱 | 165 | 53 | 79, 64, 90 |
柳严 | 163 | 51 | 82, 60, 87 |
张心予 | 169 | 56 | 89, 61, 88 |
张雨奇 | 166 | 52 | 88, 60, 88 |
严妮 | 170 | 58 | 86, 60, 89 |
李辰敏 | 168 | 53 | 90, 60, 90 |
林致铃 | 173 | 58 | 89, 62, 90 |
用你的程序,算出来,在笔记或作业里告诉我,谁是第一?