图论之图形的表示方法(二)- 相邻表法/邻接表法

package com.yc.graph;

/**
 * 
 * @author wb
 * {@docRoot} 
 * 邻接表(Adjacency List)是图的一种链式存储结构。在邻接表中,对图中的每个顶点建立一个单链表,第i个单链表中的节点表示依附于顶点vi
 * 的边(对有向图是以顶点vi为尾的弧)。每个节点由3个域组成,其中邻接点域(adjvex)指示与顶点vi邻接的点在图中的位置。链域(nextarc)
 * 指示下一条边或弧的节点;数据域(info)存储和边或弧相关的信息,如权值等。每个链表上附设一个表头节点。在表头节点中,除了设有链域(firs
 * tarc)指向链表中的第一个节点之外,还设有存储顶点vi的名或其他有关信息的数据域(data)。
 * 如下所示:
 * 			      表节点							头节点
 * 
 * 	│adjvex │ nextarc │ info│			│data │ firstarc│
 * 
 * 这些表头节点(可以链相接)通常以顺序结构的形式存储,以便随机访问任一顶点的链表,如一个图的邻接表存储结构可以是下面的样子:
 * 		//----------图的邻接表存储表示------
 * 		class ArcNode{
 * 			int	adjvex; //该弧所指向的顶点的位置
 * 			ArcNode next; //指向下一个弧的指针
 * 			InfoType info;//该弧相关信息的指针
 * 		}
 * 
 * 		class VNode{
 * 			VertexType data; //顶点信息
 *			ArcNode firstarc; //指向第一条依附该顶点的弧的指针 		
 * 		}
 * 
 * 		class  LinkGraph{
 * 			int vexnum,arcnum;	//图的当前顶点树和弧树
 * 			int kind; 			//图的种类标志
 * 			VNode[] vnodes;		//图的每条单链表的开始存在vnodes数组里
 * 		}
 * 
 * 		若无向图中有n个顶点、e条边,则它的邻接表需要n个头节点和2e个表节点。显然。在边稀疏(e<=n(n-1)/2)的情况下,用邻接表表示
 * 图比邻接矩阵节省存储空间,当和边相关的信息较多时更是如此。
 * 		在无向图的邻接表中,顶点vi的度恰为第i个链表中的节点数;而在有向图中,第i个链表中的节点个数只是顶点vi的出度。在所有链表中其
 * 邻接点域的值为i的节点的个数是顶点vi的入度。有时,为了便于确定顶点的入度或以顶点vi为头的弧,可以建立一个有向图的逆邻接表,即对每个顶
 * 点vi建立一个邻接以vi为头的弧的表。
 * 		在建立邻接表或逆邻接表是,若输入的顶点信息即为顶点的编号,则建立邻接表的时间复杂度为O(n+e),否则,需要通过查找才能得到顶点
 * 在图中的位置,则时间复杂度为O(n*e)。
 * 		在邻接表上容易找到任一顶点的第一个邻接点和下一个邻接点,但要判定任意两个顶点(vi和vj)之间是否有边或弧相连,则需要搜索第i个
 * 或第j个链表,因此,不及邻接矩阵方便。
 * 
 * 
 * 这种表示法以表结构来表示图形,他有点类似于相邻矩阵,不过忽略掉矩阵中为0的部分,直接把1的部分放入节点里,如此一来可以有效避免浪费存储空间。
 * 
 * 相关特性如下:
 * 		1.每一个顶点使用一个表。
 * 		2.在无向图中,n个顶点e个边共需n个表头节点及2*e个节点;有向图则需n个表头节点及e个节点。在相邻表中,计算所有顶点的度所需的时间
 * 复杂度为O(n+e)。
 * 
 * 下面是我随便写的一个,意思是没按上面的方法出牌。
 */
public class LinkGraph {
	class Node{
		//顶点
		int data;
		//权值(有必要写?还是不是在顶点Node这里写?)
		Object cost;
		//下一个顶点
		Node next;
		
