数据结构&算法 (C++) 个人总结


前言

STL总结


# 易错语法
// c只能是int / char 不可以是string
switch(c){
 	case 1:xxx;break;
 	case 2:xxx;break;
 	default:break;
}

常用C++库函数


isalpha(char c) 字母字符
isdigit(char c) 数字字符
isallnum() 等价于 isalpha()||isdigit()
isupper(char c) 大写
islower(char c) 小写
toupper(char c)
tolower(char c)
__gcd(x, y) //最大公约数,最小公倍数=x*y/gcd(x,y)

字符串全变小写
transform(tmp.begin(),tmp.end(),tmp.begin(),::tolower); //大写 toupper

//手写
long gcd(long a, long b) [return b == 0 ? a : gcd(b, a % b);}
 

INT_MAX
INT_MIN
LONG_MAX

关于取模

在过程中取模,为防止溢出可以用long long,同时前面声明一个mod变量(以防玄学bug)

class Solution {
public:
    int mod = 1e9 +7;
    int maximumProduct(vector<int>& nums, int k) {
       xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
       long long res;
        while(!pq.empty()){
            res = (res*pq.top()) % mod;
            pq.pop();
        }
        return res;
    }
};

STL排序

sort

有stl算法,也有stl容器带的成员函数。我一般习惯使用stl算法 即 sort(a.begin,a.end());
但根据《effective stl》同名情况的容器成员函数要比算法高效。

sort(a.begin(), a.end(), std::greater<>()); //降序 
sort(a.begin(), a.end(), std::less<>()); //升序

partial_sort

排序前n个

bool cmp(int &a, int &b) {
    return a > b;
}
partial_sort(nums.begin(),nums.begin()+k,nums.end(),cmp); 
//把按照cmp的前k个放到前k个的位置
注意!第二个参数是开区间

nth_element

找出前n个(前n个本身无序)
与partial_sort参数一致

partition

保证i左边满足条件a,右边满足条件!a,类似快排的一次定基准。

数组

strlen(a)//数组长度
memset(a,0,sizeof(a));//初始化数组,只能初始化为0或-1
memset(a,1,sizeof(a));

strlen和sizeof的区别

1 strlen求的是字符串的长度 以\0结尾 sizeof求的是大小

char str[20] = "hello";
printf("strlen: %d\n", strlen(str));
printf("sizeof: %d\n", sizeof(str));

2 sizeof可以用类型或者函数作参数,sizeof只能用char*

pair

pair内部甚至可以用vector。 ex.pair<string,vector< int >>

stack

stack<int> mystack;
mystack.push(i);		//入栈
mystack.pop();		//弹栈
mystack.top();        //返回栈顶值 
mystack.size();
if(!mystack.empty()) //如果栈非空 即 若栈为空,s.empty()=1

注意:不能直接访问mystack[i],无自带迭代器,遍历需要自行设置循环
while(!mystack.empty)
{top();pop();}
or
int n=mystack.size();
for(int i=0;i<n;i++)
{top();pop();}



栈不好用双指针模拟

queue

queue<int> que; 

que.push(i);	//队尾入队
que.pop();		//队首出队
que.back();		//返回队尾
que.front();	//返回队首
!!这里要注意,所以一般都用front(),因为是队尾入队,队首出队。

empty() //是否为空
size()  //队列大小

注意:不能直接访问queue[i], 且无自带迭代器

队列能用双指针模拟

deque

deque<int> dq;
dq.emplace_back(1);
dq.empace_front(2);
int back = dq.back();
int front = dq.front();
dq.pop_back();
dq.pop_front();

有迭代器
且可以通过dq[i]访问已有元素。
https://www.cplusplus.com/reference/deque/deque/operator[]/

priority_queue

关于遍历
和queue一样,没有迭代器

top 访问队头元素  此处与队列的front不同
empty 队列是否为空
size 返回队列内元素个数
push 插入元素到队尾 (并排序)
emplace 原地构造一个元素并插入队列
pop 弹出队头元素
swap 交换内容

