dijkstra算法的改进--堆

dijksta每次都需要从所有的距离最小的点中选择一个进行扩展。而进行选择距离最下的点的时候使用的是遍历,每次遍历找出最下的那个点。这样的效率肯定是不高的。

我们可以使用一个小根堆结构,将所有的节点放入小根堆中,然后每次取出堆顶元素即可。每次更新的时候需要将小根堆中的元素的值进行更改。这显然无法使用系统提供的堆结构。所以我们只有手动写堆结构来实现。

	//弹出的节点和距离信息
	public static class NodeRecord {
		public Node node;
		public int distance;
		
		public NodeRecord(Node node,int distance) {
			this.node = node;
			this.distance = distance;
		}
	}
	//堆结构
	public static class NodeHeap{
		private Node[] nodes;//堆中的点集,堆的底层是数组结构
		private HashMap<Node,Integer> heapIndexMap;//点以及每个点在数组中的位置。
		private HashMap<Node,Integer> distanceMap;//点和源点的距离
		private int size;
		public NodeHeap(int size) {
			nodes = new Node[size];
			heapIndexMap = new HashMap<Node, Integer>();
			distanceMap = new HashMap<Node, Integer>();
			this.size = 0;
		}
		private boolean isEmpty() {
			return this.size == 0;
		}
		//是否进来过小根堆
		private boolean isEntered(Node node) {
			return heapIndexMap.containsKey(node);
		}
		//heapIndex.get(node) == -1表示的是进来过小根堆,但是以及被弹出的节点
		private boolean inHeap(Node node) {
			return isEntered(node) && heapIndexMap.get(node) != -1;
		}
		private	void swap(int index1,int index2) {
			//交换数组中两个位置的值,在记录位置的map数组中也要做出相应的交换
			heapIndexMap.put(nodes[index1], index2);
			heapIndexMap.put(nodes[index2],index1);
			Node tmp = nodes[index1];
			nodes[index1] = nodes[index2];
			nodes[index2] = tmp;
		}
		private void insertHeapify(int index) {
			//小根堆往上走
			while(distanceMap.get(nodes[index]) < distanceMap.get(nodes[(index-1)/2])) {
				swap(index,(index-1)/2);
				index = (index-1) / 2;
			}
			
		}
		
		private void heapify(int index,int size) {
			int left = index * 2 + 1;
			while(left<size) {
				int smallest = left + 1 < size && distanceMap.get(nodes[left+1]) < distanceMap.get(nodes[left])? left+1:left;
				smallest = distanceMap.get(nodes[smallest]) < distanceMap.get(nodes[index]) ? smallest :index;
				if(smallest == index) {
					break;
				}
				else {
					swap(smallest,index);
					index = smallest;
					left = index *2 + 1;
				}
				
				
				
			}
			
		}
		public void addOrUpdateOrIgnore(Node node,int distance) {
			//在堆中如果距离变小的就往上走
			if(inHeap(node)) {
				distanceMap.put(node, Math.min(distanceMap.get(node),distance));
				insertHeapify(heapIndexMap.get(node));
			}
			//如果从来没有出现在堆中就新建一个点。
			if(!isEntered(node)) {
				nodes[size] = node;
				heapIndexMap.put(node,size);
				distanceMap.put(node,distance);
				insertHeapify(size++);
			}
			//如果之前出现在堆中,但是以及被弹出了,就不用管了。因为距离一定是最小的了,不用考虑
		}
		public NodeRecord pop() {
			
			int distance = distanceMap.get(nodes[0]);
			Node node = nodes[0];
			swap(0,size-1);
			//-1表示之前在堆中,但是已经被弹出,记录一下。
			heapIndexMap.put(node, -1);
			distanceMap.remove(node);
			nodes[size-1] = null;
			heapify(0,size--);
			size--;
			
			return new NodeRecord(node, distance);
			
		}
		
		
	}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值