数据结构常见面试题

   本意用于考研复试,如下是博主本身整理,博主是大四本科生,不能保证内容彻底正确,请辩证地看,若是有问题能够在评论区指出我再修改。 整理不易,我就不挂个二维码请游客付费了,若是能够的话,麻烦高抬贵手,点一下右下角的推荐吧! 程序员

一、数组和链表的区别。算法

从逻辑结构上来看,数组必须实现定于固定的长度,不能适应数据动态增减的状况,即数组的大小一旦定义就不能改变。当数据增长是,可能超过原先定义的元素的个数;当数据减小时,形成内存浪费;链表动态进行存储分配,能够适应数据动态地增减的状况,且能够方便地插入、删除数据项。数组

从内存存储的角度看;数组从栈中分配空间(用new则在堆上建立),对程序员方便快速,可是自由度小;链表从堆中分配空间,自由度大可是申请管理比较麻烦。安全

从访问方式类看,数组在内存中是连续的存储,所以能够利用下标索引进行访问;链表是链式存储结构,在访问元素时候只可以经过线性方式由前到后顺序的访问,因此访问效率比数组要低。数据结构

 

 

二、简述快速排序过程函数

1)选择一个基准元素,一般选择第一个元素或者最后一个元素,性能

2)经过一趟排序将待排序的记录分割成独立的两部分,其中一部分记录的元素值均比基准元素值小。另外一部分记录的元素值比基准值大。优化

3)此时基准元素在其排好序后的正确位置指针

4)而后分别对这两部分记录用一样的方法继续进行排序,直到整个序列有序。blog

 

三、快速排序的改进

只对长度大于k的子序列递归调用快速排序,让原序列基本有序,而后再对整个基本有序序列用插入排序算法排序。实践证实,改进后的算法时间复杂度有所下降,且当k取值为 8 左右时,改进算法的性能最佳。

选择基准元的方式

对于分治算法,当每次划分时,算法若都能分红两个等长的子序列时,那么分治算法效率会达到最大。也就是说,基准的选择是很重要的。选择基准的方式决定了两个分割后两个子序列的长度,进而对整个算法的效率产生决定性影响。最理想的方法是,选择的基准刚好能把待排序序列分红两个等长的子序列。

  方法1 固定基准元

若是输入序列是随机的,处理时间是能够接受的。若是数组已经有序时,此时的分割就是一个很是很差的分割。

方法2 随机基准元

这是一种相对安全的策略。因为基准元的位置是随机的,那么产生的分割也不会老是会出现劣质的分割。在整个数组数字全相等时,仍然是最坏状况,时间复杂度是O(n^2)。实际上,随机化快速排序获得理论最坏状况的可能性仅为1/(2^n)。因此随机化快速排序能够对于绝大多数输入数据达到O(nlogn)的指望时间复杂度。

方法3 三数取中

引入的缘由:虽然随机选取基准时,减小出现很差分割的概率,可是仍是最坏状况下仍是O(n^2),要缓解这种状况,就引入了三数取中选取基准。

分析:最佳的划分是将待排序的序列分红等长的子序列,最佳的状态咱们可使用序列的中间的值,也就是第N/2个数。但是,这很难算出来,而且会明显减慢快速排序的速度。这样的中值的估计能够经过随机选取三个元素并用它们的中值做为基准元而获得。事实上,随机性并无多大的帮助,所以通常的作法是使用左端、右端和中心位置上的三个元素的中值做为基准元。

4、各种排序算法对比

 

 

时间复杂度来讲:

(1)平方阶(O(n2))排序
  各种简单排序:直接插入、直接选择和冒泡排序;
 (2)线性对数阶(O(nlog2n))排序
  快速排序、堆排序和归并排序;
 (3)O(n1+§))排序,§是介于0和1之间的常数。

       希尔排序
(4)线性阶(O(n))排序
  基数排序,此外还有桶、箱排序。

说明:

当原表有序或基本有序时,直接插入排序和冒泡排序将大大减小比较次数和移动记录的次数,时间复杂度可降至O(n);

而快速排序则相反,当原表基本有序时,将蜕化为冒泡排序,时间复杂度提升为O(n2);

原表是否有序,对简单选择排序、堆排序、归并排序和基数排序的时间复杂度影响不大。

 

稳定性:

