数据结构与算法学习总结

主要是通过对《数据结构与算法分析——C语言描述》(Mark Allen Weiss)的课本学习和普林斯顿大学的《算法》(Robert Sedgewick)课程进行学习(http://algs4.cs.princeton.edu/home/),都是讲的非常好的,受益良多,下面以算法课程的授课顺序进行一下总结。

1.Fundamentals

  • Union-Find。Union-Find问题主要是解决连通性问题的一种方式,这种数据结构非常简单,主要是通过find()判断是否连接,union()连接两个节点。通过对连接形成的树结构进行优化以改进find()效率。
    数据结构与算法学习总结_第1张图片
  • Bags,Queues,and Stacks。比较基础的数据结构,但是这里提到了Bags这个概念在有的数据结构书里面没有提到的,像放进一个袋子一样,是无序的。但是实际还是用node的链表实现的。
  • Analysis of Algorithm。这一部分主要讲一些算法复杂度的分级与判断,比如logN,N,NlogN,N^2等,一个方法是根据算法进行数学分析,另一个方法是不断2N增加输入查看运行事件的变化进行初略估计。大部分的算法书上都有讲,比较重要的是分析了内存的使用。以下面的MysteryBox类为例:
Public class MysteryBox{//16字节的对象头(overhead)(32位为8字节),16byte
    private boolean x0,x1;//1个boolean为1字节,1*2=2byte
    private int y0,y1,y2,y3;//一个int为4字节,4*4=16byte
    private double z0,z1;//一个double为8字节,2*8=16byte
    private long[] a=new long[128];//引用类型为8字节(32位4字节),数组类型占用24字节(暂时理解为数组包含的length属性等占用的内存),128*8+24=1048byte
    //其他类型:float:4byte,char:2byte,short:2byte,char[][]:~2MN,long[][]:~4MN
    //内部类:inner class extra overhead:8byte,其他与外部类相同
    //总内存向上对齐到8的倍数
}
//但是此处没有介绍方法具体占用的内存,也许是因为方法不在堆空间的原因。

2.Sorting

  • Selection sort。选择排序,每次选择一位最大(最小)放到正确的位置,再选择余下最大(最小)的放到正确的位置,知道剩下最后一位。
  • Insertion sort。插入排序,假定下标i以前的都是已经排序过的,取i+1位以此与前i位进行比较,找到正确的位置后结束,直到比较完所有元素,在比较元素较少的时候采用此方法提高效率(好像是7个吧)。
  • Shellsort。希尔排序,希尔排序使用一个增量序列,此时间隔增量个元素的元素为一组进行排列(下标/增量=分组号,分组号相同的为一组进行排序),然后不断减小增量直到增量为1即可完成排序。
  • Mergesort。归并排序,每次将元素组平分为两组进行排序,再量已排序的两组元素比较后合并为一组排序好的元素组。书上通常是采用递归的算法进行,此处提到采用非递归的算法,直接按照2^r个元素为一组,并将每两组进行排序(r从0到全部覆盖全部数组,0组和1组进行排序合并),避免了不停的递归调用消耗虚拟机栈内存。
  • Quicksort。快速排序,比较常用的排序方法,选定partition进行划分为两组再分别进行quicksort。partition是选定很大程度上影响quicksort的效率,通常是选取第一个元素为partition;然后采用将所有元素shuffle后选取第一个;或者选取首位、末位和中间为求三者中间大小的元素为partition;还有基于比较选取partition的方法可以选取合适的partition让quicksort最坏也是O(N)的复杂度,但是太过麻烦实际中并未使用(课程中只是提到)。3-way quicksort是对quicksort面对重复元素的优化。采用3个游标,将和partition相等的元素放在中间。
  • Heap sort。堆排序,此处讲了二叉堆的数据结构,通过二叉堆DelMin/DelMax的特性进行排序。d堆的讲解在《数据结构与算法》书中有,但是讲解的也不是特别清晰。数据结构与算法学习总结_第2张图片
  • Radix sort。桶排序,原则上就是元素分类到一个一个的桶中,然后再将桶中的元素分到一个个的桶中直到每个桶只有1个或者相同的元素。例如对1000以内数字排序就是不停的对100进行求余,然后相同的余数分到同一桶中,视为对百位数字的比较;再将每一个桶中的对10进行求余,然后相同的余数分到同一桶中,视为对十位数字的比较;再对桶中个位数进行比较即可。
    数据结构与算法学习总结_第3张图片

3.Searching
- Symbol Table。定义表的基本API,以及最简单的实现。采用链表(无序的)和数组(可以是有序的),讲解了当采用的是有序数组的时候,可以采用二分查找(Binary search in an ordered array)
- Binary Search Trees。二叉查找树,任何一个节点X,他的左子树中所有关键字值小于X的关键字值,而他的右子树的所有关键字值大于X的关键字值。
- Hash Tables。哈希表,主要有识别键值的哈希函数,以及哈希表:分离链接法和开放定址法。分离链接法是对冲突采用链表链接,开放定址法则是用策略继续寻找地址存放对象:线性探测法、平方探测法和双散列,其中双散列是指对冲突再调用一个哈希函数进行计算。当哈希表的数组快满时冲突会变多导致效率降低,因此会进行再散列,即扩大数组内存并重新进行散列。目前Java常用的HashMap是两种的结合,对冲突采用链表链接,当链表过长的话,为提高效率会将链表数据结构转为红黑树,提高效率;同时当进行再散列时,将数组扩大为原来的2倍(原数组长度为2^N),从而在进行再散列的时候可以通过位运算简化哈希函数的运算。
- 2-3 search trees。2-3树,2-3树是一颗有着2个子节点或者3个子节点的树。2个子节点的树与普通二叉树相同,3个子节点的树,左子节点小于左值,右子节点大于右值,中间子节点在左右值之间。当一个节点的值有3个的时候,中间值上升为父节点,如下图2。Search and insert operations in a 2-3 tree with N keys are guaranteed to visit at most lg N nodes.
- Red-black BSTs。红黑树,可以看作是2-3的变形(其他书中定义略有不同,但是意思差不多),定义:差不多就是,父节点是黑节;红遍链接的节点是红节点;从一个节点到NULL节点经过的黑节点一样多;红节点只在左节点(其他书上好像没这么要求,但是通过这个理解起来更加容易和清晰),图2是添加节点后的集中平衡的旋转。删除节点:同其他二叉树相同,讲要删除的节点与其后继节点(右子树的最小节点,如果没有右子树,直接左子树替换删除节点),然后调整平衡(情况比较复杂,看得我懵懵懂懂)。
-

数据结构与算法学习总结_第4张图片

4.Graphs
- Undirected Graphs。无向图。Connected components问题,可以直接用DFS搜索从v到w的路径O(V + E),或者在初始化无向图的时候建立CC[]数组。V采用数组保存,E采用链表,无向图其实就是双向的有向图。

- Directed Graphs
Topological sort:采用DFS,搜索路径,被搜索过的V标记,当V已无E可走的时候,返回V(V入)


Strong connectivity:1,计算G^R(反转G的所有方向的图)的Topological sort;2,根据Topological sort进行DFS,取V,通过DFS能够到达的都和V是Strong connectivity(任何节点与本身是Strong connectivity)。
Minimum Spanning Trees:链接所有V的最小权值和的E(无向的)。
Kruskal’s algorithm:PQ取权重最小的E,链接E,判断是否有循环,没有循环则成功,有循环则跳过,知道添加了V-1条E。

Prim’s algorithm:添加一个V,然后PQ添加与他相连的E,链接最小边;再将新V链接的E加到PQ中;不停的重复。Lazy:直接加入,但是会存在DelMin出来的是无效的,此时跳过。Eager:为每个节点保持一个最小链接的边,并排序,在不停加入V的时候,已加入T的V不再更新,但是未加入的V会不停更新最小的E。
Lazy implementation. We use a priority queue to hold the crossing edges and find one of minimal weight. Each time that we add an edge to the tree, we also add a vertex to the tree. To maintain the set of crossing edges, we need to add to the priority queue all edges from that vertex to any non-tree vertex. But we must do more: any edge connecting the vertex just added to a tree vertex that is already on the priority queue now becomes ineligible (it is no longer a crossing edge because it connects two tree vertices). The lazy implementation leaves such edges on the priority queue, deferring the ineligibility test to when we remove them.
Eager implementation. To improve the lazy implementation of Prim’s algorithm, we might try to delete ineligible edges from the priority queue, so that the priority queue contains only the crossing edges. But we can eliminate even more edges. The key is to note that our only interest is in the minimal edge from each non-tree vertex to a tree vertex. When we add a vertex v to the tree, the only possible change with respect to each non-tree vertex w is that adding v brings w closer than before to the tree. In short, we do not need to keep on the priority queue all of the edges from w to vertices tree—we just need to keep track of the minimum-weight edge and check whether the addition of v to the tree necessitates that we update that minimum (because of an edge v-w that has lower weight), which we can do as we process each edge in s adjacency list. In other words, we maintain on the priority queue just one edge for each non-tree vertex: the shortest edge that connects it to the tree.
Shortest Paths:最小路径问题。
Dijkstra’s algorithm:针对有向无环图。从s顶点入队;Q出队顶点x,x可到达的点标记,未在队列中则入队,并更新到达x距离;循环直到Q为空。
Bellman-Ford algorithm:针对有负边的。对每个顶点,更新每个E更新距离。重复V次。实际是入队s,然后更新s的Es然后入队被更新过的Vs,知道队列为空。
数据结构与算法学习总结_第5张图片
Max Flow:最大流问题。
Ford-Fulkerson_Algorithm:将capacity和flow分为两部分,正向为capacity-flow,反向为flow,找s到t的路径即可,能找到就说明还有流可以从s到t。

剩下的主题还包括Radix Sort,Tries,Substring Search,Regular Expression,Data Compression下次补充,感觉有的问题比较复杂不是特别好讲清楚了。包括流的问题也不容易说清楚。先穿点复杂度的图片。
数据结构与算法学习总结_第6张图片
数据结构与算法学习总结_第7张图片

数据结构与算法学习总结_第8张图片

数据结构与算法学习总结_第9张图片

你可能感兴趣的:(算法学习)