特点:对图中每个顶点建立一个单链表,且链表中的结点是依附于当前顶点的边(对于有向图是以该顶点为尾的弧);
表结点:即链表中的结点,对应图中的边,由3个域组成,如下所示:
adjvex | nextarc | info |
---|
其中,adjvex(邻接点域)指示与顶点邻接的点在图中的位置;nextarc(链域)指示依附于当前顶点下一条边;info(数据域)存储和顶点或边相关的信息,如权重;
头结点:对应图中的顶点结点,由2个域组成,如下所示:
data | firstarc |
---|
其中,data(数据域)存储当前顶点的名或其他相关的信息;firstarc(链域)指向链表中第一个表结点;头结点通常以顺序结构存储;
优点:用邻接表表示图比邻接矩阵节省存储空间;
缺点: 对于无向图,顶点的度为相应链表中的结点数;然而,对于有向图,链表中的结点数仅为相应顶点的出度,求入度则需要遍历整个邻接表(所有链表中的表结点的邻接点域的值为i的结点的个数是顶点Vi的入度);另外,判定任意连个顶点间是否有边或弧相连时,需要遍历第i个或第j个链域;
下面给出图的邻接表存储结构的Java实现:
package org.sky.graph;
import java.util.Scanner;
/**
* @Description 利用邻接表表示图(有向图/无向图)
* @author sky
* @date 2016/12/28
*/
public class AdjacencyListGragh {
//表结点,包含边的相关信息
@SuppressWarnings("unused")
private static class ArcNode{
int adjVex; //该弧或边所指向的顶点的位置
int value; //与弧或边相关的信息,如权值
ArcNode nextArc; //指向下一条弧或边的指针
public ArcNode(int adjVex, int value) {
super();
this.adjVex = adjVex;
this.value = value;
}
ArcNode(int adjvex, int value, ArcNode nextArc) {
super();
this.adjVex = adjvex;
this.value = value;
this.nextArc = nextArc;
}
public int getAdjVex() {
return adjVex;
}
public void setAdjVex(int adjVex) {
this.adjVex = adjVex;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public ArcNode getNextArc() {
return nextArc;
}
public void setNextArc(ArcNode nextArc) {
this.nextArc = nextArc;
}
}
//头结点,对应图中的顶点
@SuppressWarnings("unused")
private static class VNode{
Object data; //顶点信息
ArcNode firstArc; //指向第一条依附该顶点的弧或边的指针
public VNode(Object data) {
super();
this.data = data;
}
public VNode(Object data, ArcNode firstArc) {
super();
this.data = data;
this.firstArc = firstArc;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public ArcNode getFirstArc() {
return firstArc;
}
public void setFirstArc(ArcNode firstArc) {
this.firstArc = firstArc;
}
}
private int numVex; //图的当前顶点数
private int numArc; //图的当前边数或弧数
private VNode[] vexs; //存储表头结点,通常采用顺序存储结构
public AdjacencyListGragh(int numVex, int numArc, VNode[] vexs) {
super();
this.numVex = numVex;
this.numArc = numArc;
this.vexs = vexs;
}
/**
* @Desciption 创建有向网
*/
@SuppressWarnings("unused")
private void createDN(){
Scanner sc = new Scanner(System.in);
System.out.println("请分别输入图的顶点数及边数");
numVex = sc.nextInt();
numArc = sc.nextInt();
vexs = new VNode[numVex];
System.out.println("请分别输入图的各个顶点:");
for(int v = 0; v < numVex; v++){
vexs[v] = new VNode(sc.next());
}
System.out.println("请输入各个边的来给你个顶点及其权值");
for(int k = 0; k < numArc; k++){
int v = locateVex(sc.next());
int u = locateVex(sc.next());
int value = sc.nextInt();
addArc(v,u,value);
}
sc.close();
}
/**
* @Desciption 创建无向网
*/
@SuppressWarnings("unused")
private void createUDN(){
Scanner sc = new Scanner(System.in);
System.out.println("请分别输入图的顶点数及边数");
numVex = sc.nextInt();
numArc = sc.nextInt();
vexs = new VNode[numVex];
System.out.println("请分别输入图的各个顶点:");
for(int v = 0; v < numVex; v++){
vexs[v] = new VNode(sc.next());
}
System.out.println("请输入各个边的来给你个顶点及其权值");
for(int k = 0; k < numArc; k++){
int v = locateVex(sc.next());
int u = locateVex(sc.next());
int value = sc.nextInt();
addArc(v,u,value);
addArc(u,v,value);
}
sc.close();
}
/**
* @Desciption 返回与传入值相对应的定点位置
*/
public int locateVex(Object vex){
for(int v = 0; v < numVex; v++){
if(vexs[v].getData().equals(vex)){
return v;
}
}
return -1;
}
/**
* @Desciption 在位置v和u间添加边,并赋权值
*/
private void addArc(int v, int u, int value){
ArcNode arc = new ArcNode(u,value);
arc.setNextArc(vexs[v].getFirstArc());
vexs[v].setFirstArc(arc);
}
}