血泪教训与总结!
检查时先检查是否将=写为==!
函数有返回值时,退出函数用return NULL; void时可直接用return;
进制转换
p进制的x转为十进制y:
int y=0; product=1;
while(x!=0){
y += (x%10)*product; //获取x个位后乘以次方
x /= 10; //x去掉个位
product*=p;
}
十进制y转换为p进制
int d[40],num=0;
do{
d[num++] = y % p;
y/=p;
}while(y!=0); //之所以用do...while是因为避免y=0时d数组为空。d数组倒序输出
##字符串hash
//大写字母
int hashFunc(char S[], int len){
int id=0;
for(int i=0; i<len; i++){
id=id*26+(S[i]-'A);
}
return id;
}
//大写字母 52进制转十进制
int hashFunc(char S[], int len){
int id=0;
for(int i=0; i<len; i++){
if(S[i]>='A'&&S[i]<='Z'){
id=id*52+(S[i]-'A);
}else if(S[i]>='a'&&S[i]<='z'){
id=id*52+(S[i]-'a')+26;
}
}
return id;
}
全排列
#include<bits/stdc++.h>
using namespace std;
const int maxn=11;
int n,P[maxn],hashTable[maxn]={false};
void generateP(int index){
if(index == n+1){ //循环边界,到达位数输出
for(int i=1; i<=n; i++){
cout<<P[i];
}
cout<<endl;
return;
}
for(int x=1; x<=n; x++){ //每一次循环代表以x为第一个数字的排列
if(hashTable[x]==false){
P[index]=x;
hashTable[x]=true;
generateP(index+1);
hashTable[x]=false;
}
}
}
int main() {
n=3;
generateP(1);
return 0;
}
区间贪心
const int maxn=110;
struct Inteval{
int x,y;
}I[maxn];
bool cmp(Inteval a, Inteval b){
if(a.x != b.x) return a.x > b.x;
else return a.y > b.y;
}
二分查找
mid = (left + right) / 2; //可能会超出int范围
mid = left + (right - left) / 2; //这样处理避免溢出
快速幂
给定a,b,m,求 a b a^b ab % m
如果b是奇数,则 a b = a ∗ a b − 1 a^b=a*a^{b-1} ab=a∗ab−1
如果b是偶数,则 a b = a b / 2 ∗ a b / 2 a^b=a^{b/2}*a^{b/2} ab=ab/2∗ab/2
typedef long long LL;
LL binaryPow(LL a, LL b, LL m){
if(b == 0) return 1;
if(b % 2 == 1) return a * binaryPow(a, b-1, m) % m; //也可为b&1,奇数末位为1
else {
LL mul= binaryPow(a, b/2, m);
return mul * mul % m; //不能写成binaryPow(a, b/2, m) * binaryPow(a, b/2, m) % m
}
}
two pointers
while(i < j){
if(a[i] + a[j] == m){
printf();
i++;
j--;
}else if(a[i] + a[j] < m){
i++;
}else{
j--;
}
}
生成随机数
srand((unsigned)time(NULL));
//[a,b]之间
rand()%(b-a+1)+a;
//超出RAND_MAX
(int)((double)rand()/RAND_MAX*(b-a+1)+a);
整数转换为数组
void to_array(int n, int num[]){
for(int i = 0; i < 4; i++){
num[i] = n % 10;
n /=10;
}
}
int to_number(int num[]){
int sum = 0;
for(int i = 0; i < 4; i++){
sum = sum*10+num[i];
}
return sum;
}
最大公约数、最小公倍数
int gcd(int a, int b){
if(b==0) return a;
else return gcd(b, a%b);
}
//法二
int gcd(int a, int b){
return !b ? a : gcd(b, a%b);
}
//最小公倍数
d为最大公约数,因ab/d可能会造成溢出,故用
a/bd 表示最小公倍数
分数四则运算
struct Fraction{
int up,down;
};
Fraction reduction(Fraction result){
if(result.down<0){ //分母为负数
result.up = - result;
result.down = - result.down;
}
if(result.up==0){ //分子为0
result.down=1;
}else{
int d = gcd(abs(result.up), abs(result.down));
result.up /= d;
result.down /= d;
}
return result;
}
//加法示例
Fraction f1,f2,result;
result.up=f1.up+f2.up;
result.down=f1.down+f2.down;
result=reduction(result);
判断素数
const int maxn=101; //素数表长
int prime[maxn],pNum=0; //prime存放素数,pNum为素数个数
bool p[maxn]={0}; //i为素数,则p[i]为false
bool isPrime(int n){
if(n<=1) return false;
int sqr=sqrt(n);
for(int i=2; i<=sqr; i++){
if(n%i==0) return false;
}
return true;
}
//筛法 素数打表
void Find_Prime(){
for(int i=2; i<maxn;i++){
if(!p[i]){
prime[pNum++]=i;
for(int j=i+i;j<maxn;j+=i){
//筛去所有i的倍数
p[j]=true;
}
}
}
}
内存开辟与回收
C:
node* p = (node*)malloc(sizeof(node))
free§
C++:
node* p = new node;
delete§
STL
set
set中元素唯一,若要处理不唯一,则用multiset,c++11增加了unordered_set,以散列表代替红黑树,用于只去重不排序的情况
string
//printf输出string
string str="abc";
printf("%s",str.c_str());
str.insert(pos,string);
str.insert(it,it2,it3);将[it2,it3)插入it处
str.erase(first,last);//删除[first,last),first,last为迭代器
str.erase(pos,length);
str.substr(pos,len)
//string::npos是一个值为-1的常数,但其类型为unsigned_int,因此可认为是unsigned_int类型的最大值,用以作为find函数失配时的返回值
str.find(str2)//找到则返回str2第一次出现的位置,否则返回string::npos
str.find(str2,pos)//从pos位置开始find
str.replace(pos,len,str2)
queue
只能通过front()和back()来访问队首队尾元素,
push()添加到队尾
pop()删除队首元素
empty()检测是否为空队列
size()获得队内元素个数
priority_queue
:使用堆实现的默认将当前队列的最大(优先级最高)元素置于队首的容器
只能通过top()访问队首(堆顶)元素,没有front()和back()
stack
只能通过top()访问栈顶元素,没有front()和back()
pair
当想要将两个元素捆绑在一起而又不想定义一个结构体时,用它!
临时构建 pair:
- pair<string,int>(“haha”,5)
- make_pair(“haha”,5);
比较大小:可直接使用比较运算符,先比较first,first相等比较second
abs() fabs() swap() reverse() fil()
abs():整数
fabs():浮点数
swap() 交换
reverse() 反转,[it,it2),也可对string字符串进行反转
fill() 给数组或容器的某一区间赋任意值
next_permutation():给出一个序列在全排列中的下一个序列
int a[10]={1,2,3};
do{
cout<<a[0]<<a[1]<<a[2];
}while(next_permutation(a,a+3));
//next_permutation()在已经到达全排列的最后一个时会返回false
字符串大小排序
bool cmp(string str1,string str2){
return str1.length() > str2.length();
}
lower_bound() 和 upper_bound()
lower_bound(first,last,val) : [first,last)范围内第一个大于等于val的元素的位置
upper_bound(first,last,val) : [first,last)范围内第一个大于val的元素的位置
如果没有需要寻找的元素,则返回可以插入该元素的位置的指针或迭代器
数据结构
栈
STL中没有实现stack的清空,需要使用while循环反复pop(),事实上 ,直接重新定义一个栈就行
中缀转后缀
#include<bits/stdc++.h>
using namespace std;
struct node{
double num;
char op;
bool flag; //true表示操作数
};
string str;
stack<node> s; //操作符栈
queue<node> q; //后缀表达式序列
map<char,int> op; //得到相应字符的优先级数字,用于直接比较
void Change(){ //中缀转后缀
double num;
node temp;
for(int i=0; i<str.length();){
//操作数
if(str[i]>='0'&& str[i]<='9'){
temp.flag=true;
temp.num=str[i++]-'0';
//若数字不止一位
while(i<str.length() && str[i]>='0'&& str[i]<='9'){
temp.num=temp.num*10+(str[i]-'0');
i++;
}
q.push(temp);
}else{
//操作符
temp.flag=false;
while(!s.empty() && op[str[i]] <= op[s.top().op]){
q.push(s.top());
s.pop();
}
temp.op=str[i];
s.push(temp);
i++;
}
}
while (!s.empty()){
q.push(s.top());
s.pop();
}
}
double Cal(){
double temp1,temp2;
node cur,temp;
while(!q.empty()){
cur=q.front();
q.pop();
if(cur.flag) s.push(cur);
else{
//如果是操作符
temp2=s.top().num;
s.pop();
temp1=s.top().num;
s.pop();
temp.flag=true;//临时记录操作数
if(cur.op == '+') temp.num=temp1+temp2;
else if(cur.op == '-') temp.num=temp1-temp2;
else if(cur.op == '*') temp.num=temp1*temp2;
else temp.num=temp1/temp2;
s.push(temp);
}
}
return s.top().num;
}
int main(){
op['+']=op['-']=1;
op['*']=op['/']=2;
while(getline(cin,str),str!="0"){
for(string::iterator it=str.end(); it!=str.begin();it--){
if(*it ==' ') str.erase(it);
}
while(!s.empty()) s.pop();
Change();
cout<<Cal();
}
return 0;
}
链表
- 动态链表
- 静态链表:hash原理
struct Node{
typename data;
int next;
}node[size];
DFS
DFS会遍历所有路径
根据题目的限制来节省DFS计算量的方法称为**剪枝**
//背包
void DFS(int index,int sumW,int sumC){
if(index==n){
if(sumW<=V && sumC>=maxValue)
maxValue=sumC;
return;
}
//对每个物品,有选和不选两种情况,都要遍历,故需两次DFS
DFS(index+1,sumW,sumC);
DFS(index+1,sumW+w[index],sumC+c[index]);
}
BFS
void BFS(int s){
queue<int> q;
q.push(s);
while(!q.empty()){
取top元素;
使用top元素;
pop出队;
将top的下一层结点中未曾入队的结点全部入队,并设置为已入队;
}
}
https://blog.csdn.net/y_dd6011/article/details/89715169
STL中的queue的push操作只是产生了该元素的一个副本入队,该元素与其副本无关联,修改这个不会影响另一个,因此,当需要修改队列中的元素而不仅仅是访问时,队列中最好放元素的编号而不是其本身(例如数组下标)
树
祖先结点,子孙结点
完全二叉树的存储结构
- 判断结点为叶子结点 : 该结点的左子结点的编号root * 2大于结点总数n
- 判断结点为空结点 : 该结点的编号root大于结点总数n
先序,中序,后序遍历一般使用DFS,层序使用BFS
无论是知道先序序列还是后序序列还是层序序列,只有知道中序遍历序列才能唯一的确定一棵树
一般树的先根遍历序列与DFS序列相同,层序遍历序列与BFS序列相同
BST(二叉查找树)
数据域有序,左子树<根<右子树