Algorithm
中文意思是算法,是一個計算的具體步驟,常用於數據處理、計算以及自動推理。它作為C++
標准模版庫STL
中最重要的頭文件之一,其提供了大量非成員模版函數,例如排序操作、二分查找操作、集合操作以及堆操作等。同時可以通過迭代器或指針訪問任何對象序列,例如STL
容器數組或實例。更多的了解請參考官方文檔 。
本實訓主要設置了五個關卡:
- 第一個關卡是序列合並,首先將兩個無序序列進行升序排序,然后調用合並函數完成兩個升序序列的合並;
- 第二個關卡是判斷一個序列是否被另一個序列包含;
- 第三個關卡是集合的並與交操作實例;
- 第四個關卡是集合的差集與對稱差集應用;
- 第五個關卡是序列排列的問題。
- 最后在每個關卡都設置了實例,考察學員對所講內容的理解和在線編程能力。
第1關:序列合並
任務描述
本關任務:給定兩個無序數組arr1
和arr2
,編寫一個程序實現這兩個數組的升序合並。
相關知識
為了完成本關任務,你需要掌握:1.升序合並思路,2.Algorithm
中的合並函數merge
。
升序合並思路
要求解兩個無序數組的升序合並,自然的,按照升序與合並位置關系,可分為先升序后合並和先合並后升序兩種方式,假設數組一的個數為N,數組二的個數為M:
-
先升序后合並:分別對兩個數組調用
sort
函數,完成升序的要求,然后調用merge
合並函數,對兩個有序數組合並。復雜度分析:兩次排序操作復雜度為O(N×logN+M×logM),最后合並的復雜度為O(N+M)。 -
先合並后升序:
merge
合並函數要求輸入的兩個數組是升序的,因此該方法無法調用merge
函數,需要自己編寫合並代碼,然后調用sort
函數對合並后的數組進行排序。復雜度分析:先合並的復雜度為O(N+M),然后調用排序的復雜度為O((N+M)×logN+M)
Algorithm
中的合並函數merge
合並數組是一個很常見的操作,例如在歸並排序和快速排序的遞歸求解過程中,就需要將兩個有序數組合並成一個。因此通過調用C++ Algorithm
中模板函數merge
,來快速實現這一操作是非常方便有效的。
合並函數的核心思想是設置兩個頭指針,分別指向兩個升序數組首地址,通過比較兩個頭指針的大小,每次都將小的數值放入新的數組,然后小數值指針后移,最后新的數組也是有序的,從而完成合並過程,復雜度為O(N+M)。其函數原型和應用實例如下:
1 \\ 函數原型 2 template <class InputIterator1, class InputIterator2, class OutputIterator> 3 OutputIterator merge (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result) 4 { 5 while (true) { 6 if (first1==last1) return std::copy(first2,last2,result); 7 if (first2==last2) return std::copy(first1,last1,result); 8 *result++ = (*first2<*first1)? *first2++ : *first1++; 9 } 10 } 11 \\ 應用實例 12 int arr1[3] = {1,2,3}; 13 int arr2[4] = {2,3,4,5}; 14 int arr3[7]; 15 merge(arr1, arr1+n1, arr2, arr2+n2, arr3); 16 \\ arr3結果為{1,2,2,3,3,4,5}
編程要求
本關的編程任務是補全右側代碼片段Merge_Array
中Begin
至End
中間的代碼,具體要求如下:
- 在
Merge_Array
中,合並兩個數組arr1
和arr2
,完成升序排序,最后返回排序后的合並數組。
測試說明
平台將自動編譯補全后的代碼,並生成若干組測試數據,接着根據程序的輸出判斷程序是否正確。
以下是平台的測試樣例:
測試輸入:
16
14 6 57 53 30 75 32 36 73 41 76 40 94 6 37 29
13
18 52 17 12 90 95 61 78 19 27 68 89 96
預期輸出:
6 6 12 14 17 18 19 27 29 30 32 36 37 40 41 52 53 57 61 68 73 75 76 78 89 90 94 95 96
輸入格式:
第一行整數N
第二行N個整數(無序)
第三行整數M
第四行M個整數(無序)
輸出格式:
輸出一行,包含N+M個升序整數,末尾換行!!!
開始你的任務吧,祝你成功!

