頭歌 | 數據結構與算法課程設計-算法與競賽(第5章) - C++與STL基礎一


STLC++的標准模板庫,英文全稱是Standard Template Library,它稍微有點復雜,操作很多,但是非常實用。STL的目的是標准化常用的組件,這樣就不用重新開發了,可以使用現成的組件來提高編程效率。它是由Alexander Stepanov等人在惠普實驗室工作時所開發出來的,從根本上說,STLvectorsetmap等容器的集合。

本實訓主要設置了六個關卡來教學和實踐vectorsetmap

  • 第一關:介紹向量vector的相關操作並設計了一些任務,同時需要調用vector的相關操作來完成;
  • 第二關:設計了一個二維動態數組的應用,使用vector能夠非常方便解決該問題;
  • 第三關:介紹集合set的相關操作,並運用這些基本操作解決設定的小任務;
  • 第四關:基於set求解一段英語文本中的出現的26個英文字母(區分大小寫);
  • 第五關:介紹鍵值對映射map的一些操作,運用map維護一個學生成績管理系統,並提供查詢功能;
  • 第六關:運用鍵值對映射map統計一段英語文本中的26個英文字母出現的次數(區分大小寫)。

第1關:STL模板之動態數組:向量vector的操作

任務描述

本關任務:仔細閱讀下文向量vector的相關操作,並使用vector完成對n個整數序列的插入、刪除和排序功能。

相關知識

為了完成本關任務,你需要掌握:1.向量的概念;2.插入元素;3.刪除元素;4.基於sort對向量排序;5.遍歷向量;6.清空向量。

向量的概念

向量vector:是一種順序容器,與數組類似,但它比數組更優越。數組不能動態拓展,在程序運行的時候可能造成內存浪費和訪問越界。而vector正好可以彌補這一缺陷,可動態分配和拓展內存,它的隨機訪問快,在中間插入和刪除慢,但在末端插入和刪除快。

向量作為基本數組的類模板,被包含在vector頭文件中,定義方式如下(注意搭配algorithmusing namespace std一起使用):

  • vector<int> v1,定義一個元素為類型為int 整型的向量v1
  • vector<string> v2(10),定義一個元素為類型為string字符串類型的向量v2,初始存儲空間大小為10,每個元素初始為空串
  • vector<node> v3,定義一個元素為類型為node類型的向量v3,其中node一般是結構體等自定義數據類型

插入元素

往向量插入一個元素通過調用push_back()方法實現(在向量末尾插入),另外也可以通過下標訪問的方式直接在指定位置插入元素(前提是該位置已經被分配內存空間),如下實例:

1 vector <int> vec; // 創建一個整型向量vec
2 vec.push_back(1); // 向vec插入一個元素1
3 vec.push_back(2); // 向vec插入一個元素2
4 vec[1] = 3; // 直接在位置1插入元素3,原來的元素2被元素3覆蓋了
5 // 目前vec包含 1, 3兩個元素

刪除元素

向量的刪除與插入相對應,包含隊尾刪除和指定位置刪除:隊尾刪除通過調用pop_back()方法,注意,它並不會返回被刪除的元素;指定位置的刪除是基於迭代器iterator 實現的,迭代器相對應數組的指針,指向向量的存儲地址,通過調用erase(iterator pos)方法刪除迭代器位置pos所在的元素,基於上述vec的實例如下:

1 vec.pop_back(); // 刪除了元素3
2 vector<int>::iterator pos = vec.begin(); //定義一個vector<int>的迭代器pos,並指向vec的首地址
3 cout<<*pos; // 與指針一樣,通過*訪問地址上的值,輸出為1
4 vec.erase(pos); // 刪除迭代器地址pos及其元素,目前pos為vec首地址,元素值為1,刪除之后元素為空,不包含任何元素了

基於sort對向量排序

向量是基於數組的類模板,同樣可以用sort函數完成排序,使用方式如下:

sort(vec.begin(), vec.end()); // 默認從小到大排序

遍歷向量

向量的遍歷可以通過下標訪問和迭代器訪問的方式:

1 for(int i=0;i<vec.size();i++) // size()返回當前向量vec的大小
2     cout<<vec[i];
3 for(vector<int>::iterator it=vec.begin();it!=vec.end();it++)
4     cout<<*it;

清空向量

向量的清空通過調用clear()方法實現,清空后向量大小變為0

1 vec.clear()

編程要求

本關的編程任務是補全右側代碼片段mainBeginEnd中間的代碼,具體要求如下:

  • 創建一個整型類型的向量vec
  • 讀取數據:序列個數n,以及n個整數並插入向量vec
  • 通過erase操作刪除向量vec中的重復元素:保留第一次出現的元素,刪除之后出現的重復元素;
  • 使用Algorithm模板函數sort對向量vec里的元素從小到大排序;
  • 遍歷向量vec並輸出:元素中間空格隔開,末尾加換行符\n
  • 調用clear清空向量。

