拓扑排序、dijkstra算法--Java

图的定义:图G={V,E}由定点V和边E组成。边就是顶点对,如果点对是有序的,那么图就是有向图;否则就是无向图。有的时候边上还有权值的项。图有两种存储方式,一种是邻接矩阵,一种是邻接表。如果用邻接矩阵进行存储的话,当顶点很多但是变又很少的情况下,此时的矩阵是稀疏矩阵,会造成空间的浪费。邻接表就是顶点数组,与这个顶点有关联的顶点会用一个List进行存储。这样会节省不必要的空间的浪费。

定义后继节点的类

public class info {
	//需要指向这个节点在数组中的位置
	public int index;
	//这两个顶点之间的权值
	public int weight;

}

定义顶点的数组

import java.util.ArrayList;

public class minDistNode {
	//需要节点的编号
	public String number;
	//需要有个标识这个节点有没有被访问
	public boolean visited;
	//需要个从开始到这点的距离
	public int dis;
	//这个节点上一个节点的位置(求最短路径)
	public minDistNode path;
	//这个节点的后继节点
	public ArrayList<info> adj;
	//这个节点的入度(拓扑排序)
	public int indegree;
	
	public minDistNode() {
		this.indegree = 0;
	}
}

拓扑排序

在现实生活中,事情是有先后的;比如大学课程的安排,一些课只能在完成先修课之后才能学习,这样就得为这些课安排一个先后顺序,就可以用拓扑排序来完成。节点的v入度就是就是<u,v>的条数,一定是存在一个节点的入度为0的入度的,这样的就可以先行处理,然后把这个节点的直接后继节点的入度-1。然后在输出节点中入度为0的节点。

最短路径算法

单源最短路径很像搜索图的方法的广度优先遍历。该方法按层处理顶点;距离开始点最近的那些顶点首先被求值,而最远的那些顶点最后被求值。这很像树的层序遍历。

dijkstra

Dijkstra算法按阶段进行,正像无最短路径的算法一样。在每个阶段,Dijkstra算法选择一个顶点v,它在所有的unvisited顶点中有最小的dis,同时算法还得声明s->v的最短路径是已知的。剩余的阶段有dis值的更新工作完成。

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.TreeSet;

public class minDistance {
	
	//声明邻接表数组
	minDistNode[] vertex;
	 //声明节点数组
	String[] vertexNum;
	
	
	//创建邻接表
	public void creatMap() throws IOException {
		
		//文件路径
		String path = "G:\\eclipse\\DataStructure\\src\\minDistGraph.txt";
		FileReader reader = new FileReader(path);
		BufferedReader br = new BufferedReader(reader);
		String line = null;
		//要获取共有多少个节点,选择用set集合
		Set<String> set = new TreeSet<>();
		//需要把行数据进行数组化
		String[] arr;
		//因为这些数据建立邻接表的时候还要用,所以先存取起来
		StringBuilder res = new StringBuilder();
		while((line = br.readLine())!=null) {
			res.append(line+"\n");
			arr = line.split(" ");
			set.add(arr[0]);
			set.add(arr[1]);
		}
		
		//关闭文件链接
		br.close();
		reader.close();
		//得到了共有多少个节点
		int vCount = set.size();
		
		//建立节点数组
		vertex = new minDistNode[vCount];
		//节点的后继
		ArrayList<info> list;
		//先获取节点,为了方便,将其存入数组中
		Iterator<String> iter = set.iterator(); 
		vertexNum = new String[vCount];
		int index = 0;
		while(iter.hasNext()) {
			vertexNum[index++] = iter.next(); 
		}
		
		for(int i = 0;i<vCount;i++) {
			vertex[i] = new minDistNode();
		}
		//初始化数组
		for(int i = 0;i<vCount;i++) {
			list = new ArrayList<>();
			index = getIndex(vertexNum[i]);
			vertex[index].number = vertexNum[i];
			vertex[index].adj = list;
			vertex[index].dis = Integer.MAX_VALUE;
			vertex[index].visited = false;
			vertex[index].path = null;
			
		}
		//获取边的数据
		String[] edge = res.toString().split("\n");
		//两点之间边的信息
		info infor;
	
		//建立邻接表
		for(int i = 0;i<edge.length;i++) {
			arr = edge[i].split(" ");
			//首先找到这个开始节点的数组位置
			index = getIndex(arr[0]);
			//为这个后继节点补充信息
			infor = new info();
			infor.index = getIndex(arr[1]);
			vertex[infor.index].indegree++;
			infor.weight = Integer.parseInt(arr[2].trim());
			vertex[index].adj.add(infor);
		}
	}
	
	//获取节点在数组的位置
	public int getIndex(String s ) {
		for(int i = 0;i<vertexNum.length;i++) {
			if(vertexNum[i].equals(s)) {
				return i;
			}
		}
		throw new IllegalArgumentException();
	}
	
	//进行拓扑排序
	public void sort() {
		for(int count = 0;count<vertexNum.length;count++) {
			minDistNode node = getIndegreeIsZero();
			if(node == null) {
				throw new IllegalArgumentException();
			}
			System.out.println(node.number);
			node.visited = true;
			ArrayList<info> info = node.adj;
			for(info t :info) {
				 vertex[t.index].indegree--;
			}
		}
		
	}
	private minDistNode getIndegreeIsZero() {
		for(int i = 0;i<vertexNum.length;i++) {
			int index = getIndex(vertexNum[i]);
			if(vertex[index].indegree == 0 && !vertex[index].visited) {
				return vertex[index];
			}
		}
		return  null;
	}
	
	//得到最短路径,如果权值是1
	public void disLength(String start) {
		//获得这个节点的数组位置
		int index = getIndex(start);
		//领这个位置的距离为0
		vertex[index].dis = 0;
		
		//遍历整个节点
		for(int count = 0;count<vertexNum.length;count++) {
			
			//遍历所有节点
			for(minDistNode node : vertex) {
				
				if(node.visited == false && node.dis == count) {
					node.visited = true;
					ArrayList<info> infor = node.adj;
					for(info t:infor) {
						if(vertex[t.index].dis == Integer.MAX_VALUE) {
							vertex[t.index].dis = count+1;
							vertex[t.index].path = node;
						}
						
					}
				}
			}
		}
		
	}
	
	
	//权值不是1的时候的最短路径
	
	public void minLength(String start) {
		int index = getIndex(start);
		vertex[index].dis = 0;
		Queue<minDistNode> queue = new LinkedList<>();
		queue.add(vertex[index]);
		while(!queue.isEmpty()) {
			minDistNode node = queue.poll();
			node.visited = true;
			ArrayList<info> infor = node.adj;
			for(info t:infor) {
				if(vertex[t.index].dis == Integer.MAX_VALUE) {
					vertex[t.index].dis = node.dis+t.weight;
					vertex[t.index].path = node;
				}
				else {
					if(vertex[t.index].dis > node.dis+t.weight) {
						vertex[t.index].dis = node.dis+t.weight;
						vertex[t.index].path = node;
					}
				}
				if(vertex[t.index].visited == false) {
					queue.add(vertex[t.index]);
				}
			}
		}
		
	}
	
	//最短路径输出
	public void print(String end) {
		int index = getIndex(end);
		if(vertex[index].path!=null) {
			print(vertex[index].path.number);
		}
		System.out.println(vertex[index].number);
		
	}
}

像这样的文件格式:

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值