c ++固有のコンテナアルゴリズム(ソート、マージ、リバース、削除、一意)

以下はすべて特定のコンテナアルゴリズムであり、c ++、list、forward_listの特定のアルゴリズムです。

パート1:メンバー関数アルゴリズムのマージ(forward_listおよびlistのみ)

1. c ++入門書の5番目のp369ページには、lst.merge(lst2)にはlstとlst2の両方が必要であると記載されていますが、私は独自のプログラムを作成しています。lstとlst2の両方を順番に使用しても問題ありません。なぜですか。

#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <forward_list>
#include <stack>
#include <vector>
#include <forward_list>
#include <deque>
#include <array>
#include <list>
#include <algorithm>
#include <numeric>
using namespace std;
bool compare(const int ,const int);
int main()
{
forward_list<int> f1{1,2223,3,4,5,6};
forward_list<int> l1{7,8,9};
//f1.sort();这里根本就没有运行
//l1.sort();这里也根本没有运行
//下面merge算法添加第二个参数用于比较,但是结果却不给从小到大排列?
f1.merge(l1,compare);
//这里我才开始排序
f1.sort();
for(auto i : f1)
	cout << i << endl;

return 0;
}
bool compare(const int a,const int b)
{
return a < b;
}

ubuntu20.04で実行されている上記のコードの結果は次のとおりです。

r@r:~/coml_/c++/chapter10/10.6$ g++ 2.cc -o 123
r@r:~/coml_/c++/chapter10/10.6$ ./123
1
3
4
5
6
7
8
9
2223

質問:このアルゴリズムは、さまざまなタイプのコンテナーには無効ですか?つまり、一方のforward_listともう一方のリストをマージすることはできません。私自身のコンパイラはそうです。

マスターが知っているなら教えて?同じタイプのコンテナのみをマージすることは可能ですか?

そして、なぜプログラムに比較を追加したのに、実行結果がソートされないのですか?のために、家具?あなたがマスターを持っているかどうか私に説明しますか?お願いします。弟初心者。

パート2:アルゴリズムの削除

#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <forward_list>
#include <stack>
#include <vector>
#include <forward_list>
#include <deque>
#include <array>
#include <list>
#include <algorithm>
using namespace std;
bool is_odd(const int );
int main()
{
//have not function parameter
forward_list<int> fint{1,2,3,45,5,32};
fint.remove(32);
for(auto i : fint)
	cout << i << endl;

//have function parameter
forward_list<int> fint2{1,2,3,4,5,6,7};
fint2.remove_if([](const int i){return (i % 2 == 0);});
//fint2.remove_if(is_odd);
cout << endl;
for(auto i : fint2)
	cout << i << endl;
return 0;
}
bool is_odd(const int i)
{
return (i % 2);
}

いくつかの問題に注意してください。

1.アルゴリズムremoveを使用する場合、パラメーターは要素タイプの値である必要があります。アルゴリズムremove_ifを使用する場合、パラメーターは関数またはラムダ式です。つまり、単項述語です。

2.以前の非メンバー関数バージョンのremoveは、位置を返した後でこの要素を簡単に削除できるため、この要素を削除しません。ただし、メンバー関数バージョンremoveまたはremove_ifは、この要素を直接削除します。この要素を自分で削除するのは難しいからです。どのように人道的。

以下にさらに数行のコードを追加し、バインド関数(パラメーターのバインドに使用)を確認します。これを使用するには、最初にヘッダーファイル関数を追加し、名前空間std :: placeholdersを使用して名前空間を追加する必要があります。コードに:

#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <forward_list>
#include <stack>
#include <vector>
#include <forward_list>
#include <deque>
#include <array>
#include <list>
#include <algorithm>
#include <functional>
using namespace std::placeholders;
using namespace std;
bool is_odd(const int );
bool divide(const int ,const int);
int main()
{
//have not function parameter
forward_list<int> fint{1,2,3,45,5,32};
fint.remove(32);
for(auto i : fint)
	cout << i << endl;

//have function parameter
forward_list<int> fint2{1,2,3,4,5,6,7};
fint2.remove_if([](const int i){return (i % 2 == 0);});
//fint2.remove_if(is_odd);
cout << endl;
for(auto i : fint2)
	cout << i << endl;
//下面再作死一下,再编写一个bind函数调用算法remove_if
//顺便复习一下bind函数,当你编写的函数要求很苛刻的时候,bind可能越有用
//删除能被5整除且大于给定整数的数
forward_list<int> fint3{10,11,12,13,14,15,16,5,0};
//define given integer number
int key;
cout << "Enter given number:"<< endl;
cin >> key;
fint3.remove_if(bind(divide,_1,key));
for(auto i : fint3)
	cout << i << endl;

return 0;
}
bool is_odd(const int i)
{
return (i % 2);
}
//定义这个函数纯粹是为了作死,调用bind
bool divide(const int i,const int key)
{
   return (i % 5== 0 && i > key);

}

