【刷题】C++ 版刷题指南

C++ 刷题指南(自用)

    • 小tips:
      • include
      • struct节点
      • io输入输出练习
      • 其它
      • 输入
      • 迭代器
      • string
      • vector
      • deque(双端队列)
      • 优先队列priority\_queue
        • 优先队列 + tuple
        • 优先队列 + 结构体(自定义排序)
      • map
      • set
      • pair
      • tuple
    • 函数
      • 数学
      • 字符、字符串
      • 对数组操作
    • 数学
      • 最大公约数
    • 语法
      • char[0] 柔性数组
      • 结构体中初始化数组
      • lambda表达式
      • const 和 constexpr

因为以后工作后用Java了,因此慢慢地也开始要用Java刷题了,之前攒的C++刷题用到的库、用法放出来,主要是刷LeetCode时自查、收集的一些用法。


小tips:

include

#include <bits/stdc++.h>    // c++万能库

struct节点

struct ListNode {
    int val;
    ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};

io输入输出练习

来自牛客网OJ在线编程常见输入输出练习场

数字队列求和:

#include <stdio.h>
int main(){
    int i,sum=0;
    while (scanf("%d",&i)!=EOF){
        sum=sum+i;
        if (getchar()=='\n'){
            printf ("%d\n",sum);
            sum=0;
        }
    }
    return 0;
}
// 或者

#include <bits/stdc++.h>
using namespace std;
 
int main(){
    int sum=0;
    int n;
    while(cin>>n){
        sum+=n;
        if(cin.get()=='\n'){
            cout<<sum<<endl;
            sum=0;
        }
         
    }
    return 0;
}

cin.get成员读取单个字符,包括任何白色空格字符。参考

字符串队列排序

#include<bits/stdc++.h>
using namespace std;
 
int main(){
    string temp;
    while(getline(cin, temp)){
        stringstream strLineStream(temp);   // 这个必须每个循环建一个
        vector<string> target;
        string strtemp;
        while(getline(strLineStream, strtemp, ',')){
            target.push_back(strtemp);
        }
        sort(target.begin(),target.end());
        int tag = 0;
        while(tag < target.size()){
            if(tag == target.size()-1){
                cout<<target[tag]<<endl;
            }
            else{
                cout<<target[tag]<<",";
            }
            ++tag;
        }
    }
    return 0;
}

注意stringstream ss如果想多次复用,下次使用前必须调用ss.clear方法.否则只能每次创建一个新的.

而如果是使用>>从stringstream输出的话似乎需要再使用.str(""),参考《https://blog.csdn.net/jcq521045349/article/details/49888751》

  • 保留小数

参考

#include <iomanip>  //不要忘了头文件

//第一种写法
cout<<setiosflags(ios::fixed)<<setprecision(2);

//第二种写法
cout.setf(ios::fixed);
cout<<setprecision(2);

//第三种写法
cout<<fixed<<setprecision(2);

要保留几位小数setprecision(n)的括号里n就换成几。
前两种写法是一样的,第三种是简化写的。
上面的语句写一次就行了,对之后的数字都有效。

#include  <stdio.h>
int main()
{
    float PI=3.1415926;
    float R=5.3;
    printf("面积 = %.2f\n", PI * R * R); //输出:面积 = 88.25
    printf("面积 = %f\n", PI * R * R);   //输出:面积 = 88.247337
    printf("面积 = %.8f\n", PI * R * R); //输出:面积 = 88.24733734
    return 0;
}

%.2f\n中的“.2”即保留两位小数
//不设定保留几位小数,则默认六位

其它

func
move(将一个左值强制转化为右值引用)在指针类型的标准库对象赋值时避免内存的额外创建 ref
  • 随机数:使用srand((unsigned)time(NULL));每次提供不同的随机种子,否则调用rand()函数每次的输出一样

输入

参考C++中cin、cin.get()、cin.getline()、getline()、gets()等函数的用法

  • cin >>
    用法1:最基本,也是最常用的用法,输入一个数字:
    用法2:接受一个字符串,遇“空格”、“TAB”、“回车”都结束
#include <iostream>
using namespace std;
main (){
    char a[20];
    cin >> a;
    cout << a << endl;
}
  • cin.get()
    用法1: cin.get(字符变量名)可以用来接收字符
    用法2:cin.get(字符数组名,接收字符数目)用来接收一行字符串,可以接收空格
#include <iostream>
using namespace std;
main (){
    char a[20];
    cin.get(a,20);
    cout << a << endl;
}

用法3:cin.get(无参数)没有参数主要是用于舍弃输入流中的不需要的字符,或者舍弃回车,弥补cin.get(字符数组名,接收字符数目)的不足.

  • cin.getline() // 接受一个字符串,可以接收空格并输出
#include <iostream>
using namespace std;
main ()
{
    char m[20];
    cin.getline(m,5);
    cout<<m<<endl;
}

// 输入:jkljkljkl
// 输出:jklj

cin.getline()实际上有三个参数,cin.getline(接受字符串的看哦那间m,接受个数5,结束字符).当第三个参数省略时,系统默认为’\0’

// 当用在多维数组中的时候,也可以用cin.getline(m[i],20)之类的用法:

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

main ()
{
    char m[3][20];
    for(int i=0;i<3;i++)
    {
        cout<<"\n请输入第"<<i+1<<"个字符串:"<<endl;
        cin.getline(m[i],20);
    }
    
    cout<<endl;
    for(int j=0;j<3;j++)
    cout<<"输出m["<<j<<"]的值:"<<m[j]<<endl;

}
  • getline() // 接受一个字符串,可以接收空格并输出,需包含“#include”
#include<iostream>
#include<string>
using namespace std;
main ()
{
    string str;
    getline(cin,str);
    cout << str << endl;
}

和cin.getline()类似,但是cin.getline()属于istream流,而getline()属于string流,是不一样的两个函数

  • cin.getline()是输入流对象的成员函数
  • getline()是string类的成员函数

C++文档:

  • std::getline (string)
    • Get line from stream into string
    • Extracts characters from is and stores them into str until the delimitation character delim is found (or the newline character, ‘\n’, for (2)).
    1. istream& getline (istream& is, string& str, char delim);
    2. istream& getline (istream& is, string& str);
  • std::istream::getline
    • Extracts characters from the stream as unformatted input and stores them into s as a c-string, until either the extracted character is the delimiting character, or n characters have been written to s (including the terminating null character).
    • The delimiting character is the newline character (‘\n’) for the first form, and delim for the second: when found in the input sequence, it is extracted from the input sequence, but discarded and not written to s.
    1. istream& getline (char* s, streamsize n );istream& getline (char* s, streamsize n, char delim );
  • std::istream::get
    1. single character (1) int get();istream& get (char& c);
    2. c-string (2) istream& get (char* s, streamsize n);istream& get (char* s, streamsize n, char delim);
    3. stream buffer (3) istream& get (streambuf& sb);istream& get (streambuf& sb, char delim);
  • gets
    • [NOTE: This function is no longer available in C or C++ (as of C11 & C++14)]
    • Reads characters from the standard input (stdin) and stores them as a C string into str until a newline character or the end-of-file is reached.
    1. char * gets ( char * str );

迭代器

《C++ STL prev()和next()函数》

set<int> sset;
set<int>::iterator it = sset.begin();

// it 至少为双向迭代器。n 默认为 1
// 当 n 为正数时,其返回的迭代器将位于 it 左侧;反之,当 n 为负数时,其返回的迭代器位于 it 右侧。
it = prev(it, n);
// it 最少为前向迭代器。n 默认为 1
// 当 it 为前向迭代器时,n 只能为正数,该函数最终得到的新迭代器位于 it 右侧;
// 当 it 为双向迭代器或者随机访问迭代器时,若 n 为正数,则得到的新迭代器位于 it 右侧,反之位于 it 左侧。
it = next(it, n);

string

  • reverse
string s;
reverse(s.begin(), s.end());
reverse(s.begin(), s.begin()+s.length());
  • to_string:将数字常量转化为字符串
string to_string (int val);
string to_string (long val);
string to_string (long long val);
string to_string (unsigned val);
string to_string (unsigned long val);
string to_string (unsigned long long val);
string to_string (float val);
string to_string (double val);
string to_string (long double val);
  • 其它:
string s(n, 'c');   // 初始化为连续n个字符串c组成的串
getline(cin, s);    // 从cin中读取一行赋给s

if(b.find(a)==string::npos) cout<<"no find"<<endl;  // 在b中查找a,若没找到返回string::npos
// 正向查找在原字符串中第一个与指定字符串(或字符)中的某个字符匹配的字符,返回它的位置。
// 若查找失败,则返回npos。(npos定义为保证大于任何有效下标的值。)
if(b.find_first_of(a)==string::npos) cout<<"no find"<<endl;    
// 逆向查找在原字符串中最后一个与指定字符串(或字符)中的某个字符匹配的字符,返回它的位置。
// 若查找失败,则返回npos。(npos定义为保证大于任何有效下标的值。)
if(b.find_last_of(a)==string::npos) cout<<"no find"<<endl;  

stoi(str); // 将str 的内容 解析为一个 特定base的int数值。

//  std::string 类本身就提供了类似「入栈」和「出栈」的接口,因此我们直接将需要被返回的字符串作为栈即可
s.empty();
s.back(); s.front();
s.push_back();
s.pop_back();
  • C风格字符串(不建议使用)
    ——《C++ Prime》P109
#include <cstring>

char ca1[] = "string example 1";
char ca2[] = "string example 2";    // 以空字符('\0')结束

if(ca1 < ca2)   // 未定义:试图比较两个无关地址(使用数组时其实使用的是指向首元素的指针)