1 // 2 // code.cpp 3 // step1 4 // 5 // Created by ljpc on 2018/7/17. 6 // Copyright © 2018年 ljpc. All rights reserved. 7 // 8 9 #include "code.h" 10 11 int* Merge_Array(int *arr1, int n1, int *arr2, int n2) 12 // 函數功能:合並兩個數組arr1和arr2,完成升序排序,返回排序后的合並數組 13 // 參數介紹:arr1數組一的首地址,n1數組一的個數,arr2數組二的首地址,n2數組二的個數 14 { 15 // 請在這里補充代碼,完成本關任務 16 /********** Begin *********/ 17 sort(arr1,arr1+n1); 18 sort(arr2,arr2+n2); 19 static int arr3[10000]; 20 merge(arr1,arr1+n1,arr2,arr2+n2,arr3); 21 return arr3; 22 /********** End **********/ 23 }
第2關:序列包含
任務描述
本關任務:給定兩個升序數組arr1和arr2,編寫一個程序判定數組arr1是否包含數組arr2,例如arr1=[1,2,3,4],arr2=[2,3],則數組arr1包含數組arr2,若arr2=[2,5],則數組arr1不包含數組arr2。
相關知識
為了完成本關任務,你需要掌握:1.有序數組包含,2.Algorithm
中的包含函數includes
。
有序數組包含
無序數組的包含問題就像是字符串應用中的最長公共子序列,解法是動態規划,而有序數組的包含則是簡單的判斷問題,解法類似有序數組的合並。
同樣的,其核心思想也是設置兩個頭指針分別指向兩個升序數組,若指針指向的元素相等,則兩個指針都往后移動,否則指向數組arr1的指針往后移動,直到指針移向數組尾地址。
Algorithm
中的包含函數includes
Algorithm
中的包含函數includes
是不常用但卻又比較實用的函數,它避免了我們編寫復雜的代碼,同時,模板函數的優勢可以讓我們自定義數據類型,在數據庫等查詢任務中是非常方便有效的,其函數原型及應用實例如下:
1 \\ 函數原型 2 template <class InputIterator1, class InputIterator2> 3 bool includes ( InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2 ) 4 { 5 while (first2!=last2) { 6 if ( (first1==last1) || (*first2<*first1) ) return false; 7 if (!(*first1<*first2)) ++first2; 8 ++first1; 9 } 10 return true; 11 } 12 \\ 應用實例 13 int arr1[4] = {1,2,3,4}; 14 int arr2[2] = {2,3}; 15 bool judge(arr1, arr1+4, arr2, arr2+2); 16 // judge結果為true
編程要求
本關的編程任務是補全右側代碼片段Include_Array
中Begin
至End
中間的代碼,具體要求如下:
- 在
Include_Array
中,依據函數傳入的參數,基於模板函數includes
或自己編寫具體代碼,實現判定數組arr1
是否包含arr2
,並返回判定結果。
測試說明
平台將自動編譯補全后的代碼,並生成若干組測試數據,接着根據程序的輸出判斷程序是否正確。
以下是平台的測試樣例:
測試輸入:
11
6 15 25 26 40 43 54 62 70 78 81
6
6 25 40 54 70 81
預期輸出:
array1 includes array2
輸入格式:
第一行整數N
第二行N個整數(升序)
第三行整數M
第四行M個整數(升序)
輸出格式:
若數組arr1包含數組arr2,則輸出array1 includes array2,否則輸出array1 not includes array2
開始你的任務吧,祝你成功!

