一、概述
邻接表处理方法:
- 用一位数组存储顶点(为何不用单链表存储?数组可以较容易获得读取顶点信息),此外,每个数据元素还存储指向第一个邻接点的指针;
- 每个顶点Vi的所有邻接点构成一个线性表。
- data:数据域,存储顶点Vi的名或其他信息 firstedge:指针域,指向此顶点的第一个邻接点
adjvex:邻接点域,指示与Vi连接的节点在图中的位置 info:存储边或弧的相关信息,如权值,边编号等
next:下一条边或弧的相关信息
二、图的邻接表存储表示
- 头节点类
public class VertextNode {
private String data;//顶点域
private EdgeNode firstEdge;
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public EdgeNode getFirstEdge() {
return firstEdge;
}
public void setFirstEdge(EdgeNode firstEdge) {
this.firstEdge = firstEdge;
}
}
- 边表节点
public class EdgeNode {
private String Adjvex;//邻接点域,存储该顶点对应下标
private int weight;//权重
private EdgeNode next;
private int edgeInfo;//边值
public int getEdgeInfo() {
return edgeInfo;
}
public void setEdgeInfo(int edgeInfo) {
this.edgeInfo = edgeInfo;
}
public String getAdjvex() {
return Adjvex;
}
public void setAdjvex(String adjvex) {
Adjvex = adjvex;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
public EdgeNode getNext() {
return next;
}
public void setNext(EdgeNode next) {
this.next = next;
}
}
- 图的实现
public class GraphLink {
private int numInputV,numInputE;//输入的总数
VertextNode vtNode[];
Boolean kind =false;//是否为有向图
}
public GraphLink(int sizeVertexes,Boolean kind){
if(sizeVertexes>0&&sizeVertexes<65535){
vtNode = new VertextNode[sizeVertexes];//初始化顶点域
numInputV=numInputE=0;
for(int i=0;i<sizeVertexes;i++){
//顶点域置空
vtNode[i]=null;
}
}else{new RuntimeException("创建失败");}
this.kind=kind;
}
//输入头节点
public void InsertVertextes(String ev){
VertextNode vt = new VertextNode();
vt.setData(ev);
vt.setFirstEdge(null);
vt.setId(numInputV);
vtNode[numInputV]=vt;
numInputV++;
}
//建立边表_头插法,把边的next指向顶点的firstedge,顶点的firstedge指向eNode的getNext()
public void InsertEdges(String start,String end,int weight,int ID){
int pos = getVertexPos(start);
if(pos!=-1){
EdgeNode en = new EdgeNode();
en.setAdjvex(end);
en.setEdgeInfo(ID);
en.setWeight(weight);
en.setNext(vtNode[pos].getFirstEdge());
vtNode[pos].setFirstEdge(en);
numInputE++;
}
if(!kind){//无向图
int posEnd = getVertexPos(end);
if(posEnd!=-1){
EdgeNode enStart = new EdgeNode();
enStart.setAdjvex(start);
enStart.setEdgeInfo(ID);
enStart.setWeight(weight);
enStart.setNext(vtNode[posEnd].getFirstEdge());
vtNode[posEnd].setFirstEdge(enStart);
numInputE++;
}
}
}
public int getVertexPos(String vertx) {
//给出顶点vertex在图中的位置
for (int i = 0; i < numInputV; i++)
if (vtNode[i].getData() == vertx)
return i;
return -1;
}
public String GetFirstNeighbor(String vertx){
int pos=getVertexPos(vertx);
if(pos!=-1){
EdgeNode en = vtNode[pos].getFirstEdge();
return en.getAdjvex();
}
return null;
}
//给出顶点v的邻接点w,求下一个邻接点
public String GetSecNeighbor(String start,String next){
int pos1=getVertexPos(start);
int pos2=getVertexPos(next);
if(pos1!=-1&&pos2!=-1){
EdgeNode en = vtNode[pos1].getFirstEdge();
while(en!=null&&en.getAdjvex()!=next){
en=en.getNext();
}
if(en.getNext()!=null){
return en.getNext().getAdjvex();
}
}
return null;
}
public int getNumInputV() {
return numInputV;
}
public void setNumInputV(int numInputV) {
this.numInputV = numInputV;
}
public int getNumInputE() {
return numInputE;
}
public void setNumInputE(int numInputE) {
this.numInputE = numInputE;
}
public VertextNode[] getVtNode() {
return vtNode;
}
public void setVtNode(VertextNode[] vtNode) {
this.vtNode = vtNode;
}
三、测试
public class TestClass {
public static void main(String[] args){
TestClass ts = new TestClass();
ts.initGraph();
}
private void initGraph(){
GraphLink gl = new GraphLink(9,false);
gl.InsertVertextes("A");
gl.InsertVertextes("B");
gl.InsertVertextes("C");
gl.InsertVertextes("D");
gl.InsertVertextes("E");
gl.InsertVertextes("F");
gl.InsertVertextes("G");
gl.InsertVertextes("H");
gl.InsertVertextes("I");
gl.InsertEdges("A", "B", 0, 1);
gl.InsertEdges("A", "F", 0, 2);
gl.InsertEdges("B", "C", 0, 3);
gl.InsertEdges("B", "I", 0, 4);
gl.InsertEdges("B", "G", 0, 5);
gl.InsertEdges("C", "I", 1, 6);
gl.InsertEdges("C", "D", 1, 7);
gl.InsertEdges("D", "G", 1, 8);
gl.InsertEdges("D", "I", 5, 1);
gl.InsertEdges("D", "H", 4, 2);
gl.InsertEdges("D", "E", 3, 3);
gl.InsertEdges("E", "F", 2, 4);
gl.InsertEdges("E", "H", 1, 5);
gl.InsertEdges("G", "F", 1, 6);
gl.InsertEdges("G", "H", 1, 7);
DFSTraverse(gl);
System.out.println(gl.GetFirstNeighbor("A"));
System.out.println(gl.GetSecNeighbor("A", "F"));
}
Boolean [] visited;
private void DFS(GraphLink gl,int i){
visited[i]=true;
System.out.println(gl.vtNode[i].getData());
EdgeNode en = gl.vtNode[i].getFirstEdge();//获取当前结点的下一个相邻结点
while(en!=null){
int pos = gl.getVertexPos(en.getAdjvex());
if( !visited[pos]){
DFS(gl,gl.getVertexPos(en.getAdjvex()));
}
en=en.getNext();
}
}
void DFSTraverse(GraphLink gl){
visited = new Boolean[gl.getNumInputV()];
for(int i=0;i<gl.getNumInputV();i++){
visited[i]=false;
}
for(int i=0;i<gl.getNumInputV();i++){
if(!visited[i]){
DFS(gl,i);
}
}
}
}
/**
* 广度优先
* @param gl
*/
private void BFSTraverse(GraphLink gl){
Queue<String> q = new LinkedList<String>();//初始化一个辅助队列
Boolean [] visitedB = new Boolean [gl.getNumInputV()];
for(int i=0;i<gl.getNumInputV();i++){
visitedB[i]=false;
}
//访问i元素
for(int i=0;i<gl.getNumInputV();i++){
if(!visitedB[i]){
System.out.println(gl.getVtNode()[i].getData());//getData中为顶点头的内容
visitedB[i]=true;
q.add(gl.getVtNode()[i].getData());//把当前顶点添加到队列中
while(!q.isEmpty()){//队列不为空则一直循环
int j =gl.getVertexPos(q.poll());//获取当前出栈元素的位置
EdgeNode en = gl.getVtNode()[j].getFirstEdge();//当前出栈元素的连接边
while(en!=null){
j= gl.getVertexPos(en.getAdjvex());//Agjvex为String,需先获取在图中位置,当前边对应结点在图中的位置(id)
if(!visitedB[j] ){
visitedB[j]=true;
System.out.println(en.getAdjvex());
q.add(en.getAdjvex());//将顶点入栈
}
en = en.getNext();//指向下一个结点
}
}
}
}
}
~感觉写的有点麻烦~~图结构建的不是很好,后续在改进咯
邻接表的插入方法选用的为“前插法”,书中教程一般选用尾差法,所以深搜和宽搜结果会不一致,验证了下,结果是正确的~
测试用例中图的结构如下:
最后(DFS)输出结果为:
A
F
G
H
E
D
I
C
BF
B