C + + learning notes - container

Posted by AZDoc on Thu, 20 Jan 2022 23:38:44 +0100

container

classification

  • Sequence container: objects are arranged in order and indexed with values
  • Associated container: the order of objects is not important, and keys are used for indexing
  • Adapter: adjust the behavior of the original container to expose new type interfaces or return new elements
  • Generators: constructing element sequences

Sequence container

Sequence container template

  • array: a sequence container with a fixed number of elements
  • vector: a sequence container for continuous storage of elements
  • forward_list/list: container based on linked list / bidirectional linked list
  • deque: compromise between vector and list
  • basic_string: provides special support for strings

array

definition

#include <array>
std::array<int,3> a{1,2,3};
  • The container with fixed length internally maintains a built-in array, which provides interfaces such as copy operation compared with the built-in array
  • Provide interface:
    • Construction: similar to array
    • Member type: value_type
    • Element access:
      • []: a[100] no error if the index is exceeded
      • At: a.at(100) an error is reported when the index is exceeded
      • front: returns the value of the first element
      • back: returns the value of the last element
      • data: returns a pointer to the first element of the array
    • Capacity related:
      • Empty: empty
      • Size: size
      • max_size: maximum size
    • Filling and switching:
      • fill: a.fill(100)
      • Swap: a.swap(b) / / extremely expensive

vector

definition

#include <vector>
vector<int> a{1,2,3};

internal structure

size_t size
size_t cap capacity
T* buffer

Dynamic array implementation: store the contents into an array. If the spare space is insufficient, it will open up more space, copy the old, release the old space and continue to insert elements.

Interface

  • Capacity correlation
    • Size: size
    • max_size: maximum number of elements
    • Reserve: reserve space a.reserve(80) improve efficiency
    • Capacity: capacity size
    • shrink_to_fit: reduce the capacity to be the same as the current size (size=capacity)
  • insert
    • Insert: a.insert(pos, 100) a.insert(pos, 3, 100) has low performance
    • emplace
  • Additional elements
    • push_back: construct first, then copy and move to the end
    • emplace_back: constructed directly at the end, which is more efficient
  • Element deletion
    • pop_back: deletes the end element
    • erase: a.erase(it1, it2)
    • clear: delete all content

list

definition

#include <list>
std::list<int> list = { 7, 5, 16, 8 };

internal structure

Pointer to the previous elementCurrent elementPointer to the next element

characteristic

  • Insert, delete, low cost
  • Random access costs are high, so you need to start from the first element and look down
  • [] access is not supported
  • pop_front interface: delete the first element
  • push_front: insert before the first element
  • Splice interface: LIST1 splice(list1.begin(), list2. begin(), list2. end()); Insert the contents of one list into another list

forward_list

A low-cost list keeps only the pointer to the next element

  • Only incremental operation is supported, without rbegin and rend
  • size is not supported (to reduce costs)
  • Pop is not supported_ back/push_ Back (to reduce costs)
  • support:
    • insert_after
    • erase_after
    • emplace_after
    • push_front
    • emplace_front
    • pop_front
    • Resize: a.resize(5, val) list is less than 5, 0 is supplemented, and greater than 5 is deleted
    • splice_after

deque

The data storage space of deque container is composed of sections of continuous space with the same length. The sections of space are not necessarily continuous and can be located in different areas of memory. The array of deque stores this pointer to each space.

#include <deque>
std::deque<int> a{1, 2, 3, 4};
  • Bidirectional container, supporting pop_front push_front push_back pop_back
    *The efficiency of adding or deleting elements at both ends of the element is high, but the efficiency of inserting or deleting elements in the middle of the sequence is low

basic_string

String related interface:

  • to_string
//Support input parameter int/double/float/long
int a = 3;
std::string b = to_string(a);
  • stoi stol stoll stof stod
std::string a = "123.5";
double b = stod(a);
std::string c = "123";
int d = stoi(c);
  • getline
//Read in one line at a time
#include <iostream>
#include <stream>
int main()
{
    std::string name;
    std::cout << "What is your name? ";
    std::getline(std::cin, name);
    std::cout << "Hello " << name << ", nice to meet you.\n";
}

Associated container

Associated container template

  • Implementation of map underlying red black tree
  • Implementation of red black tree at the bottom of set
  • Implementation of multiset underlying red black tree
  • Implementation of red black tree at the bottom of multimap
  • unordered_ Implementation of XXX underlying hash table

map

definition

#include <map>

int main()
{
    std::map<char, int> m{{'a',3}, {'b',4}};
    std::cout << m['a'] <<std::endl;
    
    std::map<std::string, int> n { {"CPU", 10}, {"GPU", 15}, {"RAM", 20}, };
    for (const auto& [key, value] : n) {
        std::cout << key << " = " << value << "; ";
    }
}
  • Each element is a key value pair key - > value
  • Interface:
    • Count: m.count('a ') is either 1 or 0
    • Find: m.find('a ') returns an iterator pointing to a specific key. If not found, it is end()
    • begin()
    • end()
    • erase: erase(key) erase(iter)
    • clear
    • insert
    • merge
    • extract extracts key value pairs
    map<int, string> m{{1, "mango"}, {2, "papaya"}, {3, "guava"}};
    auto nh = m.extract(2);
    nh.key() = 4;
    m.insert(move(nh));
    

