保研笔记三 数据结构(未完待续)

目录

基础概念部分

链表、栈、队列

排序算法

字符串

动态规划

数据结构面试题

保研笔记——专业课面试之数据结构

数组、链表、栈、队列

头指针和头结点的区别?

数组和链表的区别?

栈和队列的区别

判断单链表是否为有环链表

栈在通过后缀表达式求值的算法思想?

队列在层次遍历中的作用?

字符串

介绍一下字符串匹配算法:KMP算法。

树与图

如何构造哈夫曼树

最小生成树

B树

最短路径的算法

介绍一下深度优先搜索和广度优先搜索是如何实现的?

介绍一下拓扑排序以及是如何实现的?

如何判断图是否连通

查找与哈希

各种查找方法(各方法是如何实现的要会用语言描述)

哈希表的概念、构造方法、冲突的解决办法?

排序

各种排序算法(各方法如何实现要会用语言描述)

算法

贪心算法和动态规划的区别


基础概念部分

链表、栈、队列

双向链表:双向链表(double linked list)_Uncertainty!!的博客-CSDN博客_双向链表

循环链表:什么是循环队列_少轩911的博客-CSDN博客_循环队列

排序算法

冒泡排序:依次两两比较,大的排在后面,一轮可在最后一个数选出最大的数,按此规律选出第二大,第三大的数。

选择排序:从第0个数开始,每次都选出最小的数与排在最前面的数交换。 

插入排序:依次将数据往前插。保证遍历到的数据之前都是有序的。

希尔排序:把整个待排序的记录序列分割成若干个子序列,分别进行插入排序。

归并排序:

 快速排序:

  • 选出一个基准数,基准值一般取序列最左边的元素
  • 重新排序序列,比基准值小的放在基准值左边,比基准值大的放在基准值右边,这就是所谓的分区

堆排序:【算法】排序算法之堆排序 - 知乎

计数排序:

桶排序:

 基数排序:

根据个位数,将元素分别分配到不同的0-9桶中,然后依次取出

根据十位数,将元素分别分配到不同的0-9桶中,然后依次取出

根据百位数,将元素分别分配到不同的0-9桶中,然后依次取出

。。。。

字符串

KMP:​​​​​​KMP算法图解易懂版(内含模板代码)_bulibuli蛋的博客-CSDN博客_kmp算法易懂版

哈夫曼树:一文搞懂如何构造哈夫曼树? - 知乎

中序线索二叉树:中序线索二叉树_Dread_naught的博客-CSDN博客_中序线索二叉树

AVL树:详解 AVL 树(基础篇) - 知乎,qwq南软和浙软都好喜欢avl树啊。还有B树

B树,蛮复杂的:B树详解 - 简书

m阶B树,一块最多m-1个数,最少m/2个数。

删父亲,父不够问子借。

子不够,兄多,兄给父,父给子。

子不够,兄不借,兄弟合并,父下来。

动态规划

树形dp:树形$dp$学习笔记 - _Lancy - 博客园

顺便学一下链式前向星:链式前向星 详解_ReverieZH的博客-CSDN博客_链式前向星

数据结构面试题

 数据结构面试题以及答案整理_けいしん的博客-CSDN博客_数据结构面试题

数据结构常见面试题,一网打尽!_黄小斜的博客-CSDN博客_面试常考数据结构

数据结构面试常见问题_小城老街的博客-CSDN博客_数据结构面试常见问题

【考研复试】数据结构常见问题_nemizr的博客-CSDN博客_数据结构考研复试常见问题

计算机考研复试面试常问问题 数据结构篇(上)_程序员宝藏的博客-CSDN博客_数据结构面试常见问题

数组、链表、栈、队列

头指针和头结点的区别?

头指针:是指向第一个节点存储位置的指针,具有标识作用,头指针是链表的必要元素,无论链表是否为空,头指针都存在。

头结点:是放在第一个元素节点之前,便于在第一个元素节点之前进行插入和删除的操作,头结点不是链表的必须元素,可有可无,头结点的数据域也可以不存储任何信息。

数组和链表的区别?

从逻辑结构来看:数组的存储长度是固定的,它不能适应数据动态增减的情况。链表能够动态分配存储空间以适应数据动态增减的情况,并且易于进行插入和删除操作。