在queue的基础上,让优先级高的排在了队列前面,队列中优先级max排在队首。本质上维护了一个堆。

//默认是大顶堆,即队头为队内最大值,(从队头到队尾)降序队列(less)
priority_queue<int,vector<int>,less<int> >que; //注意最后面>空格> 
//小顶堆,即队头为队内最小值,升序队列(greater)
priority_queue<int,vector<int>,greater<int> >que;
//pair的情况
priority_queue<pair<int,int>,vector<pair<int,int>>,cmp> que;

三个参数的含义:1.队内每个元素的类型 2.队整体的类型:直接vector<1>即可 3.排序方法(可重载)

注意:其中“1”可以为相当多的类型,比如说为pair,tuple,甚至vector,这样就能利用上自带的排序。

cmp重载方法

1 单独struct重载cmp(): 用于set map 优先队列 <,,cmp> ex. set<int,cmp>
//cmp重载方法 1.放到结构体里 2.排序与sort正好相反(升序 return a>b;降序 return a<b)
struct cmp1{  
    bool operator ()(int a,int b){  
        return a>b;//最小值优先  
    }  
};  
struct cmp2{  
    bool operator ()(int a,int b){  
        return a<b;//最大值优先  
    }  
};  
struct cmp3{
	bool operator (){pair<int,int> a, pair<int,int> b}{
		return a.second<b.second; //第二个元素最大值优先
	}
}
2 结构体内重载< :用于使用结构体的情况 --见fly刷题笔记

3 sort时重载cmp
bool cmp();
sort(a,a+n,cmp);


这里对重载sort方法的cmp又有了更深的理解。
bool cmp(int a, int b){
    return expression;
}
expression为一个表达式
若expression为true,则顺序就按参数列表里的顺序不变,即先a后b
若expression为false,则先b后a

因此,return a<b是升序,反之是降序。
当然expression也可以不包含a和b,只要是表达式即可。

以上在传参的过程中使用值传递或者引用传递&均可

 - 值传递 void x(int a):形参的变化不影响实参
 - 指针传递 void x(int *a):传递地址,所以会影响外界
 - 引用传递 void x(int &a):形参是实参的“小名”,形参的变化影响实参

string

截取子串substr(起始地址,长度)

string s="abcdefg";
s.substr(1,4)  //"bcde"
不写第二个参数即一直到结尾 
s.substr(2) //c->结尾  

erase() 去除string中的某段字符

str.erase (str.begin()+1, str.end()-5); //去掉了bc
str.erase(1,2); //去掉了bc (这时的第二参数代表长度)

string to int

string s="12345";
int num = stoi(s);
//int num = atoi(s.c_str());  

int to string

int x;
string s =to_string(x);  

char to int

char c ='1';
int x=c-'0' 

int to char

int c =1;
char x= c+48;

string ‘+’ 可以是char 也可以是string

string s="12345";
string s1="1";
char c = '1';
s=s+s1;
s=s+c;  //这种可以,因为有一个s作为加法的一部分,两个c相加则不可以。

char to string

10种方法

常用的如下:
string s;
char c = 'c';
s = c;
s.emplace_back(c);
s += c;
注意,以下的几种不可以!!!
string s = c;(必须分两步)
string s;
s = c + c;(先要构造出一个s在进行加法)

string to char

string s;
s[0],s[1]

string to char*

string s;
s.c_str();

寻找子串
find() //返回子串在主串中的起始位置

string str;
char c;

size_t pos = str.find(c,lastpos);
//从lastpos往后找的第一个c的位置
//用size_t是因为找不到了会返回string::npos
注意!
map的find找不到返回end()
string的find找不到返回string::npos

替换字串
replace() //找到子串,并替换为新的子串

string s;//主串
string lasts;//子串
string news;//新的子串
int i=s.find(lasts);//返回子串在主串中的起始位置
if(i!=std::string::npos)//找不到的情况
s=s.replace(s.find(lasts),lasts.size(),news);
//第一个参数,想要替换的起始位置,子串长度,新的子串