測試說明

平台將自動編譯補全后的代碼,並生成若干組測試數據,接着根據程序的輸出判斷程序是否正確。

以下是平台的測試樣例:

測試輸入:

7

1 2 3 1 2 3 4

預期輸出:

1 2 3 4

0

輸入格式:

第一行:序列個數n

第二行:n個整數序列

輸出格式:

第一行:遍歷並輸出向量,中間空格隔開,末尾換行\n

第二行:非學員輸出,數值0用於檢測向量是否清空


開始你的任務吧,祝你成功!

 

 1 //
 2 //  main.cpp
 3 //  step1
 4 //
 5 //  Created by ljpc on 2018/7/23.
 6 //  Copyright ? 2018年 ljpc. All rights reserved.
 7 //
 8 
 9 #include <iostream>
10 #include <algorithm>
11 #include <vector>
12 using namespace std;
13 
14 int main(int argc, const char * argv[]) {
15 
16 
17     // 請在這里補充代碼,完成本關任務
18     /********* Begin *********/
19     // 1.構建整型向量vec
20     vector<int> vec;
21 
22     // 2.讀取數據:序列個數n,以及n個整數並存入向量vec
23     int n;
24     cin>>n;
25     for(int i=0; i<n; i++) {
26         int m;
27         cin>>m;
28         vec.push_back(m);
29     }
30     
31     // 3.刪除向量vec中的重復元素
32     sort(vec.begin(),vec.end());
33     auto last = std::unique(vec.begin(),vec.end());
34     vec.erase(last,vec.end());
35 
36 
37     // 4.使用Algorithm模板函數sort對vec排序:從小到大
38     sort(vec.begin(),vec.end());
39 
40     // 5.遍歷向量vec並輸出,元素中間空格隔開,末尾加換行符'\n'
41     for(vector<int>::iterator it=vec.begin();it!=vec.end();it++) cout<<" "<<*it;
42     cout<<endl;
43 
44     // 6.清空向量vec
45     vec.clear();
46 
47     /********* End *********/
48     printf("%d\n", int(vec.size()));
49 
50     return 0;
51 }
點擊查看代碼

 

 

第2關:STL模板之動態數組:向量vector的應用

任務描述

本關任務:在一座城池中有N個谷倉,每個谷倉分別有Ni袋糧食並堆成了一列,重量分別為Wj,為了應對外敵,通常需要在谷倉間調動糧食,每次調動只會選擇糧堆最上面的一袋糧食運走,並放在目的谷倉糧堆的最上面。

相關知識

為了完成本關任務,你需要掌握:1.向量的相關操作,2.嵌套使用向量模擬二維動態數組。

向量的相關操作

糧食調動是在糧堆的最上面進行的操作,涉及的向量操作為push_backpop_back,詳細的向量具體操作和運用請參考STL模板之動態數組:向量vector的操作

嵌套使用向量模擬二維動態數組

谷倉的數量在不同的測試用例下是不同的,每個谷倉中的糧食袋數是動態變化的,因此,可以使用二維的動態數組來求解,既方便又節約內存。

  • 第一步:定義一個以糧食重量int為數據類型的動態數組vector<int>
  • 第二步:定義一個以糧食重量向量vector<int>為數據類型的動態數組vector<vector<int> > vec

這樣,vec的第一維下標就表示谷倉的ID,第二維就是對應谷倉的各袋糧食的重量。

編程要求

本關的編程任務是補全右側代碼片段mainBeginEnd中間的代碼,具體要求如下:

  • 創建一個vector<vector<int> > vec二維動態向量,讀取各個谷倉的初始糧食狀況;

  • 基於向量的push_packpop_back等基本操作,實現M次調動糧食;

  • 輸出最后各個谷倉ID、該谷倉中各袋糧食的重量以及總的重量(請嚴格遵循測試樣例的輸出格式)。

測試說明

平台將自動編譯補全后的代碼,並生成若干組測試數據,接着根據程序的輸出判斷程序是否正確。

以下是平台的測試樣例:

測試輸入:

5

3 79 32 29

4 42 41 92 6

6 68 37 63 11 34 79

2 63 36

3 27 74 67

6

move 1 2

move 3 0

move 3 0

move 4 2

move 1 4

move 2 0

預期輸出:

0 79 32 29 36 63 67 306

1 42 41 83

2 68 37 63 11 34 79 6 298

3 0 0

4 27 74 92 193

輸入格式:

第一行整數N:谷倉數量

