- if(1){} ~ if(1);
- 结构体赋值:
nds[0]=tnds[0]; // 结构体直接赋值的话,nds[0] 地址不变,数据变
DFS 中临时数组写法,保证每次回溯时,值也跟着恢复上一层的值:
void dfs(int sum) { if(sum==all) return; for(int i=0;i<len;i++) { if(cnt[i]>0) { int vis[len]; mem(vis,0); vis[i]=1; dfs(sum+1); if(vis[i]==1) { // do something... } } } }
虽然 if(1) //T,if(2) //T,以及ture==1,false==0 已定死规则了,但是 true!=2,其他类似。
set.rbegin() 与 set.end() 不相等,前者 == 后者 - 1,可以用来判断是否到达最后一个。
int fun(){...} // 如果最后没有 return 的话,默认返回一个随机值。
使用 stringstream:可以吞下不同的类型,然后吐出不同的类型。
//
int a = 30; stringstream ss; ss<<a; string s1 = ss.str(); cout<<s1<<endl; // 30 string s2; // char s3[100]; ss>>s3; 也可以转换 char[] 类型 ss>>s2; cout<<s2<<endl; // 30
%f 和 %lf 区别:
printf("%f\n",1L/2); // 0.000000 printf("%f\n",1.0/2); // 0.500000 printf("%f\n",1.0L/2); // -0.000000 printf("%f\n",1.0F/2); // 0.500000 printf("%f\n",1F/2); // 编译错误 printf("%lf\n",1.0L/2); // 0.500000 printf("%lf\n",1L/2); // 0.500000 printf("%lf\n",1.0F/2); // 0.000000
Ps:printf的%f说明符的确既可以输出float型又可以输出double型。根据“默认参数提升”规则float型会被提升为double型。因此printf()只会看到双精度数。对于scanf,情况就完全不同了,它接受指针,这里没有类似的类型提升。向float存储和向double存储大不一样,因此,scanf区别%f和%lf。
也就是说输出的时候不管输出的是双精度还是单精度都用%f就没错了,但是输入的时候,输入单精度要用%f而输入双精度要用%lf。
stringstream ss; 清空:用 “ss.str("")” 配合 “ss.clear()”:(前后顺序无关)
string s1="10",s2="12"; int a,b; stringstream ss; ss<<s1; ss>>a; cout<<a<<endl; // 10 ss<<s2; ss>>b; cout<<b<<endl; // 随机值 cout<<ss.str().capacity()<<endl; // 2 ss.clear(); cout<<ss.str().capacity()<<endl; // 2 ss.str(""); // 一定要加引号才有效 cout<<ss.str().capacity()<<endl; // 0 ss<<s2; ss>>b; cout<<b<<endl; // 12
vector:
/* vec.clear() 与 vector<int>().swap(vec) 区别 */ vector<int> vec; vec.push_back(12); vec.clear(); cout<<vec[0]<<endl; // 12 vec.push_back(20); cout<<vec[0]<<endl; // 20 vector<int>().swap(vec); cout<<vec[0]<<endl; // 报错 // Ps:clear 表面清空,但是里面的内存并未释放,swap 彻底清空,释放全部内存,跟刚刚新生成的一样。 /* vector<int> 比较:元素是否相同,或者按字典序比较 */ puts(v1 == v2 ? "Yes" : "No"); /* vector.resize(n) 申请空间大小,直接可以使用 v[i] */ vector<int> v; v.resize(100); v[3]=15; /* find(v.begin(),v.end(),泛型)-v.begin() */ // 找到则返回第一次出现的下标,若找不到,则返回 v.size() push_back() 时预留空间不够用:要重新分配内存,并且拷贝当前已有的所有元素到新的内存区域。如果已有元素很多,这个操作将变的非常昂贵。 Ps:ector的内存管理策略是:一旦空间不足,则增长一倍,对于大数据量,这也许是一块不容小朝的资源。
循环(外 / 内)反复声明变量的优缺点:
1、对于使用 int 等基本数据类型作为循环变量,只要你用的优化方面足够给力的主流的编译器,完全不需要关心在循环外还是循环内定义循环变量。
2、如果循环变量本身是复杂的对象,建议在循环外定义好,并且在 for 循环的赋值语句、判断语句中,都要避免重复创建对象。
pair<...> 用法(伪代码):
typedef pair<int,int> pii; queue<pii> q; q.push(make_pair(i,j)); x=q.front().first, y=q.front().second; q.pop();
char[ ] 大小写转换:
for(int i=0;i<len;i++) { if(s[i]>='a' && s[i]<='z') s[i]=toupper(s[i]); // 转大写 else if(s[i]>='A' && s[i]<='Z') s[i]=tolower(s[i]); // 转小写 }
- '\0' (char)-> 0(int)
- '空格'(char)-> 32(int)
- char 转 string:
string s; cout<<(s+'a')<<endl;
优先队列自定义优先级排序:
// 第 1 种方法 struct pq_cmp // 根据先到达的人先处理业务 { bool operator()(P p1,P p2) { // 它与正常的 sort_cmp 的思想反着来的 return p1.ssum>p2.ssum; // 进入的时间:从小到大 } }; priority_queue<P,vector<P>,pq_cmp> pq; // 第 2 种方法 struct node { char a[20]; int rk; friend bool operator<(node p1,node p2) // 注意写死:friend、< { return p1.rk>p2.rk; // 从小到大 } }; priority_queue<node> pq;
scanf 中 %*s 妙用:
//Robert is a child of John char a[20],with[20],b[20]; scanf("%s%*s%*s%s%*s%s",a,with,b); /* a==Robert with==child b==John */
- unordered_map / map:
- \
/* unordered_map / map 自定义排序 */ typedef pair<string,int> psi; unordered_map<string,int> ump; int cmp(psi p1,psi p2) { if(p1.second==p2.second) return p1.first<p2.first; return p1.second>p2.second; } vector<psi> vec(ump.begin(),ump.end()); sort(vec.begin(),vec.end(),cmp); // Ps:map:红黑树;unordered_map:hash 散列表。 /* 泛型里面用 char* 替代 string 以及 map 插入时排序自定义 */ struct cmp { bool operator()(const char* s1,const char* s2) const { return strcmp(s1,s2)<0; // default:map 根据 key 排序(字典序) } }; map<char*,int,cmp> mp; mp.clear(); char rr[100],rr1[100]; rr1[0]=rr[0]='a'; rr[1]='b'; rr1[2]=rr[2]='c'; mp[rr]=10; rr1[1]='a'; mp[rr1]=12; for(map<char*,int>::iterator it=mp.begin();it!=mp.end();it++) cout<<it->first<<endl; /* map / unordered_map 不要轻易使用 size() 函数 */ // 如果中途在比较的时候,有些新的ump[i]原本没有存储的会被创建,导致size会扩增 if(ump[i]!=1) {...} printf("%d",ump.size()); /* map 插入自定义排序重写 */ /* C++ STL 中 Map 的按 Key 排序 */ // map这里指定less作为其默认比较函数(对象),所以我们通常如果不自己指定Compare,map中键值对就会按照Key的less顺序进行组织存储。 map<string, int, less<string> > mp; // default ~ map<string, int> mp; map<string, int, greater<string> > mp; // 自定义 struct cmp { bool operator()(const string& k1, const string& k2) { return k1.length() < k2.length(); } }; map<string, int, cmp> mp; /* C++ STL 中 Map 的按 Value 排序 */ // 待更新... /* erase(it) or erase(key) or erase(mp.begin(),mp.end()) */
判断字符是否为:字母、大小写英文字母、数字、数字或字母:
cout<<isalpha('A')<<endl; // 1 cout<<isalpha('a')<<endl; // 2 cout<<islower('A')<<endl; // 0 cout<<islower('a')<<endl; // 2 cout<<isupper('A')<<endl; // 1 cout<<isupper('a')<<endl; // 0 cout<<isdigit('a')<<endl; // 0 cout<<isdigit('1')<<endl; // 1 cout<<isalnum('a')<<endl; // 2 cout<<isalnum('B')<<endl; // 1 cout<<isalnum('1')<<endl; // 4 cout<<isalnum('.')<<endl; // 0
连续赋值情况:
int a[200],b[200],len=0; a[len]=b[len++]=1; // a[1]==b[0]==1 a[len++]=b[len]=1; // a[0]==b[1]==1
unordered_set / multiset / hash_set / set:
1、说到这那到底hash_set与unordered_set哪个更好呢?实际上unordered_set在C++11的时候被引入标准库了,而hash_set并没有,所以建议还是使用unordered_set比较好,这就好比一个是官方认证的,一个是民间流传的。 2、set.count():O(logn); unordered_set.count() 比 set.count() 再快 4 倍左右。 3、multiset 可插入重复的值,其他用法与 set 类似。 /* set - count、insert().second */ set<int> st; int ans=st.count(1); // st 中 1 出现的次数 bool f=st.insert(1).second; // 先插入试试,最后返回是否插入成功 /* set 自定义排序 */ struct node { int val,cnt; node(int val,int cnt):val(val),cnt(cnt){} bool operator<(const node &nd)const { //return false 数据插入失败,而不是(插入成功,只是位置不一样)。 return cnt!=nd.cnt ? cnt>nd.cnt : val<nd.val ; } }; set<node> st;
- 在scanf中 “\n” 不是表示接受一个回车符,而是表示忽略所有的空白字符(包括回车、空格、Tab)。所以想要结束输入,输入任意一个非空白字符即可,但是该字符仍然会留在缓冲区中。一般不建议在 scanf 中使用 “\n”。
- 双重 for_i 循环的变量情况:
for(int i=0;i<4;i++) { for(int i=1;i<3;i++) printf("%d\n",i); } /* 1 2 1 2 1 2 1 2 */
#define 的妙用:
#define add(x,y) x+y // 不是计算好后返回,而是先返回好表达式再计算 printf("%d\n",add(1,2*add(3,4))); // 11 #define P 3 #define f(a) P*a*a printf("%d\n",f(3+5)); // 3*3+5*3+5==29 #define ABC(x) x*x int a, k=3; a = ++ABC(k+1); //9 // 由于带参宏不会对参数自行添加括号运算,因此a 的计算展开式可写为 ++k+1*k+1 这样就很明显了,由于运算优先级的关系,先执行++k,即k先进行自加,k的值变成了4,然后a=4+1*4+1,结果就为9啦~
输出自动填充:
cout<<setw(5)<<setfill('0')<<a[i]; // 等价于 printf("%05d",a[i]);
结构体:
node nd; // 等价于 node nd();
变量计算时的自动转换规则:(例如:int型除以double型,结果是double型)
自动转换遵循以下规则:
1) 若参与运算量的类型不同,则先转换成同一类型,然后进行运算。
2) 转换按数据长度增加的方向进行,以保证精度不降低。如int型和long型运算时,先把int量转成long型后再进行运算。
a.若两种类型的字节数不同,转换成字节数高的类型
b.若两种类型的字节数相同,且一种有符号,一种无符号,则转换成无符号类型
3) 所有的浮点运算都是以双精度进行的,即使仅含float单精度量运算的表达式,也要先转换成double型,再作运算。
4) char型和short型参与运算时,必须先转换成int型。
5) 在赋值运算中,赋值号两边量的数据类型不同时,赋值号右边量的类型将转换为左边量的类型。如果右边量的数据类型长度左边长时,将丢失一部分数据,这样会降低精度,丢失的部分按四舍五入向前舍入。
见名知意:
1、foo(function object oriented):面向对象编程的函数,有时候也不知道取什么名字,就代表“张三、李四”的味道。
指针声明定义语法:
node *left,*right; // T node* left, right; // F
int */ double,无需 *1.0,只要有一个是小数即可(在末尾添加“.0”):
int a=2; printf("%f\n",a*1.0/3); // 不推荐 printf("%f\n",a/3.0); // 推荐
补空格,%2d:
printf("%2d\n",1); //空1
容器:
/* 遍历倒序 */ for(set<int>::reverse_iterator it=st.rbegin(); it!=st.rend(); it++) { cout<<*it<<endl; }
C语言优先级
- printf(i,i++), fun(j,++j); // 在C中,一律都是从右到左;在Java中,一律都是从左到右。
- vector.push:如果是对象的push,则属于拷贝,与原先的对象的地址是不一样的。
- static 写在函数里作用域等同于写在main函数外面。
static int a=0; int main() { return 0; } 等价于 void fun() { static int a=0; } int main() { return 0; }
C++中int类型默认值:
1. 在全局域中声明的变量会自动初始化为0。
2. 如果变量是在局部域中定义的,则系统不会向它提供初始值0,这些对象被认为是未初始化,其值随机(有的编译器可能会为你初始化为0,但千万别依赖于这种可能行为,因为它会给你的程序带来未定义的行为)。
在C语言中,int a = -028; 这里的 0 默认当作 8 进制来看,而不是十进制。
结构体类似于基本类型,所以传参时,也只是传值。
sizeof & strlen 区别:
默认加“\0”