C++ STL库详解与最佳实践
C++标准模板库(STL)是C++语言中提供的一组标准库,它提供了包括容器类(vector、list等)、迭代器、算法等组成部分,可以帮助开发者更高效地编写C++程序。本文将深入研究C++ STL库,并分享一些最佳实践来提高代码效率和可读性。
容器类
STL提供了多种容器类,包括vector、list、deque、set、map等。这些容器类可以存储不同类型的数据,提供了各种不同的操作,可以满足不同的需求。以下是对几种常用的容器类进行介绍。
vector
vector是一种动态数组,它可以自动扩展大小,存储同一类型的元素。vector提供了快速的随机访问,但插入和删除操作的效率较低。以下是vector的一些常用操作:
push_back(value)
:将一个元素插入到vector末尾。pop_back()
:删除vector末尾的一个元素。size()
:返回vector中元素的个数。at(index)
:返回vector中指定位置的元素。begin()
:返回指向vector第一个元素的迭代器。end()
:返回指向vector最后一个元素的下一个位置的迭代器。
以下是一个使用vector存储字符串的例子:
#include <iostream>
#include <vector>
int main() {
std::vector<std::string> vec;
vec.push_back("Hello");
vec.push_back("World");
for (auto it = vec.begin(); it != vec.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
return 0;
}
上述代码中,我们定义了一个vector存储字符串类型的数据,向vector中插入了两个字符串,并使用迭代器遍历vector中的所有元素并输出。
list
list是一种双向链表,它可以存储同一类型的元素。list提供了快速的插入和删除操作,但随机访问的效率较低。以下是list的一些常用操作:
push_back(value)
:将一个元素插入到list末尾。push_front(value)
:将一个元素插入到list头部。pop_back()
:删除list末尾的一个元素。pop_front()
:删除list头部的一个元素。size()
:返回list中元素的个数。front()
:返回list头部的元素。back()
:返回list末尾的元素。begin()
:返回指向list第一个元素的迭代器。end()
:返回指向list最后一个元素的下一个位置的迭代器。
以下是一个使用list存储整数的例子:
#include <iostream>
#include <list>
int main() {
std::list<int> lst;
lst.push_back(1);
lst.push_back(2);
lst.push_front(0);
lst.pop_back();
lst.pop_front();
for (auto it = lst.begin(); it != lst.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
return 0;
}
上述代码中,我们定义了一个list存储整数类型的数据,向list中插入了三个整数,并删除了头部和尾部的元素,最后使用迭代器遍历list中的所有元素并输出。
deque
deque是一种双端队列,它可以存储同一类型的元素。deque提供了快速的随机访问和头尾插入删除操作。以下是deque的一些常用操作:
push_back(value)
:将一个元素插入到deque末尾。push_front(value)
:将一个元素插入到deque头部。pop_back()
:删除deque末尾的一个元素。pop_front()
:删除deque头部的一个元素。size()
:返回deque中元素的个数。front()
:返回deque头部的元素。back()
:返回deque末尾的元素。at(index)
:返回deque中指定位置的元素。begin()
:返回指向deque第一个元素的迭代器。end()
:返回指向deque最后一个元素的下一个位置的迭代器。
以下是一个使用deque存储浮点数的例子:
#include <iostream>
#include <deque>
int main() {
std::deque<double> deq;
deq.push_back(1.0);
deq.push_front(0.0);
deq.push_back(2.0);
deq.pop_front();
for (auto it = deq.begin(); it != deq.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
return 0;
}
上述代码中,我们定义了一个deque存储浮点数类型的数据,向deque中插入了三个浮点数,并删除了头部的元素,最后使用迭代器遍历deque中的所有元素并输出。
set
set是一种集合,它可以存储不同类型的元素,并按照元素的大小进行排序。set中的元素是唯一的,即不允许重复。以下是set的一些常用操作:
insert(value)
:将一个元素插入到set中。erase(value)
:删除set中指定的元素。size()
:返回set中元素的个数。count(value)
:返回set中等于指定元素的元素个数。find(value)
:返回set中等于指定元素的元素的迭代器,如果不存在则返回set.end()迭代器。begin()
:返回指向set第一个元素的迭代器。end()
:返回指向set最后一个元素的下一个位置的迭代器。
以下是一个使用set存储字符串的例子:
#include <iostream>
#include <set>
int main() {
std::set<std::string> st;
st.insert("Hello");
st.insert("World");
st.insert("Hello");
for (auto it = st.begin(); it != st.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
return 0;
}
上述代码中,我们定义了一个set存储字符串类型的数据,向set中插入了两个字符串,并尝试插入了一个重复的字符串,最后使用迭代器遍历set中的所有元素并输出。由于set不允许重复元素,所以最终输出的结果只包含一个"Hello"和一个"World"字符串。
map
map是一种关联数组,它可以存储键值对,键和值可以是不同类型的数据。map中的键是唯一的,即不允许重复。以下是map的一些常用操作:
insert({key, value})
:将一个键值对插入到map中。erase(key)
:删除map中指定键对应的键值对。size()
:返回map中键值对的个数。count(key)
:返回map中等于指定键的键值对的个数。find(key)
:返回map中等于指定键的键值对的迭代器,如果不存在则返回map.end()迭代器。begin()
:返回指向map第一个键值对的迭代器。end()
:返回指向map最后一个键值对的下一个位置的迭代器。
以下是一个使用map存储字符串和整数的例子:
#include <iostream>
#include <map>
int main() {
std::map<std::string, int> mp;
mp.insert({"Alice", 20});
mp.insert({"Bob", 30});
mp["Charlie"] = 25;
mp.erase("Bob");
for (auto it = mp.begin(); it != mp.end(); ++it) {
std::cout << it->first << ": " << it->second << std::endl;
}
return 0;
}
上述代码中,我们定义了一个map存储字符串和整数类型的键值对,向map中插入了三个键值对,并删除了键为"Bob"的键值对,最后使用迭代器遍历map中的所有键值对并输出。
迭代器
迭代器是STL中非常重要的概念,它可以用来遍历容器类中的元素。迭代器分为以下几种:
输入迭代器
输入迭代器可以用来读取容器类中的元素,但不能修改它们。以下是输入迭代器的一些常用操作:
*it
:返回迭代器指向的元素。it++
:使迭代器指向下一个元素。it == it2
:判断两个迭代器是否相等。
输出迭代器
输出迭代器可以用来向容器类中插入元素,但不能读取它们。以下是输出迭代器的一些常用操作:
*it = value
:向迭代器指向的位置插入一个元素。it++
:使迭代器指向下一个位置。
前向迭代器
前向迭代器可以用来读取和修改容器类中的元素,并可以向前遍历容器类中的元素。以下是前向迭代器的一些常用操作:
*it
:返回迭代器指向的元素。it++
:使迭代器指向下一个元素。it == it2
:判断两个迭代器是否相等。
双向迭代器
双向迭代器可以用来读取和修改容器类中的元素,并可以向前和向后遍历容器类中的元素。以下是双向迭代器的一些常用操作:
*it
:返回迭代器指向的元素。it++
:使迭代器指向下一个元素。it--
:使迭代器指向上一个元素。it == it2
:判断两个迭代器是否相等。
随机访问迭代器
随机访问迭代器可以用来读取和修改容器类中的元素,并支持随机访问容器类中的元素。以下是随机访问迭代器的一些常用操作:
*it
:返回迭代器指向的元素。it++
:使迭代器指向下一个元素。it--
:使迭代器指向上一个元素。it + n
:使迭代器向前移动n个位置。it - n
:使迭代器向后移动n个位置。it += n
:使迭代器向前移动n个位置。it -= n
:使迭代器向后移动n个位置。it1 == it2
:判断两个迭代器是否相等。it1 != it2
:判断两个迭代器是否不相等。it1 < it2
:判断it1是否在it2之前。it1 > it2
:判断it1是否在it2之后。it1 <= it2
:判断it1是否在it2之前或相等。it1 >= it2
:判断it1是否在it2之后或相等。
以下是一个使用迭代器遍历vector中的元素并输出的例子:
#include <iostream>
#include <vector>
int main() {
std::vector<int> vec = {1, 2, 3};
for (auto it = vec.begin(); it !=vec.end(); ++it) {
std::cout << *it << std::endl;
}
return 0;
}
上述代码中,我们定义了一个vector存储整数类型的元素,使用迭代器遍历vector中的所有元素并输出。
算法
STL中提供了丰富的算法,这些算法可以用来操作各种容器类,如vector、list、map等。以下是一些常用的STL算法:
查找算法
find
:在容器中查找指定元素,返回指向该元素的迭代器,如果不存在该元素,则返回容器的end迭代器。count
:统计容器中指定元素的个数。lower_bound
:在有序容器中查找第一个大于等于指定元素的元素,返回指向该元素的迭代器。upper_bound
:在有序容器中查找第一个大于指定元素的元素,返回指向该元素的迭代器。
排序算法
sort
:对容器中的元素进行排序。stable_sort
:对容器中的元素进行稳定排序。
修改算法
fill
:将容器中的元素全部赋值为指定值。copy
:将一个容器中的元素复制到另一个容器中。remove
:删除容器中的指定元素。replace
:将容器中的指定元素替换为另一个元素。
数值算法
accumulate
:计算容器中的元素总和。max_element
:查找容器中的最大元素,返回指向该元素的迭代器。min_element
:查找容器中的最小元素,返回指向该元素的迭代器。
以下是一个使用STL算法对vector进行排序的例子:
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> vec = {3, 5, 1, 4, 2};
std::sort(vec.begin(), vec.end());
for (auto it = vec.begin(); it != vec.end(); ++it) {
std::cout << *it << std::endl;
}
return 0;
}
上述代码中,我们定义了一个vector存储整数类型的元素,使用STL算法对vector中的元素进行排序并输出。