		public Node(int data, Object cost, Node next){
			this.data = data;
			this.cost = cost;
			this.next = next;
		}

		public String toString(){
			return "[顶点"+data+"]";
		}
	}
	
	/*//起始顶点  //讲道理这个到现在我都觉得没有必要要
	private Node start;*/
	//用于存储每个节点链的开头,最后的最后一定会存满所有的顶点
	private Node[] heads;
	
	/*public LinkGraph(){
		this.start = this.end = null;
	}*/
	public LinkGraph(int length){
		//this.start = null;
		this.heads = new Node[length];
	}
	public LinkGraph(int data, Object obj, int length){
		//this.start = new Node(data, obj, null);
		this.heads = new Node[length];
		this.heads[0] = new Node(data, obj, null);
	}
	
	//判断该图是否为空
	public boolean isEmpty(int index){
		if(heads == null){
			return true;
		}
		if(index > heads.length - 1 || index < 0){
			try {
				throw new Exception("为空判断异常");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}else{
			return heads[index] == null;
		}
		return false;
	}
	
	//插入数据1
	public void insert(int data_1, int data_2){
		Node toNode = new Node(data_2, null, null);
		Node fromNode = new Node(data_1, null, toNode);
		if(this.isEmpty(data_1 - 1)){
			heads[data_1 - 1] = fromNode;
		}
		else{
			int tmp = data_1 > data_2 ? data_1 : data_2;
			
			if(0 < tmp && tmp <= heads.length){ //如果满足条件
				Node current = heads[data_1 - 1];
				while(current != null && current.next != null){
					current = current.next;
				}
				
				current.next = toNode;
			}
		}
	}
	//插入数据2
	public void insert(int data, Object obj){
		
	}
	
	/**
	 * 将指定数组转换为图
	 * @param arr:指定数组
	 */
	public void build(int[][] arr){
		//int[][] data_1 = {{1,2},{2,1},{1,5},{5,1},{2,3},{3,2},{2,4},{4,2},{3,4},{4,3},{3,5},{5,3},{4,5},{5,4}};
		
		if(arr != null){
			for(int i = 0; i < arr.length; i ++){
				int[] tmp = arr[i];
				insert(tmp[0], tmp[1]);
			}
		}
		else{
			try {
				throw new Exception("数组异常");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	public void print(){
		System.out.println("图形的邻接表表示为:");
		if(heads == null){
			System.out.println("[]");
		}else{
			StringBuilder sb = new StringBuilder();
			for(int i = 0; i < heads.length; i ++){
				sb.append("顶点" + (i + 1) + "==>");
				for(Node node = heads[i]; node != null && node.next != null; node = node.next){
					sb.append(node.next.toString());
				}
				sb.append("->NULL\n");
			}
			System.out.println(sb.toString());
		}
	}
	
	public static void main(String[] args) {
		int[][] data_1 = {{1,2},{2,1},{1,5},{5,1},{2,3},{3,2},{2,4},{4,2},{3,4},{4,3},{3,5},{5,3},{4,5},{5,4}};
		LinkGraph graph_1 = new LinkGraph(5);
		graph_1.build(data_1);
		graph_1.print();
		
		System.out.println();
		
		int[][] data_2 = {{1,2},{2,3},{2,4},{4,3}};
		LinkGraph graph_2 = new LinkGraph(4);
		graph_2.build(data_2);
		graph_2.print();
	}
}


结果为:

图形的邻接表表示为:
顶点1==>[顶点2][顶点5]->NULL
顶点2==>[顶点1][顶点3][顶点4]->NULL
顶点3==>[顶点2][顶点4][顶点5]->NULL
顶点4==>[顶点2][顶点3][顶点5]->NULL
顶点5==>[顶点1][顶点3][顶点4]->NULL


图形的邻接表表示为:
顶点1==>[顶点2]->NULL
顶点2==>[顶点3][顶点4]->NULL
顶点3==>->NULL
顶点4==>[顶点3]->NULL


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值