首页 > 编程语言 >dijkstra算法(单源最短路径)

dijkstra算法(单源最短路径)

时间:2024-01-25 20:00:20浏览次数:30  
标签:index return int dijkstra 单源 算法 MinHeap ELEMENT data

单源最短路径是求解给定一个起点到其他所有的点的最短距离。

适用的范围:有向图、边的权值没有负数

洛谷测试链接

代码实现

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <stdbool.h>
#include <limits.h>
#define u unsigned
#define ll long long
#define sc scanf
#define pr printf 
#define fr(i, j, n) for (int i = j; i < n; i++)
#define N 100000//节点的最大个数

typedef struct {//堆中存放的变量类型
	int t;//表示从源点到t点
	int d;//源点到t点的距离
}p;

typedef p ELEMENT;

//小根堆的ADT接口
typedef struct heap {
	ELEMENT* data;//´æ·ÅÔªËصÄÊý×é 
	int size;//×îС¶ÑÖеÄÔªËظöÊý 
	int maxSize;//¶ÑÖÐ×î¶àÄܹ»ÈÝÄɵÄÔªËظöÊý 
}minHeap, * MinHeap;

MinHeap createMinHeap(int n);//´´½¨Ò»¸ö×î¶àÄܹ»ÈÝÄÉn¸öÔªËصÄ×îС¶Ñ 
int MinHeapSize(MinHeap h);//·µ»Ø×îС¶ÑµÄÔªËظöÊý 
bool isMinHeapFull(MinHeap h);//ÅжÏ×îС¶ÑÊDz»ÊÇÂúÁË 
bool addMinHeap(MinHeap h, ELEMENT item);//Íù×îС¶ÑÀïÃæÌí¼ÓÔªËØitem
ELEMENT deleteMinHeap(MinHeap h);//µ¯³ö×îС¶ÑµÄ¶Ñ¶¥ÔªËØ 
void MinHeapInsert(MinHeap h, int index);//ÔÚ×îС¶ÑindexλÖÃнøÀ´Ò»¸öÔªËØ£¬ËùÒÔÒªÏòÉϵ÷Õû£¬À´ÈöÑÈÔÈ»ÊÇÒ»¸ö×îС¶Ñ 
void MinHeapify(MinHeap h, int index);//ÔÚ×îС¶ÑindexλÖõÄÔªËرäСÁË£¬ËùÒÔÏòϵ÷Õû¶Ñ£¬À´ÈöÑÈÔÈ»ÊÇÒ»¸ö×îС¶Ñ 
bool isMinHeapEmpty(MinHeap h);//ÅжÏ×îС¶Ñ¿ÕÁËûÓÐ 
void swap(MinHeap h, int i, int j);//½»»»×îС¶ÑÖÐiºÍjλÖõÄÔªËØ 
int MinHeapCompare(ELEMENT a, ELEMENT b);//»ùÓÚijÖйæÔòÀ´±È½Ï,ÀàËÆÓë±È½ÏÆ÷ 
void freeMinHeap(MinHeap h);//ÊÍ·Å×îС¶ÑµÄ¿Õ¼ä 
ELEMENT peekMinHeap(MinHeap h);//µÃµ½×îС¶ÑÖеĶѶ¥ÔªËØ 

int n;//节点的数量
int m;//边的数量
int s;//源点
//链式前向星
int head[N + 1];//每个节点的头边
int next[2 * N + 1];//每条边的下一边
int to[2 * N + 1];//每条边指向的节点
int w[2 * N + 1];//每条边对应的权重
int cnt = 1;//边的编号从1开始
int distance[N + 1];//从源点到每个点的距离
bool v[N + 1];//标记是不是已经找到最短路径
int b[3];//存放输入的信息

