deque
deque<T>以双端队列的形式组织元素,可以在容器的头部和尾部高效地添加或删除对象,这是它相对于 vector 容器的优势。
1.初始化,访问,插入
std::deque<int> a_deque; // A deque container with no elements
std::deque<int> my_deque(10); // A deque container with 10 elements
std:: deque<std:: string> words { "one", "none", "some", "all","none","most", "many” };
std::deque<std::string> words_copy { words };// Makes a copy of the words c
std::deque<std::string> words_part { std::begin(words),std::begin(words) + 5 };
std::cout << words.at(2) << std::endl; // Output the third element in words
std::deque<int> numbers {2, 3, 4};
numbers.push_front(11); // numbers contains 11 2 3 4
numbers.push_back(12); // numbers contains 11 2 3 4 12
numbers.pop_front(); // numbers contains 2 3 4 12
2.修改元素
std::deque<std::string> words {"one", "two", "three", "four"};
auto init_list = {std::string{"seven"}, std::string{ "eight"}, std::string{"nine"}};
words.assign(init_list);
words.assign({"seven”,"eight","nine"});
std::vector<std::string> wordset {"this","that","these","those"};
words.assign(std::begin(wordset)+1, --std::end(wordset));
//Assigns "that" and "these"
最后一条语句用 init_list 中的 string 对象替换掉了 words 中的元素。
3.综合举例
// Using a deque container
#include <iostream> // For standard streams
#include <algorithm> // For copy()
#include <deque> // For deque container
#include <string> // For string classes
#include <iterator> // For front_insert_iterator & stream iterators
using std::string;
int main()
{
std::deque<string> names;
std::cout << "Enter first names separated by spaces. Enter Ctrl+Z on a new line to end:\n";
std::copy(std::istream_iterator < string > {std::cin}, std::istream_iterator < string > {}, std::front_inserter(names));
std::cout << "\nIn reverse order, the names you entered are:\n";
std::copy(std::begin(names), std::end(names), std::ostream_iterator < string > {std::cout, " "});
std::cout << std::endl;
}
list<T> 是 T 类型对象的双向链表。可以在序列已知的任何位置插入或删除元素。list 的缺点是无法通过位置来直接访问序列中的元素,也就是说,不能索引元素。
1.初始化
list 容器的构造函数的用法类似于 vector 或 deque 容器。
std::list<std::string> words;
可以创建一个带有给定数量的默认元素的列表:
std::list<std::string> sayings {20}; // A list of 20 empty strings
如何生成一个包含给定数量的相同元素的列表:
std::list<double> values(50, 3.14159265);
不能使用初始化列表 {50,3.14159265},这样列表将仅仅包含两个元素。
list 容器有一个拷贝构造函数,因此可以生成一个现有 list 容器的副本:
std::list<double> save_values {values}; // Duplicate of values
用另一个序列的开始和结束迭代器所指定的一段元素,来构造 list 容器的初始化:
std::list<double> samples {++cbegin(values), --cend(values)};
2.增加元素
std::list<std::string> names { "Jane", "Jim", "Jules", "Janet"};
names.push_front("Ian"); // Add string ("Ian") to the front of the list
names.push_back("Kitty"); // Append string ("Kitty") to the end of the list
names.emplace_front("Ian");//Create string ("Ian") in place at the front of the list
names.emplace_back("Kitty");// Create string ("Kitty") in place at the end of the list
std::list<int> data(10, 55); // List of 10 elements with value 55
data.insert(++begin(data), 66); // Insert 66 as the second element
auto iter = begin(data);
std::advance(iter, 9); // Increase iter by 9
data.insert(iter, 3, 88);// Insert 3 copies of 88 starting at the 10th
std::vector<int> numbers(10, 5)/ // Vector of 10 elements with value 5
data.insert(--(--end(data)), cbegin(numbers), cend(numbers));
std::list<std:: string> names {"Jane", "Jim", "Jules", "Janet"};
names.emplace_back("Ann");
std:: string name ("Alan");
names.emplace_back(std::move(name));
names.emplace_front("Hugo");
names.emplace(++begin(names), "Hannah");
3.删除元素
std::list<int> numbers { 2, 5, 2, 3, 6, 7, 8, 2, 9};
numbers.remove(2); // List is now 5 3 6 7 8 9
第二条语句移除了 numbers 中出现的所有值等于 2 的元素。
成员函数 remove_if() 期望传入一个一元断言作为参数。
一元断言接受一个和元素同类型的参数或引用,返回一个布尔值。断言返回 true 的所有元素都会被移除。
numbers.remove_if([](int n){return n%2 == 0;});// Remove even numbers. Result 5 3 7 9
这里的参数是一个 lambda 表达式,但也可以是一个函数对象。
成员函数 unique() 非常有意思,它可以移除连续的重复元素,留下其中的第一个。
std::list<std::string> words { "one", "two", "two", "two","three", "four", "four"};
words.unique () ; // Now contains "one" "two" "three" "four"
3.排序
sort() 函数模板要求使用随机访问迭代器。但 list 容器并不提供随机访问迭代器,只提供双向迭代器,因此不能对 list 中的元素使用 sort() 算法。
list模板定义了自己的 sort() 函数。sort() 有两个版本:无参 sort() 函数将所有元素升序排列。第二个版本的 sort() 接受一个函数对象或 lambda 表达式作为参数,这两种参数都定义一个断言用来比较两个元素。
names.sort(std::greater<std::string>()); // Names in descending sequence
names.sort(std::greater<>()); // Function object uses perfect forwarding
"Jules" "Jim" "Janet" "Jane" "Hugo" "Hannah" "Ann" "Alan"
在必要时可以将自定义的函数对象传给断言来对 list 排序。如果为自己的类定义了 operator()(),然后就可以继续使用 std::greater<>。
当我们需要比较非默认类型时,就需要一个函数对象。
例如,假设我们想对 names 中的元素进行排序,但是不想使用字符串对象标准的 std::greater<> 来比较,而是想将相同初始字符的字符串按长度排序。
// Order strings by length when the initial letters are the same
class my_greater{
public:
bool operator () (const std::strings s1, const std::strings s2)
{ if (s1[0] == s2 [0])
return si.length() > s2.length();
else return s1 > s2;
}
};
可以用这个来对 names 中的元素排序:
names.sort(my_greater()); // Sort using my_greater
"Jules" "Janet" "Jane” "Jim" "Hannah" "Hugo" "Alan" "Ann"
names 中初始字符相同的元素按长度降序排列。
如果不需要重用 my_greater() 断言,这里也可以使用 lambda 表达式。
names.sort([](const std::strings s1, const std::strings s2)
{ if (s1[0] == s2[0])
return s1.length() > s2.length();
else return s1 > s2;
});
4.合并
list 的成员函数 merge() 以另一个具有相同类型元素的 list 容器作为参数。两个容器中的元素都必须是升序。参数 list 容器中的元素会被合并到当前的 list 容器中。
std::list<int> my_values {2, 4, 6, 14};
std::list<int> your_values{ -2, 1, 7, 10};
my_values.merge (your_values);//my_values contains: -2 1 2 4 6 7 10 14
your_values.empty(); // Returns true
元素从 your_values 转移到 my_values,在执行完这个操作后,your_values 中就没有元素了。
在另一个版本的 merge() 函数中,可以提供一个比较函数作为该函数的第二个参数,用来在合并过程中比较元素。
std::list<std::string> my_words { "three","six", "eight"};
std::list<std::string> your_words { "seven", "four", "nine"};
auto comp_str = [](const std::strings s1, const std::strings s2){ return s1[0]<s2[0];};
my_words.sort (comp_str); //"eight" "six" "three"
your_words.sort (comp_str) ; //"four" "nine" "seven"
my_words.merge (your_words, comp_str) ; // "eight" "four" "nine" "six" "seven" "three"
list 容器的成员函数 splice() 有几个重载版本。这个函数将参数 list 容器中的元素移动到当前容器中指定位置的前面。可以移动单个元素、一段元素或源容器的全部元素。
std::list<std::string> my_words {"three", "six", "eight"};
std::list<std::string> your_words {"seven", "four", "nine"};
my_words.splice(++std::begin(my_words), your_words, ++std::begin(your_words));
splice() 的第一个参数是指向目的容器的迭代器。第二个参数是元素的来源。第三个参数是一个指向源list容器中被粘接元素的迭代器,它会被插入到第一个参数所指向位置之前。代码执行完中后,容器中的内容如下:
your_words: "seven", "nine"my_words : "three", "four", "six", "eight"
当要粘接源 list 容器中的一段元素时,第 3 和第 4 个参数定义这段元素的范围
your_words.splice(++std::begin(your_words),my_words,++std::begin(my_words), std::end(my_words));
将 my_words 从第二个元素直到末尾的元素,粘接到 your_words 的第二个元前。
上面两个 list 容器的内容如下:
your_words:"seven", "four", "six", "eight","nine" my_words: "three"
下面的语句可以将 your_words 的全部元素粘接到 my_words 中:
my_words.splice(std::begin(my_words), your_words);
your_words 的所有元素被移到了 my_words 的第一个元素"three”之前。然后,your_words 会变为空。即使 your_words 为空,也仍然可以向它粘接元素:
your_words.splice(std::end(your_words), my_words);
现在,my_words 变为空,your_words 拥有全部元素。第一个参数也可以是 std::begin (your_words),因为当容器为空时,它也会返回一个结束迭代器.
forward_list 容器以单链表的形式存储元素。
drward_list 和 list 最主要的区别是:它不能反向遍历元素;只能从头到尾遍历。
forward_list 的操作比 list 容器还要快,而且占用的内存更少.
无法使用反向迭代器。只能从它得到const或non-const前向迭代器,这些迭代器都不能解引用,只能自增;
没有可以返回最后一个元素引用的成员函数back();只有成员函数front();
因为只能通过自增前面元素的迭代器来到达序列的终点,所以push_back()、pop_back()、emplace_back()也无法使用。
1.大小
forward_list 的迭代器都是前向迭代器。它没有成员函数 size(),因此不能用一个前向迭代器减去另一个前向迭代器.
std::forward_list<std::string> my_words {"three", "six", "eight"};auto count = std::distance(std::begin(my_words),std::end(my_words));// Result is 3
2.访问
distance() 的第一个参数是一个开始迭代器,第二个参数是一个结束迭代器,指定了元素范围。当需要将前向迭代器移动多个位置时,advance() 就派上了用场。
std::forward_list<int> data {10, 21, 43, 87, 175, 351};
auto iter = std::begin(data);
size_t n {3};
std::advance(iter, n);
std::cout << "The " << n+1 << "th element is n << *iter << std::endl;// Outputs 87
3.插入
通过使用成员函数 cbefore_begin() 和 before_begin() 来解决。
它们分别可以返回指向第一个元素之前位置的 const 和 non-const 迭代器。可以使用它们在开始位置插入或粘接元素。
std::forward_list<std::string> my_words {"three", "six", "eight"}
std::forward_list<std::string> your_words {"seven", "four", "nine"};
my_words.splice_after(my_words.before_begin(), your_words, ++std::begin(your_words));
这个操作的效果是将 your_words 的最后一个元素粘接到 my_words 的开始位置,因此 my_words 会包含这些字符串对象:"ninef"、"three"、"six"、"eight"。这时 your_words 就只剩下两个字符串元素:"seven"和"four”。
另一个版本的 splice_afler(),将 forward_list的一段元素粘接到另一个容器中:
my_words.splice_after (my_words . before_begin () , your_words,++std::begin(your_words), std::end(your_words));
特别说明:
运算符重载在类的建立中常用。
参考博客整理好的,见https://www.cnblogs.com/xiaokang01/p/9166745.html