格式化输出数字
//格式化输出数字
int len = s.size();
for(int i = 0; i < len; i++) {
cout << s[i]; //先输出当前位置的数字
if(s[i] == '-') continue; //负号后面不输出逗号
if((i + 1) % 3 == len % 3 && i != len - 1) cout << ',';
}
格式化字符串
//sscanf与sprintf 格式化输入和输出
int sscanf(const char *str, const char *format, ...);
/*const char*需要使用字符数组,作用:将参数str的字符串根据参数format字符串来转换并格式化数据,转换后将
结果存于对应的参数内*/
int sprintf(char *str, const char *format, ...);
/**作用:格式化字符串**/
scanf("%s", a); //因a是字符数组的名字,其类型为指针,不需要加&
sscanf(a, "%lf", &temp); //从字符串a中读取浮点数部分到temp里, temp前需加&
sprintf(b, "%.2f", temp); //把temp按照小数点后保留不超过两位的格式打印到字符串b里
字符串常用函数
tring s = "Hello World";
string s2 = s;
string s3 = s + s2;
//用cin读入字符串的时候,是以空格为分隔符的,如果想读入一整行的字符串,就需要用getline
string s;
getline(cin, s);
1. =, assign() //赋以新值
2. +=, append(), push_back() //在尾部添加字符
3. insert() //插入字符
4. erase() // 删除字符
5. clear() //清除
6. replace() //替换字符
7. + //串联字符串
8. ==, !=, <, <=, >, >=, compare() //比较字符串
9. find(char) != string::npos //找到char
10.find(char) == string::npos //没找到char
素数判断
bool isPrime(int n) {
if(n <= 1) return false;
int sqr = (int)sqrt(1.0 * n);
for(int i = 2; i <= sqr; i++) //条件一定是i <= sqr
if(n % i == 0) return false;
return true;
}
素数表的获取
const int maxn = 101; //根据需要设定maxn值
int prime[maxn], pNum = 0;
bool p[maxn] = {0}; //p[i] = true表明i是素数
void Find_Prime() {
for(int i = 1; i < maxn; i++) { //枚举可以从1开始,条件一定是i < maxn;
if(isPrime(i)) {
prime[pNum++] = i;
p[i] = true;
}
}
}
筛法获取素数表
const int maxn = 100010;
int prime[maxn], pNum = 0;
bool notprime[maxn] = {false}; //i不是素数,notprime[i] = true;
void Find_Prime() {
for(int i = 2; i < maxn; ++i) { //一定从2开始,筛法不用调用isPrime函数
if(!notprime[maxn]) { //如果i是素数
prime[pNum++] = i; //打表
for(int j = i + i; j < maxn; j += i) //筛去所有i的倍数,注意增量是j += i;
notprime[j] = true;
}
}
}
堆排序(大顶堆)
/*--向下调整--*/
//heap数组下标为1到n
const int maxn = 1010;
int heap[maxn];
//对heap数组在[low, high]上进行向下调整
//其中low为欲调整结点的数组下标,high一般为堆的最后一个元素的数组下标
void downadjust(int low, int high) {
int i = low, j = 2 * i; //i为欲调整子树的根结点,j为其左孩子
while(j <= high) { //存在孩子结点
if(j + 1 <= high && heap[j + 1] > heap[i]) j = j + 1;
if(heap[j] > heap[i]) {
swap(heap[j], heap[i]); //交换最大权值的孩子与欲调整结点i
i = j; //保持i为欲调整结点、j为i的左孩子
j *= 2; //j = 2 * i;
} else{
break; //孩子的权值均比欲调整结点i小,调整结束
}
}
}
/*--建堆--*/
void createHeap() {
//从最后一个非叶结点倒着枚举
for(int i = n / 2; i >= 1; --i) {
downadjust(i, n);
}
}
/*--删除堆顶元素--*/
void deleteTop() {
heap[1] = heap[n--]; //用最后一个元素覆盖堆顶元素,并让元素总数减一
downadjust(1, n);
}
/*--向上调整--*/
//对heap数组在[low, high]范围进行向上调整
//low一般为1,high表示欲调整节点的数组下标
void upadjust(int low, int high) {
int i = high, j = i / 2; //i为欲调整结点,j为其父结点
while(j >= low) { //j在[low, high]范围内
//父亲权值小于欲调整结点i的权值
if(heap[j] < heap[i]) {
swap(heap[j], heap[i]);
i = j;
j /= 2;
} else {
break; //父结点权值比欲调整结点i的权值大,调整结束
}
}
}
/*--添加元素x--*/
void insert(int x) {
heap[++n] = x;
upadjust(1, n);
}
/*--堆排序--*/
void heapSort() {
createHeap(); //建堆
//节约空间,只在heap数组内部排序
for(int i = n; i > 1; --i) { //倒着枚举,直到堆中只有一个元素
swap(heap[i], heap[1]); //heap[i]与堆顶元素交换
downadjust(1, i - 1); //调整堆顶
}
}
DFS剪枝
const int maxn = 30;
int n, V, maxValue = 0;
int w[maxn], c[maxn];
//剪枝
void DFS(int index, int sumW, int sumC) {
if(index == n) {
return;
}
DFS(index + 1, sumW, sumC);
//只有加入第index件物品后未超过容量V,才能继续
if(sumW + w[index] <= V) {
if(sumC + c[index] > ans) {
ans = sumC + c[index];
}
DFS(index + 1, sumW + w[index], sumC + c[index]);
}
}
BFS模板
//BFS不是递归函数, 可以有返回值
void BFS(int s) {
queue<int> q;
q.push(s);
inq[s] = true; //树的层序遍历不需要inq数列
while(!q.empty()) {
取出队首元素;
访问队首元素; //访问可以是任何事情
将队首元素出队; //一定别忘了出队,否则会死循环
让队首元素的下一层结点中未曾入队的结点全部入队,并设置为已入队,层号为队首元素层号加一
}
}
并查集
void init() {
for(int i = 0; i < n; ++i) {
father[i] = i;
}
}
//寻找父结点,并进行路径压缩
int findFather(int x) {
if(x == father[x]) return x;
father[x] = findFather(father[x]);
return father[x];
}
//合并
void Union(int a, int b) {
int faA = findFather(a);
int faB = findFather(b);
//这里可以更改合并规则,根据题目具体问题具体分析
if(faA != faB) father[faA] = faB;
}
前序中序转后序
//preL是pre数组中的根结点下标
void post(int preL, int inL, int inR) {
if(inL > inR) return;
int i = inL;
while(i <= inR && in[i] != pre[preL]) ++i;
int numleft = i - inL; //左子树长度
post(preL + 1, inL, i - 1);
post(perL + numleft + 1, i + 1, inR);
printf("%d ", pre[preL]);
}
中序后序转前序
//postR为post数组中根结点下标
void pre(int postR, int inL, int inR) {
if(inL > inR) return;
int i = inL;
while(i <= inR && in[i] != post[postR]) ++i;
int numright = inR - i; //右子树长度
printf("%d ", post[postR]);
pre(postR - 1 - numright, inL, i - 1);
pre(postR - 1, i + 1, inR);
}
Dijkstra
//伪码
const int MAXV = 1000;
const int INF = 100000000000;
//G为图,一般设成全局变量,数组d为源点到达各点的最短路径长度,a为起点
int G[MAXV][MAXV], d[MAXV];
Dijkstra (s) {
初始化;
for(循环n次) { //注意这里是循环n次,与编号方式无关
u = 使d[u]最小的还未被访问过的顶点的标号;
记u已被访问过;
for(从u出发能到达的所有顶点v) { //邻接表与邻接矩阵版只有以下不同
if(v未被访问&&以u为中介点生使s到顶点v的最短距离d[v]更优) {
优化d[v];
}
}
}
}
排名输出
int r = 1;
for(int i = 0; i < n; i++) {
if(i > 0 && stu[i].score != stu[i-1].score)
r = i + 1;
//输出信息,或令stu[i].r = r;
}
AVL
/* 如果调用函数需要改变树形,需要传入node* &root */
struct node {
int v, height;
node *lchild, *rchild;
};
node* Newnode(int v) {
node *root = new node;
root->v = v;
root->height = 1;
root->lchild = root->rchild = nullptr;
}
int getH(node *root) {
if(root == nullptr) return 0;
return root->height;
}
int getBF(node *root) {
return getH(root->lchild) - getH(root->rchild);
}
void updateH(node *root) { //与红黑树获取左右子树高度类似
root->height = 1 + max(getH(root->lchild), getH(root->rchild));
}
void L(node* &root) { //左旋
node *temp = root->rchild;
root->rchild = temp->lchild;
temp.lchild = root;
updateH(root);
updateH(temp);
root = temp;
}
void R(node* &root) { //右旋
node *temp = root->lchild;
root->lchild = temp->rchild;
temp->rchild = root;
updateH(root);
updateH(temp);
temp = root;
}
void insert(node* &root, int v) {
if(root == nullptr) {
root = Newnode(v);
return;
}
if(v < root->v) {
insert(root->lchild, v);
updateH(root); //更新的是root
if(getBF(root) == 2) {
if(getBF(root->lchild) == 1) {
R(root);
} else if(getBF(root->lchild) == -1) {
L(root->lchild);
R(root);
}
}
} else {
insert(root->rchild, v);
updateH(root);
if(getBF(root->rchild) == -2) {
if(getBF(root->rchild) == -1) {
L(root);
} else if(getBF(root->rchild) == 1) {
R(root->rchild);
L(root);
}
}
}
}
node* create(int data[], int n) {
node* root = nullptr; //声明root时一定要赋初值为nullptr;
for(int i = 0; i < n; ++i) {
insert(root, data[i]);
}
return root;
}
高精度整数运算
struct bign
{
int d[1000];
int len;
bign() {
memset(d, 0, sizeof(d)); //初值全0
len = 0;
}
};
bign change(char s[]) { //把字符串转换成高精度整数
bign a;
a.len = strlen(s);
for(int i = 0; i < a.len; ++i)
a.d[i] = s[a.len - i - 1]; //将数字的高位存放到数组的高位
return a;
}
bign add(bign a, bign b) {
bign c;
int carry = 0;
for(int i = 0; i < a.len || i < b.len; ++i) {
int temp = a.d[i] + b.d[i] + carry;
c.d[c.len++] = temp % 10;
carry = temp / 10;
}
if(carry) {
c.d[c.len++] = carry;
}
return c;
}
int compare(bign a, bign b) {
if(a.len > b.len) return 1;
else if(a.len < b.len) return -1;
else {
for(int i = a.len - 1; i >= 0; --i) { //从高位开始比较
if(a.d[i] > b.d[i]) return 1;
else if(a.d[i] < b.d[i]) return -1;
}
return 0;
}
}
//进行减法之前,将两数进行比较,如果减数比被减数大, 则交换两数
bign sub(bign a, bign b) {
bign c;
for(int i = 0; i < a.len || i < b.len; ++i) { //条件是或"||"是因为
//数组高位都是0
if(a.d[i] < b.d[i]) { //不够减向高位借位
a.d[i + 1]--;
a.d[i] += 10;
}
c.d[c.len++] = a.d[i] - b.d[i];
}
while(c.len - 1 >= 1 && c.d[c.len] == 0) {
c.len--; //去除前导零,但是保留至少一位
}
return c;
}
//如果有负数,先记录负号,再将绝对值带入函数
bign multi(bign a, int b) {
bign c;
int carry = 0;
for(int i = 0; i < a.len; ++i) {
int temp = a.d[i] * b + carry;
c.d[c.len++] = temp % 10;
carry = temp / 10;
}
while(carry) { //carry可能不止一位,所以要用while
c.d[c.len++] = carry % 10;
carry /= 10;
}
return c;
}
bign divide(bign a, int b, int& r) {
bign c;
c.len = a.len;
for(int i = a.len - 1; i >= 0; --i) { //从高位开始除
r = r * 10 + a.d[i]; //先更新余数(初始余数为0)
if(r < b) c.d[i] = 0;
else {
c.d[i] = r / b;
r = r % b;
}
}
while(c.len - 1 > 0 && c.d[c.len] == 0) {
c.len--;
}
return c;
}
分数运算
int gcd(int a, int b) { //获取最大公约数
return !b ? a : gcd(b, a % b);
}
struct Fraction {
int up, down;
};
Fraction reduction(Fraction r) { //化简分数
if(r.down < 0) { //如果分母是负数,分子分母分别取相反数
r.up = -r.up;
r.down = -r.down;
}
if(r.up == 0) r.down = 1; //分子是零,分母为 1
else {
int d = gcd(abs(r.up), abs(r.down)); //注意一定是对分子分母的绝对值求最大公约数
r.up /= d;
r.down /= d;
}
return r;
}
Fraction add(Fraction f1, Fraction f2) {
Fraction r;
r.up = f1.up * f2.down + f1.down * f2.up;
r.down = f1.down * f2.down;
return reduction(r);
}
Fraction sub(Fraction f1, Fraction f2) {
Fraction r;
r.up = f1.up * f2.down - f1.down * f2.up;
r.down = f1.down * f2.down;
return reduction(r);
}
Fraction multi(Fraction f1, Fraction f2) {
Fraction r;
r.up = f1.up * f2.up;
r.down = f1.down * f2.down;
return reduction(r);
}
Fraction divide(Fraction f1, Fraction f2) {
Fraction r;
r.up = f1.up * f2.down;
r.down = f1.down * f2.up;
return reduction(r);
}
void show(Fractio r) {
r = reduction(r); //别忘了输出之前先化简
//if(r.up < 0) printf("(");
if(r.down == 1) printf("%d", r.up); //整数
else if(abs(r.up) > abs(r.down)) { //假分数
printf("%d %d/%d", r.up / r.down, abs(r.up) % r.down, r.down); //整数部分带符号,所以是
//r.up / r.down
} else { //真分数
printf("%d/%d", r.up, r.down);
}
//if(r.up < 0) printf(")");
}