关于手写子串全部替换replace

void replace(string sub, string rep, string & s){
	size_t pos = 0;
	pos = s.find(sub);
	while(pos!=string::npos){
	    s.replace(pos,sub.size(),rep);
	    pos = s.find(sub);
	}
	return ;
 }
string a;
string b;
vector<int> ca(26),cb(26); //这个方法可以直接给vector设置大小,且初值为0
int n=a.size(),m=b.size();
for(char c:a) ca[c-'a']++; //string的迭代简化
for(char c:b) cb[c-'a']++;

(str1) int compare(pos,len,str2) //pos len是str1的

int ret = str1.compare(pos,len,str2);
ret = 0 -> =
ret > 0 -> str1 > str2 
ret < 0 -> str1 < str2

关于 +=
!!!注 意 !!!
+=比 = x+要快很多!!!
https://blog.csdn.net/weixin_43222324/article/details/106814953

list

参考链接

list构造函数

list<T> lstT;//list采用采用模板类实现,对象的默认构造形式:
list(beg,end);//构造函数将[beg, end)区间中的元素拷贝给本身。
list(n,elem);//构造函数将n个elem拷贝给本身。
list(const list &lst);//拷贝构造函数。

list数据元素插入和删除操作

push_back(elem);//在容器尾部加入一个元素
pop_back();//删除容器中最后一个元素
push_front(elem);//在容器开头插入一个元素
pop_front();//从容器开头移除第一个元素
insert(pos,elem);//在pos位置插elem元素的拷贝,返回新数据的位置。
insert(pos,n,elem);//在pos位置插入n个elem数据,无返回值。
insert(pos,beg,end);//在pos位置插入[beg,end)区间的数据,无返回值。
clear();//移除容器的所有数据
erase(beg,end);//删除[beg,end)区间的数据,返回下一个数据的位置。
erase(pos);//删除pos位置的数据,返回下一个数据的位置。
remove(elem);//删除容器中所有与elem值匹配的元素。

list大小操作

size();//返回容器中元素的个数
empty();//判断容器是否为空
resize(num);//重新指定容器的长度为num,
若容器变长,则以默认值填充新位置。
如果容器变短,则末尾超出容器长度的元素被删除。
resize(num, elem);//重新指定容器的长度为num,
若容器变长,则以elem值填充新位置。
如果容器变短,则末尾超出容器长度的元素被删除。


list赋值操作

assign(beg, end);//将[beg, end)区间中的数据拷贝赋值给本身。
assign(n, elem);//将n个elem拷贝赋值给本身。
list& operator=(const list &lst);//重载等号操作符
swap(lst);//将lst与本身的元素互换。

list数据的存取

front();//返回第一个元素。
back();//返回最后一个元素。

list反转排序

reverse();//反转链表,比如lst包含1,3,5元素,运行此方法后,lst就包含5,3,1元素。
sort(); //list排序 使用方式:l.sort();

list iterator的prev和next
prev() next()

实操使用细节

