数据结构&贪心(二)
BST binary search tree 二叉搜索树
对一个二叉搜索树,从根节点开始比较大小搜索。
任意节点:左后代比根节点小、右后代比根节点大。左小右大。
BBST:balanced binary search tree 平衡二叉树。
对于深度比较深的节点,步骤和时间会花费比较多一些。
对于树进行平衡化,深度比较平均
散列表-哈希表 hashtable
怎么去做这么一个映射 比如:取模 mod (%) 一般M为素数散列表的长度
hash(key) = hey % M
dictionary map 的底层就是一种 hashtable
Huffman Tree 哈弗曼树
选择两个权重最小的树,将它俩和二为一。
(如何有效地组织?) 组成一个vector/list
取出两颗树,在插入。一共要和n-1次。此外还要每次去寻找最小的两个值。遍历复杂度为n
此时复杂度为:n*(n-1 ) 即为 O(n^2)
寻找数据最小值–降低算法复杂度的方法
若将数据排成三角形(堆)的形式:
能够找到最小值、最大值、getMin()、delMin() -> 此时的复杂度O(logn)
底数一般默认为常数2,不写。即使写了,由于常数对其无影响,而忽略不计。
n=1000 时 O(n)1000 O(logn) 1024(若2为底)->10
堆Heap 一种优先级队列。优先队列Priority Queue -> 堆 Heap
insert() getMax()
max或min 会放在堆顶的位置。最容易获得。
运用栈&队列进行Huffman树的构建: 与heap构建Huffman树同样都是O(nlogn)
将词频率最大的依次push进入栈中 此处最优的排序复杂度为O(nlogn)
pop取出两个次大的。将其频次之和 enqueue
每次均在栈和队列中、寻找两个最小的。2+2四个元素就可以。每一次的算法复杂度O(4)->O(1)
n-1次的话,算法复杂度为 O(n) 线性的复杂度
一共有四种情况:1、栈顶两个元素pop出来 2、栈顶pop与queue中的各一个 3、queue
最小生成树MST(minimum spanning tree)
连通性:任何两个节点均要连通。
规划航线、路程—>有权图(network)
原则 :边不能太少要保证连通性,不能有环路。 每条边均有权重。
找到最小的这样一个MST使权重最小。
如何寻找Prim(人)寻找到了一种方法。cut\cross
cut(割集):U V\U(去除了)
边(三类):各自域内;连接两个域的(桥\连接边\cross ) || 点分为:2类
任何一个树,有n个节点,必有n-1条边。
任何一个cut后的最小权重跨域边都会出现在(一个)MST中
操作思路:
将将一个点作为U 其余均为其割集(V\U)。
直接取出 该点相连的最小权重边。
加入这条最小权重边,使得U扩充为两个点。将其余作为割集。
确认第二条最小权重边
重复之前的过程即可寻找到最小生成树MST
(注意最小生成树可能不止一颗。起点选得不同、生成的树也不太相同。)
因为无向有权图可以转化为对称的二维矩阵。network
在第一行(第0个节点)寻找权重最小的另一编号点。
在这个权重最小的点所在的行列中寻找最小的那个编号。
将该编号点也加入。一共有两个编号。
将这两个点,所在的行列中寻找权重最小的点。
重复之前的过程
Prim算法 : Heap
采用Heap(堆)数据结构去实现。一种优先级队列。(实际上只用一个数组就可以实现)
在所有的跨边中寻找到最短的,让每一个下面的点都去计数(他们自己的权重-距离)
dist(v)= min {|v,u| } 即待连接的与上面已生成的树的最小记录。
只需要调用delMin()把最小权重的那条边取出来。时间成本O(logn)。
整个Prim算法的时间复杂度为O(n logn)
Kruskal算法:sorting by weight
优先选择权重最小的那条边。这条权重最小的边应该会出现在所有的MST中。(利用Prim比较好理解)
然后再倒数第二条权重的边也会被MST采用。
分析:最短边有三种情况1、全在U里面
2、跨域(先让最短边包进去、次短边第二次包进去)3、全在另一半割集中。
但是第三条最短边则不一定了。需要符合一定条件才能加进来。(因为第三条边加进去很有可能会成环)
该条件是:新引入的这条边是否会形成环路。
若这条边所连接的顶点、来自于同一棵树表明他们并不安全、会形成环路。
若来自不同的树则表明是可以加入的
该算法对于稀疏图是非常好的。因为出现在同一个现存树中的概率比较小。
难点分析:如何查找?是否在同一个树中。
采用一种数据结构:并查集Union-find。
查找一个元素,寻找到以后,返回其相应的值。
若在同一树中,则返回同一值。
若不在同一棵树中,则在将这两个集合和在一块(union)
采用list链表数据结构 link方式
此算法为O(n) quick-find slow-union
quick-find 在常数时间O(1)内查询到
union(7,4)——>再直接将4改为7.因为数组的下标已经标识了其位置。
slow-union 需要把所有的元素来回搬,复杂度会比较高、时间会收到惩罚。O(n)
此算法为O(logn) quick-union slow-find
quick-union
确定是哪一组的方式?由link决定,由父节点确定–若自己与父节点相等则为班长。
实现union:将一个班的班长重新归属到一个新的班长。其复杂度为O(logn)
slow-find 取决于该点在此树中的深度。一般其复杂度为O(logn)
最好组成一个班的树的结构高度为2 ,仅两层,O(1)就可以到班长。
改进union实现浅层的tree。
A班、B班。将深度浅一些的树归类到深度深一些的树中。时间复杂度为O(logn)
find操作表面看是一种静态的操作复杂度为 logn。
Path Compression(路径压缩):改变为一种动态操作、将寻找的路径folding起来。
逐渐减小树的深度,将自己的标签直接链接到班长上即可。