目录
0,最基础的关于子函数的传入
#include <bits/stdc++.h>
using namespace std;
void x(int &a, int &b) {
b = a;
return;
}
int main() {
int a = 1;int b = 2;
x(a, b);
cout << a << " " << b << endl;
return 0;
}
这样输出的是1 1
void x(int a,int b){}
这样输出的就是1 2(
即使用&传入指针会改变值,直接传入不会改变值)
1,关于string:
C++中的String的常用函数用法总结_string函数-CSDN博客
string是一个数组,其中的每一个元素都是char类型,即str[i]是一个char
string str:生成空字符串
string s(str):生成字符串为str的复制品
string s(str, strbegin,strlen):将字符串str中从下标strbegin开始、长度为strlen的部分作为字符串初值
string s(cstr, char_len):以C_string类型cstr的前char_len个字符串作为字符串s的初值
string s(num ,c):生成num个c字符的字符串
string s(str, stridx):将字符串str中从下标stridx开始到字符串结束的位置作为字符串初值
string str1; //生成空字符串
string str2("123456789"); //生成"1234456789"的复制品
string str3("12345", 0, 3);//结果为"123"
string str4("012345", 5); //结果为"01234"
string str5(5, '1'); //结果为"11111"
string str6(str2, 2); //结果为"3456789"
size()和length():返回string对象的字符个数,他们执行效果相同。
cout << "size=" << s.size() << endl;
cout << "length=" << s.length() << endl;
插入:push_back() 和 insert()
s1.push_back('a');
// insert(pos,char):在制定的位置pos前插入字符char
s1.insert(s1.begin(),'1');
提取:substr
string s="ABAB";
cout << s.substr(2) <<endl ; //输出AB
cout << s.substr(0,2) <<endl ; //同上,从下标0开始,提取两个
拼接:append() 和 + 操作符
string s1("abc");
s1.append("def"); // s1:abcdef
string s2 = "abc";
/*s2 += "def";*/
string s3 = "def";
s2 += s3.c_str(); // s2:abcdef
删除:erase()
string s1 = "123456789";
// s1.erase(s1.begin()+1); // 结果:13456789
// s1.erase(s1.begin()+1,s1.end()-2); // 结果:189
查找:find/rfind
string s("dog bird chicken bird cat");
//字符串查找-----找到后返回首字母在字符串中的下标
if(s.find('x')==string::npos){ }//如果没有找到的返回结果
// 1. 查找一个字符串
cout << s.find("chicken") << endl; // 结果是:9
// 2. 从下标为6开始找字符'i',返回找到的第一个i的下标
cout << s.find('i',6) << endl; // 结果是:11
// 3. 从字符串的末尾开始查找字符串,返回的还是首字母在字符串中的下标
cout << s.rfind("chicken") << endl; // 结果是:9
// 4. 从字符串的末尾开始查找字符
cout << s.rfind('i') << endl; // 结果是:18-------因为是从末尾开始查找,所以返回第一次找到的字符
排序:sort(s.begin(),s.end())
判断字符串是否有空格:==' '
翻转:reverse(str.begin()+idx1, str.end()-idx2);
string类下的begin,end,rbegin,rend的用法:
begin
语法:iterator begin();
解释:begin()函数返回一个迭代器,指向字符串的第一个元素.
end
语法:iterator end();
解释:end()函数返回一个迭代器,指向字符串的末尾(最后一个字符的下一个位置).
rbegin
语法:const reverse_iterator rbegin();
解释:rbegin()返回一个逆向迭代器,指向字符串的最后一个字符。
rend
语法:const reverse_iterator rend();
解释:rend()函数返回一个逆向迭代器,指向字符串的开头(第一个字符的前一个位置)。
2,最大公约数:
辗转相除法:
while(len1%len2!=0){
int yu=len1%len2;
len1=len2;
len2=yu;
}
return len2;
自带函数:
__gcd(int a,int b);
3,int与char之间的转换
// 利用ASCII码的差值,直接用char的值减去'0'或者加上'0'
char a = '1';
int b = a - '0'; // b = 1;
int c = 1;
char d = c + '0'; // d = '1';
4,vector的使用
C++ 数组(vector)常用操作总结_vector操作-CSDN博客
5,哈希表的使用与“增删改查”
unordered_map<int,int> map;
unordered_set<int> set;
增加元素:map[1]=10或者map.insert(pair<int,int>(1, 10))
(对于set:set.insert(1))
遍历方法:for(auto it:map){it.first和it.second}
迭代器方法:for(auto it = map.begin(); it != map.end(); ++it){it->first和it->second}
查找:map.find(Key):
没找到返回map.end();(set也是)
找到的话返回一个迭代器:map.find()->second即可得到对应的value
计数:map.count(Key)查找哈希表中key的键值对,返回其数量,为1,则找到,若没找到则返回0
也可用来查找是否存在某个Key
删除:map.erase(Key)(set也是)
大小:map.size() 返回键值对的个数
map.empty() 判断是否为空,返回true/false
清除:map.clear()
补充:关于迭代器
for(vector<int>::iterator it = vec.begin();it!=vec.end();it++){
cout<<*it<<endl;
}
for(unordered_set<int>::iterator it = set.begin();it!=set.end();it++){
cout<<*it<<endl;
}
6,指针p
*p:p这个指针指向的对象
p=&a:取a的地址给p
int* p=&a:定义指针p,该指针指向一个int
7,链表
写一个链表结构:
struct ListNode {
//基础内部结构
int val;
ListNode *next;//一个指向ListNode的指针
//包含的用法
ListNode() : val(0), next(nullptr) {}//一个用法
ListNode(int x) : val(x), next(nullptr) {}//一个用法,可以联想创建一个新的节点时的操作,创建一个给定值的节点
ListNode(int x, ListNode *next) : val(x), next(next) {}//一个用法,创建一个给定值并且指定指向节点的新节点
};
2130. 链表最大孪生和 - 力扣(LeetCode)(快慢指针+反转链表)
链表的快慢指针技巧
(快的走两个next,慢的走1个next)(可用于判断中点,但是需要考虑节点数奇偶)
链表的荷兰国旗,如果让一个链表按照小于等于大于排,咋排呢?
遍历链表,不断构建三个部分的链表,最后首尾相连。
链表的创建节点与修改!!!!!!!!!!!
ListNode* ji=head:对ji修改就是对head修改。
克隆的写法:ListNode* cloneNode = new ListNode(node->val)
8,关于栈和队列的知识:
定义栈:stack<数据类型:可以是int、TreeNode*等>名称;
压:p.push(被压元素);
弹:p.pop(); 弹出栈顶的元素
p.empty() 如果栈中元素个数为0返回true,栈不为空返回false
p.top() 返回栈顶部的元素
p.size() 返回栈中元素的个数
定义队列:queue<数据类型:可以是int、TreeNode*等>名称;
压:q.push(被压元素);
弹:q.pop(); 弹出队列头部的元素
q.empty() 如果栈中元素个数为0返回true,栈不为空返回false
q.front() 返回队列头部的元素
q.size() 返回队列元素的个数
.emplace()比push()更好使!!!!!!!!!!!!
堆:
大根堆表示父节点都比子节点大
小根堆表示父节点都比子节点小
heap操作的四个函数
- make_heap( vec.begin(), vec.end(), less<int>() ):建立堆(要么大顶堆,要么小顶堆)
- 通过对vector进行建堆操作,将原vector转换为堆,调用元素时依然可以用vec[n]
- 大顶堆,就每一个函数都加上第三个参数
less<int>(),假如元素是int类型的
;
小顶堆,就每一个函数都加上第三个参数greater<int>(),假如元素是int类型的
,一直加上,一直一致。
- push_heap( ): 在堆中添加元素
- push_heap()用于把数据插入到堆中,它也有三个参数,其意义与make_heap()的相同,第三个参数应与make_heap时的第三个参数保持一致。
- 使用时需要注意的是:在使用push_heap()前,请确保已经把数据通过q.push_back()传入q中,而不是在push_heap()后再使用q.push_back(t)!!
- 1:vec.push_back(12); 2:push_heap(q.begin(), q.end(), less<int>());
- pop_heap( ): 在堆中删除元素
- pop_heap()用于将堆的第0个元素与最后一个元素交换位置,然后针对前n - 1个元素调用make_heap()函数,它也有三个参数,参数意义与make_heap()相同,第三个参数应与make_heap时的第三个参数保持一致。
-
因此,需要注意:pop_heap()函数,只是交换了两个数据的位置,如果需要弹出这个数据,请记得在pop_heap()后加上:vec.pop_back();
- sort_heap( ): 堆排序
-
sort_heap()是将堆进行排序,排序后,序列将失去堆的特性(子节点的键值总是小于或大于它的父节点)。它也具有三个参数,参数意义与make_heap()相同,第三个参数应与make_heap时的第三个参数保持一致。大顶堆sort_heap()后是一个递增序列,小顶堆是一个递减序列。
-
优先队列:
使用优先队列表示大小根堆:(省略第三个参数或者写成less都是大根堆(默认大值在堆顶 )。greater是小根堆。)
priority_queue<int, vector<int>, less<int>>s;//less表示按照递减(从大到小)的顺序插入元素
priority_queue<int, vector<int>, greater<int>>s;//greater表示按照递增(从小到大)的顺序插入元素
1.区别:它和queue不同的就在于我们可以自定义其中数据的优先级, 让优先级高的排在队列前面,优先出队,并且没有front(),back()函数,只用top()访问队首元素
2.相同:优先队列具有队列的所有特性,包括基本操作,只是在这基础上添加了内部的一个排序,它本质是一个堆实现的,都包含同一个头文件.
和队列基本操作相同:
- top 访问队头元素
- empty 队列是否为空
- size 返回队列内元素个数
- push 插入元素到队尾 (并排序)
- emplace 原地构造一个元素并插入队列
- pop 弹出队头元素
- swap 交换内容
-
struct cmp{ bool operator ()(pair<int,int>& m,pair<int,int>& n){ return m.second>n.second;//最小值优先 } }; priority_queue<pair<int,int>,vector<pair<int,int>>,cmp> q;
按照数据对中的第二个值进行排序,并且小的在前。
9,牛客网的输入输出样式:
输入:
(1)cin
注意1:cin可以连续从键盘读入数据
注意2:cin以空格、tab、换行符作为分隔符
注意3:cin从第一个非空格字符开始读取,直到遇到分隔符结束读取
(2)getline()
从cin的注意中,也可以看出,当我们要求读取的字符串中间存在空格的时候,cin会读取不全整个字符串,这个时候,可以采用getline()函数来解决。
注意1:使用getline()函数的时候,需要包含头文件
<string>
注意2:getline()函数会读取一行,读取的字符串包括空格,遇到换行符结束
(3)getchar()
该函数会从缓存区中读出一个字符,经常被用于判断是否换行
输出:
cout
使用sort函数进行排序(自定义)
sort(begin, end, cmp)
begin为指向待sort()的数组的第一个元素的指针
,end为指向待sort()的数组的最后一个元素的下一个位置的指针
,cmp参数为排序准则,cmp参数可以不写,如果不写的话,默认从小到大进行排序。
如果我们想从大到小排序可以将cmp参数写为greater<int>()就是对int数组进行排序,当然<>中我们也可以写double、long、float等等。如果我们需要按照其他的排序准则,那么就需要我们自己定义一个bool类型的函数来传入。自行定义的例子:
static bool compareFirstElement(const std::vector<int>& a, const std::vector<int>& b) {
return a[0] < b[0];
}
int main() {
// 创建一个二维vector
std::vector<std::vector<int>> twoDVector = {
{3, 2},{1, 4},{2, 6},{5, 3}
};
// 按每行的第一个数进行排序
sort(twoDVector.begin(), twoDVector.end(), compareFirstElement);
return 0;
}
重点:写cmp子函数时,加上static!!!!!!!!!!!!!!!!!!!(要不会报错)