C/C++语言学习记录

C/C++语言学习笔记及简单程序Demo记录


1- 判别素数小程序

#include <iostream>
#include <stdio.h>
using namespace std;

int isPrime(int);

int main() {
    int a;
    cin >> a;
    while (a != -1) {
        printf("%d %s 素数\n", a, isPrime(a) ? "是" : "不是");
        cin >> a;
    }
    return 0;
}

int isPrime(int a) {
    if (a <= 1) return 0;
    for (int i=2; i*i<=a; i++) {
        if (a % i == 0) return 0;
    }
    return 1;
}

2- 1015. Reversible Primes (20)

代码如下:

#include <iostream>
#include <math.h>
#include <stdio.h>
using namespace std;
int isPrime(int n) {
    if (n < 2) return 0;
    for (int i = 2; i <= sqrt(n); i++)
        if (n % i == 0) return 0;
    return 1;
}
int main() {
    int n, r;
    cin >> n;
    while (n >= 0) {
        cin >> r;
        if (isPrime(n)) {
            int len = 0, a[20];
            while (n) {
                a[len++] = n % r;
                n /= r;
            }
            int temp = 0;
            for (int i = 0; i < len; i++)
                temp = temp * r + a[i];
            printf("%s\n", isPrime(temp) ? "Yes" : "No");
        }
        else printf("No\n");
        cin >> n;
    }
}

3-1019. General Palindromic Number (20)

#include <iostream>
#include <stdio.h>
using namespace std;
int main() {
    int n, r;
    cin >> n >> r;
    int len = 0, a[40];
    while (n)
        a[len++] = n % r, n /= r;
    bool flag = false;
    for (int i = 0; i < len / 2; i++)
        if (a[i] != a[len - i - 1]) {
            flag = true; break;
        }
    if (flag) printf("No\n");
    else printf("Yes\n");
    for (int i = len - 1; i >= 0; i--)
        if (i == 0) printf("%d", a[i]);
        else  printf("%d ", a[i]);
    if (len == 0) printf("0");
    return 0;
}

这里注意判断回文时候不要使用左右指针,因为右指针right可能为-1,所以应该按照柳神的折半判断法,不会出错;


4- 1020. Tree Traversals (25)

#include <iostream>
#include <stdio.h>
#include <queue>
using namespace std;
int po[30], in[30];
typedef struct node {
    int val;
    struct node *left, *right;
} Node;
struct node* create(int pl, int pr, int inl, int inr) {
    if (pl > pr || inl > inr) return NULL;
    //struct node *temp = (node*)malloc(sizeof(node));
    Node *temp = new Node();
    if (pl == pr) {
        temp->val = po[pl];
        /*temp->right = NULL;
        temp->left = NULL;*/
    }
    else {
        temp->val = po[pr];
        int index = -1;
        for (int i = inl; i <= inr; i++) {
            if (in[i] == po[pr]) {
                index = i;
                break;
            }
        }
        int len = index - inl;
        temp->left = create(pl, pl + len - 1, inl, index - 1);
        temp->right = create(pl + len, pr-1, index+1, inr);
    }
    return temp;
}
int main() {
    int n;
    cin >> n;
    for (int i = 0; i < n; i++)
        cin >> po[i];
    for (int i = 0; i < n; i++)
        cin >> in[i];
    struct node *head = create(0, n-1, 0, n-1);
    queue<struct node> q;
    q.push(*head);
    bool flag = true;
    while (!q.empty()) {
        struct node temp = q.front();
        q.pop();
        if (flag) {
            printf("%d", temp.val);
            flag = false;
        }
        else printf(" %d", temp.val);
        if (temp.left != NULL) q.push(*temp.left);
        if (temp.right != NULL) q.push(*temp.right);
    }
}

这道题让我学习到了结构体在c语言里的使用的很多注意点,

  • 如果不适用typedef定义的结构体别名去初始化时,必须使用malloc函数;而且使用malloc函数必须将左右孩子指针初始化为NULL,而new直接干了这件事;
  • 使用了C++的queue函数,常用的几个功能,非常简单就学会;
  • 复习了指针的使用方法;
  • 复习了二叉树的重建和层次遍历;

其实

柳神给出了这个题目非常简练的一个版本,看完真的佩服的五体投地,赶紧自己手写一遍来学习下,代码如下;

#include <iostream>
#include <stdio.h>
#include <vector>
using namespace std;
vector<int> po, in, level(10000, -1);
void help(int root, int start, int end, int le) {
    if (start > end) return;
    level[le] = po[root];
    int i = start;
    while (i < end && po[root] != in[i]) i++;
    help(root - (end - i + 1), start, i - 1, le * 2 + 1);
    help(root - 1, i+1, end, le * 2 + 2);
}
int main() {
    int n;
    cin >> n;
    po.resize(n);
    in.resize(n);
    for (int i = 0; i < n; i++)
        cin >> po[i];
    for (int i = 0; i < n; i++)
        cin >> in[i];
    help(n - 1, 0, n - 1, 0);
    bool flag = true;
    for (int i = 0; i < level.size(); i++) {
        if (level[i] != -1) {
            if (flag) {
                printf("%d", level[i]);
                flag = 0;
            }
            else printf(" %d", level[i]);
        }
    }
}

