一、相邻矩阵法
对于图形G=(V,E),假设有n个顶点,则可以将n个顶点的图形利用一个n*n二维矩阵表示,假如A(i,j)=1,则表示图形中有一条边(Vi,Vj)存在,否则A(i,j)=0,表示Vi到Vj之间不存在边。
- 对无向图形,相邻矩阵一定是对称的,对角线为0。
- 在无向图形中,任意节点i的度是矩阵第i行所有元素的和;在有向图中,节点i的出度是第i行所有元素的和,入度是第j列所有元素的和。
- 用相邻矩阵法表示图形共需要n*n空间,无向图具有对称关系,仅需存储上三角或下三角,因此仅需n(n-1)/2空间。
我们以下图为例,用相邻矩阵进行存储。(有向图和无向图思路相同,只是矩阵不一定对称)
代码实现如下:
public class Test {
public static void main(String[] args) {
int[][] data= {{1,2},{1,5},{2,1},{2,3},{2,4},{3,2},{3,4},{3,5},{4,2},{4,3},{4,5},{5,1},{5,3},{5,4}};
int[][] array=new int[6][6]; //矩阵大小为图顶点个数+1,下标0的位置不存数据
int tempi,tempj;
//核心代码
for(int i=0;i<data.length;i++) {
tempi=data[i][0]; //起始顶点
tempj=data[i][1]; //终止顶点
array[tempi][tempj]=1; //有边的点填入1
}
System.out.println("无向图形矩阵:");
for(int i=1;i<array.length;i++) {
for(int j=1;j<array.length;j++) {
System.out.print(array[i][j]+" ");
}
System.out.println();
}
}
}
程序运行结果如下:
优点:
- 实现简单
- 计算度相当方便
- 要在图形中加入新边时,插入和删除简单
缺点:
- 顶点与顶点之间路径不多时,易造成稀疏矩阵浪费空间
- 计算所有顶点的分支度时,其时间复杂度为O(n2)
二、相邻表法
每个顶点使用一个链表,与该顶点相邻的节点存入该节点的链表中,即相当于把相邻矩阵中1的部分放入链表,忽略掉值为0的部分,可以避免浪费存储空间。
在无向图中,n个顶点e个边共需n个表头节点及2*e个节点,有向图中,链表只存放出度节点,因此需要n个表头节点及e个节点。
我们以上图为例,该图用相邻表法表示如下:
代码实现思路:我们先声明GraphLink类即链表类,该类中包括节点打印节点插入等函数。在主函数中声明存放链表的数组,大小为顶点个数,对每个顶点进行遍历,寻找与该顶点相邻的顶点存入链表中,该顶点处理完后打印链表。
具体代码如下:
public class Test {
public static void main(String[] args) {
int[][] data= {{1,2},{1,5},{2,1},{2,3},{2,4},{3,2},{3,4},{3,5},{4,2},{4,3},{4,5},{5,1},{5,3},{5,4}};
System.out.println("图形的邻接表内容为:");
GraphLink[] head=new GraphLink[6]; //声明一个存放链接表的数组,长度为顶点个数+1,下标为0的位置不存放
for(int i=1;i<6;i++) {
head[i]=new GraphLink(); //为第i个顶点创建链表
System.out.print("顶点"+i+"=>");
for(int j=0;j<data.length;j++) { //寻找与该顶点相邻的顶点
if(data[j][0]==i) //起始顶点为i
head[i].insert(data[j][1]); //终止顶点插入链表
}
head[i].print(); //每个顶点处理完后输出该顶点的链表
}
}
}
class Node{
int data; //顶点
Node next;
public Node(int data) {
this.data=data;
this.next=null;
}
}
class GraphLink{
public Node first; //头节点
public Node last; //尾节点
public boolean isEmpty() {
return first==null;
}
public void print() { //打印链表
Node current=first;
while(current!=null) {
System.out.print("["+current.data+"]");
current=current.next;
}
System.out.println();
}
public void insert(int data) { //将节点插入链表
Node newNode=new Node(data);
if(this.isEmpty()) { //判断链表是否为空
first=newNode;
last=newNode;
}
else { //尾插法
last.next=newNode;
last=newNode;
}
}
}
程序运行结果:
优点:
- 和相邻矩阵相比较节省空间
- 计算所有顶点的度时,其时间复杂度为O(n+e)
缺点:
- 要求入度时,必须先求其反转表
- 图形新边的加入和删除会改动到相关的表链接