图的遍历(深度、广度、最小生成树、最短路径)

 有向连通图如下所示在这里插入图片描述

 

 


#include<stdio.h>
#include<malloc.h>
#include <deque>
#include <iostream>
#include <algorithm>
#include <set>
#include <queue>
#define MAXV 7									//最大顶点个数
#define INF unsigned short(-1)					//定义 ∞ 
//∞ == INF(表示 两点不可直达)
//深度优先遍历:Depth First Search (DFS) 
//广度优先比例:Breadth First Search (BFS) 

typedef struct eNode {
	int adjVer;					//该边的邻接点编号 
	int weight;					//该边的的信息,如权值 
	struct eNode* nextEdge;		//指向下一条边的指针 
}EdgeNode; 						//别名,边结点的类型 

typedef struct vNode {
	EdgeNode* firstEdge;		//指向第一个边结点 (其实数组比较方便)
}VNode; 						//别名,邻接表的头结点类型 

typedef struct list
{
	int vertexCnt;				//顶点个数
	int edgeCnt;				//边数
	VNode adjList[MAXV];		//邻接表的头结点数组 
}ListGraph;						//别名,完整的图邻接表类型 

								// 每个顶点到最近其他顶点的数据
typedef struct closedge
{
	int adjVer;	// 最近邻接顶点
	int weight;	// 两顶点的权重
}Closedge;
Closedge PrimClosedge[MAXV] = { 0 };

// 边
typedef struct edge
{
	edge(int v1, int v2, int w) :ver1(v1), ver2(v2), weight(w) {}
	int ver1;	// 顶点1
	int ver2;	// 顶点2
	int weight;	// 两顶点的权重
}Edge;

struct EdgeSortFun
{
public:
	bool operator()(const Edge& a, const Edge& b)// 按权重升序
	{
		return a.weight < b.weight;
	}
};

// 最短路径:贝尔曼福特算法(Bellman_Ford算法),Floyd算法的优化(因为只针对v0点,从二维降到一维)
// 作用:计算不含负圈图的最短路径 返回是否有圈
// v到各点的距离
bool ShortestPath_Bellman_Ford(int matrix[MAXV][MAXV], int v0 = 0,int val = 6)
{
	int D[MAXV] = { 0 };		// v0点到其余各点的距离
	int Path[MAXV] = { 0 };		// 前置点
	//初始化
	for (int i = 0; i < MAXV; i++)
	{
		D[i] = matrix[v0][i];
		if (D[i] && D[i] != INF)
			Path[i] = v0; // i为v的邻接点
		else 
			Path[i] = -1;
	}
	D[v0] = 0;

	//初始化结束,开始双重循环
	for (int k = 0; k < MAXV ; ++k)
	{
		for (int i = 0; i < MAXV; ++i) //i为源点
		{
			for (int j = 0; j < MAXV; j++) //j为终点
			{
				if (D[i] + matrix[i][j] < D[j])// v0到i + i到j < v0到j
				{
					D[j] = D[i] + matrix[i][j];// 更新距离
					Path[j] = i;	// 更新j前置
				}
			}
		}
	}
	//判断是否含有负圈
	bool flag = true;
	for (int j = 0; j < MAXV; j++) //j为源点
	{
		for (int k = 0; k < MAXV - 1; k++) //k为终点
		{
			if (D[k] > D[j] + matrix[j][k])
			{
				flag = false;
				break;
			}
		}
	}

	// 输出
	std::cout << v0 << "点到其他各点的最短路径:" << std::endl;
	for (int i = 0; i < MAXV; ++i)
	{
		if (i != v0)
		{
			std::cout << "--> 点" << i;
			if (D[i] != INF)
				std::cout << " 距离为: " << D[i] << std::endl;
			else
				std::cout << " 不可达" << std::endl;
		}
	}

	std::cout << "顶点" << v0 << " 到 " << val << "的路径为:" << std::endl;
	std::cout << val << "<-";;
	while (Path[val] != 0)
	{
		std::cout << Path[val] << "<-";
		val = Path[val];
	}
	std::cout << v0 << std::endl;
	return flag;
}