3番目の部分:逆に、次のコードには不要なヘッダーファイルがたくさん含まれています。

#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <forward_list>
#include <stack>
#include <vector>
#include <forward_list>
#include <deque>
#include <array>
#include <list>
#include <algorithm>
using namespace std;
int main()
{
forward_list<int> f1{1,2,3,4};
f1.reverse();
for(auto i : f1)
	cout << i << endl;
return 0;
}

概要:幸い、この機能はシンプルで、以前ほど問題は発生しませんでした。

4番目の部分:並べ替え、元々は説明しないように計画されていました。よく見ると、パラメータを使用した並べ替えのバージョンではifが追加されないため、実行するにはプログラムを作成する必要があります。

 



#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <forward_list>
#include <stack>
#include <vector>
#include <forward_list>
#include <deque>
#include <array>
#include <list>
#include <algorithm>
using namespace std;
int main()
{
//have no parameter
forward_list<int> f1{1,2,3,4};
f1.reverse();
for(auto i : f1)
	cout << i << " ";
cout << endl;

//have parameter 
forward_list<int> f2{1,2,3,4,5,6,7,8,9,10};
//按照除以5的余数大小进行排序
f2.sort([](const int i,const int j){return (i % 5 < j % 5);});
 for(auto i : f2)
	 cout << i << " ";
 cout << endl;

return 0;
}



バイナリ述語を使用したソートのバージョンは、その後、実際にはNima NiuBの場合は追加されません。

パート5:ユニーク、簡単には紹介しません。

これらの2つの関数はオーバーロードされた関数です。Nimaのパラメーターとパラメーターなしの間にifの違いはありますか?

#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <forward_list>
#include <stack>
#include <vector>
#include <forward_list>
#include <deque>
#include <array>
#include <list>
#include <algorithm>
using namespace std;
int main()
{
forward_list<int> f{1,2,3,4,5,4,5,1,2};
//sort the number by the remainder divided by 5
f.sort([](const int i,const int j){return (i%5 < j%5);});
//if remainder devided by 5 is the same,then equal
f.unique([](int i,int j){return (i %5 == j %5);});
for(auto i : f)
	cout << i << endl;
    return 0;
}

概要:一意のバイナリ述語パラメーターの場合、関数はifを追加しません。

パート3:リストのスプライスアルゴリズム、forward_listのsplice_afterアルゴリズム

#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <forward_list>
#include <stack>
#include <vector>
#include <forward_list>
#include <deque>
#include <array>
#include <list>
#include <algorithm>
using namespace std;
int main()
{
/*forward_list*/
//member function 1:flst.splice_after(p,flst2),insert flst2 after p
forward_list<int> f1{1,2,3,4,5,6};
forward_list<int> f2{11,22,33};
f1.splice_after(f1.begin(),f2);
for(auto i : f1)
	cout << i << endl;

//f2 has no elements
for(auto j : f2)
	cout << j << endl;

//member function 2:flst.splice_after(p,lst2,p2),move elements which pointed by  p2's next interator 
//把p2位置之后的元素插入到p之后
forward_list<int> f21{21,23,24,35};
forward_list<int> f22{33,34,54,54};
f21.splice_after(f21.begin(),f22,++f22.begin());
for(auto i : f21)
	cout << i << " ";
cout << endl;
//member function3:flst.splice_after(p,lst2,b,e):把lst2中(b,e)中的元素移动到flst中p之后,注意(b,e)是两边开区间。
//把lst2的第二个到第五个元素移动到lst中
forward_list<int> lst{1,2,3,4};
forward_list<int> lst2{11,22,33,44,55,66,77,88};
int i = 0;
forward_list<int>::iterator p1 = lst2.begin(),p2 =lst2.begin();
while(i !=5)
{
++ p2;
++ i;
}
//now p2 point to 6th element of lst2,p1 point to 1th element of lst2
//注意这里(p1,p2)是两边开区间,因为forward_list本身的特性,是把p1后面且p2前面的元素移动到lst中
lst.splice_after(lst.before_begin(),lst2,p1,p2);
cout << "lst is:" << endl;
for(auto i : lst)
	cout << i << " ";
	cout << endl;
/*list*/
list<int> l1{1,2,3,4,5};
list<int> l2{11,22,33};
list<int> l3{1024,1025,1026};
l1.splice(l1.begin(),l2);
for(auto i : l1)
	cout << i << " ";
cout << endl;
cout << "list"<< " " << endl;
//member function 2: insert element which pointed by l3.begin() into l1(before ++ l1.begin())
l1.splice(++l1.begin(),l3,l3.begin());
for(auto i : l1)
	cout << i << " ";
cout << endl;
//member function 3:lst.splice(p,lst2,b,e):把lst2中的[b,e)中的元素移动到lst中的p之前,注意[b,e)是前面闭区间,后面开区间.

//把lst_new中第3-6个元素移动到lst2_new中
list<int> lst_new{20,21,22,23,24,25};
list<int> lst2_new{30,31,32,33,34,35,36,37,38};
int ii = 0,jj = 0;
list<int>::iterator it1 = lst2_new.begin();
list<int>::iterator it2 = lst2_new.begin();
while(ii != 2)
{
it1 ++;
ii ++;
}
while(jj != 6)
{
it2 ++;
++ jj;
}
lst_new.splice(lst_new.begin(),lst2_new,it1,it2);
cout << "print:" << endl;
for(auto i : lst_new)
	cout << i << " ";
	cout << endl;
return 0;
}

