CPP_STL总结
Overview of the STL
The STL is logically divided into six pieces, each consisting of generic components that interoperate with the
rest of the library:
•
Containers. At the heart of the STL are a collection of container
classes, standard C++'s analog to
the CS106B/X ADTs. For example, you can store an associative collection of key/value pairs in an
STL
map, or a growing list of elements in an STL
vector.
•
Iterators. Each STL container exports iterators, objects that view
and modify ranges of stored
data. Iterators have a common interface, allowing you to write code that operates on data stored
in arbitrary containers.
•
Algorithms. STL algorithms are functions that operate over ranges
of data specified by iterators.
The scope of the STL algorithms is staggering – there are algorithms for searching, sorting, reordering,
permuting, creating, and destroying sets of data.
•
Adapters. STL
adapters
are objects which transform an object from one form into another. For example,
the
stack
adapter transforms a regular
vector
or
list
into a LIFO container, while the
istream_iterator
transforms a standard C++ stream into an STL iterator.
•
Functors. Because so much of the STL relies on user-defined callback
functions, the STL provides
facilities for creating and modifying functions at runtime. We will defer our discussion of functors
to much later in this text, as they require a fairly nuanced understanding of C++.
•
Allocators. The STL allows clients of the container classes to customize
how memory is allocated
and deallocated, either for diagnostic or performance reasons. While allocators are fascinating
and certainly worthy of discussion, they are beyond the scope of this text and we will not cover
them here.
注:
Here, the containers rely on the allocators for memory and produce iterators. Iterators can then be used
in conjunction with the algorithms. Functors provide special functions for the algorithms, and adapters
can produce functors, iterators, and containers.
一、Vector
1.Vector只能存储一种类型的元素。
However, while the
vector
can store elements of any type, any single
vector
can only
store elements of a single type. It is illegal to create a
vector
that stores a sequence of many different
types of elements, meaning that you can't represent the list 0, Apple, 2.71828 because each of the list elements
has a different type. This may seem like a rather arbitrary restriction – theoretically speaking,
there's no reason that you shouldn't be able to have lists of all sorts of elements – but fortunately in most
cases this restriction does not pose too much of a problem.
2.Vector定义时需要指定好类型
vector<int> intVector;
// Stores ints
vector<string> strVector;
// Stores strings
vector<double> realVector; // Stores real numbers
3.使用前需要导入vector头文件
In order to use the
vector
type, you will need to
#include <vector>
at the top of your program. As we
explore some of the other STL containers, this pattern will also apply.
4.size_t的特殊用法
This code is fairly dense and introduces some syntax you have not yet seen before, so let's take a few moments
to walk through exactly how it works. The first detail that might have caught your eye is this one:
for (size_t i = 0; i < v.size(); ++i)
This
for
loop looks strange for two reasons. First, instead of creating an
int
variable for the iteration, we
create a variable of type
size_t. A
size_t
is a special type of variable that can hold values that represent
sizes
of things (size_t
stands for “size type”). In many aspects
size_t
is like a regular
int
– it holds an
integer value, can be incremented with
++, compared using the relational operators, etc.
However, unlike
regular
ints,
size_ts cannot store negative values. The
intuition behind this idea is that no collection of
elements can have a negative size. You may have a list of no elements, or a list of billions of elements, but
you'll
never
encounter a list with -1 elements in it. Consequently, when iterating over an STL container, it
is customary to use the special type
size_t
to explicitly indicate that your iteration variable should always
be nonnegative. The other detail of this for loop is that the loop iterates from 0 to
v.size(). The
size()
member function on the STL
vector
returns the number of elements stored in the sequence, just
like the
size()
and
length()
functions on the standard
string
class. In this particular case we could
have iterated from 0 to
kNumValues, since we're guaranteed that the
main
function will produce a
vector
of that many elements, but in general when iterating over a
vector
it's probably a wise idea to use the
vector's
size
as an upper bound so that the code works for
vectors of arbitrarily many elements.
5.容器作为函数参数时最好作为引用传递,这可以避免拷贝
Consequently, it is considered good programming practice to pass STL containers into functions by reference rather than by value, since this avoids an
expensive copy.*
6.vector的定义需要注意
In some cases, you may want to initialize the
vector
to a certain size where each element holds a value
other than zero. You may wish, for example, to construct a
vector<string>
holding five copies of the
string “(none),”
or a vector<double>
holding twenty copies of the value 137. In these cases, C++ lets
you specify both the number and default value for the elements in the
vector
using the following syntax:
vector<double> myReals(20, 137.0);
vector<string> myStrings(5, "(none)");
Notice that we've enclosed in parentheses both the
number
of starting elements in the
vector
and the
value
of these starting elements.
An important detail is that this syntax is only legal when initially creating a
vector. If you have an existing
vector
and try to use this syntax, you will get a compile-time error. That is, the following code is illegal:
vector<double> myReals;
myReals(20, 137.0);
//
Error: Only legal to
do this when the object is created
7.可以通过resize函数修改vector的定义大小
If you want to change the number of elements in a
vector
after it has already been created, you can always
use the
push_back
and
insert
member functions. However, if you'd like to make an abrupt change
in the number of elements in the
vector
(perhaps by adding or deleting a large number of elements all at
once), you can use the
vector's
resize
member function. The
resize
function is very similar to the syntax
we've just encountered: you can specify either a number of elements or a number of elements and a
value, and the
vector
will be resized to hold that many elements. However,
resize
behaves somewhat
differently from the previous construct because when using
resize, the
vector
might already contain
elements. Consequently,
resize
works by adding or removing elements from the end of the
vector
until
the desired size is reached.
This function takes in a
vector<int>, then prints out the elements in the
vector
one at a time, followed
by a newline. Given this function, consider the following code snippet:
vector<int> myVector; // Defaults to empty vector
PrintVector(myVector); // Output: [nothing]
myVector.resize(10);
// Grow the vector, setting new elements to 0
PrintVector(myVector); // Output: 0 0 0 0 0 0 0 0 0 0
myVector.resize(5);
// Shrink the vector
PrintVector(myVector); // Output: 0 0 0 0 0
myVector.resize(7, 1);
// Grow the vector, setting new elements to 1
PrintVector(myVector); // Output: 0 0 0 0 0 1 1
myVector.resize(1, 7);
// The second parameter is effectively ignored.
Because the second argument to
resize
is only considered if new elements are added, it is effectively
ignored.
PrintVector(myVector); // Output: 0
8.vector中删除元素的操作
As you saw, the
push_back
and
insert
functions can be used to splice new elements into the
vector's sequence. These two functions are balanced
by the
pop_back
and
erase
functions.
pop_back
is the opposite of
push_back, and removes the
last element from the
vector's sequence.
erase
is the deletion counterpart to
insert, and removes an element
at a particular position from the
vector. As with
insert, the syntax for
erase
is a bit tricky. To remove
a single element from a random point in a
vector, use the
erase
method as follows:
myVector.erase(myVector.begin() + n);
where
n
represents the index of the element to erase.
In some cases, you may feel compelled to completely erase the contents of the
vector. In that case, you
can use the
clear
function, which completely erases the
vector
contents.
clear
can be invoked as follows:
myVector.clear();
二、Deque
1.vector支持的操作deque也支持
What's interesting about the
deque
is that all operations supported by
vector
are also provided by
deque. Thus we can
resize
a
deque, use the bracket syntax to access individual elements, and
erase elements
at arbitrary positions.
2.deque和vector的不同之处,前者速度更快
But this raises an interesting question: if
deque
has strictly more functionality than
vector, why
use
vector? The main reason is speed.
deques and
vectors are implemented in two different ways.
Typically, a
vector
stores its elements in contiguous memory addresses.
deques, on the other hand,
maintain a list of different “pages” that store information. This is shown here:
These different implementations impact the efficiency of the
vector
and
deque
operations. In a
vector,
because all elements are stored in consecutive locations, it is possible to locate elements through simple
arithmetic: to look up the nth element of a
vector, find the address of the first element in the
vector, then
jump forward n positions. In a
deque
this lookup is more complex: the
deque
has to figure out which page
the element will be stored in, then has to search that page for the proper item. However, inserting elements
at the front of a
vector
requires the
vector
to shuffle all existing elements down to make room for
the new element (slow), while doing the same in the
deque
only requires the
deque
to rearrange elements
in a single page (fast).
If you're debating about whether to use a
vector
or a
deque
in a particular application, you might appreciate
this advice from the C++ ISO Standard (section 23.1.1.2):
vector
is the type of sequence that should be used by default...
deque
is the data structure of
choice when most insertions and deletions take place at the beginning or at the end of the sequence.
If you ever find yourself about to use a
vector, check to see what you're doing with it. If you need to optimize
for fast access, keep using a
vector. If you're going to be inserting or deleting elements at
the beginning
or end of the container frequently, consider using a
deque
instead.
总结:仅仅是需要快速访问最好使用vector,假如需要频繁的在头部或尾部插入或删除就使用deque。
3.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.