// 最短路径:迪杰斯特拉算法(Dijkstra算法)
// 计算v0点到其他点的最短距离
void ShortestPath_Dijkstra(int matrix[MAXV][MAXV], int v0 = 0, int val = 6)
{
	std::cout << v0 << "点到其他各点的最短路径:" << std::endl;

	bool S[MAXV] = { 0 };	// v0到vi点的最短路径是否已经被确定
	int D[MAXV] = { 0 };	// v0到vi点的最短路径,否则为INF
	int Path[MAXV] = { 0 };	// vo到vi的最短路径上vi的(当前)前驱节点,默认-1
	for (int i = 0; i < MAXV; ++i)
	{
		S[i] = false;
		D[i] = matrix[v0][i];
		if (D[i] && D[i] != INF)// i点是v0点的邻接点(v0为前驱顶点)
			Path[i] = v0;
		else
			Path[i] = -1;// 当前点 或是 非邻接点
	}
	// 当前点
	S[v0] = true;
	D[v0] = 0;
	Path[v0] = -1;

	// 循环,每次求得v0到某个顶点v的最短路径,将v加入到S
	for (int i = 1; i < MAXV; ++i)
	{
		int min = INF;
		int v = -1;	// 顶点v
					// 遍历D,找到没被确定的距离最短的那个点
		for (int j = 0; j < MAXV; ++j)
		{
			if (!S[j] && D[j] < min)// j该点没被确定 且 到该点的路径较短
			{
				v = j;				// 记录当前v0能到达距离最短的那个点v
				min = D[j];			// 记录当前v0能到达点的最小距离
			}
		}
		if (v != -1)
			S[v] = true;// 确定到v点为最短
		else
			continue;
		for (int j = 0; j < MAXV; ++j)
		{
			if (!S[j] && (D[v] + matrix[v][j] < D[j]))// 从剩余没被确定的点j中,比较 [v0到v的距离(已确定) + 点v到j的距离](该距离为增加中间新顶点后,v0到j的新可达路径v0->v->j的距离) 和 当前j到点v0的距离(原j到v0的最短库里),选取较小的值
			{	// 如顶点0->1,0->2的原路径为0->1,0->2,最短分别为D[1]=4,D[2]=6,由于v(点1)被确定到S,得到新路径 v0->v(点1)->j(点2),最短为D[v] + matrix[v][j] = 5 < D[j] = 6;更新j(2)到原点的距离
				D[j] = D[v] + matrix[v][j];
				Path[j] = v;	// v中间节点为新的前置节点
			}
		}
	}

	// 输出
	for (int i = 0; i < MAXV; ++i)
	{
		if (i != v0)
		{
			std::cout << "--> 点" << i;
			if (D[i] != INF)
				std::cout << " 距离为: " << D[i] << std::endl;
			else
				std::cout << " 不可达" << std::endl;
		}
	}
	std::cout << "顶点" << v0 << " 到 " << val << "的路径为:" << std::endl;
	std::cout << val << "<-";;
	while (Path[val] != 0)
	{
		std::cout << Path[val] << "<-";
		val = Path[val];
	}
	std::cout << v0 << std::endl;
}

// 最短路径:弗洛伊德算法(Floyd算法)
// 输出v0点到其他点的最短距离
void ShortestPath_Floyd(int matrix[MAXV][MAXV], int v0 = 0, int val = 6)
{
	int D[MAXV][MAXV] = { 0 };		// D[i][j],记录两顶点i,j的最短距离
	int Path[MAXV][MAXV] = { 0 };	// Path[i][j],记录顶点i到j路径上,j当前的前置顶点

	for (int i = 0; i < MAXV; ++i)
	{
		for (int j = 0;j < MAXV; ++j)
		{
			D[i][j] = matrix[i][j];// 初始化顶点i到到j的当前最短距离
			// 初始化每个顶点到其他顶点的前置顶点
			if (D[i][j] && D[i][j] != INF)	// 邻接点
				Path[i][j] = i;
			else
				Path[i][j] = -1;
		}
	}

	for (int k = 0; k < MAXV; ++k)			// 假设从i到j要经过k
	{
		for (int i = 0; i < MAXV; ++i)
		{
			for (int j = 0; j < MAXV; ++j)
			{
				if (D[i][k] + D[k][j] < D[i][j])
				{
					D[i][j] = D[i][k] + D[k][j];
					Path[i][j] = Path[k][j];		// 更改j的前驱为k
				}
			}
		}
	}

	// 输出
	std::cout << v0 << "点到其他各点的最短路径:" << std::endl;
	for (int i = 0; i < MAXV; ++i)
	{
			if (i != v0)
			{
				std::cout << "--> 点" << i;
				if (D[v0][i] != INF)
					std::cout << " 距离为: " << D[v0][i] << std::endl;
				else
					std::cout << " 不可达" << std::endl;
			}
	}

	std::cout << "顶点" << v0 << " 到 " << val << "的路径为:" << std::endl;
	std::cout << val << "<-";;
	while (Path[v0][val] != 0)
	{
		std::cout << Path[v0][val] << "<-";
		val = Path[v0][val];
	}
	std::cout << v0 << std::endl;
}

// 最小生成树:克鲁斯卡尔算法(kruskal算法)
void MiniSpanTree_Kruskal(int matrix[MAXV][MAXV])
{
	int vexset[MAXV] = { 0 };// 联通分量
	for (int i = 0; i < MAXV; ++i)
	{
		vexset[i] = i;// 初始化每个点为联通分量
	}
	std::deque<Edge> edge;
	for (int i = 0; i < MAXV; ++i)
	{
		for (int j = 0; j < MAXV; ++j)
		{
			if (matrix[i][j] && matrix[i][j] != INF)
			{
				Edge e(i, j, matrix[i][j]);
				edge.push_back(e);
			}
		}
	}
	std::sort(edge.begin(), edge.end(), EdgeSortFun());

	for (int i = 0; i < MAXV && !edge.empty(); )
	{
		// 当前最小变得两个顶点
		int v1 = edge.front().ver1;
		int v2 = edge.front().ver2;
		// 两个点的所在联通分量
		int vs1 = vexset[v1];
		int vs2 = vexset[v2];
		if (vs1 != vs2)// 若相同则出现环
		{
			std::cout << "边:顶点" << v1 << "--" << v2 << std::endl;
			for (int j = 0; j < MAXV; ++j)// 用for循环是因为,你不知道vs1和vs2下,联通分量中的顶点数是1:n还是n:1,如果能立马判断出vs1下的是1的话,只需要vexset[v1] = vs2即可
			{
				if (vexset[j] == vs2) vexset[j] = vs1;// 都改成同一个联通分量,所以if (vexset[j] == vs1) vexset[j] = vs2;也行
			}
			++i;
		}
		edge.pop_front();
	}

	int c = 0;
}

int Min(Closedge PrimClosedge[MAXV])
{
	int min = INF;
	int idx = -1;
	for (int i = 0; i < MAXV; ++i)
	{
		if (PrimClosedge[i].weight > 0 && PrimClosedge[i].weight < min)
		{
			min = PrimClosedge[i].weight;
			idx = i;
		}
	}
	return idx;
}
// U表示已经有选定最小边的顶点(起始为rootVer),V表示所有顶点
// 最小生成树:普拉姆(prim算法),根据邻接矩阵表示
void MiniSpanTree_Prim(int matrix[MAXV][MAXV], int rootVer = 0)
{
	// 根节点(U={rootVer(0)}) 到 其他节点的最小距离
	for (int i = 0; i < MAXV; ++i)
	{
		if (i != rootVer)// 其他节点
		{
			PrimClosedge[i].adjVer = rootVer;
			PrimClosedge[i].weight = matrix[rootVer][i];
		}
	}

	for (int i = 1; i < MAXV; ++i)
	{
		int minVerIdx = Min(PrimClosedge);		// 当前最小边的那个顶点

		if (minVerIdx == -1) break;// 非连通图出错

		int u = PrimClosedge[minVerIdx].adjVer;	// 该边的一个顶点		u 属于U
		int v = minVerIdx;						// 该边的另一个顶点		v 属于V-U
		std::cout << "边:顶点" << u << "--" << v << std::endl;
		PrimClosedge[minVerIdx].weight = 0;		// 顶点并入U,(即v到u顶点的边不用在计算了)
												// U += {minVerIdx}
												// 比较其u,v到 他节点j的权重,若uj > vj;则修改j目前的最近邻接顶点为v
		for (int j = 0; j < MAXV; ++j)
		{
			if (matrix[minVerIdx][j] < PrimClosedge[j].weight)// 比较 当前最小边的顶点v和u 分别 到  其他顶点 的权重 
			{
				// 如在确定0(u)--1(v)边后,matrix[1][2] = 1(1到2的权重) < PrimClosedge[2].weight = 6(0到2的权重)
				// 得到PrimClosedge[2].adjVer = 1;即U{0,1}中的1 到 2 最近
				PrimClosedge[j].adjVer = minVerIdx;
				PrimClosedge[j].weight = matrix[minVerIdx][j];
			}
		}
	}
	return;
}


//创建图的邻接表 
void CreateAdjListGraph(ListGraph* &LG, int matrix[MAXV][MAXV], int vertexCnt, int edgeCnt)
{
	int i, j;
	EdgeNode* p;
	LG = (ListGraph*)malloc(sizeof(ListGraph));
	for (i = 0; i < vertexCnt; i++)
	{
		LG->adjList[i].firstEdge = NULL;		//给邻接表中所有头结点指针域置初值 
	}
	for (i = 0; i < vertexCnt; i++) 			//检查邻接矩阵中的每个顶点元素 
	{
		for (j = vertexCnt - 1; j >= 0; j--)	// 该顶点到其余点的数据
		{
			//if (matrix[i][j] != 0) 								//存在一条边 
			{
				p = (EdgeNode*)malloc(sizeof(EdgeNode));		//申请一个结点内存
				p->adjVer = j;									//存放邻接点 
				p->weight = matrix[i][j];						//存放权值
				p->nextEdge = NULL;

				p->nextEdge = LG->adjList[i].firstEdge;			//头插法 
				LG->adjList[i].firstEdge = p;
			}
		}
	}
	LG->vertexCnt = vertexCnt;
	LG->edgeCnt = edgeCnt;
}

//输出邻接表 
void DisplayAdjList(ListGraph* LG)
{
	int i;
	EdgeNode* p;
	for (i = 0; i < MAXV; i++)
	{
		p = LG->adjList[i].firstEdge;
		printf("%d:", i);
		while (p != NULL)
		{
			if (p->weight != INF) // 输出当前等点能直达的邻接顶点信息
			{
				printf("%2d[%d]->", p->adjVer, p->weight);
			}
			p = p->nextEdge;
		}
		printf(" NULL\n");
	}
}

//深度优先遍历
bool visitedDFS[MAXV] = { 0 };									//全局数组,记录当前顶点是否已经遍历
void DFS(ListGraph* LG, int matrix[MAXV][MAXV], int v)
{
	/*
	// 通过邻接表遍历
	EdgeNode* p;
	visitedDFS[v] = true;										//记录已访问
	std::cout << v << " ";										//输出顶点编号
	p = LG->adjList[v].firstEdge;								//p 指向顶点 v 的第一个邻接点
	while (p)
	{
		if (!visitedDFS[p->adjVer] && p->weight != INF) 		//如果下一个邻接节点 p->adjVer 没被访问,递归访问它
		{
			DFS(LG, p->adjVer);
		}
		p = p->nextEdge;										//p 指向顶点 v 的下一个邻接点
	}
	*/

	// 通过邻接矩阵遍历
	std::cout << v << " ";
	visitedDFS[v] = true;
	for (int i = 0; i < MAXV; ++i)
	{
		if (matrix[v][i] && matrix[v][i] != INF && !visitedDFS[i])
		{
			DFS(LG, matrix, i);
		}
	}
}

void DFS1(ListGraph* LG, int matrix[MAXV][MAXV])
{
	memset(visitedDFS, 0, sizeof(visitedDFS));
	for (int i = 0; i < LG->vertexCnt; ++i)
	{
		if (!visitedDFS[i])
			DFS(LG, matrix, i);
	}
}