概要:spliceアルゴリズムとsplice_afterアルゴリズムの類似点と相違点:

1.スプライスは指定されたイテレータの前に挿入され、splice_afterは指定されたイテレータの位置の後に挿入されます。

lst.splice(p、lst2)pの前にlst2を挿入、flst.splice_after(p、flst2)

lst.splice(p、lst2、p2)は、p2が指す要素をlst2のpの前に挿入します。flst.splice(p、flst2、p2)は、p2の後に要素をpの後ろに挿入します。

lst.splice(P、LST2、B、E)は、挿入要素[B、E)の中にP前LST2 、flst.splice(P、flst2、B、E)がの要素を挿入(B、E)flst2へのpの裏

2.まとめ

lst.splice()は、区間[b、e)またはイテレータp2が指す要素を挿入し、pの前に挿入します。

lst.splice_afterは、(b、e)間隔に要素を挿入するか特定のイテレータp2の後に要素挿入します。挿入範囲と挿入位置は同じではありません。splice_after挿入位置はすべて、特定のイテレータの後に配置されます。挿入位置は、特定のイテレータの前です。

スプライスによって挿入された要素は、従来のp2が参照するもの、または開く前の9つの閉じた間隔です。splice_afterによって挿入された要素は、要素の背後にある要素、または2辺の範囲を持つ要素です。

類似点:挿入および挿入する必要のある2つのリンクリスト(コンテナー)のタイプは同じです。両方ともlistまたはforward_listのいずれかです。

ちなみに、授業後の練習もやめました。これが私が書いた答えです:

10.6演習に対する自筆の回答

#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <forward_list>
#include <stack>
#include <vector>
#include <forward_list>
#include <deque>
#include <array>
#include <list>
#include <algorithm>
using namespace std;

void print(const list<string> &);

int main(int argc,char *argv[])
{
//be careful:out must be specified to fstream::out or ofstream::out or 
//fstream::app,etc..
//注意,这里fstream 流的 out必须指明文件模式是 out模式或者app模式才能自动创建文件。否则打开文件会失败。
fstream in,out(argv[2],ofstream::out);
in.open(argv[1]);
if(!out)
	cout << "open file failure" << endl;

list<string> lstr;
string str;
while(in >> str)
{
lstr.push_back(str);
}
lstr.sort();
lstr.sort([](const string &s1,const  string &s2){return (s1.size() < s2.size());});
lstr.unique();
print(lstr);
cout << argv[1] << endl;
cout << argv[2] << endl;

for(auto i : lstr)
   out << i << endl;

   return 0;
}

void print(const list<string> &s)
{
	for(auto i : s)
		cout << i << " ";


}

注:C ++出力ファイルストリームはofstreamオブジェクトとして指定する必要があります。それがfstreamオブジェクトの場合、ファイルを自動的に作成するには、出力モードまたはアプリモードを指定する必要があります。

つまり、fstreamファイルストリームオブジェクトがどのモードにも名前を付けていない場合、コンパイラはファイルの作成を担当しません。

スプライスアルゴリズムの別の例

//以下例子都运行过全部通过
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <forward_list>
#include <stack>
#include <vector>
#include <forward_list>
#include <deque>
#include <array>
#include <list>
#include <algorithm>
using namespace std;
int main()
{
 forward_list<int> l1 {1,2,3,4,5},l2{6,7,8};
 //insert all elements of l2 to l1
 //l1.splice_after(l1.begin(),l2);
 //insert some element of l2 to l1
 //l1.splice_after(l1.before_begin(),l2,++l2.begin());
 //insert elements from a scope   of l2 to l2,note that the scope is (),rather than [),becouse forward_list
 l1.splice_after(l1.before_begin(),l2,l2.begin(),l2.end());
 for(auto i : l1)
         cout << i << endl;
return 0;
}


 

おすすめ

転載: blog.csdn.net/digitalkee/article/details/112594071