堆&减而治之-最短路径(Dijkstra) by邓俊辉老师

数据结构(三)

实际上是一种特殊的树。是一种几乎完美的树也就是一种完全二叉树(completed binary tree)
完全二叉树:只能在次底层出现单分支的叶子节点,次底层的叶子节点必须在右边;最底层均为叶子节点且必须在左边。
满二叉树(full binary tree),每一层都是满的,是一种完全二叉树的定义。
堆的好处,对于顺序存储的堆——可以有效地存储
rank的换算关系:父节点k:左孩子2k+1,右孩子2k+2。即LC(k)=(k<<1)+1 RC=(k+1)<<1

对堆的操作——insert(e)、getMax() 存在一定的priority(rank) priority queue
getmax & delmax 提取最大的元素就可以了。
insert(e)操作:也是一种 减而治之的方法。逐步与父节点比较priority。放至合适的位置percolate up/silt up :上滤 在保持结构性的情况下恢复整体的堆序性。
delmax操作:把最高的那层摘取。把最尾部的元素放在最高处。然后 percolate down。
总体的复杂度不会超过log(n)

减而治之 decrease and conquer

减 e.g.愚公移山
问题规模:几万到几十万步骤 。但问题规模是固定的。
规模为一百万的问题 ——> 一个问题&999999个问题。这两个问题的形式是一致的。

二分查找 bineary search

时间复杂度为:O(logn)

// S区间中做了预排序, e为待寻找元素 。mooc上比较详细
template <typename T> static Rank binsearch(T *S, T const & e , Rank lo, Rank hi){
	while(lo<hi){ //不变性:A[0,lo]
		Rank mi = (lo+hi)>>1; //以中点为轴,经过比较后确定深入
		e < S[mi] ? hi = mi : lo = mi+1; // 如果中位数比e大[lo,mi)或中位数比e小(mi,hi)
	} //出口时,A[lo = hi] 为大于e的最小元素
	return --lo; //故lo-1 即为 不大于e的元素的最大秩
}


注意减而治之与分而治之。前者不用管另一部分,后者分开的两部分都需要照顾。

选择排序 selection sort

分为两段[0,r]prefix (r,n)sorted suffix 不会很高。
在前缀中找出max ,挪至前后缀交界处加入后缀sorted中。
前面的[0,r]重复之间的步骤

注意selection sort 前缀的排序比较随机。
bubble sort 前缀 需要一定的处理。
共同点suffix均为有序的。每次都新增一个sorted。
但是这两种都是O(n^2) 必须遍历所有节点,才能确定最大值

selection sort 每一步的效率太低。前面的效率太低,如何在前面选取最大值时、加快速度。采用堆的数据结构

heapsort 堆排序

思考:前缀采用priority queue delmax() 接口。delmax的时间复杂度(logk)

注意堆排序的时间复杂度为O(nlogn)。一共要交换n次。

heap在物理上本身也是一个数组。
建堆的算法:需要先建堆 Floyd算法。
最大值的堆顶与界桩(last element)进行交换、交换后的元素下滤进行重构堆。
(最后的元素未必全局最小。因此还需要percolate down)

insertion sort 插入排序

sorted 排序好的部分在前面。乱序的仍然在后面。
选择乱序的首位元素。按大小顺序插入前面的有序部分。
插入排序相对于选择排序更加容易理解一些。(抓牌,插入扑克牌的排序)
选择排序需要所有的元素都集齐以后才能使用;插入排序是一种online的算法、来一个处理一个。
插入排序比选择排序更好一些
其排序复杂度,最好情况为O(n) 最坏的情况为O(n^2)

quickselect:partition 选取元素。

选取第k大的元素。 为减少复杂度,不需要先排序,在找到第k个。
时间复杂度不会少于O(n)。至少每个元素都要读取一遍。
如何做到O(n)?
此法平均意义,一般都为O(n) 但是最坏的情况大于O(n)。
先随机猜某个元素为第k大的元素(pivot)。
做一个分拣操作,使所有比其小的元素落在左边、比其大的元素落在右边。可以断定其是否为第k大的。
若猜小了,那么更小的那块可以减除;若猜大了,那么更大的那块可以减除。——减而治之
将lo往前移,或者将hi往后移。

template <typename T> void quickSelet( Vector<T> & A, Rank k){
	for( Rank lo = 0, hi = A.size()-1 ; lo < hi; ){
		Rank i = lo, j = hi; T pivot =A[lo];
		while( i<j ){ 
			while(i<j && pivot<=A[j])j--; A[i] = A[j]; 
			while(i<j && A[i]<=pivot)i++; A[j] = A[i]; 
		}
		A[i] = pivot;
		if( k <= i ) hi = i-1;
		if( i <= k ) lo = i+1;
	} 		//A[k]is now a pivot
}

最短路径 Dijkstra

map——>graph 抽象的图
读法 黛 杰斯特拉 j一般不发音。 音译 dikestra 戴克stra

图的转化
珠子——地点
绳长——路径
两点之间的最短路径,就是把珠子拉直,绷直的绳子就是最短路径。

最短路径是连通的但又不成环 也就是

把所有的绳网放在桌面上起来,把需要寻找最短路径的一端起点拿起来。逐步往上提

任何的点都能分为两部分——已经提起来的、还没有提起来的。形成一个cut。跨域的边(cross)最关键。

u为已经提离桌面的珠子。v为u下一个连接的珠子(地点)。
计算最短路径—>dist(v) = min{ dist(u) + ||uv|| , dist(v) } dist(v)为之前计算的最小路径

此时一个珠子提上去以后。cut发生了变化。
桥会发生变化,路径会有更新,立足于刚提升上去的点。计算min路径。
dijkstra 如果存在一条负权重的路,该算法无法求解。只能采用动态规划。

核心的代码
一个循环。依次引入n-1个顶点和n-1条边。
遍历所有neighbor,update所有权重。
选出最小的权重边,作为一个tree edge加入进去。

采用来实现该算法。
取出最大权重的点提取上去,用logn的算法复杂度恢复堆的结构。
与刚提取上去的相连的点 用 上滤 方法提升到相应的位置。
Heap::increase(节点、priority)

highest priority 选取权重最小的也就是优先度最高的。

注意最后 一共n个点、n-1条边。
SPT (shortest path tree) 最短路径树。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值