// // code.cpp // step2 // // Created by ljpc on 2018/7/17. // Copyright © 2018年 ljpc. All rights reserved. // #include "code.h" bool Include_Array(int *arr1, int n1, int *arr2, int n2) // 函數功能:輸入兩個升序數組,判斷數組arr2是否被包含在數組arr1中(arr2不要求連續,但順序不能亂) // 參數介紹:arr1數組一的首地址,n1數組一的個數,arr2數組二的首地址,n2數組二的個數 { // 請在這里補充代碼,完成本關任務 /********** Begin *********/ bool judge=includes(arr1,arr1+n1,arr2,arr2+n2); return judge; /********** End **********/ }
第3關:集合並與交
任務描述
本關任務:給定兩個集合A和B,編寫一個程序實現這兩個集合的並集與交集。
相關知識
為了完成本關任務,你需要掌握:1.集合,2.集合的並,3.集合的交。
集合
集合是由一個或多個確定的元素所構成的整體。集合中的元素有三個特征:
-
確定性(集合中的元素是確定的);
-
互異性(集合中的元素是互不相同),例如:集合A=(1,a),則a不能等於1;
-
無序性:集合中的元素沒有先后之分,如集合(3,4,5)和(3,5,4)算作同一個集合,
但是本關卡為了在最后方便測試輸出集合是否正確,對輸出集合做了升序的要求。
集合的並
集合A和集合B的並是由所有屬於集合A或屬於集合B的元素所組成的集合,記作A⋃B 或者B⋃A,並集的一個重要屬性就是越並越多。假定集合A=(1,2,3,4,5,6,7),集合B=(6,7,8,9),那么集合A和集合B的並集為A⋃B=(1,2,3,4,5,6,7,8,9)。
Algorithm
算法模板中集成了集合的並操作,函數名稱為set_union
,其作用是將兩個集合合並成一個集合,但是要求輸入的兩個集合必須是有序的,這看似違背了集合的定義,但是有序的目的是為了讓求並的過程實現起來變得簡單。 因此,在本關卡中,首先需要將兩個集合排序,然后才調用set_union
函數計算出並集。其函數原型及應用實例如下:輸入參數是兩個集合的首尾地址以及一個保存並集結果的數組的首地址,最后返回數組尾地址:
1 \\ 函數原型 2 template <class InputIterator1, class InputIterator2, class OutputIterator> 3 OutputIterator set_union (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result) 4 { 5 while (true) 6 { 7 if (first1==last1) return std::copy(first2,last2,result); 8 if (first2==last2) return std::copy(first1,last1,result); 9 if (*first1<*first2) { *result = *first1; ++first1; } 10 else if (*first2<*first1) { *result = *first2; ++first2; } 11 else { *result = *first1; ++first1; ++first2; } 12 ++result; 13 } 14 } 15 \\ 應用實例 16 int arr1[3]={1,2,3}; 17 int arr2[3]={2,3,4}; 18 int arr3[4]; 19 int n = set_union(arr1, arr1+n1, arr2, arr2+n2, arr3)-arr3; 20 \\ arr3結果為{1,2,3,4} 21 \\ n結果為4
集合的交
集合A和B的交是由所有屬於集合A以及屬於集合B的元素所組成的集合,記作A∩B或者B∩A,交集的一個重要屬性就是越交越少。假定集合A=(1,2,3,4,5,6,7),集合B=(6,7,8,9),那么集合A和集合B的交集為A∩B=(6,7)。
Algorithm
算法模板中集成了集合的交操作,函數名稱為set_intersection
,其作用是將兩個集合交成一個集合,同樣的要求輸入的兩個集合必須是有序的。因此,首先需要將兩個集合排序,然后才調用set_intersection
函數計算出交集。其函數原型及應用實例如下,輸入參數是兩個集合的首尾地址以及一個保存交集結果的數組的首地址,最后返回數組尾地址:
1 \\ 函數原型 2 template <class InputIterator1, class InputIterator2, class OutputIterator> 3 OutputIterator set_intersection (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result) 4 { 5 while (true) 6 { 7 if (first1==last1) return std::copy(first2,last2,result); 8 if (first2==last2) return std::copy(first1,last1,result); 9 if (*first1<*first2) { *result = *first1; ++first1; } 10 else if (*first2<*first1) { *result = *first2; ++first2; } 11 else { *result = *first1; ++first1; ++first2; } 12 ++result; 13 } 14 } 15 \\ 應用實例 16 int arr1[3]={1,2,3}; 17 int arr2[3]={2,3,4}; 18 int arr3[2]; 19 int n = set_intersection(arr1, arr1+n1, arr2, arr2+n2, arr3)-arr3; 20 \\ arr3結果為{2,3} 21 \\ n結果為2
編程要求
本關的編程任務是補全右側代碼片段Set_Union
和Set_Intersection
中Begin
至End
中間的代碼,具體要求如下:
- 在
Set_Union
中,依據函數傳入的參數,實現函數的功能:計算出輸入的兩個集合的並集,首先對兩個集合排序,然后調用set_union
或自己實現集合並操作,最后返回並集大小。 - 在
Set_Intersection
中,依據函數傳入的參數,實現函數的功能:計算出輸入的兩個集合的交集,首先對兩個集合排序,然后調用set_intersection
或自己實現集合交操作,最后返回交集大小。
測試說明
平台將自動編譯補全后的代碼,並生成若干組測試數據,接着根據程序的輸出判斷程序是否正確。
以下是平台的測試樣例:
測試輸入:
7
1 2 3 4 5 6 7
4
6 7 8 9
預期輸出:
Union:9
{1,2,3,4,5,6,7,8,9}
Intersection:2
{6,7}
開始你的任務吧,祝你成功!

