JAVA数据结构------------------拓扑排序

拓扑排序介绍

拓扑排序是一个比较常用的图论算法,经常用于完成有依赖关系的任务的排序。比如如下图例题:
在这里插入图片描述
在图中,v2要想执行就必须先执行v3和v1,v0事件就可以直接执行,不需要依赖其他事件是否执行完成。依赖关系就好比打游戏,你要先选择英雄,才能进入游戏,v0就是选择英雄,v4就是进入游戏这个样子。拓扑排序就是来解决这样的问题,在不影响依赖关系的基础上,将图遍历。

代码实例

我们就以上面的例题为例子,将此图拓扑排序,我们需要用一种数据结构来表示图,在这里我们使用的是邻接表,如下图:
在这里插入图片描述
首先第一竖排是邻接顶点,也就是图中所有的点,由入度(in),数据域(data),第一个子节点(firstnode)组成,除了第一竖排之外的都是边表顶点由下标(adjvex),next组成。v0连接到v11,v5,v4,如图表示为v0的第一个子节点为v11,与v11相邻的是v5,与v5相邻的是v4。

算法思想

1.创建一个数组adjList来存放所有的邻接顶点,将图表示出来,如方法createGraph。
2.遍历数组,找到所有入度(in)为0的顶点,放入栈中。
3.在栈不为空的前提下:弹出栈顶元素,将弹出的邻接顶点后跟的所有边表顶点权值减去1,并且看是否有边表顶点的权值变为0,若有就将其放入栈中。如此不断执行知道栈为空。
算法思想还是比较简单的。

代码如下

import java.util.Stack;

/**
 * 拓扑排序
 * @author 65481
 *
 */
public class DnGraphTopolgic {
	//顶点个数
	private int numvertexes;
	//存放临界点的一维数组,接下来我们要对这个数组进行拓扑排序操作
	private VertexNode[] adjList;
	
	public DnGraphTopolgic(int  numvertexes ) {
		this.numvertexes = numvertexes;
	}
	
	//构建图
	public void createGraph() {
		VertexNode node0 = new VertexNode(0, "v0");
		VertexNode node1 = new VertexNode(0, "v1");
		VertexNode node2 = new VertexNode(2, "v2");
		VertexNode node3 = new VertexNode(0, "v3");
		VertexNode node4 = new VertexNode(2, "v4");
		VertexNode node5 = new VertexNode(3, "v5");
		VertexNode node6 = new VertexNode(1, "v6");
		VertexNode node7 = new VertexNode(2, "v7");
		VertexNode node8 = new VertexNode(2, "v8");
		VertexNode node9 = new VertexNode(1, "v9");
		VertexNode node10 = new VertexNode(1, "v10");
		VertexNode node11 = new VertexNode(2, "v11");
		VertexNode node12 = new VertexNode(1, "v12");
		VertexNode node13 = new VertexNode(2, "v13");
		
		adjList = new VertexNode[numvertexes];
		
		//临接顶点构建
		adjList[0] = node0;
		adjList[1] = node1;
		adjList[2] = node2;
		adjList[3] = node3;
		adjList[4] = node4;
		adjList[5] = node5;
		adjList[6] = node6;
		adjList[7] = node7;
		adjList[8] = node8;
		adjList[9] = node9;
		adjList[10] = node10;
		adjList[11] = node11;
		adjList[12] = node12;
		adjList[13] = node13;
		
		//边表顶点构建
		node0.firstNode = new EdgeNode(11);
		node0.firstNode.next = new EdgeNode(5);
		node0.firstNode.next.next = new EdgeNode(4);
		
		node1.firstNode = new EdgeNode(8);
		node1.firstNode.next = new EdgeNode(4);
		node1.firstNode.next.next = new EdgeNode(2);
		
		node2.firstNode = new EdgeNode(9);
		node2.firstNode.next = new EdgeNode(6);
		node2.firstNode.next.next = new EdgeNode(5);
		
		node3.firstNode = new EdgeNode(13);
		node3.firstNode.next = new EdgeNode(2);
		
		node4.firstNode = new EdgeNode(7);
		
		node5.firstNode = new EdgeNode(12);
		node5.firstNode.next = new EdgeNode(8);
		
		node6.firstNode = new EdgeNode(5);
		
		node8.firstNode = new EdgeNode(7);
		
		node9.firstNode = new EdgeNode(11);
		node9.firstNode.next = new EdgeNode(10);
		
		node10.firstNode = new EdgeNode(13);
		
		node12.firstNode = new EdgeNode(9);
		
	}
	
	/**
	 * 拓扑排序 
	 */
	public void  topologicalSort() {
		
		//需要使用栈的数据结构,至于为什么用integer,因为我们这个栈中放的既要有边表顶点,又要有临接顶点,为了一视同仁
		Stack<Integer> stack = new Stack<>();
		//操作数 如果操作数小于点的个数,那么就是拓扑排序失败 也就是图不满足拓扑排序的前提
		int count = 0;
		//记录下标
		int k ;
		//遍历,将入度为0的点放入栈中
		for (int i = 0;i < numvertexes;i ++) {
			if(adjList[i].in == 0) {
				stack.push(i);
			}
		}
		while(!stack.isEmpty()) {
			//弹出栈中第一个点
			int pop = stack.pop();
			System.out.println("顶点"+adjList[pop].data);
			count ++;
			//将这个点后面的边表顶点的入度减去1
			for(EdgeNode node = adjList[pop].firstNode;node != null;node = node.next) {
				k = node.adjVert;
				if (--adjList[k].in == 0) {
					stack.push(k);
				}
			}
		}
		if (count < numvertexes) {
			System.out.println("图不符合拓扑排序条件");
		}
		}
	
	
	
	public static void main(String[] args) {
		
		DnGraphTopolgic dnGraphTopolgic = new DnGraphTopolgic(14);
		dnGraphTopolgic.createGraph();
		dnGraphTopolgic.topologicalSort();
		
	}
	
	//边表顶点
	class EdgeNode{
		//顶点下标
		private int adjVert;
		//边表顶点之后的边表顶点
		private EdgeNode next;
		//权重
		private int weight;
		
		public EdgeNode(int adjVert) {
			this.adjVert = adjVert;
		}

		public int getAdjVert() {
			return adjVert;
		}

		public void setAdjVert(int adjVert) {
			this.adjVert = adjVert;
		}

		public EdgeNode getNext() {
			return next;
		}

		public void setNext(EdgeNode next) {
			this.next = next;
		}

		public int getWeight() {
			return weight;
		}

		public void setWeight(int weight) {
			this.weight = weight;
		}
		
		
	}
	
	
	//临接顶点
	class VertexNode{
		//入度
		private int in;
		//顶点的数据
		private String data;
		//临接顶点的第一个边表顶点
		private EdgeNode firstNode;
		
		public VertexNode(int in,String data) {
			this.in = in;
			this.data = data;
		}

		public int getIn() {
			return in;
		}

		public void setIn(int in) {
			this.in = in;
		}

		public String getData() {
			return data;
		}

		public void setData(String data) {
			this.data = data;
		}

		public EdgeNode getFirstNode() {
			return firstNode;
		}

		public void setFirstNode(EdgeNode firstNode) {
			this.firstNode = firstNode;
		}
		
	}

}

运算结果

顶点v3
顶点v1
顶点v2
顶点v6
顶点v9
顶点v10
顶点v13
顶点v0
顶点v4
顶点v5
顶点v8
顶点v7
顶点v12
顶点v11

猜你喜欢

转载自blog.csdn.net/qq_43507104/article/details/102712191