从访问方式来看:数组在内存中是一片连续的存储空间,可以通过数组下标对数组进行随机访问,访问效率较高。链表是链式存储结构,存储空间不是必须连续的,可以是任意的,访问必须从前往后依次进行,访问效率较数组来说比较低。

如果从第i个位置插入多个元素,对于数组来说每一次插入都需要往后移动元素,每一次的时间复杂度都是O(n),而单链表来说只需要在第一次寻找i的位置时时间复杂度为O(n),其余的插入和删除操作时间复杂度均为O(1),提高了插入和删除的效率。

栈和队列的区别

队列是允许在一段进行插入另一端进行删除的线性表,对于进入队列的元素按“先进先出”的规则处理,在表头进行删除在表尾进行插入。

栈是只能在表尾进行插入和删除操作的线性表。对于插入到栈的元素按“后进先出”的规则处理,插入和删除操作都在栈顶进行。由于进栈和出栈都是在栈顶进行,所以要有一个size变量来记录当前栈的大小,当进栈时size不能超过数组长度,size+1,出栈时栈不为空,size-1。

判断单链表是否为有环链表

在一个链表中,如果 2 个指针(假设为 H1 和 H2)都从表头开始遍历链表,其中 H1 每次移动 2 个节点的长度(H1 = H1->next->next),而 H2 每次移动 1 个节点的长度(H2 = H2->next),如果该链表为有环链表,则 H1、H2 最终必定会相等;反之,如果该链表中无环,则 H1、H2 永远不会相遇。

有关在有环链表中 H1 和 H2 必定会相遇的结论,假设有环链表中的环包含 n 个节点,则第一次遍历,H1 和 H2 相差 1 个节点;第二次遍历,H1 和 H2 相差 2 个节点;第三次遍历,H1 和 H2 相差 3 个节点…,最终经过多次遍历,H1 和 H2 会相差 n-1 个节点,此时就会在环中重合,此时 H1 和 H2 相等。

栈在通过后缀表达式求值的算法思想?

顺序扫描表达式的每一项,然后根据它的类型做如下相应操作:若该项是操作数,则将其压入栈中;若该项是操作符,则连续从栈中退出两个操作数y 和x, 形成运算指令XY, 并将计算结果重新压入栈中。当表达式的所有项都扫描并处理完后,栈顶存放的就是最后的计算结果。

img

队列在层次遍历中的作用?

在信息处理中有一大类问题需要逐层或逐行处理。这类问题的解决方法往往是在处理当前层 或当前行时就对下一层或下一行做预处理,把处理顺序安排好,待当前层或当前行处理完毕,就可以处理下一层或下一行。使用队列是为了保存下一步的处理顺序。下面用二叉树层次遍历的例子,说明队列的应用。

img

字符串

介绍一下字符串匹配算法:KMP算法。

①上下子串前缀匹配

②找到公共前后缀(取最长且小于比较的上下字串长度)

③将下面的p子串前缀移动到后缀位置

树与图

如何构造哈夫曼树

找w最小求和,再找w最小;左小右大;构造结束后,左0右1

最小生成树

普里姆(prim)算法的基本思想为:顶点集到其他点权值最小边,加入新的顶点集,再找边…直到遍历所有点

克鲁斯卡尔(kruskal)算法的基本思想为:依次选择最小边,使得无环且所有点遍历结束

B树

根据B类树的特点,构造一个多阶的B类树,然后在尽量多的在结点上存储相关的信息,保证层数尽量的少,以便后面我们可以更快的找到信息,磁盘的I/O操作也少一些,而且B类树是平衡树,每个结点到叶子结点的高度都是相同,这也保证了每个查询是稳定的。

B树和B+树的区别,以一个m阶树为例。

  1. 关键字的数量不同;B+树中分支结点有m个关键字,其叶子结点也有m个,其关键字只是起到了一个索引的作用,但是B树虽然也有m个子结点,但是其只拥有m-1个关键字。

  2. 存储的位置不同;B+树中的数据都存储在叶子结点上,也就是其所有叶子结点的数据组合起来就是完整的数据,但是B树的数据存储在每一个结点中,并不仅仅存储在叶子结点上。

  3. 分支结点的构造不同;B+树的分支结点仅仅存储着关键字信息和儿子的指针(这里的指针指的是磁盘块的偏移量),也就是说内部结点仅仅包含着索引信息。

  4. 查询不同;B树在找到具体的数值以后,则结束,而B+树则需要通过索引找到叶子结点中的数据才结束,也就是说B+树的搜索过程中走了一条从根结点到叶子结点的路径。