#include<bits/stdc++.h>
using namespace std;
list<int> l(5,0); //list的初始化,第一个参数代表长度,第二个参数代表每个节点的值
void preinsert(int i,int x) //在第i个节点前插入x  (i从0到n-1)
{
    if(l.size()==0&&i==0) l.push_back(x);
    if(i>=l.size()) return; //错误指令

    int times=i;
    /*
    insert和erase要注意迭代器失效的情况,通过这种遍历方式可以避免。
    同时,这种处理的方式是万能的,map,hash都可以尝试用这种方式解决迭代器失效的问题
    list自带的insert就是在该节点前插入新值
    写break是因为这道题每次只操作一个点
    */

    for(auto it=l.begin();it!=l.end();)
    {
        if(times==0)
        {
            it = l.insert(it,x);
            break;
        }
        else ++it;

        times--;
    }
}
void nextinsert(int i,int x)//在第i个节点后插入x
{
    if(l.size()<=i) return;
    int times=i;
    //list自带的insert是在该节点前插入新值
    //因此,可以使用stl的next(),自动调用该节点的下一个,同时这种方法也不用担心最后的null,stl内部已经考虑到了
    for(auto it=l.begin();it!=l.end();)
    {
        if(times==0)
        {
            auto p =next(it);
            l.insert(p,x);
            break;
        }
        else ++it;
        times--;
    }
}
void replacel(int i,int x)//把第i个节点的值替换为x
{
    if(l.size()<=i) return;
    int times=i;
    for(auto it=l.begin();it!=l.end();)
    {
        if(times==0)
        {
            *it=x;
            break;
        }
        else ++it;
        times--;
    }
    /*
    or
    int times=i;
    for(auto &it:l)
    {
        times--;
        if(times==0)
        {
            it=s;
            break;
        }
    }
    */
}
void erasel(int i)//把第i个节点去掉
{
    if(l.size()<=i) return;
    int times=i;
    for(auto it=l.begin();it!=l.end();)
    {
        if(times==0)
        {
            it=l.erase(it);
            break;
        }
        else ++it;
        times--;
    }
}
void print()//打印
{
    for(auto elem:l) cout<<elem<<" ";
    cout<<endl;
}
int main()
{
    print();
    preinsert(0,1);
    print();
    nextinsert(0,2);
    print();
    replacel(2,3);
    print();
    erasel(1);
    print();
    return 0;
    /*
    output:
    0 0 0 0 0
    1 0 0 0 0 0
    1 2 0 0 0 0 0
    1 2 3 0 0 0 0
    1 3 0 0 0 0
    */
}

vector

当作数组来用即可

vector无法直接cout,需要遍历输出。
vector遍历不用迭代器也可,有时不用更方便

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

bool cmp(int a, int b)
{
    return a>b;
}
int main()
{
    //新建 输入 输出
    vector<int>a;
    vector<int>b;
    for(int i=0;i<5;i++)
    {
        a.push_back(i);
        // b[i]=i;     ATTENTION! WRONG! 下标只能获取元素,不能新建
        b.push_back(2*i);
        cout<<"a"<<a[i]<<" ";
        cout<<"b"<<b[i]<<" ";
    }
    cout<<endl;
    //去掉容器最后的数据
    for(int i=0;i<a.size();i++)
    {
        a.pop_back();
    }
    //排序
    sort(b.begin(),b.end(),cmp);//默认升序排列,降序排列的改变

    //迭代器使用
    cout<<"after sorting"<<endl;
    for(auto iter=b.begin();iter!=b.end();++iter)
    {
        //cout<<b[i]<<endl;
        cout<<*iter<<" ";
    }
    cout<<endl;
    reverse(b.begin(),b.end()); //容器的颠倒
    cout<<"after reversing"<<endl;
    
    //伪迭代器使用(加&后循环内部可以改变vector本身,无&时无法改变本身,只为使用)
    for(auto &elem:b)
    {
        cout<<elem<<" ";
    }
    
    //清除容器所有数据
    b.clear();
    return 0;
}

reverse(res.begin(),res.end());//反转vector

关于去重:unique和resize连用,因为unique会把多余的元素放在后面
需要注意,使用前要先sort,因为unique只能消除相邻的重复元素

sort可以排序嵌套的vector,例如下面例子的res类型是vector<vector< int >>

swap交换vector内部的值

关于赋初值:vector不能用memset,数组可以 memset(a,0,sizeof(a))
用resize即可
resize(n,value); 第二个参数为vector元素的默认值,不写第二个参数默认为0

需要注意注意注意的是!!!!

需要注意注意注意的是!!!!resize不与memset等价,
它不会改变已有的值,所以可以先clear,再resize。
https://www.icode9.com/content-4-855235.html 

初始化vector也可以这样:vector a(10);
默认开一个10空间且值为0的vector,很方便!

        sort(res.begin(),res.end());//去重
        res.resize(unique(res.begin(),res.end())-res.begin());
        这里也可以
        int n = unique(res.begin(),res.end())-res.begin();
        实际上[0-n)的范围内是去重

		swap(res[2],res[4]);
		res.back();//res的最后一个元素 相当于栈顶

