最短路径算法——dijsktra和floyd的c++实现

下列算法中的图的定义请看这篇文章:(56条消息) 最小生成树算法——kruskal和prim算法的c++实现_Aaaverage JOE的博客-CSDN博客icon-default.png?t=N4N7https://blog.csdn.net/m0_73961454/article/details/130814908

Dijsktra算法的实现:这是一个单源路径算法,即只能求一个点到其他各点的最短路径 

Node* getMindistanceAndUnselectedNode(unordered_map<Node*,int>& distanceMap,set<Node*>& selectedNode) {
	int mindistance = INT_MAX;
	Node* minNode = NULL;
	for (pair<Node*,int> it : distanceMap) {
		Node* node = it.first;
		int distance = it.second;
		if (distance < mindistance && selectedNode.count(node) == 0) {
			mindistance = distance;
			minNode = node;
		}
	}
	return minNode;
}
unordered_map<Node*, int> Dijsktra(Node* head) {
	unordered_map<Node*, int> distanceMap;
	if (head == NULL) {
		return distanceMap;
	}
	distanceMap[head] = 0;
	set<Node*> selectedNode;
	Node* minNode = getMindistanceAndUnselectedNode(distanceMap, selectedNode);
	while (minNode != NULL) {
		int distance = distanceMap[minNode];
		for (Edge* edge : minNode->edges) {
			Node* to = edge->to;
			if (distanceMap.count(to) == 0) {
				distanceMap[to] = distance + edge->weight;
			}
			distanceMap[to] = fminf(distanceMap[to], distance + edge->weight);
		}
		selectedNode.insert(minNode);
		minNode = getMindistanceAndUnselectedNode(distanceMap, selectedNode);
	}
	return distanceMap;
}

Dijsktra的优化版(利用了加强堆,即给堆加了个索引):

unordered_map<Node*,int> dijsktraByheap(Node* node,int size) {
	unordered_map<Node*, int> result;
	if (node == NULL) {
		return result;
	}
	Nodeheap heap(size);
	heap.AddorUpdateorIgnore(node, 0);
	while (!heap.isEmpty()) {
		NodeRecord* temp = heap.pop();
		int distance = temp->distance;
		node = temp->node;
		for (Edge* edge : node->edges) {
			Node* to = edge->to;
			heap.AddorUpdateorIgnore(to, edge->weight + distance);
		}
		result[node] = distance;
	}
	return result;
}
//dijsktra算法的堆优化写法
class NodeRecord {
public:
	int distance;
	Node* node;
	NodeRecord(Node* n,int v) :distance(v), node(n) {}
};
class Nodeheap {
private:
	Node** arr;//储存Node*元素的数组
	unordered_map<Node*, int> distanceMap;
	unordered_map<Node*, int> indexMap;//标记结点在数组中的下标,若不在数组中,则为-1
	int heapsize;
public:
	Nodeheap(int s) {
		heapsize = 0;
		arr = new Node*[s]();
	}
	void swap(int index1, int index2) {
		//交换数组中的元素
		Node* temp = arr[index1];
		arr[index1] = arr[index2];
		arr[index2] = temp;
		//交换索引表中的索引
		indexMap[arr[index1]] = index2;
		indexMap[arr[index2]] = index1;
	}
	//index位置和其孩子进行比较,若distance大则进行交换
	void heapify(int index) {
		int left = index * 2 + 1;
		while (left < heapsize) {
			int min = left + 1 < heapsize && distanceMap[arr[left]] < distanceMap[arr[left + 1]] ? left : left + 1;
			min = distanceMap[arr[index]] < distanceMap[arr[min]] ? index : min;
			if (index == min) {
				return;
			}
			swap(index, min);
			index = min;
			left = index * 2 + 1;
		}
	}
	//index位置和其父进行比较,若distance大则进行交换
	void heapInsert(int index) {
		while (distanceMap[arr[index]] < distanceMap[arr[(index - 1) / 2]]) {
			swap(index, (index - 1) / 2);
			index = (index - 1) / 2;
		}
	}
	//若不在堆中,直接添加;若在堆中,需要进行比较,若更小,则进行更新;否则什么都不做
	void AddorUpdateorIgnore(Node* node, int distance) {
		if (!isEntered(node)) {
			arr[heapsize] = node;
			distanceMap[node] = distance;
			indexMap[node] = heapsize;
			heapInsert(heapsize++);
			return;
		}
		if (inheap(node) && distanceMap[node] > distance) {
			distanceMap[node] = distance;
			heapify(indexMap[node]);
		}
	}
	//将此时最小的距离弹出,弹出这个操作就相当于把此结点加入到selectedNodes以及选出minNode了
	NodeRecord* pop() {
		NodeRecord* res = new NodeRecord(arr[0], distanceMap[arr[0]]);
		swap(0, --heapsize);
		indexMap[arr[heapsize]] = -1;
		distanceMap.erase(arr[heapsize]);
		heapify(0);
		return res;
	}

	//判断这个结点是否进过堆中,为了给Add函数使用(如果没有进来过,直接添加)
	bool isEntered(Node* node) {
		return indexMap.count(node) != 0;
	}

	//判断这个结点是否在堆中,只有在堆中才有可能进行更新
	bool inheap(Node* node) {
		return isEntered(node) && indexMap[node] != -1;
	}
	bool isEmpty() {
		return heapsize == 0;
	}
};

 

多源最短路径算法:求图中各顶点到其他顶点的最短路径,当然我们可以调用多个Dijsktra算法,单未免效率过低,故有了floyd算法

floyd算法的实现:

void floyd(int(*G)[MAX_VEX], int(*A)[MAX_VEX], int(*path)[MAX_VEX]) {
	if (G == NULL || A == NULL || path == NULL) {
		return;
	}
	for (int i = 0; i < MAX_VEX; i++) {
		for (int j = 0; j < MAX_VEX; j++) {
			A[i][j] = G[i][j];
			path[i][j] = -1;
		}
	}
	for (int v = 0; v < MAX_VEX; v++) {
		for (int i = 0; i < MAX_VEX; i++) {
			for (int j = 0; j < MAX_VEX; j++) {
				if (A[i][j] > A[i][v] + A[v][j]) {
					A[i][j] = A[i][v] + A[v][j];
					path[i][j] = v;
				}
			}
		}
	}
}

这里函数形参讲一下:

这是二维数组的指针,因为数组实质就是在内存中一段连续的空间,二维数组arr就是以一维数组为元素的构成,例如arr[0] = *(arr + 0),arr就是基地址,这样得到的就是二维数组中的第0个一维数组

arr[0][1] = *(*(arr + 0) + 1)

故数组名就是内存中开辟一段连续空间的基地址,地址即是指针,加上数字就会由编译器根据其类型来加上对应的内存编号,比如int* p;p[1] = *(p + 1),这里加的是int类型的4个字节,一个内存单元是一个字节

如何得到所给定结点之间的最短路径:

int GetMindistanceByFloyd(int(*A)[MAX_VEX], int(*path)[MAX_VEX], int i, int j) {
	if (path[i][j] == -1) {
		return A[i][j];
	}
	int v = path[i][j];
	int val1 = GetMindistanceByFloyd(A, path, i, v);
	int val2 = GetMindistanceByFloyd(A, path, v, j);
	return val1 + val2;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值