广度优先遍历、深度优先遍历-JS

在这里插入图片描述
使用邻接表存储图

广度优先遍历

A->B->C->D->E->F
遍历A元素的时候,将A元素的邻接节点(B、C)插入数组,访问完B,将B的邻接表(C、D)插入数组,C已经在遍历表中了,因此不添加到遍历表中,接下来访问C,将邻接表(D、E)插入遍历数组中,同样,D已经在遍历表中,就不添加进去,避免重复访问。
遍历的过程没有重复元素
访问栈、记录表

//邻接点制成的表
var graph={
	"A":["B","C"],
	"B":["A","C","D"],
	"C":["A","D","E"],
	"D":["B","E","F"],
	"E":["C","D"],
	"F":["D"],
}
//将对象转成Map,方便访问
var graphM=new Map();
for(var [key,value] of Object.entries(graph)){
	graphM.set(key,value);
}
//console.log(graphM);
//  B—— D
// /|  /|\
//A | / | F
// \|/  |
//  C——E
function BFS(root,s){
	//用来记录访问过的节点 Set()中不能有重复的元素
	var remark=new Set();
	//遍历节点邻接表存储
	var arr=[];
	//用来返回的存储广度优先的遍历顺序
	var bfs=[];
	arr.push(s);
	//将当前遍历到的元素的父元素存储起来,方便最短路径进行访问
	//A的父元素为空
	var parent=new Map([[s,NaN]]);

	remark.add(s);
	var vet;
	while(arr.length>0){
		//从队列中将顶点取出,添加邻接表
		vet=arr.shift();
		bfs.push(vet);
		// console.log(vet,root.get(vet));
		for(var item of root.get(vet)){
			if(!remark.has(item)){
				//将节点存储
				arr.push(item);
				remark.add(item);
				parent.set(item,vet);
			}
		}
	}
	//返回广度遍历结果
 return bfs;
 //返回父节点表
//return parent;
}

// arr:用来存储访问的结果
var bfs=BFS(graphM,'A');
console.log(bfs);

深度优先遍历

以A节点为起点,深度遍历,访问A节点,将A的邻接表(B、C)都未访问过,将C、B压入栈中,选择访问B节点,将B的邻接表(C、D)压入栈中,由于C已经访问过,只将D压入栈中,栈顶弹出D,访问D的邻接表(C、E、F、B),其中C、B都访问过了,只将E、F压入栈中,从栈顶依次弹出进行访问。
只要将节点压入栈中,节点的状态就变成已访问。

//邻接点制成的表
var graph={
	"A":["B","C"],
	"B":["A","C","D"],
	"C":["A","D","E"],
	"D":["B","E","F"],
	"E":["C","D"],
	"F":["D"],
}
//将对象转成Map,方便访问
var graphM=new Map();
for(var [key,value] of Object.entries(graph)){
	graphM.set(key,value);
}
//console.log(graphM);
//  B—— D
// /|  /|\
//A | / | F
// \|/  |
//  C——E
//深度优先遍历
function DFS(root,s){
	//用来记录访问过的节点
	var remark=new Set();
	//用来存储剩余访问的节点
	var arr=[];
	//用来记录深度遍历节点
	var dfs=[];
	arr.push(s);
	//标记访问过的节点
	remark.add(s);
	var vet;
	while(arr.length>0){
		//从栈顶弹出当前需要访问的节点
		vet=arr.pop();

		dfs.push(vet);
		for(var item of root.get(vet)){
			//如果当前的邻接表中节点没有访问过 放入栈中,并添加访问记号
			if(!remark.has(item)){
				arr.push(item);
				remark.add(item);
			}
		}
	}
	return dfs;
}
var dfs=DFS(graphM,'A');
console.log(dfs);

最短路径:

BFS遍历,得到的父节点数组,根据直接父节点数组得到
假如获得从A-E的最短路径:
利用终点E和parent父节点数组,不断的回溯,直到找到A节点
在这里插入图片描述
打印路径,在访问的时候,将parent遍历到路径节点从数组的头部开始添加

