仅通过OJ, 不保证正确。
作业1
翻转数字
1、注意int的范围是-2147483648-2147483647 可用INT_MAX和INT_MIN
#include <iostream>
#include <limits>
using namespace std;
int main(){
int N;
bool pos = true;
bool of = false;
cin >> N;
// 在这里卡了很久,注意这里不能直接取反,否则会溢出
if(N == -2147483648){
cout << -1 << endl;
of = true;
}
if(N < 0 && !of) {
pos = false;
N = (-1) * N;
}
int temp = N % 10;
N /= 10;
long long ans = 0;
while (!of && (temp > 0 || N != 0)){
ans = ans * 10 + temp;
if(ans > numeric_limits<int>::max() || ans < numeric_limits<int>::min()){
cout << -1 << endl;
of = true;
break;
}
temp = N % 10;
N /= 10;
}
if(!of){
if(pos){
cout << ans << endl;
}
else{
cout << (-1) * ans << endl;
}
}
return 0;
}
或者直接用longlong存输入N,可以避免溢出的情况
#include <iostream>
#include <limits>
using namespace std;
int main(){
long long N;
bool pos = true;
bool of = false;
cin >> N;
// 在这里卡了很久,注意这里不能直接取反,否则会溢出
if(N < 0) {
pos = false;
N = (-1) * N;
}
int temp = N % 10;
N /= 10;
long long ans = 0;
while (temp > 0 || N != 0){
ans = ans * 10 + temp;
if(ans > numeric_limits<int>::max() || ans < numeric_limits<int>::min()){
cout << -1 << endl;
of = true;
break;
}
temp = N % 10;
N /= 10;
}
if(!of){
if(pos){
cout << ans << endl;
}
else{
cout << (-1) * ans << endl;
}
}
return 0;
}
部分乘积
#include <iostream>
#include <limits>
using namespace std;
int main(){
int N;
cin >> N;
int temp;
long long ans = 1;
for(int i = 0; i < N; i++){
cin >> temp;
ans *= temp;
if(ans > numeric_limits<int>::max() || ans < numeric_limits<int>::min()){
cout << -1 << endl;
break;
} else{
cout << ans << " " << endl;
}
}
return 0;
}
特殊元素
2、位运算符^按位异或:任何数和0异或,仍为本身,和自己异或为0.
#include <iostream>
using namespace std;
int main(){
int N;
int ans = 0;
while (cin >> N){
ans = ans ^ N;
}
cout << ans << endl;
return 0;
}
单词计数
3、注意这些bool的变化条件,然后注意空串这个cornercase
#include <iostream>
using namespace std;
int main(){
char c;
int cnt = 0;
bool wordNum = false;//检测到输入非' ''\n'后,调成true;若再有' ''\n',调成false
bool retNum = false;//出现ret后会标记为true,若再有内容则标记为false,ret++
int ret = 0;//记录行数
int word = 0;//记录单词数
while(cin.get(c)){//读未知数量的char
cnt++;
if(c != ' ' && c != '\n' && !wordNum){
word++;
wordNum = true;
}
if((c == ' ' || c == '\n') && wordNum){
wordNum = false;
}
if(ret == 0 && (c != ' ' && c != '\n')){//不把ret = 1是因为空串时行数为0
ret++;
}
if(retNum){
ret++;
retNum = false;
}
if(c == '\n' && !retNum){
retNum = true;
}
}
cout << cnt << " " << word << " " << ret << endl;
return 0;
}
#include <iostream>
using namespace std;
int main(){
char c;
int lineNum = 0;
int wordNum = 0;
int charNum = 0;
bool word = true;
bool attention = false;
while(cin.get(c)){
charNum++;
if(c == ' '){
attention = true;
word = true;
}else if(c == '\n'){
lineNum++;
word = true;
}else{
if(word){
wordNum++;
word = false;
}
}
}
cout << charNum << " " << wordNum << " " << lineNum;
return 0;
}
审题时不要把表示和实际弄混了就行。
Base64编码
4、base64:https://www.cnblogs.com/magisk/p/8809922.html 学习bitset的用法
c++ str.substr(start, length)而不是传首尾
#include <iostream>
using namespace std;
char findBase64(int index){
if(index >= 0 && index <= 25){
return 'A' + index;
}else if(index >= 26 && index <= 51){
return 'a' + index - 26;
}else if(index >= 52 && index <= 61){
return '0' + index - 52;
}else if(index == 62){
return '+';
}else if(index == 63){
return '/';
}
}
string int2bin(int n){
string ans = "";
while(n > 0){
if(n % 2 == 0){
ans = "0" + ans;
}else{
ans = "1" + ans;
}
n /= 2;
}
while(ans.size() < 8){
ans = "0" + ans;
}
return ans;
}
int bin2int(string str){
int n = 1;
int ans = 0;
for(int i = str.size() - 1; i >= 0; i--){
if(str[i] == '1'){
ans += n;
}
n *= 2;
}
return ans;
}
string threeByte(string str){
string temp = "";
string ans = "";
for(int i = 0; i < 24; i += 6){
temp = str.substr(i, 6);
int n = bin2int(temp);
ans += findBase64(n);
}
return ans;
}
string twoByte(string str){
string temp = "";
string ans = "";
temp = str.substr(0, 6);
ans += findBase64(bin2int(temp));
temp = str.substr(6, 6);
ans += findBase64(bin2int(temp));
temp = str.substr(12, 4) + "00";
ans += findBase64(bin2int(temp));
return ans + "=";
}
string oneByte(string str){
string temp = "";
string ans = "";
temp = str.substr(0, 6);
ans += findBase64(bin2int(temp));
temp = str.substr(6, 2) + "0000";
ans += findBase64(bin2int(temp));
return ans + "==";
}
int main(){
char c;
string str;
string ans;
int cnt = 0;
while(cin.get(c)){
str += int2bin((int)c);
cnt++;
if(cnt == 3){
ans += threeByte(str);
cnt = 0;
str = "";
}
}
if(cnt == 1){
ans += oneByte(str);
}else if(cnt == 2){
ans += twoByte(str);
}
cout << ans << endl;
return 0;
}
习题课讲解
#include <iostream>
#include <iomanip>
#include <string>
#include <cassert>
#include <functional>
#include <cstdint>
using namespace std;
int read_input(uint32_t &ans);
string encode_1byte(int cs);
string encode_2bytes(int cs);
string encode_3bytes(int cs);
function<string(int)> jump_table[] = {
nullptr,
encode_1byte,
encode_2bytes,
encode_3bytes,
};
char index_to_char(int i);
int main() {
string ans;
int cs = 0;
int n_bytes;
while ((n_bytes = read_input(cs)) > 0) {
ans += jump_table[n_bytes](cs);
}
cout << ans << endl;
}
const int MASK = 0x0000003f;//00111111 低6位是1
string encode_1byte(int cs) {
string ans;
ans.push_back(index_to_char((cs >> 2) & MASK));
ans.push_back(index_to_char((cs << 4) & MASK));
ans.push_back('=');
ans.push_back('=');
return ans;
}
string encode_2bytes(int cs) {
string ans;
ans.push_back(index_to_char((cs >> 10) & MASK));
ans.push_back(index_to_char((cs >> 4) & MASK));
ans.push_back(index_to_char((cs << 2) & MASK));
ans.push_back('=');
return ans;
}
string encode_3bytes(int cs) {
string ans;
//提取高位的6bits
ans.push_back(index_to_char((cs >> 18) & MASK));
ans.push_back(index_to_char((cs >> 12) & MASK));
ans.push_back(index_to_char((cs >> 6) & MASK));
ans.push_back(index_to_char(cs & MASK));
return ans;
}
int read_input(uint32_t &ans) {
ans = 0;
char c;
for (int i = 0; i < 3; i++) {
if (!cin.get(c)) {
return i;
}
ans = (ans << 8) | static_cast<uint32_t>(c);
}
return 3;
}
char index_to_char(int i) {
const char *alphabet = "ABCDEFG";
return alphabet[i];
/*
if (0 <= i && i < 26) {
return 'A' + i;
} else if (26 <= i && i < 52) {
return 'a' + (i - 26);
} else if (52 <= i && i < 62) {
return '0' + (i - 52);
} else if (i == 62) {
return '+';
} else if (i == 63) {
return '/';
}
assert(0);
*/
}
作业2(数组)
计算年龄和
#include <iostream>
#include <bitset>
using namespace std;
int main(){
int N;
cin >> N;
int fage = 0;
int mage = 0;
int age = 0;
string name = "";
char sex;
for(int i = 0; i < N; i++){
cin >> age >> sex >> name;
if(sex == 'm'){
mage += age;
}else{
fage += age;
}
}
cout << "f: " << fage << endl;
cout << "m: " << mage << endl;
return 0;
}
螺旋打印矩阵
1、顺时针打印矩阵 错因:dir[4] [2]的书写 和上下左右边界都要变
#include <iostream>
using namespace std;
int a[105][105];
int dir[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
int m, n;
int top, low, l, r;
int cnt;
bool in(int x, int y){
return x >= top && x < low && y >= l && y < r;
}
int main(){
cin >> m >> n;
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
cin >> a[i][j];
}
}
int direct = 0;//指示方向
int tx = 0, ty = 0;
top = 0, low = m;
l = 0, r = n;//上下边界会变,左右边界不会变
while (cnt < m * n){
if(in(tx, ty)){
cout << a[tx][ty] << " ";
cnt++;
} else{
tx -= dir[direct][0];
ty -= dir[direct][1];
switch (direct) {
case 0:
top += 1;
break;
case 1:
r -= 1;
break;
case 2:
low -= 1;
break;
case 3:
l += 1;
break;
}
direct = (direct + 1) % 4;
}
tx += dir[direct][0];
ty += dir[direct][1];
}
return 0;
}
旋转矩阵
旋转矩阵:我写的毫无技术含量
#include <iostream>
using namespace std;
int a[105][105];
int n, rev;
int main(){
cin >> n >> rev;
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++){
cin >> a[i][j];
}
}
rev = (rev / 90) % 4;
switch (rev) {
case 0:
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++){
cout << a[i][j] << " ";
}
cout << "\n" << endl;
}
break;
case 1:
for(int i = 0; i < n; i++){
for(int j = n - 1; j >= 0; j--){
cout << a[j][i] << " ";
}
cout << "\n" << endl;
}
break;
case 2:
for(int i = n - 1; i >= 0; i--){
for(int j = n - 1; j >= 0; j--){
cout << a[i][j] << " ";
}
cout << "\n" << endl;
}
break;
case 3:
for(int i = n - 1; i >= 0; i--){
for(int j = 0; j < n; j++){
cout << a[j][i] << " ";
}
cout << "\n" << endl;
}
break;
}
return 0;
}
ArrayList
#include <iostream>
#include <cstring>
using namespace std;
int a[1005];
int size = 0;
int capacity = 0;
void add(int n){
if(size >= capacity){
if(capacity == 0) capacity = 10;
else capacity = capacity + (capacity / 2);
}
a[size++] = n;
return;
}
void remove(int n){
for(int i = 0; i < size; i++){
if(a[i] == n){
for(int j = i; j < size - 1; j++){
a[j] = a[j + 1];
}
size--;
break;
}
}
return;
}
int get(int n){
if(n < 0 || n >= size) return -1;
else return a[n];
}
int main(){
char s[12] = "\0";
int num = 0, n = 0;
cin >> n;
for(int i = 0; i < n; i++){
cin >> s;
//除非是两个string,否则不用==.char数组可用strcmp,string可用compare
if(!strcmp(s, "add")){
cin >> num;
add(num);
}else if(!strcmp(s, "remove")){
cin >> num;
remove(num);
}else if(!strcmp(s, "get")){
cin >> num;
cout << get(num) << endl;
}else if(!strcmp(s, "getSize")){
cout << size << endl;
}else if(!strcmp(s, "getCapacity")){
cout << capacity << endl;
}
}
return 0;
}
Z形变换
#include <iostream>
using namespace std;
int main(){
int n = 0;
string str;
string ans = "";
cin >> str >> n;
int len = str.size();
int cycle = 2*n - 2;//注意到每行的数为周期第i个或周期第cycle-i个
if(n == 1 || n >= len){//如果行数为1或行数多于字符串长度,直接输出原串即可
cout << str << endl;
} else{
for(int i = 0; i < n; i++){//i表示余数 范围在0-len-1之间
for(int j = 0; j + i < len; j += cycle){//a[j+i]与cycle的余数是i 所以a[j+i]在第i行
ans += str[j + i];
if(i != 0 && i != cycle / 2 && j + cycle - i < len){//余cycle为0和n-1的数一个周期都只有一个
ans += str[j + cycle - i];
}
}
}
cout << ans << endl;
}
return 0;
}
5、注意[]的存储 find不要用递归 否则会爆栈
#include <iostream>
#include <cstdint>
#include <map>
#include <string>
#include <vector>
using namespace std;
map<int, int> jmpTable;
int a[1005];
vector<int> l;//用栈构建好跳转表
string str;
int temp;
void find(int index, int len){
for(int i = index + 1; i < len; i++){
if(str[i] == '['){
l.push_back(i);
}else if(str[i] == ']' && !jmpTable.count(i)){
temp = l.back();
jmpTable.insert(make_pair(i, temp));
jmpTable.insert(make_pair(temp, i));
l.pop_back();
if(l.size() == 0) break;
}
}
return;
}
int main(){
std::getline(std::cin, str);
char c;
uint8_t byte = 0;//如果遇到eof赋给目前指针指向的值
int now = 0;//数据指针
for(int i = 0; i < str.size(); i++){
switch (str[i]) {
case '>':
now++;
break;
case '<':
now--;
break;
case '+':
a[now]++;
break;
case '-':
a[now]--;
break;
case ',':
if(!std::cin.get(c)){
a[now] = byte;
} else{
a[now] = c;
}
break;
case '.':
cout << (char)a[now];
break;
case '[':
if(!jmpTable.count(i)){//第一次遇见[
l.push_back(i);
find(i, str.size());
}
if(a[now] == 0){
i = jmpTable[i];
}
break;
case ']':
if(a[now] != 0){
i = jmpTable[i];
}
break;
}
}
return 0;
}
BF解释器
#include <iostream>
#include <cstdint>
#include <map>
#include <string>
#include <vector>
using namespace std;
map<int, int> jmpTable;
int a[1005];
vector<int> l;
string str;
int temp;
void find(int index, int len){
for(int i = index + 1; i < len; i++){
if(str[i] == '['){
l.push_back(i);
}else if(str[i] == ']' && !jmpTable.count(i)){
temp = l.back();
jmpTable.insert(make_pair(i, temp));
jmpTable.insert(make_pair(temp, i));
l.pop_back();
if(l.size() == 0) break;
}
}
return;
}
int main(){
std::getline(std::cin, str);
char c;
uint8_t byte = 0;//如果遇到eof赋给目前指针指向的值
int now = 0;//数据指针
for(int i = 0; i < str.size(); i++){
switch (str[i]) {
case '>':
now++;
break;
case '<':
now--;
break;
case '+':
a[now]++;
break;
case '-':
a[now]--;
break;
case ',':
if(!std::cin.get(c)){
a[now] = byte;
} else{
a[now] = c;
}
break;
case '.':
cout << (char)a[now];
break;
case '[':
if(!jmpTable.count(i)){//第一次遇见[
l.push_back(i);
find(i, str.size());
}
if(a[now] == 0){
i = jmpTable[i];
}
break;
case ']':
if(a[now] != 0){
i = jmpTable[i];
}
break;
}
}
return 0;
}
讲解:双端队列
#include <iostream>
#include <assert.h>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
//链表节点
struct Node{
Node* next;//后一个节点
Node* prev;//前一个节点
int val;//该节点存放的数字
};
//双端队列
struct Deque{
int size;//有效节点数
Node* front;//虚拟头节点,不作为有效节点
Node* rear;//虚拟尾节点,不作为有效节点
};
void push_front (Deque* self, int value){
Node *newNode = new Node;
newNode->val = value;
newNode->prev = self->front;
newNode->next = self->front->next;
self->front->next->prev = newNode;
self->front->next = newNode;
self->size++;
}
void push_back (Deque* self, int value){
Node *newNode = new Node;
newNode->val = value;
newNode->next = self->rear;
newNode->prev = self->rear->prev;
self->rear->prev->next = newNode;
self->rear->prev = newNode;
self->size++;
}
void pop_front (Deque* self){
if(self->size == 0){
cout << -1 << endl;
}else{
cout << self->front->next->val << endl;
Node *tmp = self->front->next->next;//待删除结点的后一个结点
tmp->prev = self->front;
self->front->next = tmp;
self->size--;
}
}
void pop_back (Deque* self){
if(self->size == 0){
cout << -1 << endl;
}else{
cout << self->rear->prev->val << endl;
Node *tmp = self->rear->prev->prev;//待删除结点的前一个结点
tmp->next = self->rear;
self->rear->prev = tmp;
self->size--;
}
}
int main(){
Node *front = new Node;
Node *rear = new Node;
Deque *deque = new Deque;
front->val = -1;
rear->val = -1;
front->next = rear;
front->prev = nullptr;
rear->next = nullptr;
rear->prev = front;
deque->front = front;
deque->rear = rear;
deque->size = 0;
int n;
cin >> n;
string instr;
int num;
for(int i = 0; i < n; i++){
cin >> instr;
if(instr.compare("pushFront") == 0){
cin >> num;
push_front(deque, num);
}else if(instr.compare("pushBack") == 0){
cin >> num;
push_back(deque, num);
} else if(instr.compare("popBack") == 0){
pop_back(deque);
} else if(instr.compare("popFront") == 0){
pop_front(deque);
} else if(instr.compare("getSize") == 0){
cout << deque->size << endl;
}
}
}
作业3(链表)
翻转链表
1、翻转链表:类似栈,从开头插入即可
#include <iostream>
#include <assert.h>
using namespace std;
struct Node{
int k;
Node *next;
};
//不返回,因为dummy一直不变
void *insert(Node *head, int val){
assert(head != nullptr);
Node *n = new Node;
n->k = val;
n->next = nullptr;
n->next = head->next;
head->next = n;
}
void print(const Node *head){//const 因为不需要改内容
assert(head != nullptr);
if(head -> next == nullptr){
cout << "<null>" << endl;
return;
}
const Node *p = head->next;
while (p != nullptr){
cout << p->k;
if(p->next != nullptr){
cout << " ";
}
p = p->next;
}
cout << endl;
}
//回收链表占用的空间
void release(Node *head){
assert(head != nullptr);
Node *p = head;
while(p != nullptr){
Node *q = p->next;//先把下一个指针记录 否则删了p后就不合法 可能地址值会变
delete p;
p = q;
}
}
int main(){
int n;
Node *dummy = new Node;
dummy->k = -1;//-1在二进制补码里全1 可能有帮助
dummy->next = nullptr;
while(cin >> n){
insert(dummy, n);
}
print(dummy);
release(dummy);
}
矩阵连乘
2、矩阵连乘:感觉效率比较低 用mat1和ans交替存结果
#include <algorithm>
#include <cstddef>
#include <iostream>
#include <iterator>
using namespace std;
//size_t:与机器相关的unsigned类型,其大小足以保证存储内存中对象的大小。
int main() {
size_t N;
cin >> N;
int mat1[100][100];//矩阵所有的值都可以用int容纳
int mat2[100][100];
int ans[100][100];
size_t rows, cols;
size_t n_rows, n_cols;
cin >> rows >> cols;//读入行数与列数
for (int i = 0; i < rows; i++) {
copy_n(istream_iterator<int>(std::cin), cols, mat1[i]);
}
for(size_t j = 0; j < N - 1; j++){
cin >> n_rows >> n_cols;//读入行数与列数
for (int i = 0; i < n_rows; i++) {
copy_n(istream_iterator<int>(std::cin), n_cols, mat2[i]);
}
for(size_t m = 0; m < rows; m++) {
for (size_t n = 0; n < n_cols; n++) {
for (size_t k = 0; k < n_rows; k++) {
if (j % 2 == 0) {
if (k == 0) {
ans[m][n] = mat1[m][k] * mat2[k][n];
} else {
ans[m][n] += mat1[m][k] * mat2[k][n];
}
} else {
if (k == 0) {
mat1[m][n] = ans[m][k] * mat2[k][n];
} else {
mat1[m][n] += ans[m][k] * mat2[k][n];
}
}
}
}
}
}
//最后知行数为rows 列数为n_cols
for(size_t i = 0; i < rows; i++){
for(size_t j = 0; j < n_cols; j++){
if(N % 2 == 0)cout << ans[i][j] << " ";
else cout << mat1[i][j] << " ";
}
cout << endl;
}
}
sort
3、sort指令 错因为-d str2那里写错了
#include <iostream>
#include <assert.h>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
vector<string> strSet;
//插入时默认按照字典序升序排列
bool cmp(string a, string b){
return a < b;
}
bool cmp_n(string a, string b){
return atoi(a.c_str()) < atoi(b.c_str());
}
bool cmp_r(string a, string b){
return a >= b;
}
bool cmp_d(string a, string b){
string str1;
string str2;
for(int i = 0; i < a.size(); i++){
if(isdigit(a[i]) || isalpha(a[i]) || isblank(a[i])){
str1 += a[i];
}
}
for(int i = 0; i < b.size(); i++){
if(isdigit(b[i]) || isalpha(b[i]) || isblank(b[i])){
str2 += b[i];
}
}
return str1 < str2;
}
bool cmp_i(string a, string b){
string tmp1 = a;
string tmp2 = b;
transform(tmp1.begin(), tmp1.end(), tmp1.begin(), ::tolower);
transform(tmp2.begin(), tmp2.end(), tmp2.begin(), ::tolower);
if(tmp1 > tmp2){
return false;
} else if(tmp1 == tmp2 && a > b){
return false;
}
return true;
}
void print(){//const 因为不需要改内容
for(int i = 0; i < strSet.size(); i++){
cout << strSet[i] << endl;
}
}
int main(){
int n;
cin >> n;
cin >> ws;//跳过行中的空白符
string s;
for(int i = 0; i < n; i++){
getline(cin, s);
strSet.push_back(s);
}
cin >> n;
cin >> ws;//跳过行中的空白符
char c;
for(int i = 0; i < n; i++){
cin >> c;
cin >> ws;//跳过行中的空白符
if(c == '-'){
sort(strSet.begin(), strSet.end(), cmp);
} else if(c == 'n'){
sort(strSet.begin(), strSet.end(), cmp_n);
} else if(c == 'i'){
sort(strSet.begin(), strSet.end(), cmp_i);
} else if(c == 'd'){
sort(strSet.begin(), strSet.end(), cmp_d);
} else if(c == 'r'){
sort(strSet.begin(), strSet.end(), cmp_r);
}
print();
}
}
双端队列
4、双端队列 老师给的模板很好
#include <iostream>
#include <assert.h>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
//链表节点
struct Node{
Node* next;//后一个节点
Node* prev;//前一个节点
int val;//该节点存放的数字
};
//双端队列
struct Deque{
int size;//有效节点数
Node* front;//虚拟头节点,不作为有效节点
Node* rear;//虚拟尾节点,不作为有效节点
};
void push_front (Deque* self, int value){
Node *newNode = new Node;
newNode->val = value;
newNode->prev = self->front;
newNode->next = self->front->next;
self->front->next->prev = newNode;
self->front->next = newNode;
self->size++;
}
void push_back (Deque* self, int value){
Node *newNode = new Node;
newNode->val = value;
newNode->next = self->rear;
newNode->prev = self->rear->prev;
self->rear->prev->next = newNode;
self->rear->prev = newNode;
self->size++;
}
void pop_front (Deque* self){
if(self->size == 0){
cout << -1 << endl;
}else{
cout << self->front->next->val << endl;
Node *tmp = self->front->next->next;//待删除结点的后一个结点
tmp->prev = self->front;
self->front->next = tmp;
self->size--;
}
}
void pop_back (Deque* self){
if(self->size == 0){
cout << -1 << endl;
}else{
cout << self->rear->prev->val << endl;
Node *tmp = self->rear->prev->prev;//待删除结点的前一个结点
tmp->next = self->rear;
self->rear->prev = tmp;
self->size--;
}
}
int main(){
Node *front = new Node;
Node *rear = new Node;
Deque *deque = new Deque;
front->val = -1;
rear->val = -1;
front->next = rear;
front->prev = nullptr;
rear->next = nullptr;
rear->prev = front;
deque->front = front;
deque->rear = rear;
deque->size = 0;
int n;
cin >> n;
string instr;
int num;
for(int i = 0; i < n; i++){
cin >> instr;
if(instr.compare("pushFront") == 0){
cin >> num;
push_front(deque, num);
}else if(instr.compare("pushBack") == 0){
cin >> num;
push_back(deque, num);
} else if(instr.compare("popBack") == 0){
pop_back(deque);
} else if(instr.compare("popFront") == 0){
pop_front(deque);
} else if(instr.compare("getSize") == 0){
cout << deque->size << endl;
}
}
}
HashDict
5、多次重复扩容卡了很久 学习struct的建立和删除指针的操作
#include <iostream>
#include <string>
#include <vector>
#include "assert.h"
using namespace std;
//链表节点
struct Entry{
int size;//每个桶的有效大小
int key;//该节点存放的数字
string value;
Entry* next;//后一个节点
};
struct HashDict{
int cnt;//table中元素的总数
int l;//table的长度
Entry *tables;
};
long long hashFunc(HashDict *hashDict, int key){
return llabs(3LL * key * key * key + 5LL * key * key + 7LL * key + 11LL) % hashDict->l;
}
void reHash(HashDict* hashDict);
void initialize(HashDict *hashDict, int l){
hashDict->l = l;
hashDict->cnt = 0;
hashDict->tables = new Entry[l];
Entry *entries = hashDict->tables;
for(int i = 0; i < l; i++){//给每个桶设一个dummy结点
entries[i].value = "";
entries[i].key = -1;
entries[i].next = nullptr;
entries[i].size = 0;
}
}
bool adjust(HashDict *hashDict){
Entry *entries = hashDict->tables;
bool adjust = false;
for(int i = 0; i < hashDict->l; i++){
if(entries[i].size > 4){
adjust = true;
break;
}
}
if(hashDict->cnt > hashDict->l || adjust){
return true;
}
return false;
}
void add(HashDict *hashDict, int key, string value){
Entry *newNode = new Entry;
newNode->key = key;
newNode->value = value;
newNode->next = nullptr;
int pos = hashFunc(hashDict, newNode->key);
Entry *entries = hashDict->tables;
Entry *prev = entries + pos;
Entry *curr = prev->next;
while (curr != nullptr && curr->key < newNode->key){
prev = curr;
curr = curr->next;
}
// newNode插在prev和curr之间 即使curr为nullptr也很正确
prev->next = newNode;
newNode->next = curr;
hashDict->cnt++;
entries[pos].size++;
while(adjust(hashDict)){//这里的多次扩容卡了很久!! 因为只有add可能引起扩容,放这儿也行
reHash(hashDict);
}
}
void del(HashDict *hashDict, int key){
int pos = hashFunc(hashDict, key);
Entry *entries = hashDict->tables;
Entry *prev = entries + pos;
Entry *curr = prev->next;
while (curr != nullptr && curr->key != key){
prev = curr;
curr = curr->next;
}
// 要删除的结点就是curr
prev->next = curr->next;
delete curr;
hashDict->cnt--;
entries[pos].size--;
}
void mySearch(HashDict *hashDict, int pos){
Entry *entries = hashDict->tables;
Entry *curr = entries[pos].next;
if(curr == nullptr){
cout << "null" << endl;
}
while (curr != nullptr){
if(curr->next != nullptr){
cout << curr->key << ":" << curr->value << "->";
}else{
cout << curr->key << ":" << curr->value << endl;
}
curr = curr->next;
}
}
void reHash(HashDict* hashDict){
int oldLen = hashDict->l;
Entry *entries = hashDict->tables;//指向Entry[oldLen]的指针
initialize(hashDict, 2 * oldLen + 1);//指向新的table
//桶中除dummy结点外的结点,用完就删
for(int i = 0; i < oldLen; i++){
Entry *currEntry = entries + i;
currEntry = currEntry->next;
if(currEntry == nullptr){
delete currEntry;
} else{
while (currEntry != nullptr){
Entry * tempEntry = currEntry;
add(hashDict, currEntry->key, currEntry->value);
currEntry = currEntry->next;
delete tempEntry;
}
}
}
delete[] entries;//删除头指针(指针指向的动态空间)
}
int main(){
HashDict* hashDict = new HashDict;
int l;
cin >> l;
initialize(hashDict, l);
int n;
cin >> n;
string instr;
int num;
string value;
int pos;
for(int i = 0; i < n; i++){
cin >> instr;//输入指令
if(instr.compare("add") == 0){
cin >> num >> value;
add(hashDict, num, value);
} else if(instr.compare("delete") == 0){
cin >> num;
del(hashDict, num);
} else if(instr.compare("search") == 0){
cin >> pos;
mySearch(hashDict, pos);
}
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h6naMvO7-1654267062966)(C:\Users\84368\AppData\Roaming\Typora\typora-user-images\image-20220326230447878.png)]
作业4(内存管理)
深拷贝容器
注意自赋值不会进行重新构造!
//并没有任何拷贝,因为构造时把m指针传入
MyContainer get(){
MyContainer m {1};
return m;
}
int main(){
MyContainer m = get();
return 0;
}
问题1:析构函数不手动写吗?要手动写
2:delete[] _data;//只释放指向的,不释放_data指针?qs,要置null、
3:成员变量在进入构造函数时进行初始化?qs
#include <iostream>
class MyContainer {
public:
MyContainer(int size) : _size(size) {
_data = new int[size];//开辟相应大小的内存
_count++;
}
~MyContainer() {
delete[] _data;//释放堆上申请的内存
// 栈上的指针要置null
_data = nullptr;
_count--;
}
MyContainer(const MyContainer &Other) {//拷贝构造
_data = new int[Other.size()];
_size = Other.size();
_count++;
}
MyContainer &operator=(const MyContainer &Other) {//操作符重载
if(this != &Other){//注意自赋值不会重新构造 要判断!这里的&Other是地址,上面是引用
delete[] _data;//删掉原来的
_data = new int[Other.size()];//申请新空间
_size = Other.size();
}
return *this;
}
int size() const {//获取私有变量的方法 加const可保护
return _size;
}
int* data() const {
return _data;
}
static int count() {//获取共享静态变量
return _count;
}
static int _count;//静态成员,要共享
private:
// C++11 引入的 initializer_list
int *_data{nullptr};//堆内存上某个地址
int _size{0};//数组长度
};
int MyContainer::_count = 0;//因为只定义一次,所以写在类外部(不用再写static了这里)
void test1(){
MyContainer m(5);
std::cout << m.count() << std::endl;
MyContainer m2(m);
std::cout << m2.count() << std::endl;
MyContainer m3 = m2;
std::cout << m3.count() << std::endl;
}
void test2(){
MyContainer m1(5);
std::cout << m1.count() << std::endl;
MyContainer m2 = m1;
std::cout << m2.count() << std::endl;
std::cout << (m2.data() == m1.data()) << std::endl;
}
void test3(){
MyContainer m1(3);
std::cout << m1.count() << std::endl;
MyContainer m2 = m1;
std::cout << m2.count() << std::endl;
std::cout << (m2.data() == m1.data()) << std::endl;
m1 = m2;
std::cout << m1.count() << std::endl;
std::cout << (m2.data() == m1.data()) << std::endl;
m2 = m1;
std::cout << m2.count() << std::endl;
std::cout << (m2.data() == m1.data()) << std::endl;
int * prev_ptr = m1.data();
m1 = m1;
std::cout << m1.count() << std::endl;
std::cout << (m1.data() == prev_ptr) << std::endl;
}
void test4(){
MyContainer m1(3);
std::cout << m1.count() << std::endl;
{
MyContainer m2 = m1;
std::cout << m2.count() << std::endl;
std::cout << (m2.data() == m1.data()) << std::endl;
m1 = m2;
std::cout << m1.count() << std::endl;
std::cout << (m2.data() == m1.data()) << std::endl;
m2 = m1;
std::cout << m2.count() << std::endl;
std::cout << (m2.data() == m1.data()) << std::endl;
}
std::cout << m1.count() << std::endl;
}
int main(){
test1();
test2();
test3();
test4();
return 0;
}
共享内存
- 构造函数为什么会使用explicit关键字进行标注
- 如果不使用explicit,对于
MyContainer m = 10
,编译器会进行隐式类型转换,此时程序的行为可能不符合我们预期 - 有的时候利用explicit的特性可以帮助我们简化代码,但可能会对可读性造成影响
- 如果不使用explicit,对于
- 成员变量定义时为什么加上{}
- 这是一个好习惯,可以防止一些因未初始化问题导致的难以分析的bug
- 思考如何扩展本练习中的共享内存容器,以支持对任意类型内存的共享
- 请参考shared_ptr的基本原理,可能需要一些模板编程的知识
- 有了shared_ptr,我们是不是可以只需要创建资源,剩下的都交给shared_ptr管理
- shared_ptr可能产生循环引用而导致的内存泄漏
- shared_ptr的额外性能开销
- 标准库的shared_ptr不是线程安全的
- shared_ptr既然能清理不被使用的内存,那么垃圾收集又是什么?
- 前者回收资源是eager的;后者回收资源是lazy的
- 前者有循环引用问题;后者没有
- …
不太懂,暂时复制在这里。
_data = new Content(mem_id);//new返回的是指针
//注意不能这么写 *_data = Content(mem_id);
#include <iostream>
#include <string>
using namespace std;
class Content {
public:
explicit Content(int id) : id(id) {
std::cout << "create " << id << std::endl;
}
int get_id() const{
return id;
}
~Content() {
std::cout << "destroy " << std::to_string(id) << std::endl;
}
private:
int id{-1};//当前内存块的序号
char data[1024]{};//可以存具体内容
};
class SharedContainer {
public:
explicit SharedContainer(int mem_id){
_data = new Content(mem_id);//新建一个Content对象实例
_ref_count[_data->get_id()]++;
};
~SharedContainer(){
_ref_count[_data->get_id()]--;//引用数减1
if(_ref_count[_data->get_id()] == 0){//如果当前对象没有被共享,则被消除
delete _data;
}
}
SharedContainer(const SharedContainer &other){//拷贝构造函数
_data = other.get_content();//不用开辟新内存,指向同一块!
_ref_count[_data->get_id()]++;
}
SharedContainer& operator=(const SharedContainer &other){
if(this != &other){//不要自赋值
if(_data->get_id() != other.get_content()->get_id()) {//如果相等可以忽略这条语句了
_ref_count[_data->get_id()]--;
if(_ref_count[_data->get_id()] == 0){//如果当前对象没有被共享,删除元素
delete _data;
}
_ref_count[other.get_content()->get_id()]++;
_data = other.get_content();
}
}
return *this;
}
Content* get_content() const {//获得当前SharedContainer持有的Content
return _data;
}
int get_count() const{//获得引用数量
return _ref_count[_data->get_id()];
}
SharedContainer(const SharedContainer &&) = delete;//表示禁用
SharedContainer &operator=(const SharedContainer &&) = delete;
static int _ref_count[];//记录每个Content被多少个Container持有
private:
Content *_data{nullptr};//维护的Context对象实例
};
int SharedContainer::_ref_count[10];//静态变量编译时赋初值分配内存,除非const可以在构造函数里赋值
//因为是静态,初始值为0
void test1(){
SharedContainer m1(1);
SharedContainer m2 = m1;
SharedContainer m3(m2);
std::cout << m1.get_count() << std::endl;
std::cout << m2.get_count() << std::endl;
std::cout << m3.get_count() << std::endl;
}
void test2(){
SharedContainer m1(1);
SharedContainer m2 = m1;
m1 = m1;
{
SharedContainer m3 = m1;
std::cout << m1.get_count() << std::endl;
}
std::cout << m1.get_count() << std::endl;
std::cout << m2.get_count() << std::endl;
}
void test3(){
SharedContainer m1(1);
SharedContainer m2(2);
m1 = m2;
std::cout << m1.get_count() << std::endl;
std::cout << m2.get_count() << std::endl;
{
SharedContainer m3(3);
m1 = m3;
std::cout << m1.get_count() << std::endl;
std::cout << m2.get_count() << std::endl;
std::cout << m3.get_count() << std::endl;
}
std::cout << m1.get_count() << std::endl;
std::cout << m2.get_count() << std::endl;
}
int main(){
test1();
test2();
test3();
return 0;
}
动态内存
分别利用队列实现先进先出,栈实现后进先出。
#include <cassert>
#include <functional>
#include <iostream>
#include <memory>
#include <string>
#include <unordered_map>
#include <stack>
#include <queue>
// 除了 TODO 标出的部分,不要修改原有的声明和定义,否则后果自负!
using namespace std;
class MemoryContext {
public:
/**
* @param parent 父节点,可能为 nullptr
*/
MemoryContext(MemoryContext *parent);
~MemoryContext();
// void HelpDelete(MemoryContext *memoryContext);
// 禁止拷贝和移动
MemoryContext(const MemoryContext &) = delete;
MemoryContext &operator=(const MemoryContext &) = delete;
MemoryContext(MemoryContext &&) = delete;
MemoryContext &operator=(MemoryContext &&) = delete;
using chunk_id_t = std::string;//用一个别名表示string
void alloc(const chunk_id_t &chunk_id);
private:
stack<chunk_id_t> chunks;//记录内存块 stack后进先出
queue<MemoryContext*> children;//记录子孙节点 queue先进先出
};
//函数可以在类外面写,写清楚类名即可
MemoryContext::MemoryContext(MemoryContext *parent) {//传入父节点
if(parent != nullptr){//要判断非空,否则没意义
parent->children.push(this);
}
}
MemoryContext::~MemoryContext() {
// HelpDelete(this);
while(children.size() != 0){
MemoryContext* curr = children.front();
children.pop();
delete curr;//在这里完成递归,即使有重复因为chunks空了也不会重复输出,加个状态标识或许也可以
}
while (chunks.size() > 0){//全部输出
cout << "Chunk " << chunks.top() << " freed." << endl;
chunks.pop();
}
}
// void MemoryContext::HelpDelete(MemoryContext *memoryContext) {//本来想沿着dfs的思路写一个,但析构函数本身就可以用于递归了
// while(memoryContext->children.size() != 0){
// MemoryContext* curr = memoryContext->children.front();
// memoryContext->children.pop();
// HelpDelete(curr);
// }
// while (memoryContext->chunks.size() > 0){
// cout << "Chunk " << memoryContext->chunks.top() << " freed." << endl;
// memoryContext->chunks.pop();
// }
// }
void MemoryContext::alloc(const chunk_id_t &chunk_id) {//传入内存块id 是一条string
chunks.push(chunk_id);
}
void test_1() {
std::unique_ptr<MemoryContext> A = std::make_unique<MemoryContext>(nullptr);
A->alloc("1");
A->alloc("2");
A->alloc("3");
}
void test_2() {
std::unique_ptr<MemoryContext> A = std::make_unique<MemoryContext>(nullptr);
MemoryContext *B = new MemoryContext(A.get());
MemoryContext *C = new MemoryContext(B);
A->alloc("1");
A->alloc("2");
A->alloc("3");
B->alloc("1/1");
B->alloc("1/2");
B->alloc("1/3");
C->alloc("1/1/1");
C->alloc("1/1/2");
C->alloc("1/1/3");
}
void test_3() {
std::unique_ptr<MemoryContext> A = std::make_unique<MemoryContext>(nullptr);
MemoryContext *B = new MemoryContext(A.get());
MemoryContext *C = new MemoryContext(A.get());
MemoryContext *D = new MemoryContext(B);
MemoryContext *E = new MemoryContext(C);
MemoryContext *F = new MemoryContext(C);
MemoryContext *G = new MemoryContext(E);
A->alloc("1");
A->alloc("2");
A->alloc("3");
B->alloc("1/1");
C->alloc("1/2");
D->alloc("1/1/1");
D->alloc("1/1/2");
G->alloc("1/2/1/1");
}
void test_4() {
std::unique_ptr<MemoryContext> A = std::make_unique<MemoryContext>(nullptr);
MemoryContext *B = new MemoryContext(A.get());
MemoryContext *C = new MemoryContext(A.get());
MemoryContext *D = new MemoryContext(B);
MemoryContext *E = new MemoryContext(B);
MemoryContext *F = new MemoryContext(C);
MemoryContext *G = new MemoryContext(C);
A->alloc("1");
A->alloc("2");
A->alloc("3");
B->alloc("1/1");
C->alloc("1/2");
D->alloc("1/1/1");
D->alloc("1/1/3");
E->alloc("1/1/2");
F->alloc("1/2/1");
G->alloc("1/2/3");
G->alloc("1/2/5");
G->alloc("1/2/2");
G->alloc("1/2/4");
}
void test_5() {
std::unique_ptr<MemoryContext> A = std::make_unique<MemoryContext>(nullptr);
MemoryContext *B = new MemoryContext(A.get());
MemoryContext *C = new MemoryContext(A.get());
MemoryContext *D = new MemoryContext(B);
MemoryContext *G = new MemoryContext(C);
A->alloc("2");
A->alloc("1");
A->alloc("3");
A->alloc("4");
B->alloc("2/1");
B->alloc("3/5");
C->alloc("1024/2");
C->alloc("1024/1");
G->alloc("8192/1/4095");
}
#define REGISTER_TEST_CASE(name) \
{ #name, name }
int main() {
std::unordered_map<std::string, std::function<void()>>
test_functions_by_name = {
REGISTER_TEST_CASE(test_1), REGISTER_TEST_CASE(test_2),
REGISTER_TEST_CASE(test_3), REGISTER_TEST_CASE(test_4),
REGISTER_TEST_CASE(test_5),
};
std::string test_case_name;
std::cin >> test_case_name;
auto it = test_functions_by_name.find(test_case_name);
assert(it != test_functions_by_name.end());
auto fn = it->second;
fn();
}
下棋
注意行和列、正对角线和反对角线的判断。
#include <iostream>
#include <string>
class Piece {
public:
explicit Piece(int pos_x, int pos_y, char c): x(pos_x), y(pos_y){
type = c == 'X'? 1 : -1;
};
int getX() const{
return x;
}
int getY() const{
return y;
}
int getType() const{
return type;
}
private:
int x;
int y;
int type;//用int标识是X还是O
};
class Board {
public:
explicit Board(int n, int m) : M(m),N(n),cnt(0){//构造函数 n是行列数
board = new int*[n];//board指向n个int*
for(int i = 0; i < n; i++){
board[i] = new int[n];
}
}
~Board() {//析构函数
for(int i = 0; i < N; i++){
delete[] board[i];
}
delete[] board;
board = nullptr;
}
bool place(Piece piece){
board[piece.getX()][piece.getY()] = piece.getType();
cnt++;//棋子数
if(cnt >= M){
return judge();
}
return false;
}
bool judge(){//判断胜负,以及游戏是否进行
bool flag = false;
// 行和列的判断
for(int i = 0; !flag && i < N; i++){//[i,j]标识起点
for(int j = 0; !flag && j + M <= N; j++){
int lineSum = 0;
int colSum = 0;
for(int k = 0; k < M; k++){
lineSum += board[i][j + k];
colSum += board[j + k][i];
}
if(lineSum == M || colSum == M) {
std::cout << "X Success";
flag = true;
}else if(lineSum == (-1)*M || colSum == (-1)*M){
std::cout << "O Success";
flag = true;
}
}
}
// 正对角线和反对角线的判断
for(int i = 0; !flag && i + M <= N; i++){//[i,j]标识起点
for(int j = 0; !flag && j + M <= N; j++){
int posDiagonalSum = 0;
int negDiagonalSum = 0;
for(int k = 0; k < M; k++){
posDiagonalSum += board[i + k][j + k];
negDiagonalSum += board[i + k][N - 1 -(j + k)];
}
if(posDiagonalSum == M || negDiagonalSum == M) {
std::cout << "X Success";
flag = true;
}else if(posDiagonalSum == (-1)*M || negDiagonalSum == (-1)*M){
std::cout << "O Success";
flag = true;
}
}
}
if(!flag && cnt == N * N){//平局
std::cout << "Dogfall";
flag = true;
}
return flag;
}
private:
int** board;//当前的棋盘
int M;//当前内存块的序号
int N;//当前棋盘的行列数
int cnt;
};
int main(){
int N, M;
std::cin >> N >> M;
Board game(N, M);
int turn = 0;//用于表示不同轮次谁出棋
int x, y;
//每下一步棋都会判断一次
while (std::cin >> x){
std::cin >> y;
if(turn % 2 == 0){
Piece piece(x, y, 'O');
if(game.place(piece)){
break;
}
}else{
Piece piece(x, y, 'X');
if(game.place(piece)){
break;
}
}
turn++;
}
return 0;
}
UI-design
不知道自己写的好不好,不过注意
- gray排序时如果一样,按照id!
- 注意gray用double存储!!小数加权。
- 尽量用Manager统一管理,然后多用vector存储,循环找对象。
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
class Rec {
public:
explicit Rec(string t, string ploygonid): type(t){
//把字符串转成id string->int
ploygonid = ploygonid.substr(1);
id = atoi(ploygonid.c_str());
};
int getId(){
return id;
}
int getR(){
return R;
}
int getG(){
return G;
}
int getB(){
return B;
}
double getGray(){
return GRAY;
}
void set(int r, int g, int b){
if(type == "normal"){
R = r;
G = g;
B = b;
}else if(type == "single"){
R = r;
G = 0;
B = 0;
}else if(type == "reverse"){
R = 255 - r;
G = 255 - g;
B = 255 - b;
}
GRAY = R * 0.299 + G * 0.587 + B * 0.114;
}
private:
int id;
int R{0};
int G{0};
int B{0};
double GRAY{0};
string type;
};
class Group {
public:
void setId(string ploygonid){
//把字符串转成id
ploygonid = ploygonid.substr(1);
id = atoi(ploygonid.c_str());
};
void add(Rec *rec){
recs.push_back(rec);
}
int getId(){
return id;
}
void set(int r, int g, int b){
// 遍历group,对每一个矩形设置颜色
for(int i = 0; i < recs.size(); i++){
recs[i]->set(r, g, b);
}
}
private:
vector<Rec *> recs;//当前创建的数组
int id;
};
class RecManager {
public:
void addRec(Rec *rec){
recs.push_back(rec);
}
void addGroup(Group *group){
groups.push_back(group);
}
static bool sort_normal(Rec *a, Rec *b){
return a->getId() < b->getId();
}
static bool sort_gray(Rec *a, Rec *b){
if(a->getGray() != b->getGray()){
return a->getGray() < b->getGray();
}else{//注意gray相同时,按照id大小排序!!!
return a->getId() < b->getId();
}
}
void sortRecs(string type){
if(type == "Normal"){
sort(recs.begin(), recs.end(), sort_normal);
}else if(type == "Gray"){
sort(recs.begin(), recs.end(), sort_gray);
}
for(int i = 0; i < recs.size(); i++){//将recs按顺序输出
cout << "P" << recs[i]->getId() << " " << recs[i]->getR() << " " << recs[i]->getG() << " " << recs[i]->getB() << endl;
}
}
Rec* findRec(string name){//根据名称寻找指定的recs
name = name.substr(1);
int tmpId = atoi(name.c_str());
for(int i = 0; i < recs.size(); i++){
if(recs[i]->getId() == tmpId){
return recs[i];
}
}
}
Group* findGroup(string name){
name = name.substr(1);
int tmpId = atoi(name.c_str());
for(int i = 0; i < groups.size(); i++){
if(groups[i]->getId() == tmpId){
return groups[i];
}
}
}
private:
vector<Rec *> recs;//当前创建的数组
vector<Group* > groups;//当前拥有的组
};
int main(){
int N;
cin >> N;
string op;
RecManager *recManager = new RecManager;
for(int i = 0; i < N; i++){
cin >> op;
if(op == "Add"){
string type, name;
cin >> type >> name;
Rec *rec = new Rec(type, name);//创建
recManager->addRec(rec);//加入recs
}else if(op == "Group"){
int n;
string index, groupId;
cin >> n;
Group *group = new Group;
while (n > 0){
cin >> index;
group->add(recManager->findRec(index));//向组内加入指定的rec
n--;
}
cin >> groupId;
group->setId(groupId);
recManager->addGroup(group);
}else if(op == "Set"){
string name;
int r, g, b;
cin >> name >> r >> g >> b;
if(name[0] == 'P'){//如果是P
recManager->findRec(name)->set(r, g, b);
}else if(name[0] == 'G'){//如果是G
recManager->findGroup(name)->set(r, g, b);
}
}
}
while (cin >> op){//不占用N条命令
if(op == "Normal" || op == "Gray"){
recManager->sortRecs(op);
}
}
return 0;
}
作业5(操作符重载、模板)
斐波拉契数列
#include <cstdint>
#include <functional>
#include <iostream>
#include <unordered_map>
template <uintmax_t N>//uintmax_t是能实现的最宽的无符号整型
struct Fib {
static constexpr uintmax_t value = Fib<N - 1>::value + Fib<N - 2>::value;
};
template<> class Fib<0>{
public:
enum{value = 0};//枚举整型常量
};
template<> class Fib<1>{//template<>一定要写,为了使编译器将该语句认定为template specialization,在进行初始化。
public:
enum{value = 1};
};
void test_1() { std::cout << Fib<0>::value << std::endl; }
void test_2() { std::cout << Fib<1>::value << std::endl; }
void test_3() { std::cout << Fib<2>::value << std::endl; }
void test_4() { std::cout << Fib<5>::value << std::endl; }
void test_5() { std::cout << Fib<20>::value << std::endl; }
int main() {
std::unordered_map<std::string, std::function<void()>> test_cases_by_name = {
{"test_1", test_1}, {"test_2", test_2}, {"test_3", test_3},
{"test_4", test_4}, {"test_5", test_5},
};
std::string tname;
std::cin >> tname;
auto it = test_cases_by_name.find(tname);
if (it == test_cases_by_name.end()) {
std::cout << "输入只能是 test_<N>,其中 <N> 可取整数 1 到 5." << std::endl;
return 1;
}
(it->second)();
}
整数流
注意operator bool表示自定义类型到bool的隐式转换,这里指的是流是否被榨干(即是否遇到过增加stride失败的情况)
#include <functional>
#include <iostream>
#include <limits>
#include <string>
#include <unordered_map>
#include <queue>
class IntStream {
public:
explicit IntStream(int first);
IntStream(int first, int last);
IntStream(int first, int last, int stride);
IntStream &operator++();//++a 返回左值
IntStream operator++(int);//a++ 返回值
int operator*() const;//用于获得当前int流最前面的值
operator bool() const;//将int流转换为bool值
long long f;
long long l;
int s;
long long curr;
bool flag;
};
IntStream::IntStream(int first): f(first){
l = -1;
s = 1;
curr = f;
flag = false;
};
IntStream::IntStream(int first, int last) : f(first), l(last){
s = 1;
curr = f;
flag = false;
}
IntStream::IntStream(int first, int last, int stride) : f(first), l(last), s(stride){
curr = f;
flag = false;
}
IntStream IntStream::operator++(int) {//返回++之前的对象拷贝
IntStream tmp = *this;
if(l == -1){//如果没有结束值
curr += s;
}else{
if(s > 0 && l > curr + s){//有结束值的话要比较一下
curr += s;
}else if(s < 0 && l < curr + s){
curr += s;
}else if(curr + s == l){
flag = true;
}
}
return tmp;
}
IntStream &IntStream::operator++() {//返回左值,*this
if(l == -1){//如果没有结束值
curr += s;
}else{
if(s > 0 && l > curr + s){//有结束值的话要比较一下
curr += s;
}else if(s < 0 && l < curr + s){
curr += s;
}else if(curr + s == l){//切实遇到榨干
flag = true;
}
}
return *this;
}
int IntStream::operator*() const {//获取当前 int 流最前面的值
return curr;
}
IntStream::operator bool() const {//看流中是否还有值
return !flag;//看流是否被榨干
}
void print_answer(const IntStream &s, int expect) {
std::cout << std::boolalpha;
if (s) {
std::cout << (*s == expect) << ' ' << *s << std::endl;
} else {
std::cout << false << std::endl;
}
}
/**
* @brief 测试 IntStream(int) 每次加1
*/
void test_1() {
IntStream s(0);
for (size_t i = 0; i < 10; i++) {
++s;
}
print_answer(s, 10);
}
/**
* @brief 测试 IntStream(int, int) 有结束值
*/
void test_2() {
IntStream s(0, 10);
for (size_t i = 0; i < 9; i++) {
s++;
}
print_answer(s, 9);
}
/**
* @brief 测试 IntStream(int, int, int) - 不考虑溢出 有步长
*/
void test_3() {
IntStream s(0, 10, 2);
for (size_t i = 0; i < 4; i++) {
++s;
}
print_answer(s, 8);
}
/**
* @brief 测试 IntStream(int, int, int) - 步长为负数
*/
void test_4() {
IntStream s(10, 0, -1);
for (size_t i = 0; i < 10; i++) {
s++;
}
print_answer(s, 0);
}
/**
* @brief 测试 IntStream(int, int, int) - 考虑溢出,大于最大值
*/
void test_5() {
IntStream s(std::numeric_limits<int>::max() - 10000,
std::numeric_limits<int>::max(), 123);
for (size_t i = 0; i < 50; i++) {
++s;
}
print_answer(s, 2147479797);
}
/**
* @brief 测试 IntStream(int, int, int) - 考虑溢出,小于最小值
*/
void test_6() {
IntStream s(std::numeric_limits<int>::min() + 10000,
std::numeric_limits<int>::min(), -123);
for (size_t i = 0; i < 50; i++) {
s++;
}
print_answer(s, -2147479798);
}
/**
* @brief 测试步长为 0 的情况
*/
void test_7() {
IntStream s(std::numeric_limits<int>::min(), std::numeric_limits<int>::max(),
0);
for (size_t i = 0; i < 10000; i++) {
s++;
}
print_answer(s, std::numeric_limits<int>::min());
}
/**
* @brief 测试范围 [first, last) 非常大的情况
*/
void test_8() {
IntStream s(std::numeric_limits<int>::min(), std::numeric_limits<int>::max());
for (size_t i = 0; i < 10000; i++) {
s++;
}
print_answer(s, std::numeric_limits<int>::min() + 10000);
}
int main() {
std::unordered_map<std::string, std::function<void()>> test_cases_by_name = {
{"test_1", test_1}, {"test_2", test_2}, {"test_3", test_3},
{"test_4", test_4}, {"test_5", test_5}, {"test_6", test_6},
{"test_7", test_7}, {"test_8", test_8},
};
std::string tname;
std::cin >> tname;
auto it = test_cases_by_name.find(tname);
if (it == test_cases_by_name.end()) {
std::cout << "输入只能是 test_<N>,其中 <N> 可取整数 1 到 8." << std::endl;
return 1;
}
(it->second)();
}
有理数
注意构造函数时就要进行约分,注意除法转换成乘法。
注意加法和减法不是直接对分子分母啊喂。
#include <cctype>
#include <cstring>
#include <functional>
#include <iostream>
#include <stdexcept>
#include <string>
#include <unordered_map>
template <typename T>
class Rational {
private:
T N, D;
public:
Rational(const T &n, const T &d){
//测试用例会catch exception,所以这里只用throw
T tmp_d = d, tmp_n = n;
if(d > n){
tmp_d = n, tmp_n = d;
}
while(tmp_d != 0 && tmp_n % tmp_d != 0){
tmp_d = tmp_n % tmp_d;
tmp_n = tmp_d;
}
if(tmp_d > 1){
N = n / tmp_d;
D = d / tmp_d;
}else{
N = n;
D = d;
}
if(D == 0 && N != 0)throw std::logic_error("denominator must be != 0");
};//n是分子,d是分母
Rational(const Rational<T> &rhs){//拷贝构造函数
N = rhs.N;
D = rhs.D;
};
T numerator() const{return N;}//返回分子
T denominator() const{return D;}//返回分母
Rational<T> operator+(const Rational<T> &rhs) const{
return Rational<T>(D * rhs.N + N * rhs.D, D * rhs.D);
};
Rational<T> operator-(const Rational<T> &rhs) const{
return Rational<T>(N * rhs.D - D * rhs.N, D * rhs.D);
};
Rational<T> operator*(const Rational<T> &rhs) const{
return Rational<T>(N * rhs.N, D * rhs.D);
};
Rational<T> operator/(const Rational<T> &rhs) const{//注意除法要转换成乘法!
return Rational<T>(N * rhs.D, D * rhs.N);
};
Rational<T> &operator=(const Rational<T> &rhs){
N = rhs.N;
D = rhs.D;
};
//输出一个有理数,要约分
friend std::ostream &operator<<(std::ostream &out, const Rational<T> &r){//友元函数可以访问私有成员
if(r.N == 0){
out << 0;
}else{
if(r.D == 1){//如果分母等于1
out << r.N << std::endl;
}else{
out << r.N << "/" << r.D << std::endl;
}
}
};
};
Rational<int> operator""_r(const char *str, size_t len){
int n, d;
std::string f = str;
int index = 0;
while(index < len && str[index] != '/'){
index++;
}
n = atoi(f.substr(0, index).c_str());
d = atoi(f.substr(index + 1, len - index - 1).c_str());
return Rational<int>(n, d);
};//后缀构造一个有理数
void test_1() {
Rational<int> r(3, 4);
std::cout << r << std::endl;
}
void test_2() {
bool exception_thrown = false;
bool expected_message = false;
try {
Rational<int> r = Rational<int>(1, 0);
} catch (std::logic_error &exn) {
exception_thrown = true;
if (!strncmp(exn.what(), "denominator must be != 0", 24)) {
expected_message = true;
}
} catch (...) {
}
if (exception_thrown) {
std::cout << "std::logic_error thrown!" << std::endl;
if (expected_message) {
std::cout << "the message is as expected." << std::endl;
}
} else {
std::cout << "Oops!" << std::endl;
}
}
void test_3() {
Rational<int> r(3, 4);
std::cout << r.numerator() << ' ' << r.denominator() << std::endl;
}
void test_4() {
Rational<int> lhs(1, 6), rhs(1, 3);
std::cout << (lhs + rhs) << std::endl;
}
void test_5() {
Rational<int> lhs(1, 2), rhs(1, 6);
std::cout << (lhs - rhs) << std::endl;
}
void test_6() {
Rational<int> lhs(2, 4), rhs(4, 6);
std::cout << (lhs * rhs) << std::endl;
}
void test_7() {
Rational<int> lhs(2, 4), rhs(4, 6);
std::cout << (lhs / rhs) << std::endl;
}
void test_8() {
Rational<int> r(3, 4);
std::cout << r << std::endl;
Rational<int> rhs(101, 203);
r = rhs;
std::cout << r << ' ' << rhs << std::endl;
}
void test_9() {
auto r = "3/4"_r;
std::cout << r << std::endl;
}
void test_10() { std::cout << Rational<int>(4, 2) << std::endl; }
void test_11() {
std::cout << (Rational<int>(1, 2) - Rational<int>(2, 4)) << std::endl;
}
void test_12() { std::cout << Rational<int>(3, 6) << std::endl; }
int main() {
std::unordered_map<std::string, std::function<void()>> test_cases_by_name = {
{"test_1", test_1}, {"test_2", test_2}, {"test_3", test_3},
{"test_4", test_4}, {"test_5", test_5}, {"test_6", test_6},
{"test_7", test_7}, {"test_8", test_8}, {"test_9", test_9},
{"test_10", test_10}, {"test_11", test_11}, {"test_12", test_12},
};
std::string tname;
std::cin >> tname;
auto it = test_cases_by_name.find(tname);
if (it == test_cases_by_name.end()) {
std::cout << "输入只能是 test_<N>,其中 <N> 可取整数 1 到 12." << std::endl;
return 1;
}
(it->second)();
}
Bit_Vector
主要需要注意变长数组的创建,其他还好。
#include <iostream>
#include <vector>
using namespace std;
class MyBitVector {
private:
int len;
int *nums;//数组
public:
explicit MyBitVector(int size): len(size) {
nums = new int[len];
for(int i = 0; i < len; i++){
clear(i);
}
}
explicit MyBitVector(const string &s) {
len = s.size();
nums = new int[len];
for(int i = 0; i < s.size(); i++){
nums[i] = s[i] - '0';
}
}
void set(int index) {
nums[index] = 1;
}
void clear(int index) {
nums[index] = 0;
}
bool get(int index) {
return nums[index] == 1? true: false;
}
void print() {
for(int i = 0; i < len; i++){
cout << nums[i];
}
cout << endl;
}
MyBitVector operator&(MyBitVector &other) {
MyBitVector bv(max(len, other.len));
for(int i = 0; i < bv.len; i++){
if(get(i) && other.get(i)){
bv.set(i);
}
}
return bv;
}
MyBitVector operator|(MyBitVector &other) {
MyBitVector bv(max(len, other.len));
for(int i = 0; i < bv.len; i++){
if(get(i) || other.get(i)){
bv.set(i);
}
}
return bv;
}
MyBitVector operator^(MyBitVector &other) {
MyBitVector bv(max(len, other.len));
for(int i = 0; i < bv.len; i++){
if(get(i) != other.get(i)){
bv.set(i);
}
}
return bv;
}
MyBitVector operator~() {//按位取反
MyBitVector bv(len);
for(int i = 0; i < bv.len; i++){
if(!get(i)){
bv.set(i);
}
}
return bv;
}
//原地按位与操作
MyBitVector &operator&=(MyBitVector &other) {
for(int i = 0; i < len; i++){
if(get(i) && other.get(i)){
set(i);
}else{
clear(i);
}
}
}
MyBitVector &operator|=(MyBitVector &other) {
for(int i = 0; i < len; i++){
if(get(i) || other.get(i)){
set(i);
}else{
clear(i);
}
}
}
MyBitVector &operator^=(MyBitVector &other) {
for(int i = 0; i < len; i++){
if(get(i) != other.get(i)){
set(i);
}else{
clear(i);
}
}
}
};
void test1() {
MyBitVector bv1("01010100");
MyBitVector bv2("11101111");
MyBitVector bv3 = bv1 & bv2;
bv1 &= bv2;
bv1.print();
bv2.print();
bv3.print();
}
void test2() {
MyBitVector bv1("00001000");
MyBitVector bv2("11010011");
MyBitVector bv3 = bv1 | bv2;
bv1 |= bv2;
bv1.print();
bv2.print();
bv3.print();
}
void test3() {
MyBitVector bv1("00010010");
MyBitVector bv2("10111001");
MyBitVector bv3 = bv1 ^ bv2;
bv1 ^= bv2;
bv1.print();
bv2.print();
bv3.print();
}
void test4() {
MyBitVector bv1("00100100");
MyBitVector bv2 = ~bv1;
bv1 = ~bv1;
bv1.print();
bv2.print();
}
void test5() {
MyBitVector bv1("00000001");
bv1.set(2);
bv1.print();
}
#define TEST(x) std::cout << "test" << #x << "\n"; test##x();
int main() {
TEST(1);
TEST(2);
TEST(3);
TEST(4);
TEST(5);
return 0;
}
编写GenericAdder
注意一级指针和二级指针的使用即可。
#include <iostream>
class MyComplex {
public:
MyComplex(int real, int imag) : real(real), imag(imag) {}
int real;
int imag;
MyComplex operator+(const MyComplex& other) const {
return MyComplex(real + other.real, imag + other.imag);
}
friend std::ostream& operator<<(std::ostream& os, const MyComplex& mc);
};
std::ostream& operator<<(std::ostream& os, const MyComplex& mc) {
os << "(" << mc.real << "," << mc.imag << ")";
return os;
}
template <typename Ty1, typename Ty2>
auto GenericAdder(Ty1 a, Ty2 b) {//这个类型不同且未定义时会失败
return a + b;
}
// sample
template<>
auto GenericAdder(int a, std::string b) {
return std::to_string(a) + b;
}
auto GenericAdder(std::string a, int b) {
return a + std::to_string(b);
}
auto GenericAdder(int a, MyComplex b) {
MyComplex c(a, 0);
return c + b;
}
auto GenericAdder(MyComplex* a, MyComplex* b) {//求解指针指向的元素之和
return *a + *b;
}
auto GenericAdder(MyComplex** a, MyComplex** b) {//求解指针指向的元素之和
return GenericAdder(*a, *b);
}
void test1() {
std::cout << GenericAdder(1, 2) << "\n";
std::cout << GenericAdder(1.0, 2.0) << "\n";
std::cout << GenericAdder(1, std::string("1")) << "\n";
}
void test2() {
std::cout << GenericAdder(1, MyComplex(1, 3)) << "\n";
std::cout << GenericAdder(MyComplex(1, 3), MyComplex(1, 3)) << "\n";
}
void test3() {
MyComplex a{1, 3};
MyComplex b{2, 6};
std::cout << GenericAdder(&a, &b) << "\n";
}
void test4() {
MyComplex a{1, 3};
MyComplex b{2, 6};
MyComplex *pa = &a;
MyComplex *pb = &b;
std::cout << GenericAdder(&pa, &pb) << "\n";
}
#define TEST(x) std::cout << "test" << #x << "\n"; test##x();
int main(){
TEST(1);
TEST(2);
TEST(3);
TEST(4);
return 0;
}