不需要利用结构体创建一个二叉树,而只需要利用动态数组去固定分配好子节点所在的位置,然后存在就赋值,不存在就让他为-1,最后再逐一打印出各层的节点数值,brilliant as she is!


5- 1021. Deepest Root (25)

这道题源码我全部贴到另一篇帖子去,因为里面设计到了许多巧妙的算法,很受用;再此处只想检出里面的c语言中的几个必须掌握的知识点;

  • vector的使用,使用resize(int n)来实现初始化大小,虽然是动态数组;以及通过vector<vector<int>>来表示邻接链表,比java的
List<List<Integer>>[] li = new ArrayList[100];

容易的多(省去了一遍初始化?);

  • set<int>的使用,存储不重复的元素的集合类,set.insert(int n)用于插入元素;
  • fill函数用于填充数组里元素,如下一行代码所示;
bool flag[10005]; fill(flag, flag + 10005, false);
  • for的遍历集合时候,常用的几种方式;
//遍历vector temp
for (int j = 0; j < temp.size(); j++)
    s.insert(temp[j]);
//遍历set s,实现从小到大输出元素
for (auto it : s) {
    printf("%d\n", it);
}

//以及下种形式;
for (auto it = s.begin(); it != s.end(); it++) {
    printf("%d\n", *it);
}

6- 1023. Have Fun with Numbers (20)

#include <iostream>
#include <string>
using namespace std;

int main() {

    string s;
    cin >> s;
    int num[10], ch[21], len = s.size();
    fill(num, num + 10, 0);
    fill(ch, ch + 21, 0);
    for (int i = 0; i < len; i++) {
        num[s[i] - '0'] ++;
    }
    int in = 0;
    for (int i = len - 1; i >= 0; i--) {
        int temp = s[i] - '0';
        if (temp * 2 + in > 9) {
            ch[i + 1] = temp * 2 + in - 10;
            in = 1;
        }
        else {
            ch[i + 1] = temp * 2 + in;
            in = 0;
        }
    }
    if (in == 1) {
        printf("No\n1");
        for (int i=1; i<=len; i++)
            printf("%d", ch[i]);
    }
    else {
        for (int i = 1; i <= len; i++) {
            num[ch[i]] --;
        }
        int f = 0;
        for (int i=0; i<10; i++)
            if (num[i] != 0) {
                f = 1;
                break;
            }
        if (f) printf("No\n");
        else printf("Yes\n");
        for (int i = 1; i <= len; i++)
            printf("%d", ch[i]);
    }
    return 0;
}
  • string的使用技巧,在这里值得注意一下;
  • 对于string,格式化输出时,不能用%s,这是对char * 才采用发的方式,只能用cout;
  • 在字符串和int之间转换过程中,可以记住一下几个函数: itoa(int num, char * ch, int radix), 该函数功能是将int数字num转化为字符串ch,其中的radix是进制,而最后想打印字符串,只需要将ch输出即可;
  • atoi(char *s)函数,将字符串转化为int数据;常见 int num = atoi(s);其中的s是一个字符数组;

7- c++常用类是使用技巧总结;

  • cin读整数时,如果下一行的使用getline的话,会报错,因为cin末尾的’\n’没读出来,所以要再使用getchar();
  • sort对vector排序时候,使用sort(v.begin(), v.end())即可;
  • set默认是使用红黑树存储的,所以auto在for里获得set的迭代器时,直接按照从小到大的顺序输出,并未排序,意味着auto对vector遍历时,按照插入顺序进行输出;
  • map对某一个键元素(key)是否存在,常用的判断方式是map.find(key) == map.end();或者是map.count(key)==1;

8- 1025. PAT Ranking (25)

#include <iostream>
#include <string>>
#include <vector>
#include <algorithm>
using namespace std;
struct stu {
    string id;
    int score, place, localrank;
};
bool cmp(stu s1, stu s2) {
    if (s1.score != s2.score) return s1.score > s2.score;
    else return s1.id<s2.id;
}
vector<stu> v;
int main() {
    int n, k, score, number = 0;
    string id;
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> k;
        number += k;
        for (int j = 0; j < k; j++) {
            cin >> id >> score;
            v.push_back(stu {id, score, i+1, 1});
        }
        sort(v.end() - k, v.end(), cmp);
        int rank = 1;
        for (int j = 0; j < k; j++) {
            if (!(j == 0 || v[v.size() - k + j].score == v[v.size() - k + j - 1].score)) rank = j + 1;
            v[v.size() - k + j].localrank = rank;
        }
    }
    sort(v.begin(), v.end(), cmp);
    cout << number << endl;
    int rank = 1;
    for (int i = 0; i < number; i++) {
        cout << v[i].id + " ";
        if (!(i == 0 || v[i].score == v[i-1].score)) {
            rank = i + 1;
        }
        cout << rank <<" "<< v[i].place << " " << v[i].localrank << endl;
    }
    return 0;
}
  • 比较器的使用,和结构体排序;
  • 如何给一个结构体的一个实例初始化:
struct stu {
    string id;
    int score, place, localrank;
};
// vector<stu> v
v.push_back(stu {id, score, i+1});

9- Kuchiguse (20)

#include <iostream>
#include <stdio.h>
#include <string>
#include <vector>
using namespace std;
int main() {
    int n;
    scanf("%d", &n);
    getchar();
    vector<string> v;
    string temp;
    for (int i=0; i<n; i++) {
        getline(cin, temp);
        v.push_back(temp); 
    }
    temp = v[0];
    string suffix = "";    
    for (int i=0; i<n; i++) {

        int r1 = temp.size()-1, r2 = v[i].size()-1;
        while (r1 >= 0 && r2 >= 0 && temp[r1] == v[i][r2]) {        
            suffix = temp[r1] + suffix;
            r1 --;
            r2 --;
        }
        temp = suffix;
        suffix = "";
    }
    if (temp.size() == 0) cout << "nai"<< endl;
    else cout << temp << endl;
    return 0;
}
  • 注意此题的重要一点是getchar的使用,scanf和cin等在配合getline读取整行数据的时候,都必须将前面的换行符当掉;
  • 这是一道非常简单的求算公共字符串后缀问题,算法思路并不难;

10-1097. Deduplication on a Linked List (25)

#include <stdio.h>
#include <vector>
#include <stdlib.h>
#include <set>
using namespace std;
int val[100005], nex[100005], b[100005];
int main() {
    int head, n;
    scanf("%d%d", &head, &n);
    for (int i=0; i<n; i++) {
        int temp;
        scanf("%d", &temp);
        scanf("%d%d", &val[temp], &nex[temp]);
    }
    vector<int> v, u, nv;
    while (head != -1) {
        nv.push_back(head);
        head = nex[head];
    }
    set<int> s;
    for (int i=0; i<nv.size(); i++) {
        if (s.find(abs(val[nv[i]])) == s.end()) {
            s.insert(abs(val[nv[i]]));
            b[nv[i]] = 1;
        }
    }
    for (int i=0; i<nv.size(); i++) {
        if (b[nv[i]] == 1) v.push_back(nv[i]);
        else u.push_back(nv[i]);
    }
    for (int i=0; i<v.size(); i++) {
        if (i == 0) printf("%05d %d", v[i], val[v[i]]);
        else printf(" %05d\n%05d %d", v[i], v[i], val[v[i]]);
    }
    printf(" -1\n");
    for (int i=0; i<u.size(); i++) {
        if (i == 0) printf("%05d %d", u[i], val[u[i]]);
        else printf(" %05d\n%05d %d", u[i], u[i], val[u[i]]);
        if (i == u.size()-1) printf(" -1\n");
    }
    return 0;
}
  • 这道题,是链表的经典题型,注意这种题目,输入结点n可能有非链表节点,所以得用重新遍历以便将所有从head出发的节点重新串联起来,然后从头开始一次遍历;
  • 本来是使用set作为一个中间保存有所有不重复元素的一个集合,遇到重复的就先挂到新链表后去,然后在当前vector删除即可,但最后超时,细想了下vector的erase函数也是O(n),不划算,所以最好还是选用了一个新的vector来装重新剔除重复元素后的初始链表,这才没有超时;

11-1092. To Buy or Not to Buy (20)

#include <cstdio>
#include <map>
#include <vector>
using namespace std;
const int maxn = 1005;
char ch[maxn], des[maxn];
int main() {
    int n;
    scanf("%s%s", ch, des);
    map<char, int> map;
    for (int i=0; i<maxn&&ch[i] != '\0'; i++) {
        map[ch[i]] ++;
    }
    for (int i=0; i<maxn&&des[i] != '\0'; i++) {
        map[des[i]] --;
    }
    bool f = true;
    vector<int> v;
    for (auto it=map.begin(); it!=map.end(); it++) {
        if (it->second < 0) f = false;
        v.push_back(it->second);
    }
    printf("%s ", f ? "Yes" : "No");
    int num = 0;
    if (f) {
        for (int i=0; i<v.size(); i++) 
            num += v[i];
    } else {
        for (int i=0; i<v.size(); i++) 
            if (v[i] < 0) num += -v[i];
    }
    printf("%d", num);
}
  • 这里需要注意的是map的遍历,每一个it项都表示一对键值对,取first和second来表示键和值;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值