爆锤数据结构(期末复习笔记)(上)

简介: 爆锤数据结构(期末复习笔记)

写在前面


笔者按去年实际考试内容,回忆并编写本博客。建议大家收藏,如对考试有帮助,记得回来丢个赞。如果对部分内容有疑问可以直接留言。


机考篇


大致内容


去年第一题、第二题为顺序表,第三题为排序,第四题主要考dfs。第五题为压轴题考了三叉霍夫曼树


数据结构期末机考大致有5道题,难度由浅入深,根据去年实际体验,大致人均AC2~3题。前三题的难度会相对比较简单,主要需要重点复习下顺序表,链表等线性结构,排序算法(选择,插入,冒泡…),哈希查找。第四题一般会相对难一些,需要重点复习一下图的dfs,bfs。最短路径的Dijkstra算法以及最小生成树Prim和Kruskal算法。最后一题会比较难,可能会遇到比较复杂的数据结构,机考过程中前四题全部AC后可以试一下。


例题


这部分的两道题大概是去年机考的第四第五题(前面题记不清了),凭着回忆把题目重新写了下,又做了一遍,自己敲了标程。


无向图求割点


按输入顺序输出无向图的所有割点。(割点:在一个无向图中,如果删除某个顶点以及与该顶点相关联的所有边后,图的连通分量增多,就称这个点为割点。)

输入

第一行为测试数据数。对于每组测试数据,第一个整数n nn表示该无向图的大小。接下来n nn个字符串为每个顶点的名称。接下来输入一个n ∗ n n*nn∗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 tt,表示有t 个 t个t个测试实例

第二行先输入n nn,表示第1个实例有n nn个权值,接着输入n nn个权值,权值全是小于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 OO标记法=>时间复杂度&空间复杂度


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函数:只与模式串有关,与主串无关

image.png

KMP算法改进:nextval

时间复杂度O ( n + m ) O(n+m)O(n+m)


image.png

相关文章
|
3月前
|
存储 算法
【单向链表】数据结构——单向链表的介绍与代码实现&笔记
【单向链表】数据结构——单向链表的介绍与代码实现&笔记
|
3月前
|
存储 算法
【树】数据结构——树和二叉树的概念&笔记
【树】数据结构——树和二叉树的概念&笔记
|
3月前
|
算法 Java 索引
12.12_黑马数据结构与算法笔记Java
12.12_黑马数据结构与算法笔记Java
28 1
|
2月前
|
存储 算法 C语言
软考中级之数据库系统工程师笔记总结(二)数据结构与算法
软考中级之数据库系统工程师笔记总结(二)数据结构与算法
20 0
|
3月前
|
存储 算法 Linux
【内核链表】数据结构——深入理解内核链表的概念和操作&笔记
【内核链表】数据结构——深入理解内核链表的概念和操作&笔记
【循环链表】数据结构——单向循环链表和双向循环链表操作&笔记
【循环链表】数据结构——单向循环链表和双向循环链表操作&笔记
|
4月前
|
存储 算法 搜索推荐
数据结构期末复习(fengkao课堂)
数据结构期末复习(fengkao课堂)
228 0
|
4月前
|
存储 算法 调度
数据结构期末复习(3)栈和队列
数据结构期末复习(3)栈和队列
43 0
|
4月前
|
存储 机器学习/深度学习 人工智能
【软件设计师—基础精讲笔记8】第八章 数据结构
【软件设计师—基础精讲笔记8】第八章 数据结构
80 0
|
4月前
|
算法 搜索推荐 Java
数据结构与算法(Java篇)笔记--快速排序
数据结构与算法(Java篇)笔记--快速排序