最短路径的算法

最短路径:

用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。

迪杰斯特拉(dijastra)算法

经典的单源最短路径算法主要是其采用的动态规划思想.

将先求出长度最短的一条路径,再参照该最短路径求出长度次短的一条路径 直到求出从源点到其他各个顶点的最短路径。

ps: dijkstra和prime有点像,区别在于:

1,在图论中,Prim算法解决的问题是连通无向有权图中最小生成树问题,而Dijkstra算法解决的问题是源点到目标点的最短路径问题。

2,虽然这两个算法在添加新结点时,都是选择“距离最短”的结点加入集合,但是Prim算法中,“距离最短”是指未访问的结点到已经访问的所有结点距离最小,即将已经访问的结点视为一个整体,将距离最小的结点加入到已访问的集合中;而在Dijkstra算法中,“距离最短”是指所有未访问结点(通过已访问的结点)到源点距离最小。

弗洛伊德(floyd)算法

经典的求任意顶点之间的最短路径,采用贪心思想

每次添加中介点,然后根据中介点更新顶点之间的最短距离,知道中介点覆盖所有的顶点。

介绍一下深度优先搜索和广度优先搜索是如何实现的?

深度优先搜索:(1)访问起始点v0(2)若v0的第一个邻接点没有被访问过,则深度遍历该邻接点;(3)若v0的第一个邻接点已经被访问,则访问其第二个邻接点,进行深度遍历;重复以上步骤直到所有节点都被访问过为止

广度优先搜索:(1)访问起始点v0(2)依次遍历v0的所有未访问过得邻接点 (3)再依次访问下一层中未被访问过得邻接点;重复以上步骤,直到所有的顶点都被访问过为止图的遍历和树的遍历有哪些区别?

(1)图的遍历是指从图的某一点出发访问其余顶点,且使得每一个顶点仅仅被访问一次。一般来说,图的遍历有2种,深度优先遍历和广度优先遍历。 (2)树的遍历是指依次对树中每个结点访问一次且仅访问一次。二叉树的3种最重要的遍历方式分别称为前序遍历、中序遍历和后序遍历。此外还有层次遍历等。

介绍一下拓扑排序以及是如何实现的?

拓扑排序的步骤:(1)在有向图中任意选择一个没有前驱的节点输出(2)从图中删去该节点以及与它相连的边(3)重复以上步骤,直到所有的顶点都输出或者当前图中不存在无前驱的顶点为止,后者代表该图是有环图,所以可以通过拓扑排序来判断一个图是否存在环。

如何判断图是否连通

可以用DFS(O(v^2))和BFS(O(v+e))的思想都能实现,只要从一个点出发,然后判断是否能遍历完所有的点。

查找与哈希

各种查找方法(各方法是如何实现的要会用语言描述)

查找分为静态查找表和动态查找表;

静态查找表包括:顺序查找、折半查找、分块查找;

动态查找包括:二叉排序树和平衡二叉树。

(1)顺序查找:把待查关键字key放入哨兵位置(i=0),再从后往前依次把表中元素和key比较,如果返回值为0则查找失败,表中没有这个key值,如果返回值为元素的位置i(i!=0)则查找成功,设置哨兵的位置是为了加快执行速度,时间复杂度为O(n),其特点是:结构简单,对顺序结构和链式式结构都适用,但查找效率太低。

(2)折半查找:要求查找表为顺序存储结构并且有序,若关键字在表中则返回关键字的位置,若关键字不在表中时停止查找的典型标志是:查找范围的上界<=查找范围的下界。

(3)分块查找:先把查找表分为若干子表,要求每个子表的元素都要比后面的子表的元素小,也就是保证块间是有序的(但是子表内不一定有序),把各子表中的最大关键字构成一张索引表,表中还包含各子表的起始地址。特点是:块间有序,块内无序,查找时块间进行索引查找,块内进行顺序查找。

