图1---------------图的表示和遍历算法

图的表示方法:

邻接矩阵法(太浪费空间,但确实把所有信息都表示了出来,计算度或者各种操作的话很方便,当然用无向图的对称性、只存放非0结点可以优化)

邻接表(算比较好的一种方法,但是对于有向图计算入度必须遍历,用逆邻接表、十字链表优化)

十字链表(和邻接表太类似)


遍历算法:

图是标准的多对多结构,因此不构成环并且不重复访问vertex需要一个标志数组visited,循环这个保证全部都访问,遍历过程中可以有DFS和BFS

DFS:递归方式,首先访问vertex,循环找邻接节点,找到并且该vertex没有被访问过,将顶点当成参数进入下一层。

BFS:需要堆栈配合,找到自己邻接的顶点如果没有被访问过则访问并将其入栈,然后用stack非空控制循环直到全部访问过。


还有一些计算连通分量个数、度的问题,就是遍历算法的应用。


代码(结构写的有点乱,回头看的时候可以优化下):

package nuaa.ds;

public class Graph {
	private String[] vertexes;//邻接矩阵法所
	private int[][] vr;       //使用的成员变量
	private CreateGraph g;
	
	private VertexNode[] vertexNodes;//邻接表所使用的成员变量

	
	/**
	 * 图的构成实在太多,写个标准无向图熟悉算法
	 * 顶点ABCD(其中BC不连)彼此互连,EF彼此互连
	 */
	public Graph(CreateGraph c){
		this.g = c;
		switch(c){
		case AdjacencyMatrix://邻接矩阵
			vertexes = new String[]{"A","B","C","D","E","F"};//ABCDEF6个顶点
			vr = new int[6][6];
			vr[0] = new int[]{0,1,1,1,0,0};//邻接矩阵法表示边,相连值为1,不连值为0
			vr[1] = new int[]{1,0,0,1,0,0};//优点是所有信息全部显示出来
			vr[2] = new int[]{1,0,0,1,0,0};//这样顶点的度等计算或者对图的所有操作都比较容易
			vr[3] = new int[]{1,1,1,0,0,0};//缺点也很明显
			vr[4] = new int[]{0,0,0,0,0,1};//存储空间极大的浪费
			vr[5] = new int[]{0,0,0,0,1,0};//当然通过使用对称或者只存储非0元素可以优化
			break;
		case AdjacencyTable://邻接表表示,省了很多存储空间,
							//但有时会带来不便,比如求有向图的某个节点的入度
			
			//结点数组的初始化
			vertexNodes = new VertexNode[6];
			String[] temp = new String[]{"A","B","C","D","E","F"};
			for(int i=0;i<vertexNodes.length;i++){
				vertexNodes[i] = new VertexNode(temp[i]);
			}
			//结点数组连接的边结点的初始化
			//写de好麻烦,还不如由输入流输进来循环构造。但每次测试重新输入图结构也很烦。
			//顶点A的初始化
			vertexNodes[0].arcNode = new ArcNode(1);
			vertexNodes[0].arcNode.arcNode = new ArcNode(2);
			vertexNodes[0].arcNode.arcNode.arcNode = new ArcNode(3);
			//顶点B的初始化
			vertexNodes[1].arcNode = new ArcNode(0);
			vertexNodes[1].arcNode.arcNode = new ArcNode(3);
			//顶点C的初始化
			vertexNodes[2].arcNode = new ArcNode(0);
			vertexNodes[2].arcNode.arcNode = new ArcNode(3);
			//顶点D的初始化
			vertexNodes[3].arcNode = new ArcNode(0);
			vertexNodes[3].arcNode.arcNode = new ArcNode(1);
			vertexNodes[3].arcNode.arcNode.arcNode = new ArcNode(2);
			//顶点E的初始化
			vertexNodes[4].arcNode = new ArcNode(5);
			//顶点F的初始化
			vertexNodes[5].arcNode = new ArcNode(4);
		}
			
	}
	
