Data structures in C++ (notes)

Random notes, for reference only

Data structures in C++

Header files that need to be imported

#include <iostream>
#include <vector>		// vector
#include <algorithm>	// find, swap, sort, unique, reverse, lower_bound, min, max, max_element
#include <functional>	// less, greater
#include <queue>		// priority_queue, queue
#include <stack>		// stack
#include <unordered_map> // unordered_map
#include <unordered_set> // unordered_set
#include <map> 			// map, multimap
#include <set> 			// set, multiset
#inlcude <utility> 		// pair, swap(exchange values of two objects)
#include <tuple> 		// tuple (get)
#include <string>		// string
using namespace std;

sum of two numbers

Enter description

输入数据有多组, 每行表示一组输入数据。
每行不定有n个整数,空格隔开。(1 <= n <= 100)

Output description

每组数据输出求和的结果

Example:
Import:

1 2 3
4 5
0 0 0 0 0

Output:

6
9
0

Code:

#include <iostream>
#include <vector>
using namespace std;

using ll = long long;
int solution(vector<int>& nums){
    
    
    int n = nums.size();
    ll sum = 0;
    for(int i=0;i<n;i++){
    
    
        sum += nums[i];  
    }
    return sum;
}
void submit(int ans){
    
    
    cout << ans << endl;
}

int main() {
    
    
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    int n;
    vector<int> nums;
    while(cin >> n){
    
    
        nums.push_back(n);
        if(cin.get() == '\n'){
    
    
            int ans = solution(nums);
            submit(ans);
            nums.clear();
        }
    }
    return 0;
}
// 64 位输出请用 printf("%lld")

Sort the input string

Enter description

多个测试用例,每个测试用例一行。
每行通过,隔开,有n个字符,n<100

Output description

对于每组用例输出一行排序后的字符串,用','隔开,无结尾空格

Example
Import:

a,c,bb
f,dddd
nowcoder

Output:

a,bb,c
dddd,f
nowcoder

Code:

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;

using ll = long long;
vector<string> solution(vector<string>& nums){
    
    
    int n = nums.size();
    sort(nums.begin(), nums.end());
    return nums;
}
void submit(vector<string>& ans){
    
    
    int n = ans.size();
    for(int i=0;i<n;i++){
    
    
        cout << ans[i];
        if(i != n-1){
    
    
            cout << ",";
        }
    }
    cout << endl;
}
void split(string& s, vector<string>& tokens, const string& delimiters=" "){
    
    
    auto last_pos = s.find_first_not_of(delimiters, 0);
    auto pos = s.find_first_of(delimiters, last_pos);
    while(pos!=string::npos || last_pos !=string::npos){
    
    
        tokens.push_back(s.substr(last_pos, pos-last_pos));
        last_pos = s.find_first_not_of(delimiters, pos);
        pos = s.find_first_of(delimiters, last_pos);
    }
}

int main() {
    
    
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    string a;
    while(getline(cin, a)){
    
    
        vector<string> nums;
        split(a, nums, ",");
        auto ans = solution(nums);
        submit(ans);
    }
    return 0;
}
// 64 位输出请用 printf("%lld")

Array (vector) -- vector

#include <vector>

object definition method

//一维vector
vector<int> *v = new vector<int>();
//二维vector
vector<vector<int>> *v2 = new vector<vector<int>*>();
Traverse
//打印输出(二维数组)
for(int i=0;i<v2->size();i++){
    
    
    for(int j=0;j<v2->at(0)->size();j++){
    
    
        cout << v2->at(i)->at(j) << endl;
    }
}

ordinary definition

//声明R行C列的数组,赋初值为0
vector<vector<int>> flag(R, vector<int>(C, 0));

Declaration of vector with dimensions (n,2)

The first:

vector<vector<int>> cp(n,vector<int>(2,0));
for(int i=0;i<n;i++){
    
    
    cp[i][0] = capital[i];
    cp[i][1] = profits[i];
}

The second type:

vector<vector<int>> cp(n);
for(int i=0;i<n;i++){
    
    
    // cp[i].emplace_back(capital[i]);
    // cp[i].emplace_back(profits[i]);

    cp[i].push_back(capital[i]);
    cp[i].push_back(profits[i]);
}

Logic aboveemplace_back()Good point.
ExistingIn this example, push_back()Small ratioemplace_back()Good point.
Third type:

vector<pair<int,int>> cp;
for(int i=0;i<n;i++){
    
    
    // cp[i] = {capital[i],profits[i]};
    cp.push_back({
    
    capital[i],profits[i]});
}

The third method is the fastest, the second is the second, and the first is the slowest.
vector<pair<int,int>> is twice as fast as vector<vector<int>>.


vector operations

push_backInsert at the end

void push_back(const T& x): Add an element X to the tail of the vector

emplace_backConstruct at the tail

push_back() When adding an element to the end of the container, it will firstcreate this element, and then add this element Copy or move into the container (if copied, the previously created element will be destroyed afterwards) < When /span>The process of copying or moving elements saves Go directly at the end of the container, creates the element
emplace_back() is implemented,

pop_backDelete at the end

void pop_back(): delete the last element in the vector

back() gets the tail element
v.back()
front() gets the head element
v.front()
The number of size elements

int size() const: returns the number of elements in the vector

insert(i,x) insert before i
iterator insert(iterator i,x)
A.insert(A.begin()+k,x)
Insert – merge vector
//在A的后面插入
A.insert(A.end(),B,begin(),B.end());
delete –erase
iterator erase (iterator position);
iterator erase (iterator first, iterator last);
Get the first element reference front and the last element reference back
reference front():返回首元素的引用
reference back():返回尾元素的引用
resize(n, value) Modify size

Modify the container size, and use value to change the larger part to the default value.

for (int i=1;i<10;i++) myvector.push_back(i);
myvector.resize(5);
myvector.resize(8,100);
myvector.resize(12);
//myvector包含:1 2 3 4 5 100 100 100 0 0 0 0
array flip

Use reverse() in <algorthm>

#include <algorithm>
reverse(A.begin(),A.end())
copy vector

Copy during initialization and construction

vector<int> tem(list);

assign

vector<int> temlist;
temlist.assign(list.begin(), list.end());

Algorithm

unique

unique removes adjacent duplicate elements. If you want to remove all (including non-adjacent) elements, you must first sort the sequence so that all duplicate elements are adjacent.

unique returns, the next iterator of the last retained element

vector<int> myvector = {
    
    1,2,2,2,3,3,2,2,1}

vector<int>::iterator it = unique(myvector.begin(),myvecotr.end())
#out:1,2,3,2,1,?,?,?,?

myvector.erase(it,myvector.end())
#out:1,2,3,2,1

sortsort

//升序
sort(A.begin(),A.end(),less<int>());
//降序
sort(A.begin(),A.end(),greater<int>());

Custom comparison function

[sort] is generated in the opposite order to [Heap/Priority Queue].
are all default less<>() comparison functions, but after [sort] the elements are arranged in ascending order ; [heap /priority queue] generateslarge top heap.

Note: Note that >= or <= must not be written in the comparison function. The comparison function requires that if two elements are equal, false should be returned. If the two elements here are equal, true is returned, causing the stl sort to be executed abnormally and causing a segfault.

Pass in comparison function

How to write anonymous functions

struct Edge {
    
    
    int len, x, y;
    Edge(int len, int x, int y) : len(len), x(x), y(y) {
    
    
    }
};
sort(edges.begin(), edges.end(), [](Edge a, Edge b) -> int {
    
     return a.len < b.len; });
Overloaded operators

The comparison result of priority_queue is [opposite]

class Point{
    
    
    public:
        int x;
        int y;
        int dist;
        Point(int x,int y,int dist){
    
    
            this->x = x;
            this->y = y;
            this->dist = dist;
        }
        //根据【希望】的情况进行返回
        bool operator<(const Point &p) const{
    
    
            return dist>p.dist;
        }
};
priority_queue<Point> q;

max_element

vector<int> arr = {
    
    1,2,3,4};
int maxNum = *max_element(arr.begin(),arr.end());
cout << maxNum << endl; // 4

Queue — queue

#include <queue>
queue<int> q;

Queue operations

Get the team leader
q.front();		//获得队列最前面一个元素引用
Get to the end of the queue
q.back();		//返回队列最后一个元素引用
Call it short
q.empty();   //检查是否为空的方法 
Join the team
q.push();		//在队列尾添加一个数据
Dequeue

Return void

q.pop();      //删除队列头的一个数据,返回void

size()The number of elements in the queue

Stack —Stack

#include <stack>
stack<int> mystack;

Stack operations

short operation
s.empty();         //如果栈为空则返回true, 否则返回false;
Get size
s.size();          //返回栈中元素的个数
Get the top element of the stack
s.top();           //返回栈顶元素, 但不删除该元素
pop
s.pop();           //弹出栈顶元素, 但不返回其值
push into stack
s.push();       //将元素压入栈顶
s.emplace();    //构造并插入元素

heap

The heap is not a container, but a special way of organizing container elements.

Heap operations

create heap
vector<int> A = {
    
    };
//构造 小顶堆
mack_heap(A.begin(),A.end(),greater<>());
//构建 大顶堆(默认)
mack_heap(A.begin(),A.end(),less<>());
insert into heap
A.push_back(x);
//greater/less必须与创建堆使用的相同
push_heap(A.begin(),A.end(),greater<>());

push_heap() will therefore think that the last element is a new element, and will rearrange the sequence in order to maintain the heap structure.

Delete the top of the heap
pop_heap(A.begin(),A.end());
A.pop_back();

pop_head moves the first element to the end

Check if it is a heap
is_heap(A.begin(),A.end());
Heap sort
//大顶堆
make_heap(A.begin(), A.end());//{12 10 3.5 6.5 8 2.5 1.5 6}
//升序排列
sort_heap(A.begin(), A.end());//{1.5 2.5 3.5 6 6.5 8 10 12}
//小顶堆
make_heap(A.begin(), A.end(),greater<>());// {1.5 6 2.5 6.5 8 12 3.5 10}
//降序排列
sort_heap(A.begin(), A.end(),greater<>());//{12 10 8 6.5 6 3.5 2.5 1.5}

priority queue

When comparing pairs, compare the first element first, and compare the second element if the first element is equal.

//pair<x,y>键值对
priority_queue<pair<int, int>> q;
//降序队列,大顶堆,默认
priority_queue <int,vector<int>,less<int> >q;
//升序队列,小顶堆
priority_queue <int,vector<int>,greater<int> > q;
insert
//构造插入
q.emplace(dist, i);
push();
delete
q.pop();  //无返回值
get top
q.top();

Custom comparison function

Example 1

Anonymous function + decltype inferred type + constructor

auto cmp = [](const pair<string, int>& a, const pair<string, int>& b) {
    
    
	return a.second == b.second ? a.first < b.first : a.second > b.second;
};
priority_queue<pair<string, int>, vector<pair<string, int>>, decltype(cmp)> queue(cmp);

Example 2

Comparison function in the structure + passing in the comparison function generic

struct cmp {
    
    
    bool operator ()(pair<string, int>& a, pair<string, int>& b) {
    
    
        return a.second == b.second ? a.first < b.first : a.second > b.second;
    }
};
priority_queue<pair<string, int>, vector<pair<string, int>>, cmp> queue;

Hash table

map ascending and descending order

map<int,int,less<int>> mmap;  //默认升序
map<int,int,greater<int>> mmap;  //降序

Hash table operations

#include <unordered_map>
unordered_map<string,int> map,
insert
map.insert (x);                        		  // 复制插入
map.insert (make_pair<string,double>("x",y)); // 移动插入
map.emplace(7, "456");						  //构造插入
delete
map.erase(map.begin()+x);  //通过位置
map.erase("x");   		   //通过key
Clear
map.clear();
Find
if(map.find("x") != map.end()){
    
    
	//查找成功
}else{
    
    
	//查找失败
}
if (map.count("x")) {
    
    
	//查找成功
}
int val = map["x"]; 
//直接使用key值访问键值对,如果没有访问到,返回0
Traverse
map里面的数据类型是pair<T,P> p = {
    
    key,value}
//first 是map的key
//second 是map的value
for (auto& [key,value]: map)
cout << key << " "<< value << endl;

for(auto it=map.begin();it!=map.end();it++){
    
    

}

gather

The difference between set and unordered_set in c++ std is similar to the difference between map and unordered_map:

set is implemented based on the red-black tree. The red-black tree has the function of automatic sorting, so all the data inside the map is in order at all times.

unordered_set Based on the hash table, the time complexity of data insertion and search is very low, almost constant time, but the cost is that it consumes a lot of memory and has no automatic sorting function. In the underlying implementation, an array with a relatively large subscript range is used to store elements, forming many buckets, and the hash function is used to map the keys to different areas for storage.

unordered_set<int,int> set;
insert
emplace
insert
push_back()
append()
delete
erase
pop_back()
Find
count
find
Traverse
for (auto& x: set)
cout << x << endl;
Custom set sorting

【StackOverflow】Using custom std::set comparator

Modern C++20

auto cmp = [](int a, int b) {
    
     return ... };
set<int, decltype(cmp)> sset;

Modern C++11
The lambda expression needs to be passed into the constructor.

auto cmp = [](int a, int b) {
    
     return ... };
std::set<int, decltype(cmp)> sset(cmp);

Old solution uses struct's operator()
function followed by const to indicate a constant function (const member function).

An explanation of C++’s constant Member function

  • const member functionMember variables (data members) cannot be modified within.
  • const objectcan only callconst member function.
struct cmp {
    
    
    bool operator() (int a, int b) const {
    
    
        return ...
    }
};
set<int, cmp> sset;

for loop

for-each

//for-each
for(auto c:S){
    
    
    ascii[c]++;
}

Array assignment memset

memset(A,0,sizeof(A));

key-value pair

Create pair
//创建一个空的pair对象(使用默认构造),它的两个元素分别是T1和T2类型,采用值初始化。
pair<T1, T2> p1;
//创建一个pair对象,它的两个元素分别是T1和T2类型,其中first成员初始化为v1,second成员初始化为v2。
pair<T1, T2> p2(v1, v2);
Create new pair
// 以v1和v2的值创建一个新的pair对象,其元素类型分别是v1和v2的类型。
pair<T1, T2> p3 = make_pair(v1, v2);
or
pair<T1, T2> p3 = {
    
    v1,v2};
Visit pair
// 返回对象p1中名为first的公有数据成员
p.first;
// 返回对象p1中名为second的公有数据成员
p.second;
example
//二维数组
vector<vector<int>> m;
queue<pair<int, int>> q;
q.push({
    
     r0, c0 });
//m[i][0] = r0,m[i][1]= c0
//或者说 插入一个[r0,c0] , 或者说 插入一个 一维数组
//此时二维数组元素 [ [r0,c0] ]
m.push_back({
    
     r0, c0 });

pair<int, int> cur = q.front();

//pair访问
int x1 = cur.first + x[j];
int y1 = cur.second + y[j];

tuple tuple

Use of tuple

vector<tuple<int, int, int, int>> ans;
ans.emplace_back(steps, grid[i][j], i, j);

Create a tuple

# 1.
tuple<int,flaot,vector<int>> t;

# 2.
tuple<string,vector<double>,int> someVal("tuple",{
    
    2.14,3.15},100);

# 3.
tuple<int,int,double> someVal{
    
    2,3,3.15};

access tuple

auto item = make_tuple("string",3,20.01);
auto book = get<1>(item);

Query the number of tuple members

auto sz = tuple_size<decltype(item)>::value;
//sz = 3

Query tuple member type

tuple_element<1,decltype(item)>::type ctype;
//ctype的类型为int

string string

There is no need to add '\0' at the end of string

string::npos 表示 字符串末尾
Basic operations
string s;
1)  s.empty();  // s为空串 返回true
2)  s.size();s.length();  // 返回s中字符个数 类型应为:string::size_type
3)  s[n];  // 从0开始相当于下标访问
4)  s1+s2;  // 把s1和s2连接成新串 返回新串 
5)  s1=s2;  // 把s1替换为s2的副本
6)  v1==v2;  // 比较,相等返回true
7)  `!=, <, <=, >, >=`  惯有操作 任何一个大写字母都小于任意的小写字母
8) s.push_back() //其他操作类似于vector
Case conversion
string str = 'Abc';
//转大写
transform(str.begin(), str.end(), str.begin(), toupper);
>>> str = 'ABC'
//转小写
transform(strA.begin(), strA.end(), strA.begin(), tolower);
substr finds substring

pos:
Position of the first character to be copied as a substring.
If this is equal to the string length, the function returns an empty string.
If this is greater than the string length, it throws out_of_range.
Note: The first character is denoted by a value of 0 (not 1).

  • What is returned is a copy of the original string.
  • Start counting from 0
  • If pos is exactly [equal to] the length of the string, an empty string is returned.
  • If pos is [greater than] the string length, an out_of_rang exception is thrown.

len:
Number of characters to include in the substring (if the string is shorter, as many characters as possible are used).
A value of string::npos indicates all characters until the end of the string.

  • If the length of len is [greater than] the length of the remaining substring, take all of them.
  • string::npos means removing all remaining substrings.

size_t:
size_t is an unsigned integral type (the same as member type string::size_type).

  • Unsigned integer.
string substr(size_t pos,size_t len) const
//第一个参数是index,第二个参数是子串长度
stinrg str = s.substr(index,len);
string => const char*
string str = "Hello World";
const char *ch1 = str.c_str();
const char *ch2 = str.data();
Character deletion erase
c++98
sequence (1)	string& erase (size_t pos = 0, size_t len = npos);
character (2)	iterator erase (iterator p);
range (3)	    iterator erase (iterator first, iterator last);
Character operations
//替换字符


String splitting
s为原字符串,tokens为分割后字符串(需要传入),delimiters为分割符
void split(const string& s, vector<string>& tokens, const string& delimiters = " "){
    
    
    string::size_type lastPos = s.find_first_not_of(delimiters, 0);
    string::size_type pos = s.find_first_of(delimiters, lastPos);
    while (string::npos != pos || string::npos != lastPos) {
    
    
        tokens.push_back(s.substr(lastPos, pos - lastPos));//use emplace_back after C++11
        lastPos = s.find_first_not_of(delimiters, pos);
        pos = s.find_first_of(delimiters, lastPos);
    }
}
//示例:
string s = "a,b,c";
vector<string> tokens;
split(s,tokens,",");
for(auto &t:tokens){
    
    
	cout << t << " ";
}
>>> a b c
stringstream word segmentation (single space)

C++ std::move principle implementation and usage summary
move() Its only function is to force an lvalue into an rvalue reference, and then the value can be used through an rvalue reference , for move semantics.

884. Uncommon words in two sentences

vector<string> uncommonFromSentences(string s1, string s2) {
    
    
	unordered_map<string, int> freq;
	
	//分割空格
	auto insert = [&](const string& str){
    
    
		stringstream ss(str); // ss << s;
		string buffer;
		while(ss >> buffer){
    
    
			++freq[move(buffer)];
		}
	}
	
	insert(s1);
	insert(s2);
	...
}

Character search

C++ string search substring position

//返回str在字符串中第一次出现的位置(从index开始查找),如果没找到则返回string::npos
//string
size_type find( const basic_string &str, size_type index=0 );

//c-string
size_type find( const char *str, size_type index=0 ); // 同上

//返回str在字符串中第一次出现的位置(从index开始查找,长度为length),如果没找到就返回string::npos
//buffer
size_type find( const char *str, size_type index, size_type length );

// 返回字符ch在字符串中第一次出现的位置(从index开始查找),如果没找到就返回string::npos
//character 
size_type find( char ch, size_type index=0 );
String comparison compare
unsigned int val = a.compare(b);

//string (1)	
int compare (const string& str) const;

//substrings (2)	
int compare (size_t pos, size_t len, const string& str) const;
int compare (size_t pos, size_t len, const string& str,size_t subpos, size_t sublen) const;

//c-string (3)	
int compare (const char* s) const;
int compare (size_t pos, size_t len, const char* s) const;

//buffer (4)	
int compare (size_t pos, size_t len, const char* s, size_t n) const;
char* => int
const char *str1 = "3.14159";
int num1 = std::atoi(str1);
string => int, double, long, long long …
string s = "123";
int num1 = stoi(s);
double num2 = stod(s);
long num3 = stol(s);
long long num4 = stoll(s);
stod(string str,size_t idx)

str:
String type image.

idx:
Pointer of type size_t. If idx is not empty,
sets idx to the next character after [numeric string]. Therefore, idx should be passed as pointer type, or reference type.


example:

string orbits("365.24 29.53");
size_t sz;   //unsigned int64
double earth = stod(orbits,&sz);
cout << sz << orbits[sz] << 1 << endl;
double moon = stod(orbits.substr(sz));
cout << "The moon completes " << (earth/moon) << " orbits per Earth year.\n";

out:
6 1
The moon completes 12.3684 orbits per Earth year.
int => string
int num = 123;
string str = to_string(num);
char=>string
char ch = 'a'
string a = *new string(1, ch);
character stream stringstream
#include <sstream>
stringstream stream;
string sint="1";
string sfloat="1.1";
string sdouble="1.2";
int dint;
float dfloat;
double ddouble;
//string to int
stream << sint;
stream >> dint;
//string to float
stream.clear(); //注意需要清空对象
stream << sfloat;
stream >> dfloat;
//string to double
stream.clear(); //注意需要清空对象
stream << sdouble;
stream >> ddouble;
Determine whether a string is a letter isalpha
isalpha(s)

Returns true for uppercase and lowercase letters, false for others.

anonymous function

C++11 provides support for anonymous functions, called Lambda functions (also called Lambda expressions). The specific form of Lambda expressions is as follows:
     [capture](parameters )->return-type{body}
If has no parameters, the empty parentheses () can be omitted.
     [capture]->return-type{body}
Ifthere is no return value, the return value can also be omitted,
     [capture](parameters){body}

//例子
[](int x, int y) -> int {
    
     int z = x + y; return z; }

A Lambda function canreference variables declared outside it. The collection of these variables is called a closure. The closure is defined in the Lambda Within square brackets [] in an expression declaration. This mechanism allows these variables to be captured by value or by reference. Examples of these are:

[]        //未定义变量.试图在Lambda内使用任何外部变量都是错误的.
[x, &y]   //x 按值捕获, y 按引用捕获.
[&]       //用到的任何外部变量都隐式按引用捕获
[=]       //用到的任何外部变量都隐式按值捕获
[&, x]    //x显式地按值捕获. 其它变量按引用捕获
[=, &z]   //z按引用捕获. 其它变量按值捕获

decltype keyword

Sometimes we want to infer the type of a variable to be defined from the type of an expression, but we don't want to initialize the variable with the value of the expression (if we want to initialize, use auto). In order to meet this demand, the new C++11 standard introduces the decltype type specifier. Its function is to select and return the data type of the operand. In this process, the compiler analyzes the expression and obtains its type, but does not Actually evaluates the expression.

int getSize();

int main(void)
{
    
    
    int tempA = 2;
    
    /*1.dclTempA为int*/
    decltype(tempA) dclTempA;
    /*2.dclTempB为int,对于getSize根本没有定义,但是程序依旧正常,因为decltype只做分析,并不调用getSize,*/
    decltype(getSize()) dclTempB;

    return 0;
}

Both decltype and auto can be used to infer types, but there are several obvious differences between them:

  1. auto ignores top-level const, decltype retains top-level const;
  2. For reference operations, auto infers the original type, and decltype infers the reference;
  3. For dereference operations, auto infers the original type and decltype infers the reference;
  4. Auto inference will actually be executed, decltype will not be executed, only analysis will be done.

In short, special care needs to be taken when combining const, references and pointers during use.

Guess you like

Origin blog.csdn.net/LittleSeedling/article/details/108897774