C++ Primer 学习笔记_46_STL实践与分析(20)--容器特有的算法

STL实践与分析


--容器特有的算法

与其它顺序容器所支持的操作相比,标准库为list容器定义了更精细的操作集合,使它不必仅仅依赖于泛型操作。当中非常大的一个原因就是list容器不是依照内存中的顺序进行布局的,不支持随即訪问,这样,在list容器上就不能使用随即訪问迭代器的算法,如sort等;还有其它的一些算法如:merge、remove、reverse和unique,尽管能够用在list上,但却付出了高昂的性能代价。因此标准库结合list的内部结构,编写出了更快算法:























list容器特有的操作

lst.merge(lst2)

lst.merge(lst2,comp)

lst2的元素合并到lst中。这两个list容器对象都必须排序。lst2中的元素将被删除。合并后,lst2为空。返回void类型。第一个版本号使用<操作符,而第二个版本号则使用comp指定的比較运算

lst.remove(val)

lst.remove(unaryPred)

调用lst.erase删除全部等于指定值或指定的谓词函数返回非零值的元素。返回void类型。

lst.reverse()

反向排列lst中的元素

lst.sort()

lst中的元素排序

lst.splice(iter,lst2)

lst.splice(iter,lst2,iter2)

lst.splice(iter,beg,end)

lst2的元素移到lst中迭代器iter指向的元素前面。

lst2中删除移出的元素。

第一个版本号将lst2的全部元素移到lst;合并后,lst2为空。lstlst2不能是同一个list对象。

第二个版本号仅仅移动iter2所指向的元素,这个元素必须是lst2中的元素。在这样的情况中,lstlst2能够是同一个list对象。也就是说,可在一个list对象中使用splice运算移动一个元素。

第三个版本号移动迭代器
begend标记的范围内的元素。begend照例必须指定一个有效的范围。这两个迭代器可标记随意list对象内的范围,包含lst。当它们指定lst的一段范围时,假设iter也指向这个范围的一个元素,则该运算没有定义。

lst.unique()

lst.unique(binaryPred)

调用erase删除同一个值的连续副本。第一个版本号使用

==操作符推断元素是否相等;第二个版本号则使用指定的谓词函数实现推断

【最佳实践】

对于list对象,应该优先使用list容器特有的成员版本号,而不是泛型算法!

list容器特有的算法与其泛型算法版本号之间的两个至关重要的区别。

1)、remove和
unique的 list版本改动了其关联的基础容器:真正删除了指定的元素。比如,list::unique将 list中第二个和兴许反复的元素踢出了该容器。

与相应的泛型算法不同list容器特有的操作能加入和删除元素

2)、list容器提供的merge和 splice运算会破坏它们的实參。使用
merge的泛型算法版本号时,合并的序列将写入目标迭代器指向的对象,而它的两个输入序列保持不变。可是,使用list容器的 merge成员函数时,则会破坏它的实參list对象 –当实參对象的元素合并到调用 merge函数的list对象时,实參对象的元素被移出并删除。

//P362 习题11.29
bool GT4(const string &str)
{
return str.size() >= 4;
}

bool compLength(const string &s1,const string &s2)
{
return s1.size() < s2.size();
}

int main()
{
list<string> words;
ifstream inFile("input");

string str;
while (inFile >> str)
{
words.push_back(str);
}

words.sort();
words.unique();

list<string>::size_type word_cnt = count_if(words.begin(),words.end(),GT4);

cout << "Have " << word_cnt << " words more the 4 characters." << endl;

words.sort(compLength);

for (list<string>::iterator iter = words.begin(); iter != words.end(); ++iter)
{
cout << *iter << endl;
}
}


//演示样例程序:并不实现什么功能,仅仅做演示之用
#include <iostream>
#include <list>
#include <fstream>
using namespace std;

bool comp(int a,int b)
{
return a > b;
}

void printList(const list<int> &iList)
{
for (list<int>::const_iterator iter = iList.begin(); iter != iList.end(); ++iter)
{
cout << *iter << ‘\t‘;
}
cout << endl;
}

list<int> iList1,iList2;

void printAll()
{
cout << "iList1: " << endl;
printList(iList1);
cout << "iList2: " << endl;
printList(iList2);
}

void initList(list<int> &iList)
{
for (list<int>::size_type i = 0; i != 20; ++i)
{
iList.push_back(i);
}
}

int main()
{

for (list<int>::size_type i = 0; i != 20; ++i)
{
iList1.push_back(i);
iList2.push_back(i + 10);
}
printAll();

iList1.merge(iList2,comp);
printAll();

iList1.sort();
initList(iList2);
printAll();

iList1.unique();
cout << "iList1" << endl;
printList(iList1);
}

C++ Primer 学习笔记_46_STL实践与分析(20)--容器特有的算法

时间: 2024-08-07 14:32:00

C++ Primer 学习笔记_46_STL实践与分析(20)--容器特有的算法的相关文章

C++ Primer 学习笔记_45_STL实践与分析(19)--泛型算法的结构