bool visitedBFS[MAXV] = { 0 };
//广度优先遍历
void BFS(ListGraph* LG, int matrix[MAXV][MAXV], int v)
{
	/*通过邻接表遍历*/
	/*
	std::deque<EdgeNode*> d;
	visitedBFS[v] = true;
	d.push_back(LG->adjList[v].firstEdge);
	std::cout << v << " ";
	while (!d.empty())
	{
		EdgeNode* p = LG->adjList[d.front()->adjVer].firstEdge;		// 下一个访问的邻接节点的头结点 
		d.pop_front();
		while (p)
		{
			if (!visitedBFS[p->adjVer] && p->weight != INF) // 未访问过
			{
				std::cout << p->adjVer << " ";
				d.push_back(p);	// 未访问过的邻接节点的头结点 
				visitedBFS[p->adjVer] = true;
			}
			p = p->nextEdge;
		}
	}
	*/

	
	// 通过邻接矩阵遍历
	std::deque<int> d;
	d.push_back(v);
	visitedBFS[v] = true;
	while (!d.empty())
	{
		int front = d.front();
		for (int i = 0; i < MAXV; ++i)
		{
			if (matrix[front][i] && matrix[front][i] != INF && !visitedBFS[i])
			{
				visitedBFS[i] = true;
				d.push_back(i);
			}
		}
		std::cout << front << " ";
		d.pop_front();
	}
}
void BFS1(ListGraph* LG, int matrix[MAXV][MAXV])
{
	memset(visitedBFS, 0, sizeof(visitedBFS));
	for (int i = 0; i < LG->vertexCnt; ++i)
	{
		if (!visitedBFS[i])
			BFS(LG, matrix, i);
	}
}

int main()
{
	ListGraph* LG = nullptr;
	// 对应的邻接矩阵
	int matrix[MAXV][MAXV] =
	{
		 (有向非连通图,顶点6独立)
		//{ 0,   4,   6,   6, INF, INF, INF },
		//{ INF,   0,   1, INF,   7, INF, INF },
		//{ INF, INF,   0, INF,   6,   4, INF },
		//{ INF, INF,   2,   0, INF,   5, INF },
		//{ INF, INF, INF, INF,   0, INF,  INF },
		//{ INF, INF, INF, INF,   1,   0,  INF },
		//{ INF, INF, INF, INF, INF, INF,   0 }
		// 有向连通图
		{ 0,   4,   6,   6, INF, INF, INF },
		{ INF,   0,   1, INF,   7, INF, INF },
		{ INF, INF,   0, INF,   6,   4, INF },
		{ INF, INF,   2,   0, INF,   5, INF },
		{ INF, INF, INF, INF,   0, INF,   6 },
		{ INF, INF, INF, INF,   1,   0,   8 },
		{ INF, INF, INF, INF, INF, INF,   0 }

		 无向连通图
		//{   0,   4,   6,   6, INF, INF, INF },
		//{   4,   0,   1, INF,   7, INF, INF },
		//{   6,   1,   0,   2,   6,   4, INF },
		//{   6, INF,   2,   0, INF,   5, INF },
		//{ INF,   7,   6, INF,   0,   1,   6 },
		//{ INF, INF,   4,   5,   1,   0,   8 },
		//{ INF, INF, INF, INF,   6,   8,   0 }
	};

	int edgeCnt = 12;// 两个点之间连线,即边Edge的数量,通过遍历上述数组,统计非0和INF数量即可
	CreateAdjListGraph(LG, matrix, MAXV, edgeCnt);

	std::cout << "邻接表为:" << std::endl;
	DisplayAdjList(LG);
	std::cout << std::endl;

	std::cout << "深度优先遍历为(仅适用于非连通图):" << std::endl;
	DFS(LG, matrix, 0);		// 0 1 2 4 6 5 3
	std::cout << std::endl;
	std::cout << "深度优先遍历为(也使用非连通图):" << std::endl;
	DFS1(LG, matrix);
	std::cout << std::endl;


	std::cout << "广度优先遍历为(仅适用于非连通图):" << std::endl;
	BFS(LG, matrix, 0);		// 0 1 2 3 4 5 6
	std::cout << std::endl;
	std::cout << "广度优先遍历为(也使用非连通图):" << std::endl;
	BFS1(LG, matrix);
	std::cout << std::endl;

	std::cout << "Prim算法:最小生成树的各边:" << std::endl;
	MiniSpanTree_Prim(matrix, 0);

	std::cout << "Kruskal算法:最小生成树的各边:" << std::endl;
	MiniSpanTree_Kruskal(matrix);

	std::cout << "Dijkstra算法:最短路径:" << std::endl;
	ShortestPath_Dijkstra(matrix, 0);

	std::cout << "Floyd算法:最短路径:" << std::endl;
	ShortestPath_Floyd(matrix, 0);

	std::cout << "Bellman_Ford算法:最短路径:" << std::endl;
	ShortestPath_Bellman_Ford(matrix, 0);
	return 0;
}

 

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: C语言中,最小生成树可以使用Prim算法或Kruskal算法来实现。其中Prim算法是基于点的贪心算法,Kruskal算法是基于边的贪心算法。 的建立可以使用邻接矩阵或邻接表来实现。邻接矩阵是一个二维数组,其中每个元素表示两个顶点之间是否有边相连。邻接表则是一个链表数组,其中每个链表表示一个顶点的所有邻居。 遍历可以使用深度优先搜索(DFS)或广度优先搜索(BFS)来实现。DFS是一种递归算法,从一个起点开始,尽可能深地访问每个节点,直到无法继续为止。BFS则是一种迭代算法,从一个起点开始,逐层访问每个节点,直到所有节点都被访问为止。 最短路径可以使用Dijkstra算法或Bellman-Ford算法来实现。Dijkstra算法是一种贪心算法,从一个起点开始,逐步扩展到所有节点,每次选择当前距离最的节点进行扩展。Bellman-Ford算法则是一种动态规划算法,通过多次松弛操作来逐步缩小起点到其他节点的距离。 ### 回答2: C语言是一门非常流行的编程语言,同时也是计算机领域中最重要的编程语言之一。在计算机科学中,最小生成树的建立与遍历最短路径等是一个非常重要的概念,涉及到许多实际的问题,比如路由算法、人际关系、网络通信等领域。C语言正是通过数据结构与算法来实现这些问题的解决。 最小生成树论中的一个重要部分,是一张无向中的边集合,使得该的所有点都联通,同时所有边的权值之和最小。在C语言中,我们可以用prim算法或者Kruskal算法来实现最小生成树的建立,这两种算法在时间复杂度上都非常优秀。在使用prim算法时,我们需要将中所有的边按权重从小到大排序,然后使用贪心算法来进行选取。 的建立与遍历也是C语言中非常关键的一个部分。我们可以使用邻接矩阵或者邻接表来表示。在使用邻接矩阵时,我们需要用一个二维数组来表示中边的连通性;而在使用邻接表时,我们用一个链表来表示每个节点的边。通过这些数据结构,我们可以进行遍历,包括深度优先遍历广度优先遍历最短路径问题也是论中一个非常重要的问题,有许多实际的应用,比如路由算法、电信网络等领域。C语言通过Dijkstra算法和Bellman-Ford算法等方式来实现最短路径的计算。在使用Dijkstra算法时,我们需要使用一个优先队列来存储每个节点到起点的最短路径,并逐步扩展出整个最短路径;而在使用Bellman-Ford算法时,则需要对中的所有边进行多次松弛操作,计算出整个中的最短路径。 总之,最小生成树的建立与遍历最短路径等概念是计算机科学中非常重要的部分,C语言则是实现这些问题的关键工具之一。学习C语言、数据结构与算法,不仅可以让我们了解计算机科学的精髓,还可以开拓我们的思维和创造力。 ### 回答3: C语言是一种强大的编程语言,它可用于解决各种问题,包括建立最小生成树遍历以及最短路径问题。 最小生成树指的是在一个包含n个节点的连通中,通过连接n-1条边,生成一棵边权值之和最小的生成树。使用C语言实现最小生成树算法需要使用一些基本数据结构,包括队列、堆、树等。其中,堆是至关重要的数据结构,它可以在较小的时间内对边的权值进行排序,并确保最小的边被优先处理。 另一个问题是遍历。可以通过深度优先搜索和广度优先搜索等算法进行实现。在深度优先搜索中,选择任一一条未遍历的边,并沿着这条边搜索下去,直到没有新的节点可以被遍历。而广度优先搜索则是从起始节点开始,遍历与起始节点相邻的所有节点,然后遍历与这些节点相邻的所有节点,依此类推。 最短路径问题是指,在有向或无向中,找到从起点到终点的路径,使得该路径上的边权值之和最小。对于这种问题,Dijkstra算法是一个高效的解决方案。该算法使用了一个优先队列、一个数组和一个set(用于标记已经处理的节点)。通过该算法,可以找到从起点到其他节点的最短路径。 总之,C语言在论算法中发挥了重要的作用。通过使用各种数据结构和算法,可以解决最小生成树遍历最短路径等问题。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值