排序算法的稳定性:若待排序的序列中,存在多个具备相同关键字的记录,通过排序,这些记录的相对次序保持不变,则称该算法是稳定的;若经排序后,记录的相对次序发生了改变,则称该算法是不稳定的。 

稳定的排序算法:冒泡排序、插入排序、归并排序和基数排序

不是稳定的排序算法:选择排序、快速排序、希尔排序、堆排序

 

选择排序算法准则:

通常而言,须要考虑的因素有如下四点:

设待排序元素的个数为n.

1)当n较大,则应采用时间复杂度为O(nlog2n)的排序方法:快速排序、堆排序或归并排序序。

2)当n较大,内存空间容许,且要求稳定性:归并排序

3)当n较小,可采用直接插入或直接选择排序。

    直接插入排序:当元素分布有序,直接插入排序将大大减小比较次数和移动记录的次数。

    直接选择排序 :元素分布有序,若是不要求稳定性,选择直接选择排序

5)通常不使用或不直接使用传统的冒泡排序。

6基数排序
它是一种稳定的排序算法,但有必定的局限性:
  一、关键字可分解。
  二、记录的关键字位数较少,若是密集更好
  三、若是是数字时,最好是无符号的

 

 

五、冒泡排序算法的改进

1.设置一标志性变量pos,用于记录每趟排序中最后一次进行交换的位置。因为pos位置以后的记录均已交换到位,故在进行下一趟排序时只要扫描到pos位置便可。

2.传统冒泡排序中每一趟排序操做只能找到一个最大值或最小值,咱们考虑利用在每趟排序中进行正向和反向两遍冒泡的方法一次能够获得两个最终值(最大者和最小者) , 从而使排序趟数几乎减小了一半。

 

六、邻接矩阵与邻接表

邻接矩阵表示法:在一个一维数组中存储全部的点,在一个二维数组中存储顶点之间的边的权值

邻接表表示法:图中顶点用一个一维数组存储,图中每一个顶点vi的全部邻接点构成单链表

对比

1)在邻接矩阵表示中,无向图的邻接矩阵是对称的。矩阵中第 i 行或 第 i 列有效元素个数之和就是顶点的度。

在有向图中 第 i 行有效元素个数之和是顶点的出度,第 i 列有效元素个数之和是顶点的入度。

2)在邻接表的表示中,无向图的同一条边在邻接表中存储的两次。若是想要知道顶点的度,只须要求出所对应链表的结点个数便可。

有向图中每条边在邻接表中只出现一次,求顶点的出度只须要遍历所对应链表便可。求入度则须要遍历其余顶点的链表。

3)邻接矩阵与邻接表优缺点:

邻接矩阵的优势是能够快速判断两个顶点之间是否存在边,能够快速添加边或者删除边。而其缺点是若是顶点之间的边比较少,会比较浪费空间。由于是一个 n∗n 的矩阵。

而邻接表的优势是节省空间,只存储实际存在的边。其缺点是关注顶点的度时,就可能须要遍历一个链表。

 

 

7.用循环比递归效率高吗?

递归和循环二者彻底能够互换。不能彻底决定性地说循环地效率比递归的效率高。

2.1递归算法:

优势:代码简洁、清晰,而且容易验证正确性。

缺点:它的运行须要较屡次数的函数调用,若是调用层数比较深,须要增长额外的堆栈处理(还有可能出现堆栈溢出的状况),好比参数传递须要压栈等操做,会对执行效率有必定影响。可是,对于某些问题,若是不使用递归,那将是极端难看的代码。在编译器优化后,对于屡次调用的函数处理会有很是好的效率优化,效率未必低于循环。

2.2循环算法:

优势:速度快,结构简单。

缺点:并不能解决全部的问题。有的问题适合使用递归而不是循环。若是使用循环并不困难的话,最好使用循环。

 

八、解决哈希冲突的方法

哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构。

1) 线性探测法

2) 平方探测法

3) 伪随机序列法

4) 拉链法

 

九、KMP算法:在一个字符串中查找是否包含目标的匹配字符串。其主要思想是每趟比较过程让子串前后滑动一个合适的位置。当发生不匹配的状况时,不是右移一位,而是移动(当前匹配的长度– 当前匹配子串的部分匹配值)位。

 

十、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+树的搜索过程当中走了一条从根结点到叶子结点的路径。
相关文章
相关标签/搜索