(4)二叉排序树:二叉排序树的定义为:一棵空树,或者是一棵具有如下特点的树:如果该树有左子树,则其左子树的所有节点值小于根的值;若该树有右子树,则其右子树的所有节点值均大于根的值;其左右子树也分别为二叉排序树

(5)平衡二叉树:平衡二叉树又称为AVL树,它或者是一棵空树或者具有如下特点:他的左子树和右子树的高度差的绝对值不能大于1,且他的左右子树也都是平衡二叉树。

什么是并查集

并查集是一种维护集合的数据结构,支持合并和查找两种操作; 合并:合并两个集合; 查找:判断两个元素是否在一个集合中; 并查集是用数组来实现的,设数组 int father[N] ,其中 father[i] 表示元素 i 的父亲结点,另外如果father[i] = i 则表示元素 i 是该集合的根结点 例如 father[2] = 1 表示元素 2 的父结点为 1;father[1] = 1 表示该集合的根结点为 1;

哈希表的概念、构造方法、冲突的解决办法?

哈希表又称为散列表,是根据关键字码的值直接进行访问的数据结构,即它通过把关键码的值映射到表中的一个位置以加快查找速度,其中映射函数叫做散列函数,存放记录的数组叫做散列表。

哈希函数的构造方法包括:直接定址法,除留余数法,数字分析法,平方取中法,折叠法,随机数法

(1)直接定址法:取关键字的某个线性函数值作为散列地址,H(key)=a*key+b。

(2)除留余数法:取关键字对p取余的值作为散列地址,其中p

(3)数字分析法:当关键字的位数大于地址的位数,对关键字的各位分布进行分析,选出分布均匀的任意几位作为散列的地址,适用于所有关键字都已知的情况。

(4)平方取中法:对关键字求平方,再取结果中的中间几位作为散列地址。

(5)折叠法:将关键字分为位数相同的几部分,然后取这几部分的叠加和作为散列地址。适用于关键字位数较多,且关键字中每一位上数字分布大致均匀。

(6)随机数法:选择一个随机函数,把关键字的随机函数值作为散列地址。适合于关键字的长度不相同时。

哈希冲突的解决方法包括:开放定址法和拉链法,当冲突发生时,使用某种探测技术形成一个探测序列,然后沿此序列逐个单单元查找,直到找到该关键字或者碰到一个开放的地址为止,探测到开放的地址表明该表中没有此关键字,若要插入,则探测到开放地址时可将新节点插入该地址单元。其中开放定址法包括:线性探查法,二次探查法,双重散列法

(1)线性探查法:基本思想,探查时从地址d开始,首先探查T[d],在探查T[d+1]…直到查到T[m-1],此后循环到T[0],T[1]…直到探测到T[d-1]为止。

(2)二次探查法:基本思想,探查时从地址d开始,首先探查T[d],再探查T[d+12],T[d+22]…等,直到探查到有空余地址或者探查到T[d-1]为止,缺点是无法探查到整个散列空间。

(3)双重散列法:基本思想,使用两个散列函数来确定地址,探查时从地址d开始,首先探查T[d],再探查T[d+h1(d)],T[d+2*h1(d)]…

(4)链接法:将所有关键字为同义词的节点链接在同一个单链表中,若选定的散列表长度为m,则可将散列表定义为一个由m个头指针组成的指针数组,凡是散列地址为i的节点均插入到头指针为i的单链表中。

排序

各种排序算法(各方法如何实现要会用语言描述)

内部排序包括:插入排序、选择排序、交换排序、归并排序、基数排序。其中插入排序包括:直接插入排序、折半插入排序、希尔排序;选择排序包括:简单选择排序,堆排序;交换排序包括:冒泡排序、快速排序。

(1)直接插入排序(稳定):基本思想为:将序列分为有序部分和无序部分,从无序部分依次选择元素与有序部分比较找到合适的位置,将原来的元素往后移,将元素插入到相应位置上。时间复杂度为:O(n^2),空间复杂度为O(1)