set

definition

#include <set>

std::set<int> s{100, 3, 56, 7};
for(auto ptr =  s.begin(); s != s.end(); s++)
{
    std::cout << *ptr <<std::endl;
}

characteristic

  • Order is not important
  • Elements cannot be repeated. Only one element will be retained for multiple elements
  • By default, the middle order traversal starts with the left subtree, then the tree root, and then the right subtree. The output is sorted from small to large
  • The bottom layer is implemented by red black tree, so the elements in the collection must be comparable

Construct set object

//set construction template
template <class key, class Compare = std::less<key>, class Allocator = std::allocator<key>>
class set;

//compare function. The default value is less

std::set<int> a{5, 2, 7}; //a: 2 5 7
std::set<int, std::greater<int>> a{5, 2, 7}; //a: 7 5 2

//Constructor
set( std::initializer_list<value_type> init,
     const Compare& comp = Compare(),
     const Allocator& alloc = Allocator() );

set( InputIt first, InputIt last,
     const Compare& comp = Compare(),
     const Allocator& alloc = Allocator() );

Custom comparison function

struct str
{
    int x;
};

bool mycomp(const str& val1, const str& val2)
{
    return val1.x < val2.x;
}

int main()
{
    std::set<str, decltype(&mycomp)> s({str{1},str{2}}, mycomp);
)

application program interface

  • insert s.insert(str{100});
  • emplace s.emplace(100); // Construct this object with 100
  • erase s.erase(str{100}); Or s.earese(iter);
  • find auto a = s.find(key) if not found, return end() (no find in vector)
  • The set iterator returns a const iterator, and the element cannot be modified through the iterator
  • extract modifies elements. erase+insert is very expensive. extract nodes first
auto x = a.extract(1);
x.value() = 4;
a.insert(std::move(x));

map

Each node of the tree is an std::pair

definition

#include <map>
std::map<int, bool> m{{1,true}, {2,true}, {3,flase}};
for(auto ptr = m.begin(); ptr != m.end(); ++ptr)
{
    std::cout << ptr->first << ptr->second << std::endl;
}
//key must support size comparison

Interface

  • m.insert(std::pair<int, bool>(3, true));
  • m.erase(3) delete the key directly, or delete the pair
  • m.find(3) returns the iterator to the key
  • m.contain(3) returns bool
  • m[100] if there is no key, insert a pair(key, T()) default structure
  • m.at(100) reports an error without a key

multiset/multimap

Duplicate keys are allowed on the original basis

definition

#include <set>
#include <map>

std::multiset<int> s{1,3,1};
std::multimap<int,int> s{{1,3},{1,5}};

Interface

  • find returns the first element found
  • count s.count(2) returns the number of elements whose key is 2
  • auto b = s.lower_bound(1) returns an iterator pointing to the first element whose key is not less than 1
  • auto c = s.upper_bound(1) returns an iterator pointing to the first element with a key greater than 1
  • auto d = s.equal_range(1) returns a pair type object composed of the above two iterators

unordered_xxx

The underlying hash table is implemented, and the key obtains the index (position in the table) through hash function mapping. Compared with set/map, the search performance is better. The key needs to support two operations: conversion to hash value and judgment. Sometimes the insertion is very slow (when the table size needs to be expanded again).

Unordered containers are organized into a group of buckets. Each bucket holds zero or more elements (key value pairs) for a linked list. Unordered containers map elements to buckets through a hash function. The performance of unordered containers depends on the quality of hash functions and the number and size of buckets

For example, for 10 buckets, the key is 15, 15% 10 = 5. Store this key value pair in bucket 5

definition

#include <unordered_set>
#include <unordered_map>

std::unordered_set<int> s{3, 1, 5, 4, 1};
std::unordered_map<char,int> m{{'a', 1}, {'b', 2}};

Interface

  • begin
  • end
  • empty
  • size
  • max_size
  • clear
  • emplace
  • insert
  • erase
  • swap
  • extract
  • merge
  • count
  • find
  • equal_range
  • == != It can be judged, but the efficiency is very low

Construct unordered of custom hash function_ xxx

struct str
{
    int x;
}

size_t MyHash(const str& val)
{
    return val.x;
}

bool MyEqual(const str& val1, const str& val2)
{
    return val1.x == val2.x;
}

std::unordered_set<str, decltype(&MyHash), decltype(&MyEqual)> s(4, MyHash, MyEqual);
It can be used in actual and user-defined types
struct str
{
    int x;
    bool operator ==(const str& t) const
    {
        return (this->x == t.x);
    }
};
class MyHash
{
public:
    size_t operator ()(const str& t) const
    {
        return t.x;
    } 
};
//Equivalent to MyHash f; f(str{1});  To get the hash value

unordered_set<str, MyHash> a;  //But it is constructed by default
a.insert(str{});

Topics: C++ linked list Container