爆锤数据结构(期末复习笔记)
Posted 上山打老虎D
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了爆锤数据结构(期末复习笔记)相关的知识,希望对你有一定的参考价值。
目录
写在前面
笔者按去年实际考试内容,回忆并编写本博客。建议大家收藏,如对考试有帮助,记得回来丢个赞。如果对部分内容有疑问可以直接留言。
机考篇
大致内容
去年第一题、第二题为顺序表,第三题为排序,第四题主要考dfs。第五题为压轴题考了三叉霍夫曼树
数据结构期末机考大致有5道题,难度由浅入深,根据去年实际体验,大致人均AC2~3题。前三题的难度会相对比较简单,主要需要重点复习下顺序表,链表等线性结构,排序算法(选择,插入,冒泡…),哈希查找。第四题一般会相对难一些,需要重点复习一下图的dfs,bfs。最短路径的Dijkstra算法以及最小生成树Prim和Kruskal算法。最后一题会比较难,可能会遇到比较复杂的数据结构,机考过程中前四题全部AC后可以试一下。
例题
这部分的两道题大概是去年机考的第四第五题(前面题记不清了),凭着回忆把题目重新写了下,又做了一遍,自己敲了标程。
无向图求割点
按输入顺序输出无向图的所有割点。(割点:在一个无向图中,如果删除某个顶点以及与该顶点相关联的所有边后,图的连通分量增多,就称这个点为割点。)
输入
第一行为测试数据数。对于每组测试数据,第一个整数
n
n
n表示该无向图的大小。接下来
n
n
n个字符串为每个顶点的名称。接下来输入一个
n
∗
n
n*n
n∗n的方阵作为无向图,0表示两个顶点之间不存在边,1表示两个顶点之间存在边。
输出
输出各个割点的名称。每组测试数据的输出占一行。如果没有割点,则输出No!
样例输入
4
8
0 1 2 3 4 5 6 7
0 0 0 0 0 0 0 0
0 0 0 1 1 0 0 0
0 0 0 1 1 1 1 0
0 1 1 0 0 0 0 0
0 1 1 0 0 0 0 0
0 0 1 0 0 0 0 0
0 0 1 0 0 0 0 1
0 0 0 0 0 0 1 0
3
A B C
0 1 0
1 0 1
0 1 0
5
a b c d e
0 1 0 0 1
1 0 1 1 0
0 1 0 0 0
0 1 0 0 0
1 0 0 0 0
6
v1 v2 v3 v4 v5 v6
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
样例输出
2 6
B
a b
No!
参考代码
#include <iostream>
#include <vector>
using namespace std;
bool *isVisited;
int **matrix;
int n = 0;
//node:当前深搜点 cur:当前判断的割点
void dfs(int node, int cur)
isVisited[node] = true;
for (int i = 0; i < n; i++)
if ((!isVisited[i]) && i != cur && node != cur && (matrix[node][i] || matrix[i][node]))
dfs(i, cur);
int main()
int t;
cin >> t;
while (t--)
cin >> n;
vector<string> vertex;
vector<string> res;
isVisited = new bool[n];
matrix = new int *[n];
for (int i = 0; i < n; i++)
string temp;
cin >> temp;
vertex.push_back(temp);
matrix[i] = new int[n];
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
cin >> matrix[i][j];
int cc = 0;
for (int i = 0; i < n; i++)
if (!isVisited[i])
cc++;
dfs(i, -1);
for (int i = 0; i < n; i++)
int temp = 0;
for (int ii = 0; ii < n; ii++)
isVisited[ii] = false;
for (int j = 0; j < n; j++)
if (!isVisited[j])
temp++;
dfs(j, i);
if (temp > cc + 1)
res.push_back(vertex[i]);
if (res.empty())
cout << "No!" << endl;
else
for (int i = 0; i < res.size(); i++)
cout << res[i] << " ";
cout << endl;
return 0;
三叉霍夫曼
给定n个权值,根据这些权值构造三叉霍夫曼树,并进行三叉霍夫曼编码。
输入
第一行输入
t
t
t,表示有
t
个
t个
t个测试实例
第二行先输入
n
n
n,表示第1个实例有
n
n
n个权值,接着输入
n
n
n个权值,权值全是小于1万的正整数
依此类推
输出:
逐行输出每个权值对应的编码,格式如下:权值-编码
即每行先输出1个权值,再输出一个短划线,再输出对应编码,接着下一行输出下一个权值和编码。
以此类推
样例输入
2
8
1 5 3 4 9 2 6 10
10
1 5 9 6 3 4 7 8 11 12
样例输出
1-100
5-01
3-102
4-00
9-11
2-101
6-02
10-12
1-010
5-120
9-02
6-121
3-011
4-012
7-122
8-00
11-10
12-11
样例代码
#include <iostream>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
struct Node
int value;
int father = -1;
int son[3];
string code;
Node(int value, int father)
this->value = value;
this->father = father;
for (int i = 0; i < 3; i++)
this->son[i] = -1;
;
bool cmp(const Node &a, const Node &b)
return (a.father == -1 ? a.value : (9999 + a.value)) < (b.father == -1 ? b.value : (9999 + b.value));
int getNode(int num, vector<Node> nodeList)
for (int i = 0; i < nodeList.size(); i++)
if (nodeList[i].value == num && nodeList[i].father == -1)
return i;
return -1;
void dfs(int index, vector<Node> &nodeList)
if (index == -1)
return;
for (int i = 0; i < 3; i++)
if (nodeList[index].son[i] == -1)
continue;
nodeList[nodeList[index].son[i]].code += (nodeList[index].code + to_string(i));
dfs(nodeList[index].son[i], nodeList);
int main()
int t;
cin >> t;
while (t--)
int n;
cin >> n;
vector<Node> nodeList;
for (int i = 0; i < n; i++)
int temp;
cin >> temp;
nodeList.push_back(Node(temp, -1));
while (true)
vector<Node> temp(nodeList);
sort(temp.begin(), temp.end(), cmp);
if (temp[2].father == -1)
nodeList.push_back(Node(0, -1));
for (int i = 0; i < 3; i++)
nodeList[nodeList.size() - 1].value += temp[i].value;
nodeList[nodeList.size() - 1].son[i] = getNode(temp[i].value, nodeList);
nodeList[getNode(temp[i].value, nodeList)].father = nodeList.size() - 1;
continue;
else if (temp[1].father == -1)
nodeList.push_back(Node(0, -1));
for (int i = 0; i < 2; i++)
nodeList[nodeList.size() - 1].value += temp[i].value;
nodeList[nodeList.size() - 1].son[i] = getNode(temp[i].value, nodeList);
nodeList[getNode(temp[i].value, nodeList)].father = nodeList.size() - 1;
break;
else
break;
dfs(nodeList.size() - 1, nodeList);
for (int i = 0; i < n; i++)
cout << nodeList[i].value << "-" << nodeList[i].code << endl;
return 0;
笔试篇
笔试篇按上课讲课顺序,以章节为单位进行组织
Chapter 1
- 逻辑结构四种基本形式:集合结构,线性结构,树状结构,图状结构
- 数据结构是二元组(数据对象,对象中所有数据成员之间关系的有限集合)
- 存储结构(又叫物理结构)——顺式,链式(索引,散列)
- 算法:有穷性,确定性,可行性,有输入&输出
- 大 O O O标记法=>时间复杂度&空间复杂度
Chapter 2
- 顺序表
- 基本操作:插入,删除,合并
- 优点:可以随机存取,元素地址可用简单公式表示
- 缺点:插入或删除时要移动大量元素,占用连续地址空间
- 链表
- 单链表
- 每个节点只有一个指针域
- 指针是元素之间逻辑关系的映像
- 地址不连续
- 插入删除方便,查找需要遍历
- 插入:头插,尾插(头插需要逆序输入)
- 循环链表
- 每个节点有两个指针,前驱prior,后继next
- 插入删除需要改变两个方向的指针
- 链表存储密度小于1
- 一般顺序表空间为静态分配,链表动态分配
- 单链表
Chapter 3
- 栈:Stack
- 后进先出 LIFO
- 顺序栈
- top=base 空栈
- base=NULL 栈不存在
- 插入元素/删除元素:top++/top–
- top-base=stacksize 栈满
- 链栈
- 栈的应用:数制转换,括号匹配,行编辑程序,迷宫求解,表达式求解(逆波兰式)
- 队列:Queue
- 先进先出 FIFO
- rear队尾指针->头元素,front队头指针->队尾元素的下一个位置
- 单链队列:无队满问题,有队空问题
- 顺序队列:进队rear++,出队front++
- 循环队列:
- front=rear 队空
- (rear+1)%MAXSIZE=front (少用一个空间以区分空队)
- 插入:rear=(rear+1)%MAXSIZE
- 删除:front=(front+1)%MAXSIZE
- 队列长度:(rear-front+MAXSIZE)%MAXSIZE
Chapter 4
- 串
- 子串,真子串
- 块链存储,存储密度小于1
- 模式匹配
- 朴素算法:BF算法(Brute Force)
- 主串指针重复回溯
- 最优时间复杂度 O ( n ) O(n) O(n)(n为模式串长,m为主串长)
- 最差时间复杂度 O ( n ∗ m ) O(n*m) O(n∗m)
- KMP算法:主要思想是消除主串指针重复回溯
- next函数:只与模式串有关,与主串无关
- n e x t [ j ] = 0 j = 1 max ( k ∣ 1 < k < j 且 ′ t 1 . . . t k − 1 ′ = ′ t j − k + 1 . . . t j − 1 ′ ) 当 此 集 合 非 空 时 1 e l s e next[j]=\\begincases 0 & j=1 \\\\ \\max(k|1<k<j 且't_1...t_k-1'='t_j-k+1...t_j-1') & 当此集合非空时 \\\\ 1 & else \\endcases next[j]=⎩⎪⎨⎪⎧0max(k∣1<k<j且′t1...tk−1′=′tj−k+1...tj−1′以上是关于爆锤数据结构(期末复习笔记)的主要内容,如果未能解决你的问题,请参考以下文章
- 朴素算法:BF算法(Brute Force)