算法的乐趣:算法设计的基础

算法模式

  1. 处理最优化问题,贪婪法和动态规划
  2. 迷宫问题: 穷尽式和回溯
  3. 算法需要频繁查表操作:需要有序表实现
  4. 使用树和图实现,一定不要忘了递归。

算法实现中的数据结构

线性表

数组

数组可以直接通过下标进行访问,数组直接访问时没有开销的,但是插入和删除需要移动数组元素,开销比较大,因此插入和删除比较频繁地情况下不适合使用数组。数组中查找一个元素的时间复杂度是O(n),但是有序数组的情况下可以使用二分查找降到O(logn)

链表

链表的插入和删除时间是固定的时间,就是更改指针的时间,比数组的插入删除效率高。,但是访问链表元素的效率比较低,需要从链表的头部向后搜索,查找操作的时间是O(n),理论上链表的长度是不受限制的,但是时间使用过程中,链表受存储空间的限制,因此也是不能够无限增长的。

注意的是链表的头结点。因为在头结点之前进行插入或者删除头结点会导致头结点的指针失效。为了解决这个问题,我们设计了一个称谓哨兵节点或者哑节点的头节点,该节点没有数据域,只有指针域的特殊节点。这样我们就可以使用一致的方法处理空链表和非空链表;同时对链表进行插入删除不需要对数据元素的首届点和中间节点进行差异处理。

具有后进先出的特点。常常用栈: * 算法转化为非递归实现 * 穷经搜索是存储当前状态 * 深度优先搜索

队列 队列是一种先进先出的特点的数据结构。此外尤其要注意优先队列的应用。

复杂数据结构-树

没有环路的图 > 二叉查找树

AVL树和红黑树

B树

B 树的节点大小为什么是4K?而不是采用更小的,例如二叉树一样一个节点有两个。

区间树:以区间为数据元素的红黑树

线段树:以区间为数据元素的二叉查找树

堆 - 最大堆:每个节点的值都大于其子树所有节点的值 - 最小堆:每个节点的值都小于其子树所有节点的值

算法设计常用思想

二分查找

一个循环有序数组(如:3, 4, 5, 6, 7, 8, 9, 0, 1, 2),不知道其最小值的位置,要查找任一数值的位置。要求算法时间复杂度为\(log_2(n)\)

1.将一个循环有序数组一分为二,一定得到一个有序数组和另一个循环有序数组 
2.长度不超过2的循环有序数组其实就是有序数组。
  • 我们要先弄清楚这个循环有序数组的原数组是单调减的还是单调增,如果a1>an,那么a一定是增加型的循环有序数组,如果a1<an,那么a一定是减少型的循环有序数组。

注意:a1=an这种情况。 * 判断左边一半和右边一半哪一个是有序的。这里以增加型的举例,减少型的同理。如果a[mid] >= a[start],那么左边一定是有序的。因为如果左边是循环有序的,那么最大值点一定出现在左侧,且最大值点左侧的数恒大于最大值点右侧的数。这与a[mid] >= a[start]矛盾。反之同理。

  • 确定了有序的一侧后,就要判断是不是在这一侧搜索了。这个判断非常简单,只要确定待搜索的数的值是否在有序数列的两个端点值之间即可。

  • 最后通过循环,就可以类似二分法,找到待搜索的数的位置。