当vector作参数时,
参数改变外界:用引用 vector &a;
不改变:vector b;
地址(*a)一般不用,因为调用的时候需要(*a)[i],相比于其他两种直接a[i],这种比较麻烦

  vector<vector<int> > input(2,vector<int>(5,1)); //注意初始化内部的vector<int>
    for(auto elem:input)
    {
        for(auto x:elem)
        {
            cout<<x<<" ";
        }
        cout<<endl;
    }
//对应输出 
1 1 1 1 1
1 1 1 1 1

关于二维vector的初始化

vector<vector<int>> res(r, vector<int>(c, 0));
//r行 每行c列


当第二维度各个长度不确定等后续push_back时
res.resize(n);//即可

当第二维度的各个长度不一致且有确定值的时候
二维数组全局变量visit赋值 先构造一个一维 不能直接resize二维()
vector<bool> tmp(board[0].size(),false);
visit.resize(board.size(),tmp);

当第一维度不确定第二维度确定时
https://blog.csdn.net/u013040591/article/details/80329066?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1.pc_relevant_paycolumn_v3&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1.pc_relevant_paycolumn_v3&utm_relevant_index=2

二维数组玄学报错 同一层次 不能既resize又push_back
//报错
//因为 pas已经初始化空间为5,后面还push_back
vector<vector<int>> pas(5);
pas.push_back(1);
vector<int> t;
t.push_back(0);
pas.push_back(t);
cout<<pas[1][0]<<endl;

//正确
vector<vector<int>> pas;
vector<int> t;
t.push_back(0);
pas.push_back(t);
pas.push_back(t);
cout<<pas[1][0]<<endl;


vector的insert

insert(iterator it,const T& x):向量中迭代器指向元素前增加一个元素x
insert(iterator it,int n,const T& x):向量中迭代器指向元素前增加n个相同的元素x
insert(iterator it,const_iterator first,const_iterator last):向量中迭代器指向元素前插入另一个相同类型向量的[first,last)间的数据

ex. vec.insert(vec.begin(),1);在vector[0]前面插入一个0

vector的实用操作

set

关于遍历
需要使用迭代器

相当于没有value的map
插入后自带排序,底层实现红黑树

插入查找删除的复杂度均为logn

set<int> mp;

mp.count(key) //查找元素有无
insert(key); //加入元素 自动去重
erase(key); //去掉元素

将set
vector<int> t{tmp.begin(), tmp.end()}; 

map

注意事项

  1. map内部实现了一个红黑树(红黑树是非严格平衡二叉搜索树)因此,对于map进行的查找,删除,添加等一系列的操作都相当于是对红黑树进行的操作。
  2. map的特性是,所有元素都会根据元素的键值自动排序。
  3. map所有的元素都是pair, 同时拥有实值和键值,pair的第一元素被视为键值,第二元素被视为实值,map不允许两个元素有相同的键值。
  4. 我们不可以通过map的迭代器改变map的键值, 因为map的键值关系到map元素的排列规则,任意改变map键值将会严重破坏map组织。如果想要修改元素的实值,那么是可以的。
    若想去掉key值,首先要用迭代器(真正的迭代器) 之后调用 mp.erase(iter)

插入查找删除的复杂度均为log(n),遍历的复杂度是O(n)

for(auto iter=mp.begin();iter!=mp.end();++iter)
{
    //cout<<iter->first;  
    //cout<<(*iter).first
    mp.erase(iter);
}

map的优点如下:

1.有序性,这是map结构最大的优点,其元素的有序性在很多应用中都会简化很多的操作

2.红黑树,内部实现一个红黑书使得map的很多操作在log(n)的时间复杂度下就可以实现,因此效率非常的高

map的缺点如下:
1.空间占用率高,因为map内部实现了红黑树,虽然提高了运行效率,但是因为每一个节点都需要额外保存父节点、孩子节点和红/黑性质,使得每一个节点都占用大量的空间

