准备河南大学机试
一、河大机试
1.求一个数的反序数
int reverseX(int x){
int res = 0;
// 求X的反序数
while(x > 0){
res = res*10 + x % 10;
x /= 10;
}
return res;
}
2.pair的使用
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<utility> // pair 在 此头文件中
using namespace std;
const int N = 110;
pair<int, string> p[N];
int main(){
int n;
cin >> n;
for(int i = 0; i < n; i++){
int a;
string b;
cin >> a >> b;
p[i].first = a;
p[i].second = b;
}
sort(p, p + n); // 根据第一个进行升序排序
for(int i = n - 1; i >= 0; i--)
cout << p[i].second << endl;
return 0;
}
3.数组模拟单链表
#include<iostream>
#include<cstdio>
using namespace std;
const int N = 100010;
/*
head 表示头结点下标
e[i] 表示节点 i 的值
ne[i] 表示节点 i 的 next 指针是多少
idx 存储当前已经用到哪个点了
*/
int e[N], ne[N], idx, head;
// 初始化
void init(){
head = -1;
idx = 0;
}
// 向链表头部插入一个数
void headAdd(int x){
e[idx] = x;
ne[idx] = head;
head = idx;
idx ++;
}
// 删除第 k 个插入的数后面的数 k = 0 时表示删除头结点
void remove(int k){
ne[k] = ne[ne[k]];
}
// 在第 k 个插入的数后面插入一个数
void addK(int k, int x){
e[idx] = x;
ne[idx] = ne[k];
ne[k] = idx;
idx ++;
}
int main(){
int m;
cin >> m;
init(); // 初始化链表
while(m -- ){
char op;
cin >> op;
if(op == 'H'){ // 向链表头插入一个数
int x;
cin >> x;
headAdd(x);
} else if(op == 'D'){ // 删除第 k 个插入的数后面的数
int k;
cin >> k;
if(k == 0) head = ne[head];
remove(k - 1);
} else { // 在第 k 个插入的数后面插入一个数
int x;
int k;
cin >> k >> x;
addK(k-1, x);
}
}
// 遍历单链表
for(int i = head; i != -1; i = ne[i]){
cout << e[i] << " ";
}
cout << endl;
return 0;
}
4.数组模拟双链表
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 100010;
int e[N], l[N], r[N], idx;
// 初始化双链表
// 0 是左端点, 1 是右端点
void init(){
r[0] = 1;
l[1] = 0;
idx = 2;
}
// 在第 k 个数的右侧插入一个数
// 在第 k 个数的左侧插入一个数 相当于在 l[k] 的右边插入一个数
void insert(int k, int x){
e[idx] = x;
r[idx] = r[k];
l[idx] = k;
l[r[k]] = idx;
r[k] = idx;
idx ++ ;
}
// 删除第 k 个插入的数
void remove(int k){
l[r[k]] = l[k];
r[l[k]] = r[k];
}
int main(){
int m;
cin >> m;
// 初始化双链表
init();
while(m -- ){
string op;
int k, x;
cin >> op;
if(op == "L"){ // 在链表的最左端插入链表 x
cin >> x; // 在最左边插入一个数,相当于在 0 的右边插入一个数
insert(0, x);
} else if(op == "R"){ // 在最右边插入一个数,相当于在 l[1] 的右边插入一个数
cin >> x;
insert(l[1], x);
} else if(op == "D"){ // 因为第一个插入的数下标为 2 所以第k 个插入的数的下标为 k + 1
cin >> k;
remove(k + 1);
} else if(op == "IL"){
cin >> k >> x;
insert(l[k + 1], x);
} else {
cin >> k >> x;
insert(k + 1, x);
}
}
// 双链表输出
for(int i = r[0]; i != 1; i = r[i]) cout << e[i] << " ";
puts("");
return 0;
}
5.模拟栈(先进后出)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 100010;
int stk[N], tt; // tt 表示栈顶 (全局变量 tt 初始化为 0)
int m;
int main(){
cin >> m;
while(m -- ){
string op;
cin >> op;
if(op == "push"){ // 向栈顶压入一个数 x
int x;
cin >> x;
stk[++tt] = x;
} else if(op == "pop"){ // 从栈顶弹出一个数
tt -- ;
} else if(op == "empty"){ // 判断栈是否为空
if(tt == 0) puts("YES");
else puts("NO");
} else { // query 输出栈顶元素
printf("%d\n", stk[tt]);
}
}
return 0;
}
表达式求值
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<stack>
#include<unordered_map>
using namespace std;
stack<int> num; // 存操作数
stack<char> op; // 存操作符
void eval(){
auto b = num.top(); num.pop();
auto a = num.top(); num.pop();
auto c = op.top(); op.pop();
int x;
if(c == '+') x = a + b;
else if(c == '-') x = a - b;
else if(c == '*') x = a * b;
else x = a / b;
num.push(x);
}
int main(){
unordered_map<char, int> pr{{'+', 1}, {'-', 1}, {'*', 2}, {'/', 2}}; // key , value 存操作符的优先级
string str; // 存操作表达式
cin >> str;
for(int i = 0; i < str.size(); i++){
auto c = str[i]; // 拿到当前字符
if(isdigit(c)){ // 如果当前字符是数字
int x = 0, j = i;
while(j < str.size() && isdigit(str[j])) // 拿到表达式中的额这个完整的数字
x = x*10 + str[j ++ ] - '0';
i = j - 1;
num.push(x); // 当前数字入栈
}
else if(c == '(') op.push(c);
else if(c == ')'){
while(op.top() != '(') eval();
op.pop(); // 弹出 '('
}
else{
while(op.size() && op.top() != '(' && pr[op.top()] >= pr[c]) eval();
op.push(c);
}
}
while(op.size()) eval();
cout << num.top() << endl;
return 0;
}
6.模拟队列(先进先出)
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 100010;
int m;
int q[N], hh, tt = -1;
int main(){
cin >> m;
while(m -- ){
string op;
cin >> op;
if(op == "push"){
int x;
cin >> x;
q[++tt] = x;
} else if(op == "pop"){
hh++;
} else if(op == "empty"){
if(hh <= tt) puts("NO");
else puts("YES");
} else {
cout << q[hh] << endl;
}
}
return 0;
}
7.堆排序
如何手写一个堆?
1.插入一个数 heap[++size] = x; up(size);
2.求集合中的最小值 heap[1];
3.删除最小值 heap[1] = heap[size]; size --; down(1);
4.删除任意一个元素 heap[k] = heap[size]; size --; down(k);
5.修改任意一个元素 heap[k] = x; down(k); up(k);
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 100010;
int n, m;
int h[N], cnt;
void down(int u)
{
int t = u; // 默认最小值是当前的节点,看当前的节点的左右孩子,然后更新最小值
if(2 * u <= cnt && h[u * 2] < h[t]) t = u*2;
if(u * 2 + 1 <= cnt && h[u * 2 + 1] < h[t]) t = u * 2 + 1;
if(u != t) // 若最小值在左右孩子中,则交换,递归处理
{
swap(h[u], h[t]);
down(t);
}
}
int main()
{
cin >> n >> m;
for(int i = 1; i <= n; i++) scanf("%d", &h[i]);
cnt = n;
for(int i = n/2; i > 0; i--) down(i);
while(m -- ) // 输出前 m 小的数
{
printf("%d ", h[1]);
h[1] = h[cnt -- ];
down(1);
}
return 0;
}
8.模拟堆
9.vector的使用
牛客成绩排序
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cstdio>
#include<utility> // pair
using namespace std;
typedef struct Student
{
string name;
int number; //记录学生在原来样例中的位置
double score;
};
bool cmp1(const Student &s1, const Student &s2) // 降序
{
if(s1.score == s2.score) // 分数相同维持相对位置不变
return s1.number < s2.number;
else
return s1.score > s2.score;
}
bool cmp2(const Student &s1, const Student &s2) // 升序
{
if(s1.score == s2.score) // 分数相同维持相对位置不变
return s1.number < s2.number;
else
return s1.score < s2.score;
}
int main()
{
int m;
vector<Student> arr;
while(cin >> m)
{
arr.clear(); // 清空 arr
int op;
cin >> op;
int i = 0; // 记录学生在原case中的内容
while(m -- )
{
Student s;
cin >> s.name >> s.score;
s.number = i;
i ++;
arr.push_back(s);
}
if (op == 0)
{
sort(arr.begin(), arr.end(), cmp1);
}
else {
sort(arr.begin(), arr.end(), cmp2);
}
for(auto it = arr.begin(); it != arr.end(); it++) // vector 的遍历
cout << it->name << " " << it -> score << endl;
}
return 0;
}
10.约数计算
有一个数 x 求 x 的约数
i*i = x 则 根号 i 的平方为 x
假如 x = 12
3 < 根号12 = 2倍根号3 < 4
1 * 12 = 12
2 * 6 = 12
3 * 4 = 12
不难发现只需要枚举到 根号x, 根号x 之前的数必然是乘根号之后的数才能得 x 故 res += 2
若根号 x 为整数 则 res ++;
#include<iostream>
using namespace std;
int main()
{
int n;
cin >> n;
while(n -- )
{
int x;
cin >> x;
int res = 0; // 记录约数的个数
for(int i = 1; i*i <= x; i++)
{
if(x % i == 0)
{
if(i == x / i) res ++;
else res +=2;
}
}
cout << res << endl;
}
return 0;
}
11.哈希表
处理冲突
拉链法
#include<iostream>
#include<cstring>
using namespace std;
const int N = 100003; // 大于 100000 的 第一个质数
int h[N], e[N], ne[N], idx;
void insert(int x)
{
int k = (x % N + N) % N; // -10 % 3 == -1 (-1 + 3) % 3 = 2
e[idx] = x;
ne[idx] = h[k];
h[k] = idx ++;
}
bool find(int x)
{
int k = (x % N + N) % N;
for(int i = h[k]; i != -1; i = ne[i])
if(e[i] == x)
return true;
return false;
}
int main()
{
int n;
cin >> n;
memset(h, -1, sizeof h); // h 数组初始化为 -1
while(n--)
{
char op[2];
int x;
scanf("%s%d", op, &x);
if(op[0] == 'I') insert(x);
else
{
if(find(x)) puts("Yes");
else puts("No");
}
}
return 0;
}
开放寻址法 ------- 沿着 k 一直往后找,要么找到空,要么找到那个值
#include<iostream>
#include<cstring>
using namespace std;
const int N = 200003, null = 0x3f3f3f3f; // 这里的 N 取范围的两倍的的第一个质数
int h[N];
int find(int x)
{
int t = (x % N + N) % N;
while(h[t] != null && h[t] != x)
{
t ++ ;
if(t == N) t = 0; // 扫描到末尾的从头开始扫描
}
return t;
}
int main()
{
memset(h, 0x3f, sizeof h); // 设置默认值 0x3f3f3f
int n;
cin >> n;
while(n -- )
{
char op[2];
int x;
scanf("%s%d", op, &x);
int k = find(x); // 找到 x 映射的位置
if(*op == 'I') h[k] = x;
else
{
if(h[k] == null) puts("No");
else puts("Yes");
}
}
return 0;
}
12.DFS 深度优先搜索
13.结构体重载方法进行排序
// 定义一个结构体存放区间端点
struct Range{
int l, r;
// 重载一下方法
bool operator< (const Range &W)const{
// 根据 r 从小到大进行排序
return r < W.r;
}
}range[N];
14.最短路-Bellman-ford
**有边数限制 ** 最多经过不超过 k 条边的最短路径

浙公网安备 33010602011771号