// // code.cpp // step3 // // Created by ljpc on 2018/7/17. // Copyright © 2018年 ljpc. All rights reserved. // #include "code.h" int Set_Union(int *arr1, int n1, int *arr2, int n2, int *arr3) // 函數功能:給定兩個數組arr1和arr2,計算他們的並集,然后存在數組arr3中,並返回並集大小 // 參數介紹:arr1數組一的首地址,n1數組一的個數,arr2數組二的首地址,n2數組二的個數,數組arr3 { // 請在這里補充代碼,完成本關任務 /********** Begin *********/ sort(arr1,arr1+n1); sort(arr2,arr2+n2); int n=set_union(arr1,arr1+n1,arr2,arr2+n2,arr3)-arr3; return n; /********** End **********/ } int Set_Intersection(int *arr1, int n1, int *arr2, int n2, int *arr3) // 函數功能:給定兩個數組arr1和arr2,計算他們的交集,然后存在數組arr3中,並返回交集大小 // 參數介紹:arr1數組一的首地址,n1數組一的個數,arr2數組二的首地址,n2數組二的個數,數組arr3 { // 請在這里補充代碼,完成本關任務 /********** Begin *********/ sort(arr1,arr1+n1); sort(arr2,arr2+n2); int n=set_intersection(arr1,arr1+n1,arr2,arr2+n2,arr3)-arr3; return n; /********** End **********/ }
第4關:集合“差集”與“對稱差集”
任務描述
本關任務:給定兩個集合A和B,編寫一個程序實現集合B關於集合A的相對差集A−B,集合A相對集合B的相對差集B−A,以及集合A與集合B的對稱差集。
相關知識
為了完成本關任務,你需要掌握:1.集合相對差集,2.集合對稱差集。
集合相對差集
集合差集也叫集合補集,是一個相對的定義:由屬於A而不屬於B的元素組成的集合,稱為B關於A的相對補集,記作A−B。例如集合A=(1,2,3,4),集合B=(3,4,5,6),那么集合A−B=(1,2)。
Algorithm
算法模板中集成了集合的差操作,函數名稱為set_difference
,其作用是計算出兩個集合的差集,與上個關卡集合的相關操作一樣,要求輸入的兩個集合必須是有序的。其函數原型及應用實例如下:
1 \\ 函數原型 2 template <class InputIterator1, class InputIterator2, class OutputIterator> 3 OutputIterator set_difference (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result) 4 { 5 while (first1!=last1 && first2!=last2) 6 { 7 if (*first1<*first2) {*result = *first1; ++result; ++first1; } 8 else if (*first2<*first1) ++first2; 9 else { ++first1; ++first2; } 10 } 11 return std::copy(first1,last1,result); 12 } 13 \\ 應用實例 14 int arr1[4]={1,2,3,4}; 15 int arr2[4]={3,4,5,6}; 16 int arr3[4]; 17 int n = set_difference(arr1, arr1+n1, arr2, arr2+n2, arr3)-arr3; 18 \\ arr3結果為{1,2} 19 \\ n結果為2
集合對稱差集
集合A與集合B的對稱差集定義為屬於集合A與集合B,但不屬於它們交集A∩B的元素集合,記為A△B。也就是說A△B=x∣x∈A∪B且x∈/A∩B,即A△B=(A∪B)—(A∩B)。同樣也可以用相對差集的並來表示A△B=(A—B)∪(B—A)。例如上述的兩個集合,他們的對稱差集為A△B=(1,2,5,6)。
Algorithm
算法模板中集成了集合對稱差集的操作,函數名稱為set_symmetric_difference
,其作用是計算出兩個集合的對稱差集,同樣的,要求輸入的兩個集合必須是有序的。其函數原型及應用實例如下:
1 \\ 函數原型 2 template <class InputIterator1, class InputIterator2, class OutputIterator> 3 OutputIterator set_symmetric_difference (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result) 4 { 5 while (true) 6 { 7 if (first1==last1) return std::copy(first2,last2,result); 8 if (first2==last2) return std::copy(first1,last1,result); 9 if (*first1<*first2) { *result=*first1; ++result; ++first1; } 10 else if (*first2<*first1) { *result = *first2; ++result; ++first2; } 11 else { ++first1; ++first2; } 12 } 13 } 14 \\ 應用實例 15 int arr1[4]={1,2,3,4}; 16 int arr2[4]={3,4,5,6}; 17 int arr3[8]; 18 int n = set_symmetric_difference(arr1, arr1+n1, arr2, arr2+n2, arr3)-arr3; 19 \\ arr3結果為{1,2,5,6} 20 \\ n結果為4
編程要求
本關的編程任務是補全右側代碼片段Set_Difference
和Set_Symmetric_Difference
中Begin
至End
中間的代碼,具體要求如下:
-
在
Set_Difference
中,實現函數的功能:參數arr1
和n1
是集合A的首地址和集合個數,同理,參數arr2
和n2
是集合B的首地址和集合個數,計算出集合B關於集合A的相對差集A−B,存入首地址為arr3
的存儲空間,並返回相對差集的個數。 -
在
Set_Symmetric_Difference
中,實現集合對稱差集的計算,學員可以利用set_symmetric_difference
來實現這一功能,也可以調用基本的集合操作函數來實現,例如集合差集和集合並集操作。
測試說明
平台將自動編譯補全后的代碼,並生成若干組測試數據,接着根據程序的輸出判斷程序是否正確。
以下是平台的測試樣例:
測試輸入:
7
1 2 3 4 5 6 7
4
6 7 8 9
預期輸出:
A-B:5
{1,2,3,4,5}
B-A:2
{8,9}
(A-B)U(B-A):7
{1,2,3,4,5,8,9}
開始你的任務吧,祝你成功!

