容器(vector/map)与数æ®ç»„织
è¿™ä¸€å‘¨ä½ ä¼šä»Žâ€œå•个å˜é‡å¤„ç†â€èµ°å‘â€œæ‰¹é‡æ•°æ®ç®¡ç†â€ã€‚æŽŒæ¡ `vector` å’Œ `map` åŽï¼Œä½ 的程åºå°±èƒ½åº”对更真实的数æ®åœºæ™¯ã€‚
å¦å®Œè¿™å‘¨ï¼Œä½ 能用容器组织ã€é历和查询数æ®ï¼Œå¹¶å®Œæˆä¸€ä¸ªå®¹å™¨é©±åŠ¨çš„å°é¡¹ç›®ã€‚
8.1 vectorï¼šé¡ºåºæ•°æ®å®¹å™¨
`vector` 适åˆå˜æ”¾ä¸€ç»„åŒç±»åž‹æ•°æ®ï¼Œæ¯”å¦‚åˆ†æ•°åˆ—è¡¨æˆ–ä»»åŠ¡åˆ—è¡¨ã€‚ä½ å¯ä»¥åŠ¨æ€æ·»åŠ ã€é历统计,写法直接清晰。
vector<int> scores;
scores.push_back(88);
scores.push_back(92);
scores.push_back(75);
for (int s : scores) {
cout << s << " ";
}
8.2 mapï¼šé”®å€¼æ˜ å°„å®¹å™¨
`map` 适åˆâ€œé€šè¿‡é”®æ‰¾å€¼â€ï¼Œæ¯”如姓å -> 分数ã€å•†å“ -> ä»·æ ¼ã€‚æ¯”æ•°ç»„ä¸‹æ ‡æ›´æŽ¥è¿‘çœŸå®žä¸šåŠ¡è¡¨è¾¾ã€‚
map<string, int> scoreMap;
scoreMap["Mia"] = 95;
scoreMap["Leo"] = 88;
cout << "Mia 的分数: " << scoreMap["Mia"] << "\n";
8.3 é历与统计
å®¹å™¨çš„æ ¸å¿ƒä»·å€¼æ˜¯æ‰¹é‡å¤„ç†ã€‚统计之å‰å…ˆåˆ¤æ–容器是å¦ä¸ºç©ºï¼Œé¿å…æ— æ„义计算或访问异常。
double calcAverage(const vector<int>& v) {
if (v.empty()) return 0.0;
long long sum = 0;
for (int x : v) sum += x;
return static_cast<double>(sum) / v.size();
}
8.4 深度讲解:为什么容器是“项目化能力â€çš„门槛
å‰å‡ å‘¨ä½ ä¸»è¦åœ¨å¤„ç†å•个å˜é‡ï¼Œæœ¬å‘¨å¼€å§‹è¦å¤„ç†ä¸€ç»„æ•°æ®ã€‚项目里真æ£çš„éš¾ç‚¹å¾€å¾€ä¸æ˜¯æŸä¸ªå…¬å¼ï¼Œè€Œæ˜¯â€œæ•°æ®å¦‚何组织â€ã€‚如果数æ®ç»„织混乱,åŽç»åŠŸèƒ½æ‰©å±•ä¼šè¶Šæ¥è¶Šç—›è‹¦ã€‚å®¹å™¨å°±æ˜¯è§£å†³è¿™ä¸ªé—®é¢˜çš„æ ¸å¿ƒå·¥å…·ï¼š`vector` è®©ä½ æœ‰åºç®¡ç†åŒç±»æ•°æ®ï¼Œ`map` è®©ä½ é€šè¿‡é”®å¿«é€Ÿå®šä½å€¼ã€‚å¦ä¼šå®¹å™¨åŽï¼Œä½ 会从“写题æ€ç»´â€è¿ˆå‘“系统æ€ç»´â€ã€‚
很多åŒå¦ç¬¬ä¸€æ¬¡ç”¨å®¹å™¨æ—¶ä¼šæŠŠå®ƒå½““高级数组â€ï¼Œåªä¼š `push_back` å’Œä¸‹æ ‡è®¿é—®ã€‚å®žé™…ä¸Šæ›´é‡è¦çš„æ˜¯æ€è€ƒï¼šä½ 的业务更适åˆé¡ºåºç»“构还是键值结构?例如“按录入顺åºå±•示æˆç»©â€é€‚åˆ `vector`ï¼›â€œæŒ‰å§“åæŸ¥åˆ†â€é€‚åˆ `map`ã€‚å®¹å™¨é€‰æ‹©æœ¬è´¨ä¸Šæ˜¯æ•°æ®æ¨¡åž‹è®¾è®¡ã€‚模型对了,åŽé¢çš„功能会自然;模型错了,åŽé¢æ¯ä¸€æ¥éƒ½åˆ«æ‰ã€‚
æœ¬å‘¨å»ºè®®ä½ æŠŠæ‰€æœ‰ç»ƒä¹ éƒ½å…ˆç”»æ•°æ®ç»“æž„è‰å›¾ï¼šæœ‰å“ªäº›å®žä½“?æ¯ä¸ªå®žä½“æœ‰å“ªäº›å—æ®µï¼Ÿå—段之间如何关è”?哪部分用 `vector`,哪部分用 `map`ï¼Ÿä½ ä¼šå‘现,建模一旦清楚,代ç å‡ ä¹Žæ˜¯â€œé¡ºç€å†™å‡ºæ¥â€çš„。å过æ¥ï¼Œæ¨¡åž‹ä¸æ¸…æ¥šæ—¶ï¼Œä½ ä¼šä¸åœè¿”工。第8周最å®è´µçš„䏿˜¯è®°ä½å¤šå°‘ API,而是建立“先设计数æ®ï¼Œå†å†™é€»è¾‘â€çš„ä¹ æƒ¯ã€‚
8.5 vector 进阶:é历ã€ä¿®æ”¹ã€åˆ 除的安全写法
`vector` ä½¿ç”¨ä¸æœ€å¸¸è§ bug 是“é历时修改容器导致索引错乱â€ã€‚ä¾‹å¦‚ä½ åœ¨ `for` å¾ªçŽ¯é‡ŒæŒ‰ä¸‹æ ‡åˆ é™¤å…ƒç´ ï¼ŒåŽé¢çš„å…ƒç´ ä¼šå‰ç§»ï¼Œå¦‚æžœä¸è°ƒæ•´ç´¢å¼•å°±ä¼šè·³è¿‡å…ƒç´ ã€‚å¦ä¹ 阶段å¯å…ˆé‡‡ç”¨ç®€å•ç–略:先记录è¦åˆ é™¤çš„ç›®æ ‡ï¼Œå†ç»Ÿä¸€åˆ 除;或者从åŽå¾€å‰åˆ ,å‡å°‘ä½ç§»å½±å“。ä¸è¦ä¸ºäº†â€œå†™çŸä»£ç â€ç‰ºç‰²ç¨³å®šæ€§ã€‚
å¦ä¸€ä¸ªé—®é¢˜æ˜¯è¶Šç•Œè®¿é—®ã€‚`scores[5]` åªæœ‰åœ¨ä½ 确认 `size() > 5` æ—¶æ‰å®‰å…¨ã€‚å»ºè®®ä½ åœ¨å¤„ç†å¤–部输入索引时始终åšè¾¹ç•Œåˆ¤æ–,例如 `if (idx >= 0 && idx < scores.size())`。这类判æ–看起æ¥å•°å—¦ï¼Œä½†å®ƒæ˜¯çº¿ä¸Šç¨³å®šæ€§çš„底线。很多程åºå´©æºƒä¸æ˜¯ç®—法错,而是边界没守ä½ã€‚
é历写法上,范围 `for` 对åˆå¦è€…æ›´å‹å¥½ï¼›éœ€è¦ç´¢å¼•æ—¶å†ç”¨ä¼ 统 `for (size_t i = 0; i < v.size(); i++)`ã€‚å…³é”®æ˜¯é€‰æ‹©æœ€å®¹æ˜“è¯»æ‡‚çš„å†™æ³•ï¼Œè€Œä¸æ˜¯è¿½æ±‚“最炫写法â€ã€‚å¯è¯»æ€§é«˜çš„代ç ï¼Œæ‰æ›´å®¹æ˜“被未æ¥çš„ä½ ç»´æŠ¤ã€‚
vector<int> scores = {88, 92, 75, 60, 47};
for (size_t i = 0; i < scores.size(); i++) {
if (scores[i] < 60) {
cout << "å¾…æå‡åˆ†æ•°: index=" << i << ", value=" << scores[i] << "\n";
}
}
8.6 map 进阶:查询ç–略与默认值陷阱
`map` 新手常è§è¯¯åŒºæ˜¯ç›´æŽ¥ç”¨ `scoreMap[name]` æŸ¥è¯¢ã€‚è¿™æ ·å†™è™½ç„¶æ–¹ä¾¿ï¼Œä½†å½“é”®ä¸å˜åœ¨æ—¶ä¼šè‡ªåŠ¨åˆ›å»ºä¸€ä¸ªé»˜è®¤å€¼ï¼Œå¯èƒ½æ‚„悄污染数æ®ã€‚更稳妥的方法是先判æ–键是å¦å˜åœ¨ï¼Œå†è¯»å–å€¼ã€‚ä½ å¯ä»¥ä½¿ç”¨ `find` åšæ˜¾å¼æŸ¥è¯¢ï¼šæ‰¾åˆ°å†ç”¨ï¼Œæ‰¾ä¸åˆ°å°±ç»™å‡ºæç¤ºã€‚è¿™æ ·é€»è¾‘æ›´å¯æŽ§ï¼Œæ•°æ®ä¹Ÿæ›´å¹²å‡€ã€‚
在业务场景ä¸ï¼Œä½ 还è¦è€ƒè™‘“åŒå键更新â€ä¸Žâ€œé¦–次æ’å…¥â€ä¸¤ä¸ªè·¯å¾„是å¦ä¸€è‡´ã€‚例如更新å¦ç”Ÿåˆ†æ•°æ—¶ï¼Œæ˜¯è¦†ç›–旧值还是拒ç»é‡å¤ï¼Ÿè¿™å…¶å®žæ˜¯ä¸šåŠ¡è§„åˆ™ï¼Œä¸æ˜¯è¯æ³•问题。写程åºå‰å…ˆå®šè§„则,å†å†™å®¹å™¨æ“作,能é¿å…åŽæœŸè¡Œä¸ºäº‰è®®ã€‚工程开å‘里,数æ®è§„åˆ™æ¸…æ™°æ¯”ä»£ç æŠ€å·§æ›´é‡è¦ã€‚
map<string, int> scoreMap;
scoreMap["Mia"] = 95;
string name = "Leo";
auto it = scoreMap.find(name);
if (it == scoreMap.end()) {
cout << "未找到该å¦ç”Ÿ: " << name << "\n";
} else {
cout << name << " 的分数: " << it->second << "\n";
}
8.7 第二阶段收æŸï¼šä»Žè¯æ³•到å°ç³»ç»Ÿ
å¦‚æžœä½ å›žçœ‹ç¬¬4周到第8周,会å‘现自己完æˆäº†ä¸€ä¸ªé‡è¦è·¨è¶Šï¼šä»Žâ€œä¼šå†™å•æ¡è¯å¥â€åˆ°â€œèƒ½ç®¡ç†ä¸€ç»„æ•°æ®å¹¶ç»„ç»‡æˆæµç¨‹â€ã€‚è¿™å°±æ˜¯é¡¹ç›®èƒ½åŠ›çš„åŸºç¡€ã€‚æœªæ¥æ— è®ºä½ å¦é¢å‘对象ã€ç®—æ³•è¿˜æ˜¯å·¥ç¨‹åŒ–ï¼Œæ ¸å¿ƒéƒ½ç¦»ä¸å¼€è¿™å‡ 个能力:类型æ„è¯†ã€æŽ§åˆ¶æµæ„识ã€å‡½æ•°è¾¹ç•Œæ„è¯†ã€æ•°æ®ç»“æž„æ„识。
å»ºè®®ä½ åœ¨æœ¬å‘¨åšä¸€æ¬¡å®Œæ•´å¤ç›˜ï¼šç¬¬ä¸€ï¼Œåˆ—出自己最常犯的 3 个错误;第二,为æ¯ä¸ªé”™è¯¯å†™ä¸€æ¡é¢„é˜²è§„åˆ™ï¼›ç¬¬ä¸‰ï¼ŒæŠŠè§„åˆ™è´´åˆ°ä¸‹ä¸€å‘¨ä»£ç æ¨¡æ¿æœ€ä¸Šé¢ã€‚è¿™ä¸ªåŠ¨ä½œä¼šè®©ä½ çš„å¦ä¹ 从“ç»éªŒåž‹â€å˜æˆâ€œæ–¹æ³•åž‹â€ã€‚长期看,方法型å¦ä¹ 者的æˆé•¿é€Ÿåº¦é€šå¸¸æ›´å¿«ã€æ›´ç¨³ã€‚
ç¬¬äºŒé˜¶æ®µç»“æŸæ—¶ï¼Œä¸éœ€è¦è¿½æ±‚“写得åƒé«˜æ‰‹â€ï¼Œä½†è¦ç¡®ä¿â€œå†™å¾—稳定ã€çœ‹å¾—æ¸…æ¥šã€æ”¹å¾—动â€ã€‚åªè¦è¾¾åˆ°è¿™ä¸ªçжæ€ï¼Œä½ 进入第三阶段项目实战时会éžå¸¸æœ‰åº•气。
8.8 è¯¾å ‚é—®ç”与进阶练ä¹
问:`vector` å’Œ `map` éƒ½èƒ½å˜æ•°æ®ï¼Œä¸ºä»€ä¹ˆè¦åŒºåˆ†ï¼Ÿ å› ä¸ºå®ƒä»¬è§£å†³çš„é—®é¢˜ä¸åŒã€‚`vector` 擅长按顺åºç®¡ç†å’Œé历,`map` 擅长按键快速定ä½ã€‚ä½ å¯ä»¥æŠŠå®ƒä»¬ç†è§£ä¸ºä¸¤ç§æ€ç»´ï¼šä¸€ä¸ªæ˜¯â€œæŒ‰ä½ç½®æ‰¾â€ï¼Œä¸€ä¸ªæ˜¯â€œæŒ‰åå—æ‰¾â€ã€‚项目里ç»å¸¸è¦åŒæ—¶ç”¨ä¸¤è€…,例如用 `vector` ä¿æŒå±•示顺åºï¼Œç”¨ `map` åšå¿«é€Ÿç´¢å¼•。
é—®ï¼šæˆ‘è¯¥ä¼˜å…ˆå¦ API è¿˜æ˜¯å…ˆå¦æ•°æ®å»ºæ¨¡ï¼Ÿ 优先建模。API å¯ä»¥æŸ¥æ–‡æ¡£ï¼Œå»ºæ¨¡èƒ½åŠ›å¿…é¡»é è®ç»ƒã€‚æ¯æ¬¡åšé¢˜å…ˆé—®ï¼šæˆ‘有哪些实体?实体之间是什么关系?数æ®ä»¥åŽè¦æŒ‰é¡ºåºå±•ç¤ºè¿˜æ˜¯æŒ‰é”®æŸ¥è¯¢ï¼ŸæŠŠè¿™ä¸‰ä¸ªé—®é¢˜å›žç”æ¸…æ¥šï¼Œå®¹å™¨é€‰æ‹©é€šå¸¸å°±è‡ªç„¶äº†ã€‚ä½ ä¼šå‘现,真æ£å½±å“代ç è´¨é‡çš„往往䏿˜¯â€œä¸ä¼šæŸä¸ªå‡½æ•°â€ï¼Œè€Œæ˜¯â€œæ•°æ®ç»“构一开始就选错了â€ã€‚
问:为什么我程åºèƒ½è¿è¡Œï¼Œä½†è¶Šæ”¹è¶Šä¹±ï¼Ÿ å› ä¸ºç¼ºå°‘â€œæ•°æ®å±‚â€å’Œâ€œé€»è¾‘层â€è¾¹ç•Œã€‚å»ºè®®ä½ æŠŠå®¹å™¨æ“作å°è£…æˆå‡½æ•°ï¼š`addStudent`ã€`findStudent`ã€`printAllStudents`。主æµç¨‹åªè´Ÿè´£è°ƒåº¦ã€‚è¿™æ ·åŽç»æ–°å¢žåŠŸèƒ½æ—¶ï¼Œæ”¹åŠ¨èŒƒå›´å¯æŽ§ï¼Œä¸ä¼šæ¯æ¬¡éƒ½ç¢°å…¨å±€ä»£ç 。第8å‘¨ä½ è¦å»ºç«‹çš„æ ¸å¿ƒèƒ½åŠ›å°±æ˜¯â€œè®©æ•°æ®ç»“构支撑功能è¿ä»£â€ã€‚
è¿›é˜¶ç»ƒä¹ å»ºè®®ï¼šå®žçŽ°â€œè¯¾å ‚ç§¯åˆ†æ¦œç³»ç»Ÿâ€ã€‚è¦æ±‚: 第一,用 `vector` å˜æŽ’è¡Œæ¦œé¡ºåºï¼Œç”¨ `map` å˜å§“ååˆ°ç§¯åˆ†æ˜ å°„ï¼› ç¬¬äºŒï¼Œæ”¯æŒæ–°å¢žåŒå¦ã€æ›´æ–°ç§¯åˆ†ã€æŒ‰å§“åæŸ¥è¯¢ã€æŒ‰ç§¯åˆ†åŒºé—´ç»Ÿè®¡äººæ•°ï¼› 第三,处ç†å¼‚常输入(空姓åã€è´Ÿç§¯åˆ†ã€é‡å¤å§“åç–略); 第四,输出一份“数æ®ä¸€è‡´æ€§æ£€æŸ¥ç»“æžœâ€ï¼Œç¡®è®¤ `vector` 与 `map` ä¸åŒå¦æ•°é‡ä¸€è‡´ã€‚ è¿™ä¸ªç»ƒä¹ ä¼šè®©ä½ çœŸæ£ä½“验“多容器ååŒâ€çš„工程场景。
å¦‚æžœä½ å®Œæˆå¾—比较快,å¯ä»¥ç»§ç»æŒ‘战“æŒä¹…化版本â€ï¼šæŠŠç§¯åˆ†æ•°æ®å†™å…¥æ–‡æœ¬æ–‡ä»¶ï¼Œä¸‹æ¬¡è¿è¡Œç¨‹åºæ—¶è‡ªåŠ¨åŠ è½½ã€‚è¿™æ ·ä½ ä¼šæŠŠç¬¬äºŒé˜¶æ®µå‡½æ•°ã€æŽ§åˆ¶æµã€å®¹å™¨ä¸‰å—能力完整串起æ¥ï¼Œä¸ºç¬¬ä¸‰é˜¶æ®µé¡¹ç›®å®žæˆ˜æ‰“下éžå¸¸æ‰Žå®žçš„基础。
8.9 æœ¬å‘¨ç»ƒä¹ ä¸Žè‡ªæµ‹æ¸…å•
本周练ä¹
- 完æˆâ€œå¦ç”Ÿæˆç»©ç®¡ç†å™¨ v1â€ï¼ˆæ–°å¢žã€æŸ¥è¯¢ã€å¹³å‡åˆ†ç»Ÿè®¡ï¼‰ã€‚
- 使用 `vector` å˜æˆç»©ï¼Œä½¿ç”¨ `map` 建姓å索引。
- æäº¤ 8 组测试,至少 2 组为空容器场景。
自测清å•
- 我能解释何时用 `vector`ã€ä½•时用 `map`。
- 容器é历是å¦è¦†ç›–空数æ®åœºæ™¯ã€‚
- æŸ¥è¯¢å¤±è´¥æ—¶æ˜¯å¦æœ‰æ˜Žç¡®æç¤ºã€‚
- 代ç 结构是å¦ä¾¿äºŽç»§ç»æ‰©å±•。
补充建议:åšä¸€æ¬¡â€œæ•°æ®ç»“构替æ¢å®žéªŒâ€ï¼ŒæŠŠåŒä¸€éœ€æ±‚分别用å•一容器和组åˆå®¹å™¨å®žçŽ°ï¼Œå¯¹æ¯”å¤æ‚度与å¯ç»´æŠ¤æ€§ï¼Œä½ 会更直观ç†è§£å»ºæ¨¡ä»·å€¼ã€‚