接下來N行,依次為各個谷倉ID=[0,1,...,N1]的初始信息:第一個數字為該谷倉的初始糧食袋數Ni,后面接着Ni袋糧食的重量Wj

接下來一行整數M:調動糧食次數

接下來M行,每行move a b:將谷倉a糧堆的最后一袋糧食調動到谷倉b糧堆的最上面

輸出格式:

輸出N行,按順序輸出谷倉ID=[0,1,...,N1]的最終狀態信息:ID W0 W1 ... Wj Wsum,若谷倉空了,則輸出為ID 0 0

注意:每行所有數字中間空格隔開,末尾換行\n


開始你的任務吧,祝你成功!

 

 1 //
 2 //  main.cpp
 3 //  step2
 4 //
 5 //  Created by ljpc on 2018/7/23.
 6 //  Copyright © 2018年 ljpc. All rights reserved.
 7 //
 8 
 9 #include <iostream>
10 #include <algorithm>
11 #include <vector>
12 using namespace std;
13 
14 int main(int argc, const char * argv[]) {
15     
16     
17     // 請在這里補充代碼,完成本關任務
18     /********* Begin *********/
19     vector<vector<int> > vec;
20     int n;
21     scanf("%d", &n);
22     while (n--) {
23         vector<int> tmp;
24         int m;
25         scanf("%d", &m);
26         while (m--) {
27             int x;
28             scanf("%d", &x);
29             tmp.push_back(x);
30         }
31         vec.push_back(tmp);
32     }
33     int q;
34     scanf("%d", &q);
35     while (q--) {
36         char str[20];
37         int a, b;
38         scanf("%s %d %d", str, &a, &b);
39         if(!vec[a].empty()){
40             vec[b].push_back(vec[a].back());
41             vec[a].erase(vec[a].end()-1);
42         }
43     }
44     for (int i=0; i<vec.size(); i++) {
45         int tot = 0;
46         printf("%d ", i);
47         if (vec[i].empty()) {
48             printf("0 ");
49         }
50         else{
51             for (int j=0; j<vec[i].size(); j++) {
52                 printf("%d ",vec[i][j]);
53                 tot += vec[i][j];
54             }
55         }
56         printf("%d\n", tot);
57     }
58 }
點擊查看代碼

 

 

第3關:STL模板之關聯容器:集合set的操作詳解

任務描述

本關任務:仔細閱讀下文集合的相關操作,並使用set完成N次插入或刪除元素操作,以及集合的遍歷和查找等要求。

相關知識

為了完成本關任務,你需要掌握:1.集合的概念,2.插入元素,3.刪除元素,4.遍歷集合,5.查找元素,6.清空集合。

集合的概念

集合set就是數學上的集合,其中的每個元素沒有重復的,但是set中的元素在數據結構中是有序存儲的(默認升序),為了高效的實現插入、刪除和查找等操作,這與數學上的集合中元素無序性有點區別。

集合set也是STL中的一種標准關聯容器,其底層數據結構是基於平衡搜索樹(紅黑樹)實現的,插入刪除等操作都是通過迭代器指針實現的,不涉及內存操作,因此效率非常高。

集合set被包含在set頭文件中,基本定義方式如下:

  • set<int> st,定義了一個元素類型為int整型的集合st

插入元素

往集合中插入一個元素通過調用insert()方法實現:

1 set<int> st; // 創建一個整型集合st
2 st.insert(1); // 向st插入一個元素1
3 st.insert(2); // 向st插入一個元素2

刪除元素

集合元素的刪除通過調用erase()方法實現,傳入的參數可以是待刪除的元素,也可以是待刪除元素的地址:

1 set<int>::iterator it = st.begin(); // 定義一個迭代器,初始為st的首地址
2 cout<<*it; // 輸出為元素1
3 st.erase(it); // 刪除it指向的元素1
4 st.erase(2); // 刪除元素2

遍歷集合

集合的遍歷通過迭代器的方式進行,首先讓迭代器指針指向集合的首地址,然后逐步移動迭代器指針,直到集合的尾地址:

1 for(set<int>::iterator it = st.begin();it!=st.end();it++)
2     cout<<*it;

查找元素

在集合中查找指定元素通過find()方法實現,若找到了則返回該元素在集合中的地址,否則返回集合的尾地址:

1 it = st.find(2); //查找指定元素2,it結果為st.end(),因為2已經被刪除了

集合清空

集合的清空通過調用clear()方法實現,清空后集合的大小st.size()變為0

1 st.clear()
2 cout<<st.size(); // 結果為0

編程要求

