图G由两个集合V和E组成,记为:G=(V,E),其中:V是顶点的有穷非空集合,E是V中顶点偶对(称为边)的有穷集。通常,也将图G的顶点集和边集分别记为V(G)和E(G)。E(G)可以是空集。若E(G)为空,则图G只有顶点而没有边。图有两种存储结构:邻接矩阵和邻接表。邻接矩阵:用邻接矩阵表示顶点间的相邻关系, 用一个顺序表来存储顶点信息。邻接表:类似于树的孩子链表表示法。对于图G中的每个顶点vi,该方法把所有邻接于vi的顶点vj链成一个带头结点的单链表,这个单链表就称为顶点vi的邻接表(Adjacency List)。
下面是用邻接矩阵存储的图。
package cn.zhf.test;
public class Graph {
final int MAX_VERTEX = 10;// 最多20个顶点
Vertex[] vertex;// 顶点数组
int[][] adjacency;// 邻接矩阵
int numOfVertex;// 当前图中顶点的数量
public Graph() {// 构造器
vertex = new Vertex[MAX_VERTEX];
adjacency = new int[MAX_VERTEX][MAX_VERTEX];
numOfVertex = 0;
// 将邻接矩阵初始化
for (int i = 0; i < MAX_VERTEX; i++) {
for (int j = 0; j < MAX_VERTEX; j++)
adjacency[i][j] = 0;
}
}
// 添加顶点
public void addVertex(char v) {
vertex[numOfVertex++] = new Vertex(v);
}
//无向图 添加边
public void addEdge(int start, int end) {
adjacency[start][end] = 1;
adjacency[end][start] = 1;
}
//有向图添加边
public void addEdge1(int start,int end){
adjacency[start][end] = -1;
}
// 打印某个顶点
public void showVertex(int index) {
System.err.print(vertex[index].label);
}
// 打印邻接矩阵
public void show() {
for (int i = 0; i < MAX_VERTEX; i++) {
for (int j = 0; j < MAX_VERTEX; j++) {
if (j == MAX_VERTEX - 1)
System.out.println(adjacency[i][j] + " ");
else
System.out.print(adjacency[i][j] + " ");
}
}
}
/**
* 找到与某一顶点邻接而未被访问的顶点,如何做?
* 在邻接矩阵中,找到指定顶点所在的行,从第一列开始向后寻找值为1的列,列号是邻接顶点的号码,检查此顶点是否访问过。
* 如果该行没有值为1而又未访问过的点,则此顶点的邻接点都访问过了。
*/
public int getUnVisitedVertex(int index) {
for (int i = 0; i < numOfVertex; i++)
if (adjacency[index][i] == 1 && vertex[i].wasVisited == false)
return i;
return -1;
}
// 图的深度优先遍历
public void dfs() {
vertex[0].wasVisited = true;// 从头开始访问
showVertex(0);
Stack stack = new Stack();
stack.push(0);
/**
* 1.用peek()方法获取栈顶的顶点 2.试图找到这个顶点的未访问过的邻接点 3.如果没有找到这样的顶点,出栈 4.如果找到,访问之,入栈
*/
while (!stack.isEmpty()) {
int index = getUnVisitedVertex(stack.peek());
if (index == -1)// 没有这个顶点
stack.pop();
else {
vertex[index].wasVisited = true;
showVertex(index);
stack.push(index);
}
}
// 栈为空,遍历结束,标记位重新初始化
for (int i = 0; i < numOfVertex; i++)
vertex[i].wasVisited = false;
}
// 图的广度优先遍历
public void bfs() {
vertex[0].wasVisited = true;
showVertex(0);
Queue queue = new Queue();
queue.insert(0);
int v2;
while (!queue.isEmpty()) {// 直到队列为空
int v1 = queue.remove();
// 直到点v1没有未访问过的邻接点
while ((v2 = getUnVisitedVertex(v1)) != -1) {
// 取到未访问过的点,访问之
vertex[v2].wasVisited = true;
showVertex(v2);
queue.insert(v2);
}
}
for (int i = 0; i < numOfVertex; i++)
vertex[i].wasVisited = false;
}
// 最小生成树 minimum spanning tree
public void mst() {
vertex[0].wasVisited = true;
Stack stack = new Stack();
stack.push(0);
while (!stack.isEmpty()) {
int currentVertex = stack.peek();
int v = getUnVisitedVertex(currentVertex);
if (v == -1)
stack.pop();
else {
vertex[v].wasVisited = true;
stack.push(v);
//当前顶点与下一个未访问过的邻接点
showVertex(currentVertex);
showVertex(v);
System.out.print(" ");
}
}
for (int i = 0; i < numOfVertex; i++)
vertex[i].wasVisited = false;
}
public static void main(String[] args) {
Graph graph = new Graph();
graph.addVertex('A');
graph.addVertex('B');
graph.addVertex('C');
graph.addVertex('D');
graph.addEdge(1, 2);
graph.addEdge(0, 1);
graph.addEdge(2, 3);
graph.show();
// graph.dfs();
// graph.bfs();
graph.mst();
}
}
// 顶点
class Vertex {
char label;// 如A,B,C
boolean wasVisited;// 标识是否访问过此顶点
public Vertex(char vertex) {
this.label = vertex;
wasVisited = false;
}
}
// 栈
class Stack {
final int MAX_SIZE = 10;
int stack[];
int top;
public Stack() {
stack = new int[MAX_SIZE];
top = -1;
}
public void push(int idata) {
stack[++top] = idata;
}
public int pop() {
return stack[top--];
}
public int peek() {
return stack[top];
}
public boolean isEmpty() {
return top == -1;
}
}
// 队列
class Queue {
final int SIZE = 10;
int[] qarray;
int front;
int rear;
public Queue() {
qarray = new int[SIZE];
front = 0;
rear = -1;
}
// 在队尾追加
public void insert(int key) {
if (rear == SIZE - 1)
rear = -1;
qarray[++rear] = key;
}
// 队头删除数据
public int remove() {
int temp = qarray[front++];
if (front == SIZE)
front = 0;
return temp;
}
public boolean isEmpty() {
return rear + 1 == front || front + SIZE - 1 == rear;
}
}