int main(int argc, char* argv[])
{
	sc("%d%d%d", &n, &m, &s);//读入节点数和边数和源点的位置

	//链式前向星建图
	for (int i = 0; i < m; i++) {
		sc("%d%d%d", b, b + 1, b + 2);

		next[cnt] = head[b[0]];//新的边指向老的头边
		to[cnt] = b[1];//新的边指向的节点是b[1]
		w[cnt] = b[2];//边对应的权重是b[2]
		head[b[0]] = cnt++;//更新节点的头边
	}

	for (int i = 1; i <= n; i++) {//初始话距离数组,用INT_MAX表示无穷大,节点的编号从1开始
		distance[i] = INT_MAX;
	}

	distance[s] = 0;//源点到源点的距离为0

	p t = { s, 0 };//对应的变量

	MinHeap h = createMinHeap(m);//创建一个有m大小的小根堆

	addMinHeap(h, t);//把变量放入小根堆

	while (!isMinHeapEmpty(h)) {//小根堆不为空
		p temp = deleteMinHeap(h);//弹出小根堆的堆顶元素

		if (v[temp.t] == 0) {//如果源点到temp.t的点的边没有被访问过,那么才继续
			for (int j = head[temp.t]; j; j = next[j]) {//遍历访问
				if (v[to[j]] == 0 && (temp.d + w[j] < distance[to[j]])) {
					distance[to[j]] = temp.d + w[j];
					p t1 = { to[j], distance[to[j]] };
					addMinHeap(h, t1);
				}
			}
			v[temp.t] = 1;//刚刚弹出了,所以访问了,就置为1
		}
	}

	//输出起点到所有点的最短距离
	for (int i = 1; i <= n; i++) {
		pr("%d ", distance[i]);
	}

	freeMinHeap(h);

	return 0;
}