本關的編程任務是補全右側代碼片段mainBeginEnd中間的代碼,具體要求如下:

  • 創建一個空的集合st,數據類型為int

  • 讀取數據:第一行整數N,后面N行插入或刪除操作,按指定要求輸出相應信息;

  • 遍歷集合:首先在一行輸出集合的大小,然后在下一行輸出集合所有元素,中間空格隔開,末尾換行;

  • 讀取數據:整數M以及M次查找操作,並按指定要求輸出相應信息;

  • 清空集合

測試說明

平台將自動編譯補全后的代碼,並生成若干組測試數據,接着根據程序的輸出判斷程序是否正確。

以下是平台的測試樣例:

測試輸入:

7

insert 2

insert 7

insert 1

erase 3

erase 1

insert 5

erase 7

2

find 7

find 5

預期輸出:

3 not in set

print set: 2

2 5

find 7 not in set

find 5 in set

0

輸入格式:

第一行整數N

接下來N行插入或刪除操作

整數M

接下來M行查找操作

輸出格式:

插入刪除階段:若待刪除的元素x不在集合中,則輸出:x not in set

遍歷集合階段輸出兩行,第一行print set: set.size(),第二行集合所有元素x1 x2 x3 ...

查找階段:若找到元素x,則輸出find x in set,否則輸出find x not in set

非學員輸出0


開始你的任務吧,祝你成功!

 

  1 //
  2 //  main.cpp
  3 //  step5
  4 //
  5 //  Created by ljpc on 2018/7/25.
  6 //  Copyright  2018年 ljpc. All rights reserved.
  7 //
  8 
  9 #include <iostream>
 10 #include <cstring>
 11 #include <string>
 12 #include <algorithm>
 13 #include <map>
 14 using namespace std;
 15 
 16 int main(int argc, const char * argv[]) {
 17     
 18     
 19     // 請在這里補充代碼,完成本關任務
 20     /********* Begin *********/
 21     // 1.創建一個空的鍵值對映射mp: 鍵string->值int
 22     map<string,int> mp;
 23     // 2.讀取和處理數據:插入n個學生信息(姓名 成績),並按指定要求輸出
 24     int n1,i;
 25     cin>>n1;
 26     string s1,s2;
 27     int n2;
 28     pair<string,int> p;
 29     map<string,int>::iterator it;
 30         for(i=0;i<n1;i++){
 31             cin>>s1>>s2>>n2;
 32             if(s1=="insert"){
 33                 p.first=s2;
 34                 p.second=n2;
 35                 it=mp.find(p.first);
 36                 if(it==mp.end())
 37                     mp.insert(p);
 38                 else
 39                     cout<<s2<<" has been recorded\n";
 40             }     
 41         }
 42         /*if(it==mp.end()){
 43             for(i=0;i<n1;i++){
 44               p.first=s2;
 45               p.second=n2;
 46               mp.insert(p);
 47             }
 48         }
 49         else
 50         cout<<s2<<" has been recorded\n";*/
 51        
 52     // 3.讀取和處理數據:刪除m個學生信息(姓名),並按指定要求輸出
 53     int n3;
 54     cin>>n3;
 55     string s3,s4;
 56     /*cin>>s3;
 57     if(s3=="erase"){
 58         cin>>s4;
 59         p.first=s4;
 60         it=mp.find(s4);
 61         if(it!=mp.end()){
 62             for(i=0;i<n3;i++){
 63               mp.erase(s4);
 64             }
 65         }
 66         else
 67         cout<<s4<<" has not been recorded\n";
 68     }*/ 
 69     for(i=0;i<n3;i++){
 70             cin>>s3>>s4;
 71             if(s3=="erase"){
 72                 p.first=s4;
 73                 
 74                 it=mp.find(p.first);
 75                 if(it!=mp.end())
 76                     mp.erase(p.first);
 77                 else
 78                     cout<<s4<<" has not been recorded\n";
 79             }
 80             
 81         }     
 82     // 4.遍歷映射mp,並按指定要求輸出
 83     cout<<"print map: "<<mp.size()<<"\n";
 84     for(it=mp.begin();it!=mp.end();it++){
 85         cout<<it->first<<" "<<it->second<<"\n";
 86     }
 87     // 5.查找q個學生信息,並按指定要求輸出
 88     int n4;
 89     cin>>n4;
 90     string s5,s6;
 91     
 92     for(i=0;i<n4;i++){
 93         cin>>s5>>s6;
 94         if(s5=="find"){
 95             it=mp.find(s6);
 96             if(it!=mp.end()){
 97                 cout<<s6<<" score "<<it->second<<"\n";
 98             }
 99             else
100             cout<<s6<<" cannot been found\n";
101         }
102     }
103   
104     // 6.清空集合
105     mp.clear();
106     /********* End *********/
107     printf("%d\n", int(mp.size()));
108     
109     return 0;
110 }
點擊查看代碼

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM