编码技巧C++
编码技巧C++
非零都是true
在c++环境下不等于0的数值都被认为是true
在判断一个值是否为0时以下代码是等效的,但第一种效率更高
int i = 123;
if (i) cout << "i不为0";
if (i != 0) cout << "i不为0";
不需要用到下标的计数循环可以不用for语句
int n; cin >> n;
while(n--) {
}
质数判断不用从2除到n-1
提高执行效率质数判断仅需要从2除到\(\sqrt{n}\)即可
注意这里是需要除到\(\sqrt{n}\)的,循环条件为\(i \leqslant \sqrt{n}\)
计算机运行开根号运算效率低,采用 i * i <= n作为循环条件
int n;
bool prm = true; // 假设是质数
for (int i = 2; i * i <= n; ++i) {
if (n % i == 0) { // 如果能整除,则不是质数,退出循环
prm = false;
break;
}
}
更高效的方法不用每次都计算\(i\times i\),而是在循环外计算出\(\sqrt{n}\)
int n;
int sqn = floor(sqrt(n));
bool prm = true; // 假设是质数
for (int i = 2; i <= sqn; ++i) {
if (n % i == 0) { // 如果能整除,则不是质数,退出循环
prm = false;
break;
}
}
通过按位与判断一个数是不是偶数
整数在二进制表示最低位如果是1代表一定是奇数
按位与判断奇偶效率比对2求余数效率更高,以下代码等效,但第一种效率更高
uint8_t a = 0b00000001;
int i = 8;
if (i & a) cout << "i是奇数";
if (i % 2) cout << "i是奇数";
通过异或操作交换两个数
int x = 3, y = 5;
x ^= y;
y ^= x;
x ^= y;
此方法和加减法交换类似,但是效率比加减法高。通常数值交换最多使用的是中值交换法
int x = 3, y = 5;
x = x + y;
y = x - y;
x = x - y;
通过右移一位来完成除以2的操作
下面的右移操作和除以2的操作等效,第一种效率更高
int n = 100;
n >>= 1; //右移一位
n /= 2; //除以2
数组通过取模换算下标,环绕取元素
如果一个下标值超过数组可以通过对下标值取模来环绕取元素
int idx = 12345;
int a[100] = {}; // 使用大括号会自动将数组置零
int n = a[idx % 100];
// 如果数组空间没有完全使用,可以根据对已使用长度取模方法来环绕取元素
int lenUsed = 50;
n = a[idx % lenUsed];
使用getline函数从流中读取一行
cin.getline()方法需要使用字符数组及长度两个参数
使用getline函数可直接读取一行到string类型
// cin.getline()方法的使用方法
char s[101] = {0};
cin.getline(s,100);
//getline()函数的使用方法
string s;
getline(cin, s);
注意:使用cin.getline()方法和直接使用getline()函数的时候需要考虑上一行末尾的回车,如下代码
int n;
char a[100];
cin >> n; // 此处读取n之后缓存中还有一个回车未被读取
cin.getline(a, 100); // 由于有一个回车未被读取,所以这里读取到的是空字符串
cout << a;
采用getline()函数的方法优化为
int n;
string s = "";
cin >> n;
do {
getline(cin, s);
} while(s.empty()); // 如果读取后为空则继续读取
cout << s;
局部数组不会被初始化
全局数组会被自动初始化为0,局部数组需要手动初始化
int a[10] = {0};
for (int i = 0; i < 10; ++i)
cout << a[i] << " ";
输出:
0 0 0 0 0 0 0 0 0 0
如果只初始化部分内容,其余部分自动填零
int a[10] = {1, 2};
for (int i = 0; i < 10; ++i)
cout << a[i] << " ";
输出:
1 2 0 0 0 0 0 0 0 0
使用memset函数初始化数组为0
注意:多维数组初始化应使用此函数
使用cstring中的函数memset将数组中的字节设置为零,注意数值代表的是一个字节的值
#include <iostream>
#include <cstring>
using namespace std;
int main() {
int a[10];
memset(a,0,sizeof(a));
for (int i = 0; i < 10; ++i)
cout << a[i] << " ";
cout << endl;
memset(a,255,sizeof(a));
for (int i = 0; i < 10; ++i)
cout << a[i] << " ";
}
输出:
0 0 0 0 0 0 0 0 0 0
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1
在for循环中使用无符号类型循环变量不能用小于零来进行判断
size_t和uint32_t等无符号类型不能用 i >= 0来进行判断,因为无符号永远大于等于0
// 此处i始终是大于等于0的,所以循环会一直执行
for (size_t i = 31; i >= 0; --i)
cout << i << endl;
超长整数进制转换
原数不断除以新进制并取余,然后组成新进制数
#include <iostream>
#include <sstream>
#include <vector>
#include <algorithm>
using namespace std;
// 此题要点:如果当前位不够整除新进制,则循环按照旧进制向高位借位
typedef vector<int> Vint;
// 进制
string base = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// 返回对应字符的数值
size_t ValOfC(char c) {
return base.find(c);
}
// 返回数值对应的字符
char COfVal(int val) {
return base[val];
}
// 将一个字符串中的字符转换成数字逆序存入vector
void StrToVec(string& s, Vint& v) {
for (char c: s) {
v.push_back(ValOfC(c));
}
}
// 判断v是否为0
bool ISZero(Vint & v){
bool r = true;
for (int i: v) {
if (i != 0) {
r = false;
break;
}
}
return r;
}
// 执行进制转换
string Trans(int From, string s, int To) {
string r = s;
if (From != To) { // 如果进制不同
Vint v; // 用于保存数据
Vint ToV; // 用于保存结果的
StrToVec(s, v);
while (!ISZero(v)) {
int rem = 0; // 余数
int tmp = 0; // 临时变量
for(int & i: v) { // 遍历原始vector
rem = (i + tmp * From) % To;
i = (i + tmp * From) / To;
tmp = rem;
}
ToV.push_back(rem);
}
r = "";
for (int i : ToV) r = COfVal(i) + r;
}
if (r == "") r = "0";
return r;
}
int main() {
int n;
cin >> n;
for (size_t i = 0; i < n; i++) {
string t; // 临时变量用于接收一行
stringstream ss; //
cin >> t;
for (char c : t) {
if (c != ',') ss << c;
else ss << endl;
}
int From, To;
string s;
ss >> From >> s >> To;
cout << Trans(From, s, To) << endl;
}
}
核心部分代码
while (!ISZero(v)) {
int rem = 0; // 余数
int tmp = 0; // 临时变量
for(int & i: v) { // 遍历原始vector
rem = (i + tmp * From) % To;
i = (i + tmp * From) / To;
tmp = rem;
}
ToV.push_back(rem);
}
递归二进制最大公约数算法
递归终止条件
gcd(m, m) = m
递归关系
- m < n 时:gcd(m, n) = gcd(n, m)
- m为偶数,n为偶数:gcd(m, n) = 2 * gcd(m/2, n/2)
- m为偶数,n为奇数时:gcd(m, n) = gcd(m/2, n)
- m为奇数,n为偶数时:gcd(m, n) = gcd(m, n/2)
- m和n都为奇数时:gcd(m, n) = gcd(n, m - n)
int gcd(int m, int n) {
if (m == n) return m;
else if (n > m) return gcd(n, m);
if (m & 1) return (n & 1) ? gcd(m - n, n): gcd(m, n / 2);
else return (n & 1) ? gcd(m / 2, n) : 2 * gcd(m / 2, n / 2);
}

浙公网安备 33010602011771号