strlen(p);      // 返回p的长度
strcmp(p1, p2); // 比较:p1 == p2 返回0;p1 > p2 返回正值;否则返回一个负值
strcat(p1, p2); // 将p2附加到p1后,返回p1(注意p1的容量)
strcpy(p1, p2); // 将p2拷贝给p1,返回p1

可以用字符数组初始化string,不能反过来(反过来要用c_str()

string s("Hello");
const char *str = s.c_str();

vector

  • 初始化:
vector<T> v1;
vector<T> v2(v1);
vector<T> v3{a, b, c};
vector<T> v3 = {a, b, c};

// 使用数组初始化vector——《C++ Prime》P112
int int_arr[] = {0, 1, 2, 3};
vector<int> ivec(begin(int_arr), end(int_arr));     // begin和end函数返回数组的首指针和尾后指针
vector<int> subVec(int_arr + 1, int_arr + 4);   // [1, 2, 3]
  • 插入:
test.insert(test.begin(), 1)
vec.insert(vec.end(),3,100);//Inserting 100, 3 times to the vector
  • 合并:
vector<int> vec1 = {...};
vector<int> vec2 = {...};// vec1和vec2都存有内容

vector<int> vec3;//vec3是空的
vec3.insert(vec3.end(), vec1.begin(), vec1.end())//将vec1压入
vec3.insert(vec3.end(), vec2.begin(), vec2.end())//继续将vec2压入
  • 获取值:
    可以通过使用 * vector.begin()*( vector.end() - 1) 来获得 vector 中第一个或最后一个的值;
    也可以直接使用 vector.front()vector.back() 来得到 vector 首尾的值。
vec.front();    // 返回的是第一个元素的引用。
vec.back();     // 返回的的是最后一个元素的引用。
  • 添加值
vec.push_back()     // 将一个新的元素加到vector的最后面
vec.pop_back()      // 删除Vector容器中的最后一个元素
  • resize 和 reverse
// https://blog.csdn.net/yiyeshuanglinzui/article/details/126060891
vec.capacity();
vec.resize(count)
vec.reserve(count)

vec.capacity();表示的容器内可以容纳多少个对象,表示的是能力,是可以,不代表容器内就有这么多个对象。

resize 会调用构造函数,而 reserve 仅仅是开辟内存空间。直观的表现就是 resize 会改变 vector size 的值(此时 capacity 也可能会改变),而 reserve 改变的是 capacity。

  • resize()-实实在在的默认构造

    • count小于当前实际的size,则会析构掉多余的对象
    • count大于当前实际的size,小于等于capacity,则会调用默认构造。
    • count大于capacity,则会调用默认构造和复制构造(构造之前就存在的对象)。
  • reserve()-只分配足够的内存,不构造

    • count大于当前的capacity,则会调用复制构造,构造之前就存在的对象。
    • count小于capacity,则不会有任何影响。
  • 其它

vec.resize(int n, element)   // 表示调整容器vec的大小为n,扩容后的每个元素的值为element,默认为0

// 删除指定位置position的元素,并返回删除元素的下一个元素的迭代器
iterator erase (iterator position);  
// 删除从first到last(不包过last)之间的元素 [first,last),并返回last位置迭代器
iterator erase (iterator first, iterator last); 

vec.front();    // 返回的是第一个元素的引用。
vec.back();     // 返回的的是最后一个元素的引用。

// std::vector::data() 是 C++ 中的 STL,它返回一个指向内存数组的直接指针,该内存数组由向量内部用于存储其拥有的元素。
vector<int> vec = { 10, 20, 30, 40, 50 };
int* pos = vec.data();      // 该函数不接受任何参数
for (int i = 0; i < vec.size(); ++i) cout << *pos++ << " ";

deque(双端队列)

容器 deque (发音为“deck”)和 vector 非常相似。它也采用dynamic array来管理元素,提供随机访问,并有着和 vector 几乎一模一样的接口。不同的是 deque 的 dynamic array 头尾都开放,因此能在头尾两端进行快速安插和删除

  • deque 与 vector 的用法基本一致,除了以下几处不同:
    • deque 没有 reserve 和 capacity,而 vector 有;
    • deque 有 push_front() 和 pop_front() 函数,而 vector 没有;
    • deque 没有 data() 函数,而 vector 有。
// https://blog.csdn.net/qq_43448856/article/details/123009040
c.push_back(elem);	    // 附加一个 elem 的拷贝于末尾
c.pop_back();	    // 移除最后一个元素,但是不返回它
c.push_front(elem);	    // 在头部插入 elem 的一个拷贝
c.pop_front();	    // 移除第一元素(但不返回)

优先队列priority_queue

堆实现的优先队列的时间复杂度为$O(log_n)$

《priority_queue优先队列的使用方法》值得一提的是priority_queue与pair结合:

// 原文链接:https://blog.csdn.net/qq_40946453/article/details/112169855
// 小顶堆 .top 输出是从小到大
priority_queue <pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>> > q;
priority_queue <pair<int,int>,vector<pair<int,int>>,greater< > > q;
priority_queue <tuple<int, int, int>, vector<tuple<int, int, int>>, greater<>> pq;

// 默认大顶堆 .top 输出是从大到小
priority_queue <pair<int,int>,vector<pair<int,int>>,less<pair<int,int>> > q;
priority_queue <pair<int,int>,vector<pair<int,int>>,less< > > q;
priority_queue <pair<int,int>,vector<pair<int,int>> > q;
priority_queue <pair<int,int>> q;
优先队列 + tuple

Dijkstra(节点用两个数据标记)的部分代码

    // 保存的线: 当前节点dis,当前节点(本例为二维节点)
    priority_queue<tuple<int, int, int>, vector<tuple<int, int, int>>, greater<>> pq;
    // pq.push({0, 0, 0});  // 这个不对
    // pq.push(tuple<int, int, int>{0, 0, 0});
    // pq.push(tuple<int, int, int>(0, 0, 0));
    pq.emplace(0, 0, 0);
    dis[0][0] = 0;

    while(!pq.empty()){
        // auto &[t, x, y] = pq.top();  // 不对
        // 这个地方不能加引号
        auto [t, x, y] = pq.top();
        pq.pop();
        // 注意这里done标记的位置
        done[x][y] = true;
        ...
    }

其中emplace这样接受新对象的时候,自己会调用其构造函数生成对象然后放在容器内。而push,只能让其构造函数构造好了对象之后,再使用复制构造函数!相当于emplace直接把原料拿进家,造了一个。而push是造好了之后,再复制到自己家里,多了复制这一步。

所以emplace相对于push,使用第三种方法会更节省内存。

优先队列 + 结构体(自定义排序)
struct Node{
    int cnt, pos, val;
    Node(int cnt, int pos, int val) : cnt(cnt), pos(pos), val(val){};
};
struct cmp{
	bool operator()(Node &a,Node &b){
		return a.cnt == b.cnt ? a.pos < b.pos : a.cnt < b.cnt;
	};
};
priority_queue<Node, vector<Node>, cmp> pq;
// https://en.cppreference.com/w/cpp/container/priority_queue

const auto data = {1,8,5,6,3,4,0,9,7,2};
// Using a custom function object to compare elements.
struct {
    bool operator() (const int l, const int r) const { return l > r; }
} customLess;
std::priority_queue minq3(data.begin(), data.end(), customLess);

// Using lambda to compare elements.
auto cmp = [](int left, int right) { return (left ^ 1) < (right ^ 1); };
std::priority_queue<int, std::vector<int>, decltype(cmp)> q5(cmp);

其它高级用法参考《题目求助|C++11关键字decltype用法》

map

map中的元素进行了排序,而unordered_map并未进行排序。

  • 初始化:map是键-值对的组合,有以下的一些定义的方法:
map<k, v> m;
map<k, v> m(m2);
map<k, v> m(b, e);
  • 插入
    insert函数的插入方法主要有如下:
m.insert(e)
m.insert(beg, end)
m.insert(iter, e)
  • 插入:
    上述的e一个value_type类型的值。beg和end标记的是迭代器的开始和结束。更详细的说明:
unordered_map<int, string> m;

m[1] = "zhangsan";  // 如果已经存在键值 1,则会作赋值修改操作,如果没有则插入
// 插入单个键值对,并返回插入位置和成功标志,插入位置已经存在值时,插入失败
pair<iterator,bool> insert (const value_type& val);
// eg.
map<int, string> mapStudent;
mapStudent.insert(map<int, string>::value_type (1, "student_one"));

//在指定位置插入,在不同位置插入效率是不一样的,因为涉及到重排
iterator insert (const_iterator position, const value_type& val);

void insert (InputIterator first, InputIterator last);  // 插入多个
void insert (initializer_list<value_type> il);  //c++11开始支持,使用列表插入多个   
  • 查找
    若只是查找该元素是否存在,可以使用函数m.count(k),该函数返回的是k出现的次数;若是想取得key对应的值,可以使用函数m.find(k),该函数返回的是指向该元素的迭代器,若失败返回的是m.end()
auto it = m.find(e);
if(it != m.end()){
    cout << it->first << " " << it->second << endl;
}
  • 遍历
map<int, int> mp;
for (auto p : mp) cout << p.first << ' ' <<   p.second << endl;
// 或
map<int, int> mp;
map<int, int>::iterator iter;
for(iter = mp.begin();iter != mp.end();iter ++)
    cout << iter->first << ' ' << iter->second << endl;

set

参考《c++ unordered_set详细操作》

对于另一种 unordered_set 容器,可直译为“无序 set 容器”。即 unordered_set 容器和 set 容器很像,唯一的区别就在于 set 容器会自行对存储的数据进行排序,而 unordered_set 容器不会。

unordered_set<int> set1;        // 创建空的set
unordered_set<int> set2(set1);  // 拷贝构造
unordered_set<int> set3(set1.begin(), set1.end());  // 使用迭代器构造
unordered_set<int> set4(arr,arr+5);     // 使用数组作为其初值进行构造
unordered_set<int> set5(move(set2));    // 移动构造
unordered_set<int> set6 {1,2,10,10};    // 使用处置列表进行构造

set1.rbegin();set1.rend();  // 指向起始和末尾的逆向迭代器

常用内置函数:

set1.empty();   // 若容器为空,则返回 true;否则 false
set1.find(2);   // 查找2,找到返回迭代器,失败返回end()
set1.count(2);  // 返回指2出现的次数,0或1
set1.emplace(3);    // 使用转移构造函数添加新元素3,比insert效率高
set1.clear();   // 清空

insert插入元素:

set1.insert(3);     //插入元素,返回pair<unordered_set<int>::iterator, bool>
set1.insert({1,2,3});   //使用initializer_list插入元素
set1.insert(set1.end(), 4); //指定插入位置,如果位置正确会减少插入时间,返回指向插入元素的迭代器
set1.insert(set2.begin(), set2.end());  //使用范围迭代器插入

关于insert函数的返回值:
insert()只传入单个参数(待插入元素):

  1. 会返回一个 pair 对象
  2. 这个 pair 对象包含一个迭代器,以及一个附加的布尔值用来说明插入是否成功
  3. 如果元素被插入,返回的迭代器会指向新元素
  4. 如果没有被插入,迭代器指向阻止插入的元素
auto pr = words.insert("ninety"); // Returns a pair - an iterator & a bool value

insert()传入两个参数(迭代器+待插入元素):

  1. 可以用一个迭代器作为insert()的第一个参数,它指定了元素被插入的位置
  2. 在这种情况下,只会返回一个迭代器
auto iter = words.insert (pr.first, "nine"); // 1st arg is a hint. Returns an iterator

insert()传入初始化列表:

  1. 插入初始化表中的元素
  2. 在这种情况下,什么都没有返回
words.insert({"ten", "seven", "six"});  // Inserting an initializer list

erase()函数——删除元素

int flag = set1.erase(1);  //删除操作,成功返回1,失败返回0

// 删除操作,成功返回下一个pair的迭代器
// 可使用该方法进行循环删除
set<int>::iterator it = set1.erase(set1.find(1));   

// 删除set1的所有元素,返回指向end的迭代器
set<int>::iterator it = set1.erase(set1.begin(), set1.end());   

XXX注意,删除最后一个元素的迭代器,会返回指向新的最后一个元素的迭代器,参考

TODO:输出end()的迭代器能够输出最后一个值

#include <iostream>
#include <bits/stdc++.h>
using namespace std;

int main()
{
   	// cout << "Hello World";
	
	set<int> sset = {1,2,3,4,5};
	auto it = sset.begin();
	
	for(auto i=it;i!=sset.end();i++) cout << *i << " ";
	cout << endl;
	
	int cnt = 7;
	auto t = it;
	for(;t!=sset.end() && cnt > 0;t++,cnt--) cout << *t << " ";
	cout << ": " << bool(t == sset.end()) << endl;
	
	cnt = 5;
	t = it;
	t++;
	for(;t!=sset.end() && cnt > 0;++t,++t,cnt--) cout << *t << " ";
	cout << ": " << bool(t == sset.end()) << endl;
	
	cout << ": " << *t << endl;
	t++;
	cout << ": " << *t << endl;
	
	cnt = 5;
	t = it;
	for(;t!=sset.end() && cnt > 0;++t,++t,cnt--) cout << *t << " ";
	cout << ": " << bool(t == sset.end()) << endl;
	
	t = sset.erase(t);
	cout << ": " << bool(t == sset.end()) << endl;
	cout << *t << endl;
	
	
	cout << endl;
   	return 0;
}

pair

//原文链接:https://blog.csdn.net/sevenjoin/article/details/81937695

// 创建一个空的pair对象(使用默认构造),它的两个元素分别是T1和T2类型,采用值初始化。
pair<T1, T2> p1;            
// 创建一个pair对象,它的两个元素分别是T1和T2类型,其中first成员初始化为v1,second成员初始化为v2。
pair<T1, T2> p1(v1, v2);    
// 以v1和v2的值创建一个新的pair对象,其元素类型分别是v1和v2的类型。
make_pair(v1, v2);          
// 两个pair对象间的小于运算,其定义遵循字典次序:如 p1.first < p2.first 或者 !(p2.first < p1.first) && (p1.second < p2.second) 则返回true。
p1 < p2;                    
// 如果两个对象的first和second依次相等,则这两个对象相等;该运算使用元素的==操作符。
p1 == p2;                  
p1.first;                   // 返回对象p1中名为first的公有数据成员
p1.second;                 // 返回对象p1中名为second的公有数据成员

vector后入pair(eg. {a, b})的四种写法:

  • emplace(a, b)
  • emplace(make_pair(a, b))
  • push_back({a, b})
  • push_back(make_pair(a, b))

tuple

参考
元组tuple是C++的一个模板,不同tuple类型的成员类型也不相同,但是一个tuple可以有任意数量的成员。
每个tuple类型的成员个数是一定的,但是不同的tuple成员个数可以不同。

// 初始化
tuple<int, string, vector<int>> test{1, "hello,world", {4, 5, 6}};
auto test2 = make_tuple(3.14, "wasd");

// 在C++标准库里,有一个名为get的函数模板。为了使用get,
// 我们必须指定一个显式模板实参来指示访问的第几个成员,并在函数参数中给予它一个tuple对象。
tuple<int, string, vector<int>> test{ 1,"hello,world",{4,5,6} };
cout << get<0>(test) << endl;		//打印test第一个成员,其类型为int
cout << get<1>(test) << endl;		//打印test第二个成员,其类型为string
cout << get<2>(test)[0] << endl;	//打印test第三个成员vector<int>的第一个元素

函数

数学

  • 统计数字在二进制下“1”的个数——__builtin_popcount()
    该函数是C++自带的库函数,内部实现是用查表实现的。
    作用:统计数字在二进制下“1”的个数。

字符、字符串

isalpha()   // 用来判断一个字符是否为字母
isalnum()   // 用来判断一个字符是否为数字或者字母,也就是说判断一个字符是否属于a~ z||A~ Z||0~9。
isdigit()   // 用来检测一个字符是否是十进制数字0-9
islower()   // 用来判断一个字符是否为小写字母,也就是是否属于a~z。
isupper()   // 和islower相反,用来判断一个字符是否为大写字母。

// 以上部分为宏定义,并非真正函数。

toupper()   // 将小写字母转换为大写字母
tolower()   // 将大写字母转换为小写字母
// 或
char c = 'a'; c ^= 32;
// 由于每个字符的大小写形式刚好差了 32,因此在大小写装换时可以用 c⊕32 来进行转换和恢复。

对数组操作

  • 二分查找:

lower_bound() 函数用于在指定区域内查找不小于目标值的第一个元素。

int right = lower_bound(arr.begin(), arr.end(), x) - arr.begin();

相对应的upper_bound 用于在指定范围内查找大于目标值的第一个元素。

//查找[first, last)区域中第一个大于 val 的元素。
ForwardIterator upper_bound (ForwardIterator first, ForwardIterator last, const T& val);
//查找[first, last)区域中第一个不符合 comp 规则的元素
ForwardIterator upper_bound (ForwardIterator first, ForwardIterator last, const T& val, Compare comp);

lower_bound重写排序方法lambda函数,实际上第一个参数是数组的个体,第二个参数是lower_bound的第三个参数即查询值即可。

int cp = lower_bound(col[j].begin(), col[j].end(), down, [&](auto &a, auto &b){
    return a.first > b;
}) - col[j].begin();

还有equal_range该方法返回一个 pair 对象(包含 2 个双向迭代器),其中 pair.first 和 lower_bound() 方法的返回值等价,pair.second 和 upper_bound() 方法的返回值等价。也就是说,该方法将返回一个范围,该范围中包含的值为 val 的元素(但特殊的,对于set 容器自实现的equal_range方法,由于set中各个元素是唯一的,因此该范围最多包含一个元素)。

XXX注意:对于部分STL容器来说使用其自带的lower_bound等方法更快(eg. set是红黑树)。参考

  • 快速获取最大最小元素
/*
param begin : 序列起始地址(迭代器)
param end  : 序列结束地址(迭代器)
return   : 序列中最小元素地址(迭代器)
*/
min_element(nums.begin(), nums.end());
 
/*
param begin : 序列起始地址(迭代器)
param end  : 序列结束地址(迭代器)
return   : 序列中最大元素地址(迭代器)
*/
max_element(nums.begin(), nums.end());

// 前面加*直接取值
vector<int> nums = {1, 2, 3};
int maxv = *max_element(nums.begin(), nums.end());

  • 快读获取第n个元素
// 从某个序列中找到第 n 小的元素 K,并将 K 移动到序列中第 n 的位置处。
// 无返回值
nth_element(nums.begin(), nums.begin() + nums.size() / 2, nums.end());
auto nth_v = nums[nums.size() / 2];
  • 用递增序列对数组初始化——iota(希腊字母表的第9个字母,艾欧塔) 文档:用一个从value递增的数列给[first, last)的容器赋值
#include <numeric>

int numbers[10];
std::iota (numbers,numbers+10,100);     // fill with 100 101 102 103 104 105 106 107 108 109
  • 数组去重——unique
    unique函数可以删除有序数组中的重复元素:
    • 这里的删除不是真的delete,而是将重复的元素放到容器末尾
    • unique函数的返回值是去重之后的尾地址
    • 一定要先对数组进行排序才可以使用unique函数
#include <algorithm>

int arr[10]={5,8,4,12,6,8,9,5,10,3};
sort(arr, arr + 10);       //记得先排序
int len;            //用一个len来记录无重复元素的数组的长度 
len = unique(arr, arr + 10) - arr;

  • 求和
    参考《C++ accumulate函数用法详解》:
    前两个参数是定义序列的输入迭代器,第三个参数是和的初值;第三个参数的类型决定了返回值的类型。第二个版本的第 4 个参数是定义应用到总数和元素之间的二元函数对象。这时,我们在必要时可以定义自己的加法运算。例如:
std::vector<int> values {2, 0, 12, 3, 5, 0, 2, 7, 0, 8};
int min {3};
auto sum = std::accumulate(std::begin(values), std::end(values), 0, [min] (int sum, int v)
{
    if(v < min)
        return sum;
    return sum + v;
})

数学

最大公约数

#include <algorithm>
inline int gcd(int a,int b) {    
    return __gcd(a,b);
}

其它自实现最大公约数可参考:《【C++】gcd函数的写法》

语法

char[0] 柔性数组

本来是为了探究cv::Mat初始化的一种参数data的类型为什么可以是uchar*,(并且mmdeploy也是这么用的),但是还是不太懂,先记一下。

《char a[0] 柔性数组》
《[C/C++] char data[0](柔性数组)》

结构体中初始化数组

以字典序模板为例

struct Node{
    // vector<Node*> chld(26);  // 编译器可能无法区分这是一个成员函数声明还是一个成员变量声明
    // Node *chld[26]{};     // 应采用这种
    // https://blog.csdn.net/qq_32523711/article/details/107798999
    vector<Node*> chld = vector<Node*>(26);     // 明确这是一个成员变量声明
    int score = 0;
    int cnt = 0;
    
    friend bool operator < (Node &a, Node &b) {
        return a.score < b.score;
    }
    
    Node(int score) : score(score), cnt(cnt) {};
};

lambda表达式

《C++ Lambda表达式的基本使用》

const 和 constexpr

C++ const 和 constexpr 的区别? - 知乎

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/558238.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Vue2 移动端(H5)项目封装弹窗组件

前言 因vant-ui的dialog组件没有自定义footer插槽 效果 参数配置 1、代码示例&#xff1a; <t-dialog :visible.sync"show" :title"title" submit"submit"></t-dialog>2、配置参数&#xff08;t-dialog Attributes&#xff09; 参…

吹爆,一款实用的个人IT工具箱

作为一名开发人员&#xff0c;我们在日常工作和学习中常常需要使用一系列小工具&#xff0c;如JSON格式化、JSON转表格、当前时间戳、XML格式化、SQL格式化、密码生成以及UUID生成等。通常情况下&#xff0c;我们会在网上搜索各种在线工具来满足这些需求。 然而&#xff0c;这…

DePIN 赛道黑马,peaq network 如何打造全新 Web3 物联网?

当 Web2 公司仍对用户数据和资料进行“中心化”的收集与控制时&#xff0c;我们虽享受到了物联网技术的便利&#xff0c;却依旧没有逃脱个人数据和价值所有权的剥夺。由此&#xff0c;Web3 技术开始深入物联网世界&#xff0c;智能家居、智能汽车、智能手机都成为重要发力点&am…

冯喜运:4.19黄金,原油市场情绪分析:近期油价可能会回落?

【 黄金消息面解析】&#xff1a;周四(4月18日)&#xff0c;黄金上涨&#xff0c;现货金报每盎司2.384.83美元&#xff0c;上涨1%。中东地区持续的紧张局势未现缓和&#xff0c;继续扶持黄金逗留在历史高价位区域。周二美联储主席鲍威尔讲话&#xff0c;对何时可能降息三缄其口…

计算机比赛什么含金量高

acm含金量不如天梯&#xff0c;和蓝桥杯是同一层次 先说结论&#xff0c;根据专家讨论结果&#xff0c;蓝桥国一水平和icpc金牌含金量一样。&#xff08;doge 赢&#xff01;瑶瑶另先&#xff01; 会统计就多统计&#xff0c;我们acmer就是爱看这种数据 https://www.gxxsjs.co…

基于ssm高校宿舍管理系统论文

摘 要 当下&#xff0c;正处于信息化的时代&#xff0c;许多行业顺应时代的变化&#xff0c;结合使用计算机技术向数字化、信息化建设迈进。以前学校对于宿舍信息的管理和控制&#xff0c;采用人工登记的方式保存相关数据&#xff0c;这种以人力为主的管理模式已然落后。本人结…

探索 Nacos反序列化漏洞CNVD-2023-45001

在软件开发领域&#xff0c;安全漏洞是一项不容忽视的重要问题。最近&#xff0c;我们的安全团队发现了一个影响到我们的Nacos 2.1.0版本的反序列化漏洞&#xff0c;可能带来严重的安全威胁。我们已经立即采取了修复措施。本文将深入探讨这些漏洞的原理、可能造成的影响&#x…

拷贝构造函数与运算符重载

目录 一、拷贝构造函数 1.概念 2.特性 二、运算符重载 1.运算符重载 2.运算符重载实现的形式 3.赋值运算符重载 一、拷贝构造函数 1.概念 拷贝构造函数是一种特殊的构造函数&#xff0c;它在创建对象时&#xff0c;使用同一类中之前创建的对象来初始化新创建的对象…

C# 动态加载dll

方式1 using System; using System.Reflection;class Program {static void Main(){string dllPath "path/to/your/library.dll"; // 替换为你的DLL文件路径Assembly myAssembly Assembly.LoadFile(dllPath);Type myType myAssembly.GetType("YourNamespace…

力扣—2024/4/18—从双倍数组中还原原数组

代码实现&#xff1a; 快排 哈希表 ——超时 /*** Note: The returned array must be malloced, assume caller calls free().*/ void swap(int *m, int *n) {int temp *m;*m *n;*n temp; }// 快排 void sort(int *a, int l, int r) { // 左闭右开if (r - l < 2) {if (r…

MIMO(多天线)通信的四种译码算法

目录 一. 介绍 二. 极大似然译码 三. 破零译码算法 四. 最小均方误差算法 五. 球形译码 一. 介绍 发射天线数记为Mt&#xff0c;接收天线数记为Mr。由此发射信号x为向量&#xff1a; 接受信号y为向量&#xff1a; 信道H为矩阵&#xff1a; 利用n代表噪声向量&#xff0c;…

axios的封装理解和基本使用

axios的配置 ruoyi的前端对axios进行了封装&#xff0c;让我们发get请求或者是post请求更加方便了。 ruoyi对axios的封装在下面文件中&#xff1a;打开文件&#xff0c;可以看到它有三个显眼的方法&#xff0c;分别是request拦截器、response拦截器和通用下载方法。ruoYi接口地…

CommunityToolkit.Mvvm笔记---ObservableValidator

ObservableValidator 是实现 INotifyDataErrorInfo 接口的基类&#xff0c;它支持验证向其他应用程序模块公开的属性。 它也继承自 ObservableObject&#xff0c;因此它还可实现 INotifyPropertyChanged 和 INotifyPropertyChanging。 它可用作需要支持属性更改通知和属性验证的…

Redis中的Lua脚本(五)

Lua脚本 脚本复制 复制EVALSHA命令 EVALSHA命令式所有与Lua脚本有关的命令中&#xff0c;复制操作最复杂的一个&#xff0c;因为主服务器与从服务器载入Lua脚本的情况可能有所不同&#xff0c;所以主服务器不能像复制EVAL命令、SCRIPT LOAD命令或者SCRIPT FLUSH命令那样&…

2024 Polkadot Decoded 大会亮点前瞻,立即预定参会席位

原文&#xff1a;https://medium.com/polkadotnetwork/polkadot-decoded-2024-uniting-innovators-in-blockchain-technology-75fc3d8e93fe 作者&#xff1a;Polkadot 编译&#xff1a;OneBlock Polkadot 生态宣布他们的旗舰活动 —— Polkadot Decoded 将再次举行&#xff…

跟TED演讲学英文:How AI could empower any business by Andrew Ng

How AI could empower any business Link: https://www.ted.com/talks/andrew_ng_how_ai_could_empower_any_business Speaker: Andrew Ng Date: April 2022 文章目录 How AI could empower any businessIntroductionVocabularyTranscriptSummary后记 Introduction Expensiv…

von Mises-Fisher Distribution (Appendix 2)

5.3 Fast Python Sampler of the von Mises Fisher Distribution [3] 从论文中 p r o c e d u r e A n g l e G e n e r a t o r ( d , κ ) procedure~AngleGenerator(d, κ) procedure AngleGenerator(d,κ) 中的变换来看, 假设 y ∼ B e ( m − 1 2 , m − 1 2 ) y \sim …

Linux【实战】—— LAMP环境搭建 部署网站

目录 一、介绍 1.1什么是LAMP&#xff1f; 1.2LAMP的作用 二、部署静态网站 2.1 虚拟主机&#xff1a;一台服务器上部署多个网站 2.1.1 安装Apache服务 2.1.2 防火墙配置 2.1.3 准备网站目录 2.1.4 创建网站的配置文件 2.1.5 检查配置文件是否正确 2.1.6 Linux客户端…

【华为 ICT HCIA eNSP 习题汇总】——题目集17

1、以下哪项不属于网络层安全威胁&#xff1f; A、DDos攻击 B、钓鱼攻击 C、IP Spoofing D、IP地址扫描 考点&#xff1a;网络安全 解析&#xff1a;&#xff08;B&#xff09; 钓鱼攻击通常被认为是应用层的安全威胁&#xff0c;也有在网络层进行伪装实施钓鱼攻击&#xff0c;…

TCP/IP常用协议栈图解

1.引言 最近看了一些计算机网络的课程&#xff0c;总结借鉴了一些TCP/IP常用协议&#xff0c;罗列在以下图中&#xff0c;以便有一个整体观。 2.图解 先上图 3.总结 TCP/IP协议是实际用的计算机网络通信的标准协议栈&#xff0c;自上而下分为应用层&#xff0c;传输层&#xf…