MinHeap createMinHeap(int n)
{
	MinHeap h = (MinHeap)malloc(sizeof(minHeap));//¿ª±ÙÒ»¸ö×îС¶Ñ 

	h->data = (ELEMENT*)malloc(sizeof(ELEMENT) * n);//¿ª±ÙÒ»¸ön¸ö¿Õ¼äµÄELEMENTÊý×é 
	h->size = 0;//³õʼ»¯×îС¶ÑÔªËØÊÇ0 
	h->maxSize = n;//×îС¶ÑÄÜ´æ·Å×î´óÔªËصĸöÊýÊÇn 

	return h;//·µ»Ø×îС¶Ñ 
}
int MinHeapSize(MinHeap h)
{
	return h->size;//·µ»Ø×îС¶ÑÖеÄÔªËظöÊý 
}
bool isMinHeapFull(MinHeap h)
{
	return h->size == h->maxSize;//Èç¹û×îС¶ÑÖеÄÔªËظöÊýµÈÓÚÄܹ»ÈÝÄɵÄ×î´óÔªËظöÊý£¬ÄÇôÂúÁË 
}
bool addMinHeap(MinHeap h, ELEMENT item)
{
	if (isMinHeapFull(h)) {//Èç¹û×îС¶ÑÒѾ­ÂúÁË£¬ÄÇô¾Í²»ÄÜÌí¼ÓÔªËØÁË£¬·µ»Øfalse 
		return false;
	}

	h->data[h->size] = item;//°Ñitem·ÅÔÚ×î϶ÑÖÐÔªËظöÊýµÄϱêÖÐ,ÒòΪԪËظöÊýµÄϱê¾ÍÊÇÒª·ÅµÄλÖà 
	MinHeapInsert(h, h->size);//ÒòΪ¸Õ¸ÕнøÀ´Ò»¸öÔªËØ£¬ËùÒÔÏëÈöѼÌÐø±£³Ö×îС¶Ñ£¬ÄÇô¾ÍÐèÒªÏòÉϵ÷Õû¶Ñ 
	h->size++;//ÈÃ×îС¶ÑÖеÄÔªËظöÊý¼ÓÒ» 

	return true;//Ìí¼Ó³É¹¦·µ»Øtrue 
}
ELEMENT deleteMinHeap(MinHeap h)
{
	if (isMinHeapEmpty(h)) {//Èç¹û×îС¶ÑÖÐûÓÐÔªËØ£¬ÄÇô²»ÄܽøÐÐɾ³ý£¬Î¥·¨·µ»ØÒ»¸öÌض¨µÄÖµ£¬¼´ERROR 
		p t = { -1, -1 };
		return t;
	}

	ELEMENT ans = h->data[0];//·µ»Ø×îС¶ÑÖеĶѶ¥ÔªËØ 
	swap(h, 0, --h->size);//°Ñ×îС¶ÑÖеÄ×îºóÒ»¸öÔªËØÓë¶Ñ¶¥ÔªËؽøÐн»»»£¬²¢ÇÒÈöÑÖÐÔªËؼõÒ»£¬ÄÇô¾Í·ÃÎʲ»µ½¸Õ¸Õ±»É¾³ýµÄÔªËØÁË¡£ 
	MinHeapify(h, 0);//ϱê0λÖõÄÔªËرä´óÁË£¬ÄÇôΪÁ˼ÌÐø±£³ÖÒ»¸ö×îС¶Ñ£¬¾ÍÒªÏòϵ÷Õû 

	return ans;//·µ»Ø×îС¶ÑÖеĶѶ¥ÔªËØ 
}
void MinHeapInsert(MinHeap h, int index)//indexλÖõÄÊýÏòÉϵ÷ÕûС¸ù¶Ñ 
{
	while (MinHeapCompare(h->data[index], h->data[(index - 1) / 2]))//Èç¹ûϱêindexµÄֵСÓÚËüµÄ¸¸½Úµã 
	{
		swap(h, index, (index - 1) / 2);//ϱêindexµÄÖµºÍËüµÄ¸¸½ÚµãµÄÖµ½»»» 
		index = (index - 1) / 2;//¸üÐÂindexµÄλÖà 
	}
}
bool isMinHeapEmpty(MinHeap h)
{
	return !h->size;//Èç¹û×îС¶ÑÖеÄÔªËØÊÇ0¸ö£¬ÄÇô¾ÍÊÇ¿Õ£¬ÓÐÔªËؾͲ»ÊÇ¿Õ 
}
void swap(MinHeap h, int i, int j)
{
	ELEMENT t = h->data[i];
	h->data[i] = h->data[j];
	h->data[j] = t;
}
void MinHeapify(MinHeap h, int index)
{
	int left = 2 * index + 1;//¼ÆËãϱêindexµÄ×óº¢×Ó 

	while (left < h->size) {//Èç¹ûÓк¢×Ó 
		int lessest = left + 1 < h->size && MinHeapCompare(h->data[left + 1], h->data[left]) ? left + 1 : left;//Èç¹ûÓÐÓÒº¢×Ó²¢ÇÒÓÒº¢×ÓСÓÚ×óº¢×Ó£¬ÄÇôº¢×ÓÖÐ×îСµÄ¾ÍÊÇÓÒº¢×Ó£¬·ñÔò¾ÍÊÇ×óº¢×Ó 

		lessest = MinHeapCompare(h->data[index], h->data[lessest]) ? index : lessest;//Èç¹û¸¸Ç×½Úµã±Èº¢×ÓÖÐ×îСµÄ»¹ÒªÐ¡£¬ÄÇô×îСµÄ½Úµã¾ÍÊǸ¸½Úµã£¬²»È»×îСµÄ½Úµã¾ÍÊǺ¢×ÓÖÐ×îСµÄ½Úµã 

		if (lessest == index) {//Èç¹û×îСµÄ½ÚµãÊǸ¸½Úµã£¬ÄÇô²»ÓüÌÐøÁË£¬ÒѾ­ÊÇ×îС¶ÑÁË 
			break;
		}

		swap(h, index, lessest);//Óë×îСµÄº¢×Ó½øÐн»»» 
		index = lessest;//¸üÐÂindexϱ꣬ÒòΪ¸Õ¸Õ½»»»ÁË 
		left = 2 * index + 1;//ÖØмÆËãϱêindexµÄ×óº¢×Ó 
	}
}
int MinHeapCompare(ELEMENT a, ELEMENT b)
{
	return a.d < b.d;//Ö±½Ó½øÐÐÖµµÄ±È½Ï 
}
void freeMinHeap(MinHeap h)
{
	free(h->data);//ÏÈÊÍ·Å×îС¶Ñ´æ·ÅÔªËصĿռä 
	free(h);//ÔÙÊÍ·Å×îС¶ÑµÄ¿Õ¼ä 
}
ELEMENT peekMinHeap(MinHeap h)
{
	if (isMinHeapEmpty(h)) {//×îС¶ÑÀïÃæûÓÐÔªËØÄÇô£¬²Ù×÷Î¥·¨£¬·µ»ØÌض¨Öµ 
		p t = { -1, -1 };
		return t;
	}

	ELEMENT ans = deleteMinHeap(h);//µ¯³ö×îС¶ÑµÄ¶Ñ¶¥ 

	addMinHeap(h, ans);//ÔÙ·ÅÈë×îС¶Ñ£¬ÒÔ´ËÀ´ÊµÏÖ´úÂ븴Óà 

	return ans;//·µ»Ø×îС¶ÑµÄ¶Ñ¶¥ÔªËØ 
}

时间复杂度是O(m * logm),m为边的数量,这是通过最小堆来优化的。