(2)折半插入排序(稳定):基本思想为:设置三个变量low high mid,令mid=(low+high)/2,若a[mid]>key,则令high=mid-1,否则令low=mid+1,直到low>high时停止循环,对序列中的每个元素做以上处理,找到合适位置将其他元素后移进行插入。比较次数为O(nlog2n),但是因为要后移,因此时间复杂度为O(n^2),空间复杂度为O(1)。 优点是:比较次数大大减少。

(3)希尔排序(不稳定):基本思想为:先将序列分为若干个子序列,对各子序列进行直接插入排序,等到序列基本有序时再对整个序列进行一次直接插入排序。优点是:让关键字值小的元素能够很快移动到前面,且序列基本有序时进行直接插入排序时间效率会提升很多,空间复杂度为O(1)。

(4)简单选择排序(不稳定):基本思想为:将序列分为2部分,每经过一趟就在无序部分找到一个最小值然后与无序部分的第一个元素交换位置。优点是:实现简单,缺点是:每一趟只能确定一个元素的位置,时间效率低。时间复杂度为O(n^2),空间复杂度为O(1)。

(5)堆排序(不稳定):设有一个任意序列,k1,k2,…,kn,当满足下面特点时称之为堆:让此序列排列成完全二叉树,该树具有以下特点,该树中任意节点均大于或小于其左右孩子,此树的根节点为最大值或者最小值。优点是:对大文件效率明显提高,但对小文件效率不明显。时间复杂度为O(nlog2n),空间复杂度为O(1)。

(6)冒泡排序(稳定):基本思路为:每一趟都将元素进行两两比较,并且按照“前小后大”的规则进行交换。优点是:每一趟不仅能找到一个最大的元素放到序列后面,而且还把其他元素理顺,如果下一趟排序没有发生交换则可以提前结束排序。时间复杂度为O(n^2),空间复杂度为O(1)。

(7)快速排序(不稳定):基本思路为:在序列中任意选择一个元素作为中心,比它大的元素一律向后移动,比它小的元素一律向前移动,形成左右两个子序列,再把子序列按上述操作进行调整,直到所有的子序列中都只有一个元素时序列即为有序。优点是:每一趟不仅能确定一个元素,时间效率较高。时间复杂度为O(nlog2n),空间复杂度为O(log2n).

(8)归并排序(稳定):基本思想为:把两个或者两个以上的有序表合并成一个新的有序表。时间复杂度为O(nlogn),空间复杂度和待排序的元素个数相同。

(9)基数排序:时间复杂度为:对于n个记录进行链式基数排序的时间复杂度为O(d(n+rd)),其中每一趟分配的时间复杂度为O(n),回收的时间复杂度为O(rd)。

“前小后大”的规则进行交换。优点是:每一趟不仅能找到一个最大的元素放到序列后面,而且还把其他元素理顺,如果下一趟排序没有发生交换则可以提前结束排序。时间复杂度为O(n^2),空间复杂度为O(1)。

1.排序算法中那些最坏和平均的时间复杂度是一样的? 答:直接插入排序,折半插入排序,冒泡排序,简单选择排序,归并排序,堆排序,基数排序。

2.排序算法中最好和最差的时间复杂度相同的排序算法有哪些? 答:简单选择排序,归并排序,堆排序,基数排序。

3.排序算法中最好、最坏、平均时间复杂度都一样的排序算法有哪些? 答:简单选择排序、堆排序、二路归并排序、基数排序。

4.平均时间复杂度为O(nlog2n) 的排序方法有哪些? 在天勤上看到的助记口诀: 军训排队时,教官说:快些以nlogn的速度归队;快(快速),些(希尔),归(归并),队(堆)

算法

贪心算法和动态规划的区别

贪心算法:局部最优,划分的每个子问题都最优,得到全局最优,但是不能保证是全局最优解,所以对于贪心算法来说,解是从上到下的,一步一步最优,直到最后。

动态规划:将问题分解成重复的子问题,每次都寻找左右子问题解中最优的解,一步步得到全局的最优解.重复的子问题可以通过记录的方式,避免多次计算。所以对于动态规划来说,解是从小到上,从底层所有可能性中找到最优解,再一步步向上。

分治法:和动态规划类似,将大问题分解成小问题,但是这些小问题是独立的,没有重复的问题。独立问题取得解,再合并成大问题的解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值