	//求连通分量个数或者连通生成树也是遍历算法
	public void traversalByDFS(){
		this.traversalByDFS(this.g);
	}
	private void traversalByDFS(CreateGraph c){//深度优先算法访问图
		boolean[] visited;
		if(c==CreateGraph.AdjacencyTable){
			visited = new boolean[vertexNodes.length];//java默认都为false
		}else{
			visited = new boolean[vertexes.length];//java默认都为false
		}
		switch(c){
		case AdjacencyMatrix://图是用邻接表表示的深度优先遍历算法
			
			for(int i=0;i<vertexes.length;i++){
				if(!visited[i]){
					mTraversalByDFS(visited,i);
				}
			}
			break;
		case AdjacencyTable:
			for(int i=0;i<vertexNodes.length;i++){
				if(!visited[i]){
					tTraversalByDFS(visited,i);
				}
			}
		}
	}
	
	
	private void mTraversalByDFS(boolean[] visited,int index){
		visit(vertexes[index]);//和二叉树一样的问题,访问图结点可能会做些其他操作
								//还是从外部当成函子传入进来比较合适
								//对应的vertexes数组也要改成Object[],这样的封装更好
		visited[index] = true;
		for(int i=0;i<vr[index].length;i++){//循环找到下一个结点
			if(vr[index][i]==1&&!visited[i]){//有连接的未访问的结点
				mTraversalByDFS(visited,i);//访问该结点
			}
		}
	}
	
	private void tTraversalByDFS(boolean[] visited,int index){
		visit(vertexNodes[index]);
		visited[index] = true;
		ArcNode p = vertexNodes[index].arcNode;
		while(null!=p){
			if(!visited[p.serialNumber]){
				tTraversalByDFS(visited,p.serialNumber);
			}
			p = p.arcNode;
		}
	}
	
	public void traversalByBFS(){
		this.traversalByBFS(g);
	}
	private void traversalByBFS(CreateGraph c){
		boolean[] visited;
		if(c==CreateGraph.AdjacencyTable){
			visited = new boolean[vertexNodes.length];//java默认都为false
		}else{
			visited = new boolean[vertexes.length];//java默认都为false
		}
		
		Stack<VertexNode> stack = new Stack<VertexNode>();
		
		switch(c){
		case AdjacencyMatrix://图是用邻接表表示的深度优先遍历算法
			for(int i=0;i<vertexes.length;i++){
				if(!visited[i]){
					mTraversalByBFS(visited,i);
				}
			}
		break;
		case AdjacencyTable:
			for(int i=0;i<vertexNodes.length;i++){
				if(!visited[i]){
					tTraversalByBFS(stack,visited,i);
				}
			}
		}
	}
	private void tTraversalByBFS(Stack<VertexNode> stack,
										boolean[] visited,int index){
		stack.push(vertexNodes[index]);
		visit(vertexNodes[index]);
		visited[index] = true;
		ArcNode p ;
		while(!stack.isEmpty()){
			p = stack.pop().arcNode;
			while(p!=null){
				if(!visited[p.serialNumber]){
					stack.push(vertexNodes[p.serialNumber]);
					visit(vertexNodes[p.serialNumber]);
					visited[p.serialNumber] = true;
				}
				p = p.arcNode;
			}
			
		}
		 
	}
	
	private void mTraversalByBFS(boolean[] visited,int index){
		Stack<Integer> stack = new Stack<Integer>();
		stack.push(index);
		visit(vertexes[index]);
		visited[index] = true;
		while(!stack.isEmpty()){
			for(int i=0;i<vr[index].length;i++){
				if(vr[index][i]==1&&!visited[i]){
					stack.push(i);
					visit(vertexes[i]);
					visited[i] = true;
				}
			}
			index = stack.pop();
		}
		
	}
	private void visit(String vertex){
		System.out.print(vertex+" ");
	}
	
	private void visit(VertexNode node){
		System.out.println(node.vertex);
	}
	
 	class VertexNode{
		String vertex;
		ArcNode arcNode;
		public VertexNode(String vertex){
			this.vertex = vertex;
		}
	}

	class ArcNode{
		int serialNumber;//存放边连着的节点在vertexNode数组里面的位置
		ArcNode arcNode;
		public ArcNode(int serialNumber){
			this.serialNumber = serialNumber;
		}
	}
}

一些盲点: 十字链表表示法太相似没有写,邻接矩阵法用广义表的方式对空间进行优化,然后计算连通分量、度可以用来复习下遍历算法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值