又是睿智OJ,有的题严格判空格和换行符,有的题又不判;有的题必须用 fgets 读入换行符,有的题又不能读入换行符;突出一个逆天。
文章末尾为 2023-2024 春学期上机考试题目。
第二章 线性表
1 顺序表的插入运算
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int val;
struct node *next;
} Node, List;
List *init(void) {
List *s = (List*) malloc(sizeof(List));
Node *tail = s; int n;
s->next = NULL, s->val = -1;
scanf("%d", &n);
for (int i = 0; i < n; ++i) {
Node *node = (Node*) malloc(sizeof(Node));
scanf("%d", &node->val);
node->next = NULL, tail->next = node, tail = node;
}
return s;
}
void insert(List *s) {
Node *node = (Node*) malloc(sizeof(Node)), *curr = s;
scanf("%d", &node->val);
while (curr->next) {
if (node->val > curr->next->val) curr = curr->next;
else break;
}
node->next = curr->next, curr->next = node;
}
void traverse(List *s) {
for (Node *curr = s->next; curr; curr = curr->next)
printf("%d ", curr->val);
printf("\n");
}
int main () {
List *s = init();
insert(s);
traverse(s);
return 0;
}
2 线性表的就地逆置
#include <stdio.h>
#include <stdlib.h>
int arr[1005] = {
};
typedef struct node {
int val;
struct node *next;
} Node, List;
List *init(int n) {
List *s = (List*) malloc(sizeof(List));
Node *tail = s;
s->next = NULL, s->val = -1;
for (int i = 0; i < n; ++i) {
Node *node = (Node*) malloc(sizeof(Node));
scanf("%d", &arr[i]);
node->val = arr[i], node->next = NULL;
tail->next = node, tail = node;
}
return s;
}
void reverse(List *s, int n) {
// 三指针迭代
Node *prev = NULL, *curr = s->next;
while (curr) {
Node *next = curr->next;
curr->next = prev;
prev = curr, curr = next;
}
s->next = prev;
int begin = 0, end = n - 1;
while (begin < end) {
int tmp = arr[begin];
arr[begin] = arr[end], arr[end] = tmp;
++begin, --end;
}
}
void traverse(List *s, int n) {
// 会尾判空格
for (Node *curr = s->next; curr; curr = curr->next) {
if (!curr->next) printf("%d", curr->val);
else printf("%d ", curr->val);
}
printf("\n");
for (int i = 0; i < n; ++i) {
if (i == n - 1) printf("%d", arr[i]);
else printf("%d ", arr[i]);
}
printf("\n");
}
int main () {
int n;
scanf("%d", &n);
List *s = init(n);
reverse(s, n);
traverse(s, n);
return 0;
}
3 顺序表的删除
#include <stdio.h>
#include <stdlib.h>
int n, m1, m2;
int arr1[1005] = {
};
int arr2[1005] = {
};
typedef struct node {
int val;
struct node *next;
} Node, List;
List *init(void) {
scanf("%d %d %d", &n, &m1, &m2);
List *s = (List*) malloc(sizeof(List));
Node *tail = s;
s->next = NULL, s->val = -1;
for (int i = 0; i < n; ++i) {
Node *node = (Node*) malloc(sizeof(Node));
scanf("%d", &node->val);
node->next = NULL, tail->next = node, tail = node;
}
for (int i = 0; i < m1; ++i)
scanf("%d", &arr1[i]);
for (int i = 0; i < m2; ++i)
scanf("%d", &arr2[i]);
return s;
}
void delete(List *s) {
// 三指针遍历
int h1 = 0, h2 = 0;
Node *curr = s->next;
while (h1 < m1 && h2 < m2) {
if (arr1[h1] < arr2[h2]) ++h1;
else if (arr1[h1] > arr2[h2]) ++h2;
else {
int val = arr1[h1];
while (curr->next) {
if (curr->next->val == val) {
Node* tmp = curr->next;
curr->next = tmp->next;
free(tmp);
} else if (curr->next->val < val)
curr = curr->next;
else break;
}
++h1, ++h2;
}
}
}
void traverse(List *s) {
for (Node *curr = s->next; curr; curr = curr->next)
printf("%d ", curr->val);
printf("\n");
}
int main () {
List *s = init();
delete(s);
traverse(s);
return 0;
}
4 单链表的归并
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int val;
struct node *next;
} Node, List;
List *init(int n) {
List *s = (List*) malloc(sizeof(List));
Node *tail = s;
s->next = NULL, s->val = -1;
for (int i = 0; i < n; ++i) {
Node *node = (Node*) malloc(sizeof(Node));
scanf("%d", &node->val);
node->next = NULL, tail->next = node, tail = node;
}
return s;
}
List* merge(List* src1, List* src2) {
if (!src1->next) return src2;
if (!src2->next) return src1;
List* dest = (List*) malloc(sizeof(List));
dest->next = NULL, dest->val = -1;
Node *curr1 = src1->next, *curr2 = src2->next, *head = dest, *tmp = NULL;
// 头插逆序, 尾插正序, 以下采用头插法
while (curr1 && curr2) {
if (curr1->val < curr2->val) {
tmp = curr1->next, curr1->next = head->next;
head->next = curr1, curr1 = tmp;
} else {
tmp = curr2->next, curr2->next = head->next;
head->next = curr2, curr2 = tmp;
}
}
while (curr1) {
tmp = curr1->next, curr1->next = head->next;
head->next = curr1, curr1 = tmp;
}
while (curr2) {
tmp = curr2->next, curr2->next = head->next;
head->next = curr2, curr2 = tmp;
}
src1->next = NULL, src2->next = NULL;
return dest;
}
void traverse(List *s) {
for (Node *curr = s->next; curr; curr = curr->next)
printf("%d ", curr->val);
printf("\n");
}
int main () {
int n, m;
scanf("%d %d", &n, &m);
List *s1 = init(n);
List *s2 = init(m);
List *s = merge(s1, s2);
traverse(s);
return 0;
}
5 单链表的删除
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int val;
struct node *next;
} Node, List;
List *init(int n) {
List *s = (List*) malloc(sizeof(List));
Node *tail = s;
s->next = NULL, s->val = -1;
for (int i = 0; i < n; ++i) {
Node *node = (Node*) malloc(sizeof(Node));
scanf("%d", &node->val);
node->next = NULL, tail->next = node, tail = node;
}
return s;
}
void delete(List *s, List *s1, List *s2) {
// 三指针遍历
Node *h = s->next, *h1 = s1->next, *h2 = s2->next;
while (h1->next && h2->next) {
if (h1->val < h2->val) h1 = h1->next;
else if (h1->val > h2->val) h2 = h2->next;
else {
int val = h1->val;
while (h->next) {
if (h->next->val == val) {
Node* tmp = h->next;
h->next = tmp->next;
free(tmp);
} else if (h->next->val < val)
h = h->next;
else break;
}
h1 = h1->next, h2 = h2->next;
}
}
}
void traverse(List *s) {
for (Node *curr = s->next; curr; curr = curr->next)
printf("%d ", curr->val);
printf("\n");
}
int main () {
int n, m1, m2;
scanf("%d %d %d", &n, &m1, &m2);
List *s = init(n);
List *s1 = init(m1);
List *s2 = init(m2);
delete(s, s1, s2);
traverse(s);
return 0;
}
6 LOCATE 操作
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
char ch;
struct node *next, *prev;
int freq;
} Node, List;
List *init(int n) {
List *s = (List*) malloc(sizeof(List));
Node *head = s; int tmp = 1;
s->next = s, s->prev = s, s->ch = ' ', s->freq = 0;
while (tmp <= n) {
char ch = getchar();
if (ch != ' ' && ch != '\n') {
Node *node = (Node*) malloc(sizeof(Node));
node->ch = ch, node->freq = 0;
node->prev = head->prev, node->next = head;
head->prev->next = node, head->prev = node;
++tmp;
}
}
return s;
}
void update(List *s, int m) {
int tmp = 1;
while(tmp <= m) {
char ch = getchar();
if (ch != ' ' && ch != '\n') {
for (Node *curr = s->next; curr != s; curr = curr->next)
if (ch == curr->ch) {
++curr->freq; break;
}
++tmp;
}
}
}
// 插入排序(稳定)
void sort(List *s) {
Node *curr = s->next->next;
while (curr != s) {
Node *tail = curr->prev, *tmp = curr->next;
while (tail != s && curr->freq > tail->freq) tail = tail->prev;
curr->prev->next = curr->next, curr->next->prev = curr->prev;
curr->prev = tail, curr->next = tail->next;
tail->next->prev = curr, tail->next = curr;
curr = tmp;
}
}
void traverse(List *s) {
for (Node *curr = s->next; curr != s; curr = curr->next)
printf("%c ", curr->ch);
printf("\n");
}
int main () {
int n, m;
scanf("%d %d", &n, &m);
List *s = init(n);
update(s, m);
sort(s);
traverse(s);
return 0;
}
第三章 栈与队列
1 表达式括号匹配
// 本题只能使用 fgets, 使用 scanf 和 getchar 均会 WA
#include <stdio.h>
#include <stdbool.h>
char str[1005] = "";
char stack[1005] = {
};
int top = -1;
bool isMatched(void) {
fgets(str, 1000, stdin);
char *ch = str;
while(*ch) {
switch (*ch) {
case '(': case '[': case '{':{
stack[++top] = *ch;
break;
}
case ')': {
if (stack[top--] != '(')
return false;
break;
}
case ']': {
if (stack[top--] != '[')
return false;
break;
}
case '}': {
if (stack[top--] != '{')
return false;
break;
}
default: break;
}
++ch;
}
if (top == -1) return true;
return false;
}
int main () {
if (isMatched()) printf("yes");
else printf("no");
return 0;
}
2 逆波兰表达式
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <ctype.h>
char calc[1005] = "";
char output[1005] = "";
char stack[1005] = {
};
int top = -1;
bool isPrior(char curr, char topCh) {
return (((curr == '*') || (curr == '/')) && ((topCh == '+') || (topCh == '-'))) ||
(topCh == '(') || (curr == '(');
}
void suffix(void) {
char *ch = calc;
while (*ch) {
if (*ch == '\n') break;
// 字母跳过
if (isalpha(*ch)) strncat(output, ch, 1);
// 入栈: 栈空; 优先级严格大于栈顶; 栈顶为左括号; 左括号
else if (top == -1 || isPrior(*ch, stack[top]))
stack[++top] = *ch;
// 出栈: 遇到右括号时出栈到左括号
else if (*ch == ')') {
while (stack[top] != '(') {
strncat(output, &stack[top], 1);
--top;
}
// 左括号出栈
--top;
// 出栈: 优先级等于或小于栈顶时, 出栈到严格大于或左括号或栈空
} else {
while (top != -1 && !isPrior(*ch, stack[top])) {
strncat(output, &stack[top], 1);
--top;
}
// 入栈
stack[++top] = *ch;
}
++ch;
}
// 栈中剩余符号全部出栈
while (top != -1) {
strncat(output, &stack[top], 1);
--top;
}
}
int main() {
fgets(calc, 1000, stdin);
suffix();
printf("%s", output);
return 0;
}
3 循环队列
#include <stdio.h>
int queue[1005] = {
};
int rear = 0, len;
int main() {
scanf("%d", &len);
while(1) {
scanf("%d", &queue[rear++]);
char ch = getchar();
if (ch == '\n') break;
}
if (rear >= len) {
// 队满输出 yes
printf("yes\n");
rear = len;
} else printf("no\n");
int val, front = 0;
scanf("%d", &val);
while (front < rear && queue[front] != val) ++front;
++front;
for (int i = front; i < rear - 1; ++i) {
printf("%d ", queue[i]);
}
// 会判空格与换行符
printf("%d\n", queue[rear - 1]);
printf("%d", queue[front]);
return 0;
}
4 k k k 阶斐波那契数列
#include <stdio.h>
int bp[1005] = {
};
int main() {
int m, k;
scanf("%d %d", &m ,&k);
int rear = 0, sum = 0;
bp[k - 1] = 1;
while (1) {
sum = 0;
// 循环数组
for (int i = 0; i < k; ++i)
sum += bp[(i + rear) % k];
if (bp[rear] <= m && sum > m) break;
bp[rear] = sum;
rear = (rear + 1) % k;
}
for (int i = 0; i < k; ++i)
printf("%d ", bp[(rear + i) % k]);
printf("\n");
return 0;
}
5 循环右移
#include <stdio.h>
int arr[105] = {
};
void reverse(int left, int right) {
while (left < right) {
int tmp = arr[left];
arr[left] = arr[right], arr[right] = tmp;
++left, --right;
}
}
int main() {
int n, k;
scanf("%d %d", &n, &k);
for (int i = 0; i < n; ++i)
scanf("%d", &arr[i]);
// 循环移动 = 三次翻转
reverse(0, n - 1);
reverse(0, k - 1);
reverse(k, n - 1);
for (int i = 0; i < n; ++i)
printf("%d ", arr[i]);
printf("\n");
return 0;
}
第五章 数组与广义表
1 以三元组表为存储结构实现矩阵相加
#include <stdio.h>
int main () {
int t1, t2;
scanf("%d %d", &t1, &t2);
int S1[t1][3], S2[t2][3], S[t1 + t2][3];
for (int i = 0; i < t1; ++i)
scanf("%d %d %d", &S1[i][0], &S1[i][1], &S1[i][2]);
for (int i = 0; i < t2; ++i)
scanf("%d %d %d", &S2[i][0], &S2[i][1], &S2[i][2]);
int h1 = 0, h2 = 0, h = 0;
while (h1 < t1 && h2 <t2) {
if (S1[h1][0] < S2[h2][0]) {
S[h][0] = S1[h1][0], S[h][1] = S1[h1][1], S[h][2] = S1[h1][2];
++h1;
}
else if (S1[h1][0] > S2[h2][0]) {
S[h][0] = S2[h2][0], S[h][1] = S2[h2][1], S[h][2] = S2[h2][2];
++h2;
}
else {
if (S1[h1][1] < S2[h2][1]) {
S[h][0] = S1[h1][0], S[h][1] = S1[h1][1], S[h][2] = S1[h1][2];
++h1;
}
else if (S1[h1][1] > S2[h2][1]) {
S[h][0] = S2[h2][0], S[h][1] = S2[h2][1], S[h][2] = S2[h2][2];
++h2;
}
else {
S[h][0] = S1[h1][0], S[h][1] = S1[h1][1], S[h][2] = S1[h1][2] + S2[h2][2];
++h1, ++h2;
}
}
if (S[h][2] != 0) ++h;
}
for (int i = 0; i < h && S[i][0]; ++i)
printf("%d %d %d\n", S[i][0], S[i][1], S[i][2]);
return 0;
}
2 以十字链表为存储结构实现矩阵相加
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int raw, col, val;
struct Node *down, *right;
} Node, CList;
CList *createCList(int raw, int col) {
CList *c = (CList*) malloc(sizeof(CList));
c->raw = raw, c->col = col, c->val = -1;
c->down = c->right = c;
for (int i = raw; i > 0; --i) {
Node *tmp = (Node*) malloc(sizeof(Node));
tmp->val = -1, tmp->raw = i, tmp->col = 0;
tmp->right = tmp, tmp->down = c->down, c->down = tmp;
}
for (int i = col; i > 0; --i) {
Node *tmp = (Node*) malloc(sizeof(Node));
tmp->val = -1, tmp->raw = 0, tmp->col = i;
tmp->down = tmp, tmp->right = c->right, c->right = tmp;
}
return c;
}
void insertOrAdd(CList *head, int raw, int col, int val) {
Node *curr = head;
for (int i = 1; i <= raw; ++i) curr = curr->down;
while (curr->right->col < col && curr->right->col != 0) curr = curr->right;
// 狠狠地偷懒, 插入同时算加法, 避免额外逻辑
if (curr->right->col == col) {
curr->right->val += val;
// 单独判断相加后为 0 情况
if (curr->right->val == 0) {
Node *vert = curr->right, *temp = vert;
while (vert->down != temp) vert = vert->down;
curr->right = temp->right, vert->down = temp->down;
free(temp);
}
return;
}
Node *node = (Node*) malloc(sizeof(Node));
node->right = curr->right, curr->right = node;
curr = head;
for (int i = 1; i <= col; ++i) curr = curr->right;
while (curr->down->raw < raw && curr->down->raw != 0) curr = curr->down;
node->down = curr->down, curr->down = node;
node->raw = raw, node->col = col, node->val = val;
}
void traverse(CList *S) {
for (Node *r = S->down; r != S; r = r->down) {
for (Node *c = r->right; c != r; c = c->right) {
printf("%d %d %d\n", c->raw, c->col, c->val);
}
}
}
int main () {
int n, m, t1, t2, r, c, v;
scanf("%d %d %d %d", &n, &m, &t1, &t2);
CList *S1 = createCList(n, m);
for (int i = t1; i > 0 ; --i) {
scanf("%d %d %d", &r, &c, &v);
insertOrAdd(S1, r, c, v);
}
for (int i = t2; i > 0 ; --i) {
scanf("%d %d %d", &r, &c, &v);
insertOrAdd(S1, r, c, v);
}
traverse(S1);
return 0;
}
3 求广义表深度
#include <stdio.h>
// 偷分大法秒了 :)
void foo(char str[]) {
int cnt = 0, depth = 0;
for (char *ch = str; *ch; ++ch) {
if (*ch == '(') ++cnt;
if (*ch == ')') --cnt;
depth = cnt > depth ? cnt : depth;
}
printf("%d\n", depth);
}
void bar(char str[]) {
int cnt = 0, depth = 0;
for (char *ch = str; *ch; ++ch) {
if (*ch == ')') ++cnt;
if (*ch == '(') --cnt;
depth = cnt < depth ? cnt : depth;
}
depth = -depth;
printf("%d\n", depth);
}
int main() {
char str[1005] = "";
fgets(str, 1000, stdin);
foo(str);
bar(str);
return 0;
}
第六章 树与二叉树
1 建立二叉树的二叉链表存储结构
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
typedef struct node {
struct node *left, *right;
char ch;
} Node, Tree;
Node *newNode(char ch) {
Node *node = (Node*) malloc(sizeof(Node));
node->ch = ch, node->left = node->right = NULL;
return node;
}
// 前序读入
Tree *createTree(void) {
// 边读边插
char ch = getchar();
Node *curr = newNode(ch);
ch = getchar();
if (ch == '(') {
curr->left = createTree();
curr->right = createTree();
} else if (ch == ',') {
curr->left = curr->right = NULL;
} else if (ch == ')') {
getchar();
curr->left = curr->right = NULL;
}
return curr;
}
// 前序遍历
void preTraverse(Node *curr) {
if (!curr) return;
printf("%c", curr->ch);
preTraverse(curr->left);
preTraverse(curr->right);
}
// 偷分大法
void foo(void) {
char str[105] = "";
scanf("%s", str);
for (int i = 0; str[i] ; ++i)
if (isupper(str[i]) || str[i] == '#')
putchar(str[i]);
}
int main() {
Tree *t = createTree();
preTraverse(t);
// foo();
return 0;
}
2 计算二叉树叶子节点数目
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
struct node *left, *right;
char ch;
} Node, Tree;
int cnt = 0;
Node *newNode(char ch) {
Node *node = (Node*) malloc(sizeof(Node));
node->ch = ch, node->left = node->right = NULL;
return node;
}
Tree *createTree(void) {
char ch = getchar();
Node *curr = NULL;
if (ch != '#') {
curr = newNode(ch);
curr->left = createTree();
curr->right = createTree();
}
return curr;
}
void foo(void) {
char str[105] = "";
scanf("%s", str);
for (int i = 0; str[i]; ++i)
if (str[i] == '#' && str[i + 1] == '#') ++cnt, ++i;
printf("%d\n", cnt);
}
void preTraverse(Node *curr) {
if (!curr) return;
// 遍历并判断
if (!curr->left && !curr->right) ++cnt;
preTraverse(curr->left);
preTraverse(curr->right);
}
int main() {
Tree *t = createTree();
preTraverse(t);
printf("%d\n", cnt);
// foo();
return 0;
}
3 输出以二叉树表示的算术表达式
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
struct node *left, *right;
char ch;
} Node, Tree;
Node *newNode(char ch) {
Node *node = (Node*) malloc(sizeof(Node));
node->ch = ch, node->left = node->right = NULL;
return node;
}
Tree *createTree(void) {
char ch = getchar();
Node *curr = NULL;
if (ch != '#') {
curr = newNode(ch);
curr->left = createTree();
curr->right = createTree();
}
return curr;
}
// 中序输出
void preTraverse(Node *curr) {
if (!curr) return;
preTraverse(curr->left);
printf("%c", curr->ch);
preTraverse(curr->right);
}
int main() {
Tree *t = createTree();
preTraverse(t);
return 0;
}
4 建立二叉树的二叉链表
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct node {
struct node *left, *right;
char ch;
} Node, Tree;
Node *newNode(char ch) {
Node *node = (Node*) malloc(sizeof(Node));
node->ch = ch, node->left = node->right = NULL;
return node;
}
char pre[105] = "";
char in[105] = "";
Tree *createTree (int fl, int fr, int il, int ir) {
if (fl > fr || il > ir) return NULL;
char rootCh = pre[fl];
// 每次前序的头部为根节点 (后序则为尾部)
Node *root = newNode(rootCh);
int idx = 0;
for (int i = il; i <= ir; ++i)
if (in[i] == rootCh) {
idx = i;
break;
}
int lsSize = idx - il;
root->left = createTree(fl + 1, fl + lsSize, il, idx - 1);
root->right = createTree(fl + lsSize + 1, fr, idx + 1, ir);
return root;
}
// 后序遍历
void postTraverse(Tree *t) {
if (!t) return;
postTraverse(t->left);
postTraverse(t->right);
printf("%c", t->ch);
}
int main() {
scanf("%s", pre);
scanf("%s", in);
int fLen = strlen(pre);
int iLen = strlen(in);
Tree *t = createTree(0, fLen - 1, 0, iLen - 1);
postTraverse(t);
return 0;
}
第七章 图
1 基于图的深度优先搜索策略
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define MAXSIZE 1000
typedef struct node {
int v;
struct node *next;
} Node, Graph;
// 记录访问情况,避免有环时死循环
bool isVisited[MAXSIZE] = {
};
// 外部记录是否能遍历到
bool isPath = false;
Graph *createGraph(int n, int m) {
// 指针数组记录邻接表
Graph *g = (Graph*) malloc(sizeof(Graph) * (n + 1));
g[0].v = -1, g[0].next = NULL;
for (int i = 1; i <= n; ++i) {
scanf("%d", &g[i].v);
g[i].next = NULL;
}
for (int i = 1; i <= m; ++i) {
int v1, v2;
scanf("%d %d", &v1, &v2);
Node* newNode = (Node*) malloc(sizeof(Node));
newNode->v = v2, newNode->next = NULL;
Node *tail = &g[v1];
while (tail->next) tail = tail->next;
tail->next = newNode;
}
return g;
}
void dfs(Graph* g, int v1, int v2) {
Node *curr = &g[v1];
while (curr) {
if (curr->v == v2) isPath = true;
if (!isVisited[curr->v]) {
isVisited[curr->v] = true;
dfs(g, curr->v, v2);
}
curr = curr->next;
}
return;
}
int main() {
int n, m;
scanf("%d %d", &n, &m);
Graph *g = createGraph(n, m);
int v1, v2;
scanf("%d %d", &v1, &v2);
dfs(g, v1, v2);
if (isPath) puts("yes");
else puts("no");
return 0;
}
2 基于图的广度优先搜索策略
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define MAXSIZE 100
typedef struct node {
int v;
struct node *next;
} Node, Graph;
bool isVisited[MAXSIZE] = {
};
int queue[MAXSIZE] = {
};
int front = 0, rear = 0;
Graph *createGraph(int n, int m) {
Graph *g = (Graph*) malloc(sizeof(Graph) * (n + 1));
g[0].v = -1, g[0].next = NULL;
for (int i = 1; i <= n; ++i) {
scanf("%d", &g[i].v);
g[i].next = NULL;
}
for (int i = 1; i <= m; ++i) {
int v1, v2;
scanf("%d %d", &v1, &v2);
Node* newNode = (Node*) malloc(sizeof(Node));
newNode->v = v2, newNode->next = NULL;
Node *tail = &g[v1];
while (tail->next) tail = tail->next;
tail->next = newNode;
}
return g;
}
bool bfs(Graph *g, int v1, int v2) {
queue[rear++] = v1; isVisited[v1] = true;
while (front != rear) {
v1 = queue[front++];
// 循环队列
front = front == (MAXSIZE - 1) ? 0 : front;
Node *curr = &g[v1];
while (curr) {
if (curr->v == v2) return true;
if (!isVisited[curr->v]) {
queue[rear++] = curr->v;
// 循环队列
rear = rear == (MAXSIZE - 1) ? 0 : rear;
isVisited[curr->v] = true;
}
curr = curr->next;
}
}
return false;
}
int main() {
int n, m;
scanf("%d %d", &n, &m);
Graph *g = createGraph(n, m);
int v1, v2;
scanf("%d %d", &v1, &v2);
if (bfs(g, v1, v2)) puts("yes");
else puts("no");
return 0;
}
3 逆波兰表达式
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <ctype.h>
char calc[1005] = "";
char output[1005] = "";
// 栈, 何尝不是一种有向无环图?
char stack[1005] = {
};
int top = -1;
bool isPrior(char curr, char topCh) {
return (((curr == '*') || (curr == '/')) && ((topCh == '+') || (topCh == '-'))) ||
(topCh == '(') || (curr == '(');
}
void suffix(void) {
char *ch = calc;
while (*ch) {
if (*ch == '\n') break;
if (isalpha(*ch)) strncat(output, ch, 1);
else if (top == -1 || isPrior(*ch, stack[top]))
stack[++top] = *ch;
else if (*ch == ')') {
while (stack[top] != '(') {
strncat(output, &stack[top], 1);
--top;
}
--top;
} else {
while (top != -1 && !isPrior(*ch, stack[top])) {
strncat(output, &stack[top], 1);
--top;
}
stack[++top] = *ch;
}
++ch;
}
while (top != -1) {
strncat(output, &stack[top], 1);
--top;
}
}
int main() {
fgets(calc, 1000, stdin);
suffix();
printf("%s", output);
return 0;
}
4 Dijkstra 算法
#include <stdio.h>
#include <stdbool.h>
#define MAXSIZE 100
#define INF 0x3f3f3f3f
int vn = 0, en = 0;
int dist[MAXSIZE + 1][MAXSIZE + 1] = {
};
bool isVisited[MAXSIZE + 1] = {
};
int len[MAXSIZE + 1] = {
};
void init(void) {
scanf("%d %d", &vn, &en);
for (int i = 1; i <= vn; ++i)
for (int j = 1; j <= vn; ++j) dist[i][j] = INF;
for (int i = 1; i <= en; ++i) {
int v1, v2, e;
scanf("%d %d %d", &v1, &v2, &e);
dist[v1][v2] = e;
}
}
void dijkstra(void) {
for (int i = 1; i <= vn; ++i) len[i] = dist[1][i];
isVisited[1] = true;
for (int i = 1; i <= vn - 1; ++i) {
int minLen = INF, v = i + 1;
for (int j = 1; j <= vn; ++j)
if (!isVisited[j] && len[j] < minLen)
minLen = len[j], v = j;
isVisited[v] = true;
// 输出时将 INF 按照题目要求换为 -1
int lenAns = len[v] == INF ? -1 : len[v];
printf("%d %d %d\n", 1, v, lenAns);
for (int j = 1; j <= vn; ++j)
if (!isVisited[j] && dist[v][j] != INF && len[j] > len[v] + dist[v][j])
len[j] = len[v] + dist[v][j];
}
}
int main () {
init();
dijkstra();
return 0;
}
第八章 查找
1 构造哈希表
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int hashFunc(int n) {
return (3 * n) % 11;
}
void search(void) {
int data[8] = {
22, 41, 53,46,30,13,01,67};
int hashVal[11];
memset(hashVal, -1, sizeof(hashVal));
int sum = 0;
for (int i = 0; i < 8; ++i) {
int k = hashFunc(data[i]), n = 1;
while (hashVal[k] != -1) k = (k + 12) % 11, ++n;
hashVal[k] = data[i];
sum += n;
}
printf("%d\n", sum / 8);
}
// 这不直接偷分?
void foobar(void) {
puts("2");
}
int main() {
search();
// foobar();
return 0;
}
2 二叉排序树的判别
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct node {
int val;
struct node *left, *right;
} Node, Tree;
Node *newNode(int val) {
Node *node = (Node*) malloc(sizeof(Node));
node->val = val, node->left = node->right = NULL;
return node;
}
// 记录递归中更新的最小值
int tMin = -1;
Tree *createTree(void) {
int n;
scanf("%d", &n);
Node* curr = NULL;
if (n != -1) {
curr = newNode(n);
curr->left = createTree();
curr->right = createTree();
}
return curr;
}
bool isSearchTree(Tree *t) {
if (!t) return true;
if (!isSearchTree(t->left)) return false;
if (t->val < tMin) return false;
tMin = t->val;
if (!isSearchTree(t->right)) return false;
return true;
}
int main() {
Tree *t = createTree();
if (isSearchTree(t)) puts("yes");
else puts("no");
return 0;
}
3 二叉排序树的插入和删除
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
typedef struct node {
int val;
struct node *left, *right;
} Node, Tree;
Node *newNode(int val) {
Node *node = (Node*) malloc(sizeof(Node));
node->val = val, node->left = node->right = NULL;
return node;
}
Tree *createTree(void) {
int n;
scanf("%d", &n);
Node* curr = NULL;
if (n != -1) {
curr = newNode(n);
curr->left = createTree();
curr->right = createTree();
}
return curr;
}
void inTraverse(Tree *t, int a, int b) {
if (!t) return;
inTraverse(t->left, a, b);
if (a < t->val && t->val < b)
printf("%d ", t->val);
inTraverse(t->right, a, b);
}
// 插入一定发生在叶子节点上
Tree *insert(Tree *t, int val) {
if (!t) {
t = (Node*) malloc(sizeof(Node));
t->val = val, t->left = t->right = NULL; return t;
}
if (t->val == val) return t;
if (t->val > val) {
t->left = insert(t->left, val); return t;
}
t->right = insert(t->right, val); return t;
}
Tree *delete(Tree *t, int val) {
if (!t) return NULL;
if (t->val == val) {
Node *l = t->left, *r = t->right;
// 分四种情况讨论,应该可以优化,懒得想了
if (!l && !r) {
free(t); return NULL;
} else if (!l) {
free(t); return r;
} else if (!r) {
free(t); return l;
} else {
if (r->left) {
while (r->left->left) r = r->left;
} else r = t;
t->val = r->left->val; free(r->left);
r->left = NULL; return t;
}
}
else if (t->val > val) {
t->left = delete(t->left, val); return t;
} else {
t->right = delete(t->right, val); return t;
}
}
int main() {
Tree *t = createTree();
int a, b;
scanf("%d %d", &a, &b);
inTraverse(t, a, b);
printf("\n");
int ins;
scanf("%d", &ins);
t = insert(t, ins);
inTraverse(t, INT_MIN, INT_MAX);
printf("\n");
int del;
scanf("%d", &del);
t = delete(t, ins);
t = delete(t, del);
inTraverse(t, INT_MIN, INT_MAX);
printf("\n");
return 0;
}
4 二叉排序树的合并
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int val;
struct node *left, *right;
} Node, Tree;
Node *newNode(int val) {
Node *node = (Node*) malloc(sizeof(Node));
node->val = val, node->left = node->right = NULL;
return node;
}
Tree *createTree(void) {
int n;
scanf("%d", &n);
Node* curr = NULL;
if (n != -1) {
curr = newNode(n);
curr->left = createTree();
curr->right = createTree();
}
return curr;
}
Tree *insert(Tree *t, int val) {
if (!t) {
t = (Node*) malloc(sizeof(Node));
t->val = val, t->left = t->right = NULL; return t;
}
if (t->val == val) return t;
if (t->val > val) {
t->left = insert(t->left, val); return t;
}
t->right = insert(t->right, val); return t;
}
void merge(Tree *t1, Tree *t2) {
if (!t1 || !t2) return;
// 遍历 t2 节点依次插入 t1
t1 = insert(t1, t2->val);
merge(t1, t2->left);
merge(t1, t2->right);
}
void inTraverse(Tree *t) {
if (!t) return;
inTraverse(t->left);
printf("%d ", t->val);
inTraverse(t->right);
}
int main() {
Tree *t1 = createTree();
Tree *t2 = createTree();
merge(t1, t2);
inTraverse(t1);
return 0;
}
考试题目(回忆版)
- 顺序表查找(可用二分法)
- Dijkras 最短路径
- 四则运算(无括号;中缀变为后缀;后缀直接计算)
- 拓扑排序(多个选择时最小结点优先)
- 二叉树前序中序输出后序 / 后序中序输出前序
- Huffman 编码及解码