Common Algorithms
C++ STL Containers
Sequence containers:
1**. **vector
A contiguous storage structure: its elements are contiguous in memory. It supports efficient random access and insertion/deletion at the end, but insertion/deletion elsewhere is inefficient. It is equivalent to an array, with one difference: expansion of memory space. A vector supports storage without specifying its size, whereas array expansion must be written by the programmer.
How vector memory allocation works:
In STL’s internal implementation, a very large memory block is first allocated in preparation for storage—the size returned by capacity(). When this allocated space is exceeded, a new block is allocated for the entire storage (twice the size in VS6.0, 1.5 times in VS2005). This creates the impression that a vector does not require you to specify its size, that is, the size of a contiguous memory block. This default allocation usually meets storage needs in most situations.
Expanding the space (by any amount) should follow these steps:
(1) Allocate a new block of space
(2) Move the old elements one by one to the new location
(3) Release the original space back to the system
Note: vector’s data layout and operations are very similar to array’s. The only difference is flexibility in space utilization. Programmers must write array expansion themselves.
The vector class defines several constructors for defining and initializing vector objects:
vector<T> v1; The vector holds objects of type T. The default-constructed v1 is empty.
vector<T> v2(v1); v2 is a copy of v1.
vector<T> v3(n, i); v3 contains n elements with the value i.
vector<T> v4(n); v4 contains n copies of a value-initialized element.
2**. **deque
A contiguous storage structure, meaning each element is also contiguous in memory, similar to vector. The difference is that deque provides a two-level array structure: the first level is exactly like vector and represents the actual container; the other maintains the container’s starting address. Thus, in addition to all vector functionality, deque supports efficient insertion/deletion at the front and back.
deque: double-end queue
In terms of functionality, deque combines vector and list.
Advantages: (1) Convenient random access, supporting the [ ] operator and vector.at()
(2) Convenient insertion and deletion internally
(3) Supports push and pop at both ends
Disadvantage: High memory usage
When to use each:
(1) If you need efficient random access and do not care about insertion and deletion efficiency, use vector
(2) If you need extensive insertion and deletion and do not care about random access, use list
(3) If you need random access and care about inserting and deleting data at both ends, use deque
3**. **list
A noncontiguous storage structure with a doubly linked list structure. Each element maintains a pair of forward and backward pointers, supporting traversal in both directions. It supports efficient insertion/deletion at arbitrary positions, but random access is inefficient, and maintaining additional pointers adds considerable overhead. Each node includes an information block Info, a predecessor pointer Pre, and a successor pointer Post. Elements can be conveniently added and deleted without allocating a required memory size. Storage uses noncontiguous memory.
Advantages: (1) Performs dynamic operations without contiguous memory.
(2) Convenient insertion and deletion internally
(3) Supports push and pop at both ends
Disadvantages: (1) Cannot perform internal random access; it does not support the [ ] operator or vector.at()
(2) Uses more memory than vector
When to use each:
(1) If you need efficient random access and do not care about insertion and deletion efficiency, use vector
(2) If you need extensive insertion and deletion and do not care about random access, use list
(3) If you need random access and care about inserting and deleting data at both ends, use deque
4**. vector VS. list VS. deque:**
a. Choose vector if random access is needed;
b. Choose vector if the number of elements to store is already known;
c. Choose list if insertion/deletion at arbitrary positions (not just at the ends) is needed
d. Choose deque only when insertion/deletion at the front is needed while also maintaining random access efficiency; otherwise, choose vector.
e. If both insertion/deletion at arbitrary positions and random access are needed, use deque as a compromise between vector and list.
f. When storing large, complex class objects, list is better than vector; of course, vector can also store pointers to objects,
which likewise provides high efficiency, but maintaining pointers is very error-prone and therefore not recommended.
Associative containers:
Container adapters:
Stack: stack
Queue: queue
Priority queue: priority_queue
Lvalue References and Rvalue References
Q: What are lvalue references and rvalue references?
A: Before C++11, all traditional references were lvalue references
An lvalue reference requires that the value on the right have an address that can be taken. If its address cannot be taken, a const reference can be used;
An lvalue reference refers to any lvalue (addressable, named, and nontemporary). It is the traditional C++ form of reference
An rvalue reference refers to any rvalue (not addressable, unnamed, temporary values such as literals). It is a new C++11 feature. Like a const reference, it creates a new address for storage, but the difference is that a const reference is read-only while an rvalue reference allows reading and writing
Q: Does creating an lvalue reference occupy a new address?
A: No. A reference is an alias and does not use a new address

However, referencing a literal with a const reference generates a temporary address

Q: Why is a function’s return value an rvalue rather than an lvalue?
Because rvalues include all temporarily valid values
A function’s return value is valid only when it is returned, so it is an rvalue reference