// // code.cpp // step4 // // Created by ljpc on 2018/7/17. // Copyright © 2018年 ljpc. All rights reserved. // #include "code.h" int Set_Difference(int *arr1, int n1, int *arr2, int n2, int *arr3) // 函數功能:給定兩個數組arr1和arr2,計算arr1-arr2的差集,然后存在數組arr3中,並返回差集大小 // 參數介紹:arr1數組一的首地址,n1數組一的個數,arr2數組二的首地址,n2數組二的個數,數組arr3 { // 請在這里補充代碼,完成本關任務 /********** Begin *********/ sort(arr1,arr1+n1); sort(arr2,arr2+n2); int n=set_difference(arr1, arr1+n1, arr2, arr2+n2, arr3)-arr3; return n; /********** End **********/ } int Set_Symmetric_Difference(int *arr1, int n1, int *arr2, int n2, int *arr3) // 函數功能:給定兩個數組arr1和arr2,計算(arr1-arr2)U(arr2-arr1),然后存在數組arr3中,最后數組大小 // 參數介紹:arr1數組一的首地址,n1數組一的個數,arr2數組二的首地址,n2數組二的個數,數組arr3 { // 請在這里補充代碼,完成本關任務 /********** Begin *********/ sort(arr1,arr1+n1); sort(arr2,arr2+n2); int n=set_symmetric_difference(arr1, arr1+n1, arr2, arr2+n2, arr3)-arr3; return n; /********** End **********/ }
第5關:序列排列問題
任務描述
本關任務:給定排列的大小n,計算出從1,2,3,..,n開始的下m個排列,以及從n,..,3,2,1開始的上m個排列,並輸出結果。
例如n=3,m=4,那么從1,2,3開始的下4個排列為:1,2,3; 1,3,2; 2,1,3; 2,3,1
,從3,2,1開始的上4個排列為:3,2,1; 3,1,2; 2,3,1; 2,1,3
。
相關知識
為了完成本關任務,你需要掌握:1.序列排列,2.Algorithm
中下一個排列模板函數,3.Algorithm
中上一個排列模板函數。
序列排列
一般地,從n個不同元素中取出m個元素,按照一定的順序排成一列,叫做從n個元素中取出m個元素的一個排列permutation
。特別地,當m=n時,這個排列被稱作全排列all permutation
,本關卡就是關於n的全排列問題。
Algorithm
中下一個排列模板函數
給定一個排列序列,Algorithm
中的模板函數next_permutation
可以產生該排列的下一個序列,輸入參數為序列的首地址和尾地址,其函數模板及應用實例如下:
1 \\ 函數模板 2 template <class BidirectionalIterator> 3 bool next_permutation (BidirectionalIterator first, BidirectionalIterator last); 4 \\ 應用實例 5 int myints[] = {1,2,3}; 6 do { 7 std::cout << myints[0] << ' ' << myints[1] << ' ' << myints[2] << '\n'; 8 } while ( std::next_permutation(myints,myints+3) ); 9 輸出結果為: 10 1 2 3 11 1 3 2 12 2 1 3 13 2 3 1 14 3 1 2 15 3 2 1
Algorithm
中上一個排列模板函數
給定一個排列序列,Algorithm
中的模板函數prev_permutation
可以產生該排列的上一個序列,輸入參數為序列的首地址和尾地址,其函數模板及應用實例如下:
1 \\ 函數模板 2 template <class BidirectionalIterator> 3 bool prev_permutation (BidirectionalIterator first, BidirectionalIterator last); 4 \\ 應用實例 5 int myints[] = {3,2,1}; 6 do { 7 std::cout << myints[0] << ' ' << myints[1] << ' ' << myints[2] << '\n'; 8 } while ( std::prev_permutation(myints,myints+3) ); 9 輸出結果為: 10 3 2 1 11 3 1 2 12 2 3 1 13 2 1 3 14 1 3 2 15 1 2 3
編程要求
本關的編程任務是補全右側代碼片段Next_Permutation
和Prev_Permutation
中Begin
至End
中間的代碼,具體要求如下:
-
在
Next_Permutation
中,依據傳入的排列序列首地址arr
及其個數n
,輸出1,2,..,n的下m
個排列序列。 -
在
Prev_Permutation
中,依據傳入的排列序列首地址arr
及其個數n
,輸出n,..,2,1的上m
個排列序列。
測試說明
平台將自動編譯補全后的代碼,並生成若干組測試數據,接着根據程序的輸出判斷程序是否正確。
以下是平台的測試樣例:
測試輸入:
3 4
預期輸出:
Next_Permutation:
1 2 3
1 3 2
2 1 3
2 3 1
Prev_Permutation:
3 2 1
3 1 2
2 3 1
2 1 3
開始你的任務吧,祝你成功!

// // code.cpp // step5 // // Created by ljpc on 2018/7/18. // Copyright © 2018年 ljpc. All rights reserved. // #include "code.h" void Next_Permutation(int *arr, int n, int m) { // 請在這里補充代碼,完成本關任務 /********** Begin *********/ int a=1; do{ for(int i=0;i<n;i++){ if(i==n-1)cout<<arr[i]; else cout<<arr[i]<<" "; } cout<<endl; a++; if(a==m+1)break; }while(next_permutation(arr,arr+n)); /********** End **********/ } void Prev_Permutation(int *arr, int n, int m) { // 請在這里補充代碼,完成本關任務 /********** Begin *********/ int a=1; do{ for(int i=0;i<n;i++){ if(i==n-1)cout<<arr[i]; else cout<<arr[i]<<" "; } cout<<endl; a++; if(a==m+1)break; }while(prev_permutation(arr,arr+n)); /********** End **********/ }