图(无向图)的生成及深度优先遍历,及广度优先遍历
图的广度和深度优先遍历 用如下图来解决
图的创建:
java代码:
class Graph{
private int edgesNum; //边数
private char [] vertexs; //顶点
private int [][] weight; //描述两边是否联通
public Graph(int edgesNum){
vertexs= new char[edgesNum];
weight= new int[edgesNum][edgesNum];
}
public int getEdgesNum() {
return edgesNum;
}
public void setEdgesNum(int edgesNum) {
this.edgesNum = edgesNum;
}
public char[] getVertexs() {
return vertexs;
}
public void setVertexs(char[] vertexs) {
this.vertexs = vertexs;
}
public int[][] getWeight() {
return weight;
}
public void setWeight(int[][] weight) {
this.weight = weight;
}
}
通过客户端传入参数给 operategraph对象,进行初始化
客户端代码 vertexs 描述顶点
二位邻接矩阵表示对边的描述,例如 a[0][0]=0 表示A 和 A相连 0 表示连不通,1表示能连通
char []vertexs = {'A','B','C','D','E'};
int[][] weight ={
{0,1,1,0,0},
{1,0,1,1,1},
{1,1,0,0,0},
{0,1,0,0,0},
{0,1,0,0,0}
};
OperateGraph 对图的各种操作’
OperateGraph类的代码
//图的操作类
class OperateGraph{
private Graph graph;
private boolean []isVisited;
public OperateGraph(Graph graph) {
this.graph = graph;
}
public void createGraph(char[] vertexs,int [][] weight){
graph.setVertexs(vertexs);
graph.setWeight(weight);
}
public void showWeight(){
for (int i=0;i<graph.getWeight().length;i++){
for(int j=0;j<graph.getWeight()[i].length;j++){
System.out.printf("%d\t", graph.getWeight()[i][j]);
}
System.out.println();
}
}
public void bfs(){
this.isVisited = new boolean[this.graph.getVertexs().length];
for(int j=0;j<this.graph.getVertexs().length;j++){
if(isVisited[j] == false){
bfs(isVisited,j); // 对每一个节点进行试探,看有没有被访问
}
}
}
//图的广度优先遍历
public void bfs(boolean[] isVisited,int i){
//首先打印首先要遍历的节点
System.out.println(this.graph.getVertexs()[i]);
//打印后该节点已经访问,标记 为true
isVisited[i] = true;
//将此节点放入栈
Stack<Integer> stack = new Stack<>();
stack.add(i);
while(!stack.isEmpty()){ //退出遍历节点的
int cur = stack.pop();
int w = this.getFirstIndex(cur);
//持续输出遍历节点的下一个相邻节点,直到找不到退出循环
while (w!=-1){
if(isVisited[w]==false){
System.out.println(this.graph.getVertexs()[w]);
isVisited[w] = true;
//入栈
stack.add(w);
}
//如果第一个相邻节点已经被访问,则访问当前节点的下一个邻接节点
w=getNextIndex(i,w);
}
}
}
//此时只是遍历完一个节点
public void dfs(boolean []isVisited,int i){ // 从那开始深度优先遍历
int length =this.graph.getVertexs().length;
char [] ver = this.graph.getVertexs();
System.out.println(this.graph.getVertexs()[i]);
isVisited[i] = true;
//先得到第一个邻接节点下标
int FirstNerbor = this.getFirstIndex(i);
while(FirstNerbor!=-1){
//如果还没有访问,则开始递归访问
if(isVisited[FirstNerbor]==false){
dfs(isVisited,FirstNerbor);
}
//如果已经访问过了,则访问下一个邻接点
FirstNerbor = getNextIndex(i,FirstNerbor);
}
}
public void dfs(){
this.isVisited = new boolean[this.graph.getVertexs().length];
//遍历所有节点
for(int i=0;i<this.graph.getVertexs().length;i++){
if(this.isVisited[i]==false) {
dfs(this.isVisited, i);
}
}
}
//得到下一个邻接节点
public int getNextIndex(int h1,int h2){
int index=-1;
for(int j=h2+1;j<this.graph.getVertexs().length;j++){
if(this.graph.getWeight()[h1][j]!=0){
index = j;
break;
}
}
return index;
}
//得到第一个最近相邻节点下标
public int getFirstIndex(int index){
int nextIndex =-1;
for(int j=0;j<this.graph.getVertexs().length;j++){
if(this.graph.getWeight()[index][j]>0){
nextIndex = j;
break;
}
}
return nextIndex;
}
//得到该节点的当前下标
public int getCurrentIndex(char ch) {
int realIndex = -1;
for(int i=0;i<this.graph.getVertexs().length;i++){
if(ch==this.graph.getVertexs()[i]){
realIndex = i;
}
}
return realIndex;
}
}
最终运行结果如图
难点在于:深度和广度遍历的思想维度不一样,因此实现不一样
深度优先遍历的思路
1.访问初始节点v,并标记该节点已被访问
2.查找节点v的第一个邻接接节点w
3.若w存在,则执行4,如果不存在,则回到第一步,将从v的下一个结点出发
4若w未被访问,对w进行深度优先遍历递归(即把w当作v,进行123步)
5若w已被访问,则对该邻接节点的下一个邻接节点,转到步骤3
广度优先遍历思路:类似与一个分层搜索的过程,广度优先搜索遍历需要使用一个队列(或栈)以保持访问过节点顺序,已遍按这个顺序来访问这些节点的邻接节点
1.访问初始结点v并标记为已访问,
2节点入栈(队列)
3,如果栈不为空 while循环继续执行,否则算法结束
4出栈,取得该节点
5查找结点的第一个节点w
6.1若不存在,则转到步骤三
6.2若节点存在,且节点的邻接节点未被访问,则打印该节点,入栈
6.3若节点存在,且节点的邻接节点已被访问,则访问该节点的下一个邻接点,转到6.