数据结构与算法之美 | 笔记

个人笔记,仅供备忘

  • 部分参考课程评论

08、栈

  • 1、内存中的堆栈和数据结构堆栈不是一个概念,可以说内存中的堆栈是真实存在的物理区,数据结构中的堆栈是抽象的数据存储结构

  • 内存空间在逻辑上分为三部分:代码区、静态数据区和动态数据区,动态数据区又分为栈区和堆区。

    • 代码区:存储方法体的二进制代码。高级调度(作业调度)、中级调度(内存调度)、低级调度(进程调度)控制代码区执行代码的切换。
    • 静态数据区:存储全局变量、静态变量、常量,常量包括final修饰的常量和String常量。系统自动分配和回收。
    • 栈区:存储运行方法的形参、局部变量、返回值。由系统自动分配和回收
    • 堆区:new一个对象的引用或地址存储在栈区,指向该对象存储在堆区中的真实数据
  • 2、为什么函数调用要用“栈”来保存临时变量呢?用其他数据结构不行吗?

    • 其实,我们不一定非要用栈来保存临时变量,只不过如果这个函数调用符合后进先出的特性,用栈这种数据结构来实现,是最顺理成章的选择。

    • 从调用函数进入被调用函数,对于数据来说,变化的是什么呢?是作用域。所以根本上,只要能保证每进入一个新的函数,都是一个新的作用域就可以。而要实现这个,用栈就非常方便。在进入被调用函数的时候,分配一段栈空间给这个函数的变量,在函数结束的时候,将栈顶复位,正好回到调用函数的作用域内。

09、队列

  • 循环队列判断队空和队满,具体代码要写出来。

    • (tail+1)/ % n == head // 队列满了
    • head == tail // 队列为空
  • 阻塞队列就是入队、出队操作可以阻塞

  • 并发队列就是队列的操作多线程安全

数据结构与算法之美 | 笔记

10、递归

  • 递归满足的三个条件

    • 1、一个问题的解可以分解为几个子问题的解
    • 2、这个问题与分解之后的子问题,除了数据规模不同,求解思路完全一样
    • 3、 存在递归终止条件
  • 写递归代码最关键的是

    • 找到如何将大问题分解为小问题的规律,基于此写出递推公式,找到终止条件,最后将递推公式和终止条件翻译成代码
    • 只要遇到递归,就把它抽象成一个递推公式,不用想一层层调用关系,不要试图用人脑分解递归的每个步骤
  • 递归代码要警惕堆栈溢出(由于递归很深)

    • 1、可以限制递归调用的最大深度
  • 递归药警惕重复计算

    • 可以通过一个数据结构(如哈希表)来保存已经求解过的计算。当递归遇到此计算时,查看是否求过,是则直接返回值。
      数据结构与算法之美 | 笔记
  • 会将递归代码改写成非递归代码

    • 可以改成迭代循环的方法
  • 递归调试技巧:

    • 1、打印日志发现递归值
    • 2、结合条件断点进行调试

11、排序

  • 排序方法总览
    数据结构与算法之美 | 笔记

  • 原地排序:特指空间复杂度为O(1)的排序算法

  • 排序算法的衡量指标:时间空间复杂度、稳定性(若待排序的序列中存在值相等的元素,经过排序之后,相等元素之间原有的先后顺序不变)

  • 1、冒泡排序:只操作相邻的两个数据,比较大小,然后互换排序。

  • 2、插入排序:插入新数据,排序。

    • 包含元素的比较,和元素的移动(插入点后的元素顺序后移)。
  • 3、选择排序:每次从未排序区间找到最小元素,将其放到已排序末尾。

  • 【为什么插入排序比冒泡排序更受欢迎?】

    • 冒泡排序代码更复杂,且快速排序算下来时间要少一点。
      数据结构与算法之美 | 笔记
  • 4、归并排序分治思想,递归编程。先把数组从中间分割成前后两部分,然后对前后两部分分别排序,再将排好序的两部分合并在一起。
    数据结构与算法之美 | 笔记

  • 归并排序应用不广泛都原因是,它不是原地排序算法。归并排序的合并函数,在合并两个有序数组为一个有序数组时,需要借助额外的存储空间。

  • **5、快速排序:**如果要排序数组中下标从p到r之间的一组数据,我们选择p到r之间的任意一个数据作为哦pivot(分区点)。
    数据结构与算法之美 | 笔记

  • 总结:归并排序算法是一种任何情况下时间复杂度都比较稳定的排序算法,这也是致命的缺点,即归并排序不是原地排序算法,空间复杂度较高,是O(n)。正因如此,应用没快排广泛。

  • 快排平均时间复杂度O(nlogn)。

数据结构与算法之美 | 笔记