一、图的基本概念
图是一种和树相像的数据结构,通常有一个固定的形状,由物理或者抽象的问题来觉得。
顶点:就是图中每个数据
邻接:如果两个顶点被同一条边所连接,称这两个顶点是邻接的
路径:路径是从一个顶点到另外一个顶点所经过的边
连通图和非连通图:至少有一条路径可以连接到所有的顶点,那么这个图就是连通图,否则是非连通图,但是非连通图的子图又可以是连通图
有向图和无向图:有向图表示边是有方向的,无向图的边是没有方向的
带权图:在有些图中,边被赋予了一个权值,权值是一个数字,可以是两个顶点间的距离、时间等等,这样的图就叫做带权图。
二、 图的实现
图的实现有两种方式:
• 邻接表:二维链表
• 邻接矩阵:二维数组
邻接矩阵来完成图:
创建顶点类:
/**
- 顶点
- @author Administrator
*/
public class Vertex {
private char label;//顶点名称
public char getLabel() {
return label;
}
public void setLabel(char label) {
this.label = label;
}
public Vertex(char label) {
this.label = label;
}
}
创建图操作类:
public class Graph {
//顶点数组
private Vertex[] vertexList;
//邻接矩阵
private int[][] adjMat;
//顶点最大数目
private int maxSize;
//定义当前的顶点
private int nVertext;
public Vertex[] getVertexList() {
return vertexList;
}
public void setVertexList(Vertex[] vertexList) {
this.vertexList = vertexList;
}
public int[][] getAdjMat() {
return adjMat;
}
public void setAdjMat(int[][] adjMat) {
this.adjMat = adjMat;
}
public int getMaxSize() {
return maxSize;
}
public void setMaxSize(int maxSize) {
this.maxSize = maxSize;
}
public int getnVertext() {
return nVertext;
}
public void setnVertext(int nVertext) {
this.nVertext = nVertext;
}
public Graph() {
vertexList = new Vertex[maxSize];
adjMat = new int[maxSize][maxSize];
for (int i = 0; i < adjMat.length; i++) {//给邻接矩阵设置初始值
for (int j = 0; j < adjMat[i].length; j++) {
adjMat[i][j] = 0;
}
}
nVertext = 0;
}
/**
* 添加顶点
* @param label
*/
public void addVertex(char label) {
vertexList[nVertext++] = new Vertex(label);
}
public void addEdga(int start,int end) {
adjMat[start][end] = 1;
adjMat[end][start] = 1;
}
}
测试类:
public class GraphTest {
public static void main(String[] args) {
Graph g = new Graph();
g.addVertex('A');
g.addVertex('B');
g.addVertex('C');
g.addEdga(0, 1);
g.addEdga(0, 2);
g.addEdga(1, 2);
}
}
三、 图的搜索
图的搜索是指从一个顶点可以到达哪些顶点,图的搜索可以分为两类:
• 深度优先搜索DFS
• 广度优先搜索BFS
深度优先搜索规则:
• 1,如果可能,访问一个邻接未访问的顶点,标记它并把它放入栈中
• 2,当不能执行规则1时,如果栈不为空,就从栈中弹出一个顶点
• 3,当不能执行规则1和规则2时,就完成对整个图的搜索过程
修改顶点类:
/**
- 顶点
- @author Administrator
*/
public class Vertex {
private char label;//顶点名称
private boolean isVisited;//是否被访问过
public boolean isVisited() {
return isVisited;
}
public void setVisited(boolean isVisited) {
this.isVisited = isVisited;
}
public char getLabel() {
return label;
}
public void setLabel(char label) {
this.label = label;
}
public Vertex(char label) {
this.label = label;
this.isVisited = false;
}
}
修改图的操作类:
public class Graph {
//顶点数组
private Vertex[] vertexList;
//邻接矩阵
private int[][] adjMat;
//顶点最大数目
private int maxSize = 10;
//定义当前的顶点
private int nVertext;
//栈
private MyStack stack;
public MyStack getStack() {
return stack;
}
public void setStack(MyStack stack) {
this.stack = stack;
}
public Vertex[] getVertexList() {
return vertexList;
}
public void setVertexList(Vertex[] vertexList) {
this.vertexList = vertexList;
}
public int[][] getAdjMat() {
return adjMat;
}
public void setAdjMat(int[][] adjMat) {
this.adjMat = adjMat;
}
public int getMaxSize() {
return maxSize;
}
public void setMaxSize(int maxSize) {
this.maxSize = maxSize;
}
public int getnVertext() {
return nVertext;
}
public void setnVertext(int nVertext) {
this.nVertext = nVertext;
}
public Graph() {
vertexList = new Vertex[maxSize];
adjMat = new int[maxSize][maxSize];
for (int i = 0; i < adjMat.length; i++) {//给邻接矩阵设置初始值
for (int j = 0; j < adjMat[i].length; j++) {
adjMat[i][j] = 0;
}
}
nVertext = 0;
stack = new MyStack(maxSize);
}
/**
* 添加顶点
* @param label
*/
public void addVertex(char label) {
vertexList[nVertext++] = new Vertex(label);
}
/**
* 添加边
* @param start
* @param end
*/
public void addEdga(int start,int end) {
adjMat[start][end] = 1;
adjMat[end][start] = 1;
}
/**
* 获取邻接没有访问过的节点
*/
public int getVertex(int v) {
for (int i = 0; i < nVertext; i++) {
if(adjMat[v][i] == 1 && vertexList[i].isVisited() == false) {//有边相连,并且没有访问过
return i;
}
}
return -1;
}
/**
* 定义搜索方法
*
*/
public void dfs() {
//首先访问0号节点
vertexList[0].setVisited(true);
displayVertex(0);//压入前进行访问
//压入栈中
stack.push(0);
while( ! stack.isEmppty()) {
//获得一个未访问的节点
int v = this.getVertex(stack.peek());
if(v == -1) {
//弹出一个顶点
int x = stack.pop();
// displayVertex(x);//弹出的时候进行访问
}else {
vertexList[v].setVisited(true);//表示访问
displayVertex(v);//压入前进行访问
//压入栈中
stack.push(v);
}
}
//搜索完成,要将访问标记修改为原始状态
for (int i = 0; i < nVertext; i++) {
vertexList[i].setVisited(false);
}
}
public void displayVertex(int v) {
System.out.println(vertexList[v] .getLabel());//显示节点
}
}
修改栈:
public class MyStack {
private int maxSize;
private int[] arr;
private int top;//表示栈顶元素的位置
public MyStack(int size) {
this.maxSize = size;//定义栈的大小
this.arr = new int[this.maxSize];
this.top = -1;//表示是一个空栈
}
/**
* 压入数据
* @param value
*/
public void push(int value) {
arr[ ++ top] = value;
}
/**
* 数据弹出
* @return
*/
public int pop() {
return arr[top--];
}
/**
* 判断栈是否为空
* @return
*/
public boolean isEmppty() {
return top == -1;
}
/**
* 判断栈是否满了
* @return
*/
public boolean isFull() {
return top == (maxSize-1);
}
public int peek() {
return arr[top];
}
}
广度优先搜索原则:
• 访问下一个邻接位访问的顶点,这个顶点必须是当前节点的临界点,标记它,并且将它插入队列
• 如果无法执行1,那么就从对头的取出一个顶点,并使用其作为当前顶点
• 当队列为空不能执行规则2时,就完成整个搜索的过程
借鉴于:https://www.cnblogs.com/g177w/p/8475492.html
以及大学数据结构课程