2022春C++OJ

仅通过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的特性可以帮助我们简化代码,但可能会对可读性造成影响
  • 成员变量定义时为什么加上{}
    • 这是一个好习惯,可以防止一些因未初始化问题导致的难以分析的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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值