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来表示键和值;