map的适用处:对于那些有顺序要求的问题,用map会更高效一些

map的操作

multimap

multimap和map的操作类似,唯一区别multimap键值可重复。同一个key可以有n个value
即,multimap可以一对多,map只能一对一
multimap如何find

hash

即, unordered_map

优点: 因为内部实现了哈希表O(1),因此其查找速度非常的快<查找key值> key----value
缺点: 哈希表的建立比较耗费时间
适用处:对于查找问题,unordered_map会更加高效一些,因此遇到查找问题,常会考虑一下用unordered_map
使用count,返回的是被查找元素的个数。如果有,返回1;否则,返回0。注意,hash中不存在相同元素,所以返回值只能是1或0。
使用find(key),返回的是被查找元素的位置,没有则返回map.end()。
关于auto的使用:auto 可以自动写好变量的类型,当使用迭代器时,一般类型名较长,所以采用auto。
find(key)
当使用find的时候,需要与迭代器的类型连用,所以一般前面+auto
count返回值是数,所以一般不需要,直接写在if里即可。
for(int i)可以完全替换迭代器,有的时候迭代器可能会简便一些。

Hash的O(1)指的是插入 删除 查找 修改的平均速度
其最差情况都是O(n)
其中的查找包括hash[i],count,find

key值顺序
hash的key值按插入时的顺序排列

上面的简要看看
重点是下面这个!<建立+count+遍历>

注:hash遍历见之前iter的文章

//建立hash
unordered_map<int,int> hashmap={{1,10},{2,20},{3,30}};
  or
unordered_map<int,int> hashmap;
hashmap[1]=10;
hashmap[2]=20;
hashmap[3]=30;

//判断hash表中是否存在某key值
if(!hashmap.count(key)) //count返回key在map中出现的次数 hash只能是1
{不存在这个key值}
else
{存在这个key值}

//ATTENTION!!!!!!!
//一个可以优化的点
//ATTENTION!!!!!!!
//收集频次的时候不用使用count 进行mp[key]=1 和 mp[key]++的分类讨论
//直接 mp[key]++就好
//因为对于尚未出现的key,mp[key]本身就是将其初始化为mp[key]=0
https://en.cppreference.com/w/cpp/container/unordered_map/operator_at

// leetcode #1 两数之和  应用hash O(1)查找特性 查找target-x

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {   

        unordered_map<int,int>hashtable;
        for(int i=0; i!=nums.size(); ++i)
        {
            auto it = hashtable.find(target-nums[i]); // 应用find
            if(it!=hashtable.end())
            {
                return {it->second, i};
            }
            hashtable[nums[i]]=i;
        }
        return {};
    }    
    
};

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int,int> hashtable;
        for (int i = 0; i != nums.size(); i++) {
            if (hashtable.count(target - nums[i])) //应用count
            {
                return { hashtable[target - nums[i]], i };
            }
            hashtable[nums[i]] = i;    
        }
        return {};
    }
};


map和hash的比较

#######注意#######
hash(unordered_set/map) 的key值不能为vector,pair,结构体等。因为没有对应的hash函数(通过std::hash)
支持的key值有什么
可见,支持大部分基本类型,没有vector,没有数组,没有vector
有string,有vector< std::bool >
同理,unordered_set里也不能放这些。

如果想用vector,可以用set(map),有一些题这样做时间是可以的。

unordered_set

相当于没有value的hash

unordered_set<int> hash;

hash.count(key) //查找元素有无
insert(key); //加入元素 自动去重
erase(key); //去掉元素

关于vector,map,hash中的排序、查找

  • sort()
    只有vector支持sort,所以有时为了实现排序需要把map/hash导入到vector<pair<key,value>>里,之后再使用重写cmp的sort()
  • 对key值的排序
    对于map,建立时自带对key值的从小到大排序
    对于hash,对key值排序需要导入vector<pair<key,value>>再sort ,复杂度O(nlogn)
  • 对value的排序
    map和hash都需要导入vector再sort,复杂度O(nlogn)
  • key值查找(count)/ 取值(mp[i])
    对于map,复杂度O(logn)
    对于hash,复杂度O(1)

