加载中...
Hello STL - 向量篇3 - 项目应用
第1节:初学C++,应该学什么?
第2节:《白话C++》练的什么“功”?
第3节:《白话C++》练的什么“武”?
第4节:打开浏览器,线上玩转C++
第5节:逐字逐句,深入理解C++最小例程
第6节:做一个“会”犯错误的程序员
第7节:Hello World 中文版
第8节:Hello World 函数版
第9节:Hello World 交互版
第10节:Hello World 分支版
第11节:Hello World 循环版
第12节:Hello Object 生死版.上
第13节:Hello Object 生死版. 下
第14节:Hello Object 成员版
第15节:Hello Object 派生版
第16节:Hello Object 多态版
第17节:Hello Object 封装版 - 上
第18节:Hello Object 封装版 - 下
第19节:Hello STL - 泛型启蒙
第20节:Hello STL - 向量篇1 - 范式对比&特性彰显
第21节:Hello STL - 向量篇2 - 内存结构&常用方法
第22节:Hello STL - 向量篇3 - 项目应用
课文封面

真实项目中,std::vector是怎么用的?答:在本课,你就能看到:遍历!遍历!!遍历!!!

附赠一套科学的亚洲青年女性身材计分方法。

真实项目中使用 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

用你的程序,算出来,在笔记或作业里告诉我,谁是第一?