`
luoweifu
  • 浏览: 60970 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

图(3)——邻接链表法

 
阅读更多

邻接链表法

基本思想:对图的每个顶点建立一个单链表,存储该顶点所有邻接顶点及其相关信息。每一个单链表设一个表头结点。

i个单链表表示依附于顶点Vi的边(对有向图是以顶点Vi为头或尾的弧)

1结点结构与邻接链表示例

链表中的结点称为表结点,每个结点由三个域组成,如图(a)所示。其中邻接点域(adjvex)指示与顶点Vi邻接的顶点在图中的位置(顶点编号),链域(nextarc)指向下一个与顶点Vi邻接的表结点,数据域(info)存储和边或弧相关的信息,如权值等。对于无权图,如果没有与边相关的其他信息,可省略此域。

每个链表设一个表头结点(称为顶点结点),由两个域组成,如图(b)所示。链域(firstarc)指向链表中的第一个结点,数据域(data)存储顶点名或其他信息。

在图的邻接链表表示中,所有顶点结点用一个向量以顺序结构形式存储,可以随机访问任意顶点的链表,该向量称为表头向量,向量的下标指示顶点的序号。

用邻接链表存储图时,对无向图,其邻接链表是唯一的,如图7-10所示;对有向图,其邻接链表有两种形式,如图7-11所示。

2邻接表法的特点

◆表头向量中每个分量就是一个单链表的头结点,分量个数就是图中的顶点数目;

◆在边或弧稀疏的条件下,用邻接表表示比用邻接矩阵表示节省存储空间;

◆在无向图,顶点Vi的度是第i个链表的结点数;

◆对有向图可以建立正邻接表或逆邻接表。正邻接表是以顶点Vi为出度(即为弧的起点)而建立的邻接表;逆邻接表是以顶点Vi为入度(即为弧的终点)而建立的邻接表;

◆在有向图中,第i个链表中的结点数是顶点Vi的出(或入)度;求入(或出)度,须遍历整个邻接表;

◆在邻接表上容易找出任一顶点的第一个邻接点和下一个邻接点;

3结点及其类型定义

顶点Vererex.java

package datastructure.graph;

import datastructure.list.LinkList;
import datastructure.list.List;
/**
 * 图的顶点
 * @author luoweifu
 *
 */
public class Vertex{
	private Object data;
	private ArcEdge firstArc;
	/**
	 * 构造函数
	 */
	public Vertex() {
		data = null;
		firstArc = null;
	}
	/**
	 * 构造函数
	 * @param data 顶点的数据
	 */
	public Vertex(Object data) {
		this.data = data;
		this.firstArc = null;
	}
	/**
	 * 获得顶点的数据
	 * @return 顶点的数据
	 */
	public Object getData() {
		return data;
	}
	/**
	 * 设置顶点的数据
	 * @param data 顶点的数据
	 */
	public void setData(Object data) {
		this.data = data;
	}
	/**
	 * 获得第一个孤结点
	 * @return
	 */
	public ArcEdge getFirstArc() {
		return firstArc;
	}
	/**
	 * 设置第一个孤结点
	 * @param firstArc
	 */
	public void setFirstArc(ArcEdge firstArc) {
		this.firstArc = firstArc;
	}
	@Override
	public boolean equals(Object obj) {
		Vertex v = (Vertex)obj;
		if(data.equals(v.getData()) )//&&  firstArc.equals(v.getFirstArc())
			return true;
		return false;
	}
	@Override
	public String toString() {
		return data + "  " + firstArc;
	}
	
}

孤结点ArcEdge.java

package datastructure.graph;

/**
* 弧结点定义
* @author luoweifu
*
*/
public class ArcEdge extends Edge{
	private Vertex vertex;
	private ArcEdge prior;
	private ArcEdge next;
	/**
	 * 构造函数
	 */
	public ArcEdge() {
		super();
	}
	/**
	 * 构造函数
	 * @param weight 权值
	 */
	public ArcEdge(double weight) {
		super(weight);
		prior = null;
		next = null;
	}
	/**
	 * 构造函数
	 * @param info 边的信息
	 * @param weight 权值
	 */
	public ArcEdge(Object info, double weight) {
		super(info, weight);
		prior = null;
		next = null;
	}
	/**
	 * 构造函数
	 * @param info 边的信息
	 * @param weight 权值
	 * @param vertex 顶点
	 */
	public ArcEdge(Object info, double weight, Vertex vertex) {
		this(info, weight);
		this.vertex = vertex;
		prior = null;
		next = null;
	}
	/**
	 * 获得顶点数据
	 * @return
	 */
	public Vertex getVertex() {
		return vertex;
	}
	/**
	 * 设置顶点
	 * @param vertex
	 */
	public void setVertex(Vertex vertex) {
		this.vertex = vertex;
	}
	/**
	 * 获得上一个孤结点
	 * @return
	 */
	public ArcEdge getPrior() {
		return prior;
	}
	/**
	 * 设置上一个孤结点
	 * @param prior
	 */
	public void setPrior(ArcEdge prior) {
		this.prior = prior;
	}
	/**
	 * 获得下一个孤结点
	 * @return
	 */
	public ArcEdge getNext() {
		return next;
	}
	/**
	 * 设置下一个孤结点
	 * @param next
	 */
	public void setNext(ArcEdge next) {
		this.next = next;
	}

	@Override
	public int compareTo(Object o) {
		double w2 = ((Edge)o).getWeight();
		if(this.weight< w2)
			return -1;
		else if(this.weight > w2)
			return 1;
		return 0;
	}
	
	@Override
	public boolean equals(Object obj) {
		ArcEdge arc = (ArcEdge)obj;
		if(this.next == arc.next && this.weight == arc.weight)
			return true;
		return false;
	}

	@Override
	public Object getFirstVertex() {
		return prior.vertex.getData();
	}


	@Override
	public Object getSecondVertex() {
		return vertex.getData();
	}
}

邻接链表法表示的图ListGraph.java

package datastructure.graph;

import datastructure.list.ArrayList;
import datastructure.list.List;
import datastructure.queue.ArrayQueue;
import datastructure.queue.Queue;

public class ListGraph implements Graph {
	private List<Vertex> vertexs;
	private int edgeNum; //边的条数 
	private enum Visit{unvisited, visited};
	
	public ListGraph() {
		vertexs = new ArrayList();
	}
	public List getVertexs() {
		return vertexs;
	}
	public ListGraph(Object[] vexs) {
		this();
		for(int i=0; i<vexs.length; i++) {
			vertexs.add(new Vertex(vexs[i]));
		}
	}

	
	private Vertex find(Object v) {
		Vertex vex = new Vertex(v);
		int i = vertexs.indexOf(vex);
		if(i<0) {
			return null;
			//throw new ArrayIndexOutOfBoundsException("顶点" + v + "不存在!");
		}
		return (Vertex)vertexs.get(i);
	}


	@Override
	public void addEdge(Object v1, Object v2, double weight) {
		Vertex vex1 = find(v1);
		Vertex vex2 = find(v2);
		if(vex1 != null && vex2 != null) {
			ArcEdge e = new ArcEdge(null, weight, vex2);
			if(vex1.getFirstArc() == null) {
				vex1.setFirstArc(e);
			} else {
				ArcEdge arc = vex1.getFirstArc();
				while(arc.getNext() != null) {
					arc = arc.getNext();
				}
				arc.setNext(e);
				e.setPrior(arc);
			}
			edgeNum ++;
		} else {
			throw new ArrayIndexOutOfBoundsException("顶点" + v1 + "或" + v2 + "不存在!");
		}
	}


	@Override
	public void addEdge(Object v1, Object v2, Object info, double weight) {
		Vertex vex1 = find(v1);
		Vertex vex2 = find(v2);
		if(vex1 != null && vex2 != null) {
			ArcEdge e = new ArcEdge(info, weight, vex2);
			if(vex1.getFirstArc() == null) {
				vex1.setFirstArc(e);
			} else {
				ArcEdge arc = vex1.getFirstArc();
				while(arc.getNext() != null) {
					arc = arc.getNext();
				}
				arc.setNext(e);
				e.setPrior(arc);
			}
			edgeNum ++;
		} else {
			throw new ArrayIndexOutOfBoundsException("顶点" + v1 + "或" + v2 + "不存在!");
		}
	}


	@Override
	public void addVex(Object v) {
		vertexs.add(new Vertex(v));
	}


	@Override
	public String bfs(Object o) {
		// ----------------该方法还有点问题-------------
		Visit visit[] = new Visit[vertexs.size()];
		for(int i=0; i<vertexs.size(); i++)
			visit[i] = Visit.unvisited;
		StringBuilder sb = new StringBuilder();
		Vertex vex = new Vertex(o);//find(o);
		bfs(vex, visit, sb);
		return sb.toString();
	}


	private void bfs(Vertex vex, Visit[] visit, StringBuilder sb) {
		Queue queue = new ArrayQueue();
		
		int n = vertexs.indexOf(vex);
		sb.append(vex.getData() + "\t");
		visit[n] = Visit.visited;
		
		queue.push(vex);
		while(!queue.isEmpty()) {
			Vertex u = (Vertex) queue.deQueue();
			Vertex v = getFirstVertex(u);
			while(null != v) {
				if(Visit.unvisited == visit[vertexs.indexOf(v)]) {
					sb.append(v.getData() + "\t");
					visit[vertexs.indexOf(v)] = Visit.visited;
					queue.push(v);
				}
				v = getNextVertex(u, v);
			}
		}
	}


	@Override
	public String dfs(Object o) {
		// ----------------该方法还有点问题-------------
		Visit visit[] = new Visit[vertexs.size()];
		for(int i=0; i<vertexs.size(); i++)
			visit[i] = Visit.unvisited;
		StringBuilder sb = new StringBuilder();
		Vertex vex = new Vertex(o);//find(o);
		dfs(vex, visit, sb);
		return sb.toString();
	}


	private void dfs(Vertex vex, Visit[] visit, StringBuilder sb) {
		int n = vertexs.indexOf(vex);
		sb.append(vex.getData() + "\t");
		visit[n] = Visit.visited;
		
		Vertex v = getFirstVertex(vex);
		while(null != v) {
			if(Visit.unvisited == visit[vertexs.indexOf(v)])
				dfs(v, visit, sb);
			v = getNextVertex(vex, v);
		}
	}


	@Override
	public void clear() {
		vertexs.clear();
	}


	@Override
	public int getEdgeSize() {
		return edgeNum;
	}


	@Override
	public Object getFirstVertex(Object v) {
		Vertex vex = find(v);
		return getFirstVertex(vex).getData();
	}
	
	private Vertex getFirstVertex(Vertex v) {
		if(v.getFirstArc() != null && v.getFirstArc().getVertex() != null) 
			return v.getFirstArc().getVertex();
		return null;
	}

	@Override
	public Object getNextVertex(Object v1, Object v2) {
		// ----------------该方法还有点问题-------------
		Vertex vex1 = find(v1);
		Vertex vex2 = find(v2);
		System.out.println("v1:" + v1);
		System.out.println("v2:" + v2);
		System.out.println("vex1:" + vex1);
		System.out.println("vex2:" + vex2);
		return getNextVertex(vex1, vex2);
	}
	/**
	 * ----------------该方法还有点问题-------------
	 * @param vex1
	 * @param vex2
	 * @return
	 */
	private Vertex getNextVertex(Vertex vex1, Vertex vex2) {
		ArcEdge arc = vex1.getFirstArc();
		while(arc.getNext() != null && arc.getVertex()!=vex2) {
			arc = arc.getNext();
		}
		if(arc.getVertex() != null)  {
			//System.out.println(arc.getVertex());
			return arc.getNext().getVertex();
		}
		return null;
	}


	@Override
	public int getVertexSize() {
		return vertexs.size();
	}


	@Override
	public void removeEdge(Object v1, Object v2) {
		Vertex vex1 = find(v1);
		Vertex vex2 = find(v2);
		if(vex1 != null && vex2 != null) {
			ArcEdge arc = vex1.getFirstArc();
			while(arc.getNext() != null && arc.getVertex() != vex2) {
				arc = arc.getNext();
			}
			if(arc.getVertex() == vex2) {
				ArcEdge priEdge = arc.getPrior();
				ArcEdge nextEdge = arc.getNext();
				priEdge.setNext(nextEdge);
				nextEdge.setPrior(priEdge);
				edgeNum --;
			} else {
				throw new ArrayIndexOutOfBoundsException("边" + v1 + "到" + v2 + "不存在!");
			}
		} else {
			throw new ArrayIndexOutOfBoundsException("顶点" + v1 + "或" + v2 + "不存在!");
		}
	}


	@Override
	public void removeVex(Object v) {
		for(int i=0; i<vertexs.size(); i++) {
			Vertex vex1 = (Vertex)(vertexs.get(i));
			ArcEdge arc = vex1.getFirstArc();
			if(arc  != null) {
				while(arc.getNext() != null) {
					if(arc.getVertex().getData() == v) {
						removeEdge(vex1, v);
					}
				}
			}
		}
		Vertex vex = find(v);
		if(vex != null) {
			int i = vertexs.indexOf(vex);
			vertexs.remove(i);
		}
		
	}

	@Override
	public String printGraph() {
			StringBuilder sb = new StringBuilder();
			for(int i=0; i<vertexs.size(); i++) {
				Vertex vex = (Vertex) vertexs.get(i);
				sb.append("\n顶点:" + vex.getData() + "\t");
				ArcEdge arc = vex.getFirstArc();
				if(arc != null) {
					sb.append("孤," + arc.getVertex().getData());
					while(arc.getNext() != null) {
						sb.append("\t" + arc.getNext().getVertex().getData());
						arc = arc.getNext();
					}
				}
			}
		return sb.toString();
	}
}


分享到:
评论

相关推荐

    建议收藏算法基础课模板大全

    链表与邻接表:树与图的存储 栈与队列:单调队列、单调栈 kmp Trie 并查集 堆 Hash表 搜索与图论 —— 代码模板链接 常用代码模板3——搜索与图论 DFS与BFS 树与图的遍历:拓扑排序 最短路 最小生成树 二分图:染色...

    AcWing算法基础课模板大全

    链表与邻接表:树与图的存储 栈与队列:单调队列、单调栈 kmp Trie 并查集 堆 Hash表 搜索与图论 —— 代码模板链接 常用代码模板3——搜索与图论 DFS与BFS 树与图的遍历:拓扑排序 最短路 最小生成树 二分图:染色...

    ACM 算法经典代码 数据结构经典代码

    3. 二分图最大匹配(hungary邻接阵形式) 10 4. 二分图最大匹配(hungary正向表形式) 11 5. 二分图最佳匹配(kuhn_munkras邻接阵形式) 11 6. 一般图匹配(邻接表形式) 12 7. 一般图匹配(邻接表形式,邻接阵接口) 13 8. ...

    图形数据结构实验.doc

    淮海工学院计算机科学系 实验报告书 课程名: 《数据结构》 题 目: 图形数据结构实验 班 级: 学 号: 姓 名: 图形数据结构实验报告要求 1目的与要求: 1)掌握图的邻接矩阵、邻接表、十字链表、邻接多重链表存储...

    算法和数据结构——左程云.zip

    例如,数组的连续存储,链表的动态分配节点,树和图的邻接矩阵或邻接表表示等。 基本操作:针对每种数据结构,定义了一系列基本的操作,包括但不限于插入、删除、查找、更新、遍历等,并分析这些操作的时间复杂度和...

    数据结构&amp;算法——Java.zip

    例如,数组的连续存储,链表的动态分配节点,树和图的邻接矩阵或邻接表表示等。 基本操作:针对每种数据结构,定义了一系列基本的操作,包括但不限于插入、删除、查找、更新、遍历等,并分析这些操作的时间复杂度和...

    程序员代码面试指南——IT名企算法和数据结构题目最优解.zip

    例如,数组的连续存储,链表的动态分配节点,树和图的邻接矩阵或邻接表表示等。 基本操作:针对每种数据结构,定义了一系列基本的操作,包括但不限于插入、删除、查找、更新、遍历等,并分析这些操作的时间复杂度和...

    C++语言描述(PDF合集)

    12.8.3 邻接链表的遍历函数 388 12.9 语言特性 389 12.9.1 虚函数和多态性 389 12.9.2 纯虚函数和抽象类 391 12.9.3 虚基类 391 12.9.4 抽象类和抽象数据类型 393 12.10 图的搜索算法 394 12.10.1 宽度优先搜索 394 ...

    数据结构算法与应用(C++语言描述).rar

    12.8.3 邻接链表的遍历函数 388 12.9 语言特性 389 12.9.1 虚函数和多态性 389 12.9.2 纯虚函数和抽象类 391 12.9.3 虚基类 391 12.9.4 抽象类和抽象数据类型 393 12.10 图的搜索算法 394 12.10.1 宽度优先搜索 394 ...

    数据结构C++描述

    12.8.3 邻接链表的遍历函数 388 12.9 语言特性 389 12.9.1 虚函数和多态性 389 12.9.2 纯虚函数和抽象类 391 12.9.3 虚基类 391 12.9.4 抽象类和抽象数据类型 393 12.10 图的搜索算法 394 12.10.1 宽度优先搜索 394 ...

    数据结构 C++描述

    12.8.3 邻接链表的遍历函数 388 12.9 语言特性 389 12.9.1 虚函数和多态性 389 12.9.2 纯虚函数和抽象类 391 12.9.3 虚基类 391 12.9.4 抽象类和抽象数据类型 393 12.10 图的搜索算法 394 12.10.1 宽度优先搜索 394 ...

    数据结构算法与应用-C__语言描述

    12.8.3 邻接链表的遍历函数 388 12.9 语言特性 389 12.9.1 虚函数和多态性 389 12.9.2 纯虚函数和抽象类 391 12.9.3 虚基类 391 12.9.4 抽象类和抽象数据类型 393 12.10 图的搜索算法 394 12.10.1 宽度优先搜索 394 ...

    数据结构算法与应用-C++语言描述

    12.8.3 邻接链表的遍历函数 388 12.9 语言特性 389 12.9.1 虚函数和多态性 389 12.9.2 纯虚函数和抽象类 391 12.9.3 虚基类 391 12.9.4 抽象类和抽象数据类型 393 12.10 图的搜索算法 394 12.10.1 宽度优先搜索 394 ...

    数据结构、算法与应用--C++语言描述

    12.8.3 邻接链表的遍历函数 388 12.9 语言特性 389 12.9.1 虚函数和多态性 389 12.9.2 纯虚函数和抽象类 391 12.9.3 虚基类 391 12.9.4 抽象类和抽象数据类型 393 12.10 图的搜索算法 394 12.10.1 宽度优先搜索 394 ...

    数据结构(C语言描述)

    12.8.3 邻接链表的遍历函数 388 12.9 语言特性 389 12.9.1 虚函数和多态性 389 12.9.2 纯虚函数和抽象类 391 12.9.3 虚基类 391 12.9.4 抽象类和抽象数据类型 393 12.10 图的搜索算法 394 12.10.1 宽度优先搜索 394 ...

    数据结构算法与应用-C C++语言描述

    12.8.3 邻接链表的遍历函数 388 12.9 语言特性 389 12.9.1 虚函数和多态性 389 12.9.2 纯虚函数和抽象类 391 12.9.3 虚基类 391 12.9.4 抽象类和抽象数据类型 393 12.10 图的搜索算法 394 12.10.1 宽度优先搜索 394 ...

    数据结构算法与应用-C++语言描述.rar

    12.8.3 邻接链表的遍历函数 388 12.9 语言特性 389 12.9.1 虚函数和多态性 389 12.9.2 纯虚函数和抽象类 391 12.9.3 虚基类 391 12.9.4 抽象类和抽象数据类型 393 12.10 图的搜索算法 394 12.10.1 宽度优先...

Global site tag (gtag.js) - Google Analytics