关于vector,map,hash中的赋值

  • map的key值可以是pair,hash的key值如果是pair的话,需要重写hash。所以一般查表型的hash表(两个元素确定一个value),选择map来实现。

  • map&hash
    首次赋值mp[i]时,可以直接mp[i]=1或者mp[i]++,之所以在一些统计次数问题中需要if else,是不确定mp[i]的初始值为0。 if(!mp.count(xxx)) mp[xxx]=1; else mp[xxx]++

  • vector

    vector<int> res(n); //该操作可以直接替代下面的操作,相当于开了个大小为n的vector,(初始值都为0),后续可以直接赋值.
    vector<int> res(n,m);第二个参数为初始值
    vector<int> ans(res); 也可以直接copy现有的vector

首次赋值时,只能push_back(),不能访问vec[i]进行操作。
第二次操作时,可以直接访问vec[i]进行。
同时,push_back(x)中的x类别不限,可以整体push_back
vector可以直接赋值

vector<int> a={1,2,3};
vector<int> s;
s=a;
但是二维vector赋值时需要注意不能直接访问vec[i]
vector<vector<int>> a;
vector<int> b={1,2,3};
a.push_back(b);//第一种方案

如果一定要直接首次访问a[i],需要先开空间,resize可加第二个参数,规定初值,不写默认为0
a.resize(10);//i:0-9
a[i]=b;

fill & memset

fill和memset的比较

cin & getline

Cin接受到空格/换行/tab
getline(cin,str) 接收到换行
https://blog.csdn.net/weixin_41042404/article/details/80934191

位操作

注意:位操作
c++位操作

x >> y //x右移y位
x << y //x左移y位

同时,要注意!位运算操作符的优先级没有大于号小于号高。
因此,要加括号。
ex.if(((1<<i)&x)>0)

二进制枚举类型题 见leetcode周赛csdn总结

/*
ques:
颠倒给定的 32 位无符号整数的二进制位。
ex.
11111111111111111111111111111101
->
10111111111111111111111111111111
*/
class Solution {
public:
    uint32_t reverseBits(uint32_t n) {
        uint32_t res = 0;
        for(int i = 0; i < 32; i++){ //不能是n!=0 因为要把前导0全颠倒到最后面
            res <<= 1;
            res += n & 1;
            n >>= 1;
        }
        return res;
    }
};

注意
& |^ 都是每一位都做运算,1 & n,因为1的前面位置都为0,所以只看最后一位就可以了。

最小生成树

Kruskal && Prim

进制转化

在这里插入图片描述

#include <iostream>
#include <cstdio>
#include <stdlib.h>
using namespace std;
int main()
{
    int a;
    printf("输入你想转化的十进制数字:");
    scanf("%d",&a);
    printf("它的八进制表示为 --> %o\n",a);
    printf("它的十六进制表示为 --> %x\n",a);
    printf("它的十进制表示为 --> %d\n",a);
    char s[1000];
    itoa(a,s,2);
    printf("它的二进制表示为 --> %s\n",s);
    itoa(a,s,4);
    printf("它的四进制表示为 --> %s\n",s);
    itoa(a,s,16);
    printf("它的十六进制表示为 --> %s\n",s);
    return 0;
}

结构体的建立

基础结构体

struct people
{
	int age;
	int height;
	string name;
	//people(int x,int y,string z):age(x),height(y),name(z){}
};
调用时需要创建结构体对象 people a; people a(1,2,"jeremy");

struct people
{
}a,b[10];
这种相当于创建了对象a,和结构体数组b

链表结构体

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */

树结构体

/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */

结构体内元素的排序

struct Student
{
}a;

bool cmp(Student &s1,Student &s2)
{
	return s1.age<s2.age;
}

sort(a,a+n,cmp);

新建结构体对象(变量/指针)


