建议收藏 10个数据结构高频知识点

1、数组和链表的区别

  • 从逻辑结构上来看
  • 数组必须实现定于固定的长度,不能适应数据动态增减的情况,即数组的大小一旦定义就不能改变 。当数据增加是,可能超过原先定义的元素的个数;当数据减少时,造成内存浪费;链表动态进行存储分配,可以适应数据动态地增减的情况,且可以方便地插入、删除数据项 。
  • 从内存存储的角度看
  • 数组从栈中分配空间(用new则在堆上创建),对程序员方便快速,但是自由度小;链表从堆中分配空间,自由度大但是申请管理比较麻烦 。
  • 从访问方式类看
  • 数组在内存中是连续的存储,因此可以利用下标索引进行访问;链表是链式存储结构,在访问元素时候只能够通过线性方式由前到后顺序的访问,所以访问效率比数组要低 。

建议收藏 10个数据结构高频知识点

文章插图
 
2、简述快速排序过程1)选择一个基准元素,通常选择第一个元素或者最后一个元素,
2)通过一趟排序将待排序的记录分割成独立的两部分,其中一部分记录的元素值均比基准元素值小 。另一部分记录的元素值比基准值大 。
3)此时基准元素在其排好序后的正确位置
4)然后分别对这两部分记录用同样的方法继续进行排序,直到整个序列有序 。
 
3、快速排序的改进只对长度大于k的子序列递归调用快速排序,让原序列基本有序,然后再对整个基本有序序列用插入排序算法排序 。实践证明,改进后的算法时间复杂度有所降低,且当k取值为 8 左右时,改进算法的性能最佳 。
选择基准元的方式
对于分治算法,当每次划分时,算法若都能分成两个等长的子序列时,那么分治算法效率会达到最大 。也就是说,基准的选择是很重要的 。选择基准的方式决定了两个分割后两个子序列的长度,进而对整个算法的效率产生决定性影响 。最理想的方法是,选择的基准恰好能把待排序序列分成两个等长的子序列 。
  • 方法1 固定基准元
  • 如果输入序列是随机的,处理时间是可以接受的 。如果数组已经有序时,此时的分割就是一个非常不好的分割 。
  • 方法2 随机基准元
  • 这是一种相对安全的策略 。由于基准元的位置是随机的,那么产生的分割也不会总是会出现劣质的分割 。在整个数组数字全相等时,仍然是最坏情况,时间复杂度是O(n2) 。实际上,随机化快速排序得到理论最坏情况的可能性仅为1/(2n) 。所以随机化快速排序可以对于绝大多数输入数据达到O(nlogn)的期望时间复杂度 。
  • 方法3 三数取中
  • 引入的原因:虽然随机选取基准时,减少出现不好分割的几率,但是还是最坏情况下还是O(n^2),要缓解这种情况,就引入了三数取中选取基准 。
分析:最佳的划分是将待排序的序列分成等长的子序列,最佳的状态我们可以使用序列的中间的值,也就是第N/2个数 。可是,这很难算出来,并且会明显减慢快速排序的速度 。这样的中值的估计可以通过随机选取三个元素并用它们的中值作为基准元而得到 。事实上,随机性并没有多大的帮助,因此一般的做法是使用左端、右端和中心位置上的三个元素的中值作为基元 。
 
4、各类排序算法对比时间复杂度来说:
  1. 平方阶(O(n))排序
  2. 各类简单排序:直接插入、直接选择和冒泡排序;
  3. 线性对数阶(O(nlog2n))排序
  4. 快速排序、堆排序和归并排序;
  5. O(n))排序,§是介于0和1之间的常数 。
  6. 希尔排序
  7. 线性阶(O(n))排序
  8. 基数排序,此外还有桶、箱排序 。
说明:
  • 当原表有序或基本有序时,直接插入排序和冒泡排序将大大减少比较次数和移动记录的次数,时间复杂度可降至O(n);
  • 而快速排序则相反,当原表基本有序时,将蜕化为冒泡排序,时间复杂度提高为O(n);
  • 原表是否有序,对简单选择排序、堆排序、归并排序和基数排序的时间复杂度影响不大 。
稳定性:
排序算法的稳定性:若待排序的序列中,存在多个具有相同关键字的记录,经过排序,这些记录的相对次序保持不变,则称该算法是稳定的;若经排序后,记录的相对次序发生了改变,则称该算法是不稳定的 。
稳定的排序算法:冒泡排序、插入排序、归并排序和基数排序
不是稳定的排序算法:选择排序、快速排序、希尔排序、堆排序
 
选择排序算法准则:


推荐阅读