本质是通过之前求出的最短路和现在有的最短路来比较,然后更新最短路,一旦从堆中弹出,那么起点到那个点的最短路也就确定了,那么之后碰到弹出的就不管了,然后再利用已知的最短路求其他点的最短路

标签:index,return,int,dijkstra,单源,算法,MinHeap,ELEMENT,data
From: https://www.cnblogs.com/lwj1239/p/17987920

相关文章

  • 【每日GIS算法】(0)不同实体的构造
    本系列文章主要使用typescript手动实现GIS算法,其目的并不在于能够在正式生产中直接使用,而是可以通过对这些算法的实现,了解一些GIS方法的具体原理。本系列文章一定程度上与计算机图形学关系密切,也可以更好地了解图形学中相关知识点。本文作为本系列文章的第一篇,首先实现一些基础的......
  • 【每日GIS算法】(1)二维矢量的运算
    二维向量的基础运算主要有以下几种矢量的加法矢量的减法矢量的乘法矢量的除法矢量的模矢量的点乘矢量的叉乘矢量的归一化针对不同的场景,我们为二维矢量类提供对应的实例方法,但是由于这些实例方法会修改对象内部的数值,因此还提供对应的静态方法,在不改变原来的向量的情况......
  • c# .Net 常见算法
    1usingSystem.Collections.Generic;2usingSystem.ComponentModel.Design;3usingSystem.Linq;45namespaceTestDelay6{7internalclassProgram8{9staticvoidMain()10{11int[]arry=new......
  • 滚动弹幕出现位置算法
    title:滚动弹幕出现位置算法date:2024-01-25categories:编程tags:-弹幕-算法-C#效果显示大量弹幕、允许重叠、弹幕字号允许不同约定为了更好地进行讨论,我们先声明一些共识:弹幕会从屏幕右边缘发射,并向左滚动弹幕出现位置应该尽量靠上几条弹幕之间应该尽......
  • 数据结构与算法 pdf下载
    《数据结构与算法》涉及计算机中数据的组织、重组、移动、使用和提取等操作方法,及相关的数学分析。《数据结构与算法》所选的主题基于以下几个朴素的原则。第一,本书只讲解实用的技术,而忽略一些理论上非常虽然出色、但不太实用的算法。第二,本书既包含经典的方法,也包括最近发现的......
  • Unity3D 游戏中的自动寻路有怎样的算法详解
    前言Unity3D是一款非常流行的游戏引擎,它的自动寻路功能可以使游戏角色在场景中自动找到最短路径并前往目标位置。本文将详细介绍Unity3D中自动寻路的算法原理以及代码实现。对惹,这里有一个游戏开发交流小组,希望大家可以点击进来一起交流一下开发经验呀在游戏开发中,自动寻路是......
  • 欧几里得算法
    欧几里得算法用于求解两个数\(a,b\)的最大公约数,\(\gcd(a,b)=\gcd(b,a\bmodb)\),为了方便证明,我们约定\(a>b\),证明:设\(r=a\bmodb=a-k\cdotb\),\(d\mida\)且\(d\midb\),显然\(a=k\cdotb+r\),那么\(\frac{r}{d}=\frac{a}{d}-\frac{k\cdot......
  • java中双指针算法(快指针与慢指针)
    双指针法:设置两个指针,分别是快指针和慢指针,分别是i和j。  设置一个变量temp用来储存第一个数据nums[0] 过程:1.nums[0]  temp  他们两个相等  那么temp不需要改变,i=i+1,j变,i=1,j=1   2.nums[i=1],temp  他们两个相等,temp不变,i=i+1,j不......
  • 文心一言 VS 讯飞星火 VS chatgpt (186)-- 算法导论14.1 3题
    三、用go语言,写出OS-SELECT的非递归版本。文心一言:下面是使用Go语言编写的OS-SELECT的非递归版本:funcOS_SELECT(T*Node,kint)*Node{//找到最小秩的节点minRankNode:=findMinRankNode(T)//如果最小秩的节点就是目标节点,则返回该节点if......
  • Unity3D Rts游戏里的群体移动算法是如何实现的详解
    实时战略(RTS)游戏是一种以管理和控制虚拟军队为主题的游戏类型。在这类游戏中,玩家需要控制大量的单位进行战斗、资源采集和建设等操作。其中,群体移动算法是实现这些操作的关键之一。本文将详细介绍Unity3DRTS游戏中群体移动算法的实现原理和代码实现。对啦!这里有个游戏开发交流小......