STL实践与分析 --泛型算法的结构 引言: 正如全部的容器都建立在一致的设计模式上一样,算法也具有共同的设计基础. 算法最主要的性质是须要使用的迭代器种类.全部算法都指定了它的每一个迭代器形參可使用的迭代器类型.比方,假设形參必须为随机訪问迭代器则可提供vector或 deque类型的迭代器,或者提供指向数组的指针.而其它容器的迭代器不能用在这类算法上. C++还提供了另外两种算法模式:一种模式由算法所带的形參定义;还有一种模式则通过两种函数命名和重载的规范定义. 一.算法的形參模式 大多数的

C++ Primer 学习笔记_29_STL实践与分析(3) --操作步骤集装箱(下一个)

STL实践与分析 --顺序容器的操作(下) 六.訪问元素 假设容器非空,那么容器类型的front和back成员将返回容器的第一个和最后一个元素的引用. [与begin和end的对照:] 1)begin和end返回容器类型的迭代器,而不是引用: 2)end返回容器最后一个元素的下一个位置的迭代器,而back返回容器的最后一个元素的引用! /* *必须保证该list容器非空! *假设容器为空,则if语句内的全部操作都是没有定义的! */ if (!iList.empty()) { list<int>

C++ Primer 学习笔记_40_STL实践与分析(14)--概要、先来看看算法【上】

STL实践与分析 --概述.初窥算法[上] 标准库容器定义的操作很少.并没有给容器加入大量的功能函数.而是选择提供一组算法,这些算法大都不依赖特定的容器类型,是"泛型"的.可作用在不同类型的容器和不同类型的元素上! 所谓泛型算法:一是由于它们实现共同的操作,所以称之为"算法";而"泛型"指的是它们可以操作在多种容器类型上--不但可作用于vector或list这些标准库类型,还可用在内置数组类型.甚至其它类型的序列上,仅仅要自己定义的容器类型仅仅要

C++ Primer 学习笔记_35_STL实践与分析(9)--map种类(在)

STL实践与分析 --map类型(上) 引: map是键-值对的集合. map类型通常能够理解为关联数组:能够通过使用键作为下标来获取一个值,正如内置数组类型一样:而关联的本质在于元素的值与某个特定的键相关联,而并不是通过元素在容器中的位置来获取. 一.map对象的定义 1.定义map对象时,必须分别指明键和值的类型: map<string,int> wordCnt; map的构造函数 map<K,V>m; 创建一个名为m的空对象,其键和值的类型分别为K和V map<K,V&

C++ Primer 学习笔记_43_STL实践与分析(17)--再谈迭代器【中】

STL实践与分析 --再谈迭代器[中] 二.iostream迭代[续] 3.ostream_iterator对象和ostream_iterator对象的使用 能够使用ostream_iterator对象将一个值序列写入流中,其操作过程与使用迭代器将一组值逐个赋值给容器中的元素同样: ostream_iterator<string> out_iter(cout,"\n"); istream_iterator<string> in_iter(cin),eof; wh

C++ Primer 学习笔记_41_STL实践与分析(15)--先来看看算法【下一个】

STL实践与分析 --初窥算法[下] 一.写容器元素的算法 一些算法写入元素值.在使用这些算法写元素时一定要当心.必须确保算法所写的序列至少足以存储要写入的元素. 1.写入输入序列的元素 写入到输入序列的算法本质上是安全的--仅仅会写入与指定输入范围数量同样的元素. 写入到输入序列的一个简单算法是fill函数: fill(iVec.begin(),iVec.end(),10); fill(iVec.begin(),iVec.begin()+iVec.size()/2,0); fill带有一对迭代

C++ Primer 学习笔记_45_STL实践与分析(19)--建筑常规算法

STL实践与分析 --泛型算法的结构 引言: 正如全部的容器都建立在一致的设计模式上一样,算法也具有共同的设计基础. 算法最主要的性质是须要使用的迭代器种类.全部算法都指定了它的每一个迭代器形參可使用的迭代器类型. 比方,假设形參必须为随机訪问迭代器则可提供vector或 deque类型的迭代器,或者提供指向数组的指针. 而其它容器的迭代器不能用在这类算法上. C++还提供了另外两种算法模式:一种模式由算法所带的形參定义;还有一种模式则通过两种函数命名和重载的规范定义. 一.算法的形參模式 大多

C++ Primer 学习笔记_44_STL实践与分析(18)--再谈迭代器【下】

STL实践与分析 --再谈迭代器[下] 三.反向迭代器[续:习题] //P355 习题11.19 int main() { vector<int> iVec; for (vector<int>::size_type index = 0; index != 10; ++index) { iVec.push_back(index); } for (vector<int>::reverse_iterator r_iter = iVec.rbegin(); r_iter !=

C++ Primer 学习笔记_42_STL实践与分析(16)–再谈迭代器【上】

STL实践与分析 --再谈迭代器[上] 引言: 另外三种迭代器类型: 1)插入迭代器:这类迭代器与容器绑定在一起,实现在容器中插入元素的功能. 2)iostream迭代器:这类迭代器可以与输入与输出流绑定在一起,用于迭代遍历所关联的IO流. 3)反向迭代器:这类迭代器实现向后遍历,而不是向前遍历,所有的容器都定义了自己的reverse_iterator类型,由rbegin和rend成员函数返回. 上述迭代器都在iterator头文件中定义. 一.插入迭代器 前面曾经提到的back_inserte