TreeNode *node = new TreeNode(nums[mid],l,r);
//结构体指针要指向一块新的内存

TreeNode node = TreeNode(nums[mid],l,r);
//构造函数 赋值 给 结构体变量

结构体内重载小于号 见fly刷题笔记

用于更改set/priority_queue的自带排序
https://zhuanlan.zhihu.com/p/368510835

    struct Node{
        int key;
        int value;
        int freq;
        int time;

        //注意:如果写了带参数的构造函数,一定要把不带参数的也写上,因为重写后,默认构造函数会失效。
        //这里貌似跟编译器有关,有的时候可以不用写这个!
        Node():key(),value(),freq(),time(){}
        Node(int a,int b,int c,int d):key(a),value(b),freq(c),time(d){}
        
        //Node类的比较函数 定义在结构体中 
        //这两处一定要写const 不然编译不过
        bool operator < (const Node &a) const{  
            return freq == a.freq ? time < a.time : freq < a.freq; //从大到小 逻辑见fly刷题笔记
        }  
    };

emplace和结构体/其他stl的丝滑操作

https://www.jianshu.com/p/3906f24d2697
要注意的点:
Node(int a,int b,int c,int d):key(a),value(b),freq©,time(d){}
如果要写这样的构造函数
一定要写 Node():key(),value(),freq(),time(){}
因为重写后 默认的就会失败。

struct Node{
    int key;
    int value;
    int freq;
    int time;

    //注意:如果写了带参数的构造函数,一定要把不带参数的也写上,因为重写后,默认构造函数会失效。
    //这里貌似跟编译器有关,有的时候可以不用写上面这个!
    Node():key(),value(),freq(),time(){}
    Node(int a,int b,int c,int d):key(a),value(b),freq(c),time(d){}
    
    //Node类的比较函数 定义在结构体中 
    //这两处一定要写const 不然编译不过
    
    bool operator < (const Node &a) const{  
        return freq == a.freq ? time < a.time : freq < a.freq;   //从大到小 逻辑见fly刷题笔记
    }  
};

set<Node> st;
st.emplace(1,2,3,4);//直接可以传给构造函数 太丝滑了

不仅仅是结构体,参数列表是其他stl也可以,有待后续继续发现,不过struct是最常用的。
ex.pair->看这个题解的用法。
https://leetcode-cn.com/problems/all-oone-data-structure/solution/quan-o1-de-shu-ju-jie-gou-by-leetcode-so-7gdv/

数学操作

z=pow(x,y); //x的y次幂
其中:z,x是double类型,y不要求类型

细节操作

int a,b,c=0;
//这种情况只初始化了c;a和b没有进行初始化
int a=0,b=0,c=0//这种情况才能将a b c全部都初始化

emplace

替换后可以使用语法糖。
例如emplace一个pair可以不用make_pair,emplace结构体是可以直接直接放置参数等。
https://blog.csdn.net/windpenguin/article/details/75581552
效率更高 尽量替换
总结相关语法如下

vector
emplace <->  insert
emplace_back​  <-> ​push_back

set
emplcace <->  insert

map
emplace <->  insert

而且emplace很丝滑 若emplace的是结构体对象,可以直接识别参数列表
详见 “emplace和结构体丝滑操作”

auto

auto [steps, i, j] = q.front(); 

tuple

https://blog.csdn.net/sevenjoin/article/details/88420885
可以用tuple来替代结构体

lambda

https://km.woa.com/group/46659/articles/show/489743?kmref=search&from_page=1&no=1
https://www.jianshu.com/p/932812748138

关于基本类型的初始化

int等需要初始化
string str; 自动初始化为空字符串

读写文件

ifstream ifs;
ifs.open("test.txt");
//按行读
string buf;
while(getline(ifs,buf)){
	cout<<buf<<endl; //each line
}

ofstream ofs;
ofs.open("output.txt"); //没有就会新增
//按行读
stirng s1,s2;
ofs << s1 << endl;
ofs << s2 << endl;
ofs.close();
  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值