var parent=BFS(graphM,'A');
console.log(parent);

var v='E';
// console.log(v)
var path=[];
//从E开始向前搜索,直到搜索到的节点值为空
while(v){
//从数组头部添加内容
	path.unshift(v);
	v=parent.get(v);
}
console.log(path);

狄克拉斯特Dijkstra

在这里插入图片描述
计算加权图的最短路径:

  • 每次遍历更新当前节点的路径,选择最短的路径弹出数组,访问该节点的邻居节点,选择没有访问过的压入数组;下次访问仍然选择数组中最小的进行访问。直到访问结束。
    加权图,使用邻接表初始化。
var map=new Map()
var graph={
	"A":new Map([["B",5],["C",1]]),
	"B":new Map([["A",5],["C",2],["D",1]]),
	"C":new Map([["A",1],["B",2],["D",4],["E",8]]),
	"D":new Map([["B",1],["C",4],["E",3],["F",6]]),
	"E":new Map([["C",8],["D",3]]),
	"F":new Map([["D",6]]),
}
//将邻接表对象转成Map
for(var [key,item] of Object.entries(graph)){
	map.set(key,item);
}
  • 获取当前unvisited节点中最小权值的节点:
    loer_dist_node=null:目的当主体函数中未访问节点表中的节点为空时,返回null便于结束此处查找。
function findMin(dists,visited){
	var lower_dist=Infinity;
	//当访问到最后一个节点的时候,在查找下一个最小节点的时候,返回null访问结束
	var lower_dist_node=null;
	//遍历距离列表中的所有节点,获得dist最小且未访问过的节点
	for(var [vertx,dist] of dists){
		//如果当前节点离起点的距离小于原始存储的节点,并且没有访问过
		if(dist<lower_dist&& !visited.has(vertx)){
			// 获得当前为遍历的最小距离的节点
			lower_dist_node=vertx;
			//记录当前最小的距离,便于下次访问
			lower_dist=dist;
		}
	}
	//遍历结束,返回当前获得的未访问过,代价最小的节点
	return lower_dist_node;
}
  • 更新dists表parent表
    当找到距离表dists中的最小节点,遍历该节点的邻居节点 root.get(node),邻居节点vertx的边距离w,根据当前遍历节点node获得从起点到vertx的距离(w+dists.get(node)小于dists表中vertx的距离(dists.get(vertx)),更新dists表,更新vertx的父节点为node。此次遍历结束,将当前节点node的状态设置为visited,并添加dijkstra访问路径表中,继续下次循环。直至node=null
function Dijkstra(root,s){
	//用来存储剩余访问的节点
	// var arr=[];
	// arr.push(s);
	//访问当前图中,从起点开始权值最小的节点
	//距离表
	var dists=new Map();
	//遍历所有节点将开销全都初始化为无群大
	for(var key of root.keys()){
		dists.set(key,Infinity);
	}
	//将起点的距离设置为0
	dists.set(s,0);
	//打印距离
	// console.log(dists);

	//父节点存储表
	var parents=new Map([[s,NaN]]);

	//存储访问过的节点
	var visited=new Set();

	//当前访问的节点 
	// var pair;

	//定义获得当前边的权重
	// var w;

	//当前访问节点的邻接表
	// var vertx;

	//dijsktra访问路径
	var dijkstra=[];
	var node=findMin(dists,visited);
	console.log(node);

	while(node){

		//此时将邻接表加入其中
		//vertx node节点的邻居节点
		//w vertx节点的权值
		for(var [vertx,w] of root.get(node)){

			// if(!visited.has(vertx)){
				if(dists.get(node)+w<dists.get(vertx))
					//更新当前节点的距离表
				dists.set(vertx,w+dists.get(node));
				//更新当前节点的父节点表
				parent.set(vertx,node);
				// console.log(parent);
			// }
		}
		//将当前父节点标记未处理过
		visited.add(node);
		//将访问路径存储起来
		dijkstra.push(node);
		// console.log('路径:'+dijkstra);
		node=findMin(dists,visited);
	}
	console.log(dijkstra,dists);
	return dists;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值