Java实现图广度优先、深度优先搜索

11 篇文章 0 订阅
欢迎关注技术公众号

图,就是我们在数据结构中学到的图,它是一种存储信息的结构。图是一类在实际应用中非常常见的数据结构,当数据规模大到一定程度时,如何对其进行高效计算即成为迫切需要解决的问题。最常见的大规模图数据的例子就是互联网网页数据,网页之间通过链接指向形成规模超过500 亿节点的巨型网页图。再如,Facebook 社交网络也是规模巨大的图,仅好友关系已经形成超过10 亿节点、千亿边的巨型图,考虑到Facebook 正在将所有的实体数据节点都构建成网状结构,其最终形成的巨型网络数据规模可以想见其规模。要处理如此规模的图数据,传统的单机处理方式显然已经无能为力,必须采用由大规模机器集群构成的并行图数据库。在处理图数据时,其内部存储结构往往采用邻接矩阵或邻接表的方式,在大规模并行图数据库场景下,邻接表的方式更加常用,大部分图数据库和处理框架都采用了这一存储结构。

本程序是基于图的邻接表存储方式实现的。遗憾的是没有实现带权图,有实现带权图的朋友欢迎留言指教!或加Q:374741295

 

package linkListGraph;

import java.util.ArrayList;
import java.util.Iterator;

/**
 * @ClassName: Graph
 * @Description: 图结构实现,封装了图的dfs、bfs遍历算法
 * @author zhoupengcheng
 * @version 2015年5月17日下午5:07:34
 */
public class Graph {
	private ArrayList<Vertex> vertexList;// 用一个ArrayList保存图中的所有结点
	private boolean isDirected = false;// 标记是否为有向图
	private int nVerts = 0;// 保存总的顶点数

	private StackX theStack;// 深度优先搜寻时使用
	private Queue theQueue; // 广度优先搜索时使用
	private ArrayList<Vertex> bfs;// 在bfs函数中使用,保存bfs得到的结果序列
	private ArrayList<Vertex> dfs;// 在dfs函数中使用,保存dfs得到的结果序列

	public Graph() {
		vertexList = new ArrayList<Vertex>();
		dfs = new ArrayList<Vertex>();
		bfs = new ArrayList<Vertex>();
	}

	public Graph(boolean is) {
		this();
		this.isDirected = is;
	}

	public boolean isDirected() {
		return this.isDirected;
	}

	public ArrayList<Vertex> getVertexList() {
		return vertexList;
	}

	public ArrayList<Vertex> getDFS() {
		return dfs;
	}

	public ArrayList<Vertex> getBFS() {
		return bfs;
	}

	public void addVertex(Vertex vertex) {
		vertex.setIndex(nVerts);
		vertexList.add(vertex);
		nVerts++;
	}

	public void addEdge(int start, int end) {
		vertexList.get(start).addAdj(vertexList.get(end));
		if (!isDirected) {
			vertexList.get(end).addAdj(vertexList.get(start));
		}
	}

	public int getVertsCount() {
		return nVerts;
	}
	
	//深度优先迭代器
	public Iterator dfsIterator(){  
        dfs();  
        return new DfsIterator();  
    } 
	
	//广度优先迭代器
	public Iterator bfsIterator(){  
        bfs();  
        return new BfsIterator();  
    }  
	
	// 打印邻接表
	public void displayGraph() {
		for (int i = 0; i < vertexList.size(); i++) {
			printVertx(vertexList.get(i));
		}
	}

	public void printVertx(Vertex vertex) {
		ArrayList<Vertex> next = vertex.getAdj();
		if (next == null) {
			System.out.println(vertex.toString() + " 无邻接点!");
		} else {
			System.out.print(vertex.toString() + "邻接表:");
			for (int i = 0; i < next.size(); i++) {
				System.out.print(next.get(i).label + " ");
			}
			System.out.println();
		}
	}

	// 深度优先遍历
	public void dfs() {
		theStack = new StackX(nVerts);
		vertexList.get(0).wasVisted = true;
		dfs.add(vertexList.get(0));
		theStack.push(vertexList.get(0));
		Vertex vertex;
		while (!theStack.isEmpty()) {
			vertex = getAdjVertex((Vertex) theStack.peek());
			if (vertex == null) {
				theStack.pop();
			} else {
				vertex.wasVisted = true;
				dfs.add(vertex);
				theStack.push(vertex);
			}
		}
		// ------遍历完成,清除所有访问标志位--------
		for (int i = 0; i < getVertsCount(); i++) {
			vertexList.get(i).wasVisted = false;
		}

	}

	// 广度优先遍历
	public void bfs() {
		theQueue = new Queue(nVerts);
		vertexList.get(0).wasVisted = true;
		bfs.add(vertexList.get(0));
		theQueue.insert(vertexList.get(0));
		Vertex vertex1;
		while (!theQueue.isEmpty()) {
			Vertex vertex2 = (Vertex) theQueue.remove();
			while ((vertex1 = getAdjVertex(vertex2)) != null) {
				vertex1.wasVisted = true;
				bfs.add(vertex1);
				theQueue.insert(vertex1);
			}
		}
		// ------遍历完成,清除所有访问标志位--------
		for (int i = 0; i < getVertsCount(); i++) {
			vertexList.get(i).wasVisted = false;
		}
	}

	// 返回vertex顶点的一个未曾访问过的邻接点
	public Vertex getAdjVertex(Vertex vertex) {
		ArrayList<Vertex> adjVertexs = vertex.getAdj();
		for (int i = 0; i < adjVertexs.size(); i++) {
			if (!adjVertexs.get(i).wasVisted) {
				return adjVertexs.get(i);
			}
		}
		return null;
	}

	//专门写个迭代器来遍历结果
	private abstract class GraphIterator implements Iterator {
		int count = 0;
		public GraphIterator() {
		}

		public boolean hasNext() {
			return count != getVertsCount() ;
		}

		public Object next() {
			// TODO Auto-generated method stub
			return null;
		}

		public void remove() {
			// TODO Auto-generated method stub
		}
	}

	// 深度优先迭代
	private class DfsIterator extends GraphIterator {
		public DfsIterator() {
			super();
		}

		public Vertex next() {
			return dfs.get(count++);
		}
	}

	// 广度优先迭代
	private class BfsIterator extends GraphIterator {
		public BfsIterator() {
			super();
		}

		public Object next() {
			return bfs.get(count++);
		}
	}
}
package linkListGraph;

import java.util.Iterator;

public class GraphApp {

	public static void main(String[] args) {
		Graph myGraph = new Graph();
		Vertex vertex;
		myGraph.addVertex(new Vertex('A'));//位置为0
		myGraph.addVertex(new Vertex('B'));//位置为1
		myGraph.addVertex(new Vertex('C'));//位置为2
		myGraph.addVertex(new Vertex('D'));//位置为3
		myGraph.addVertex(new Vertex('E'));//位置为4
		myGraph.addVertex(new Vertex('F'));//位置为5
		myGraph.addVertex(new Vertex('G'));//位置为6
		myGraph.addVertex(new Vertex('H'));//位置为7
		myGraph.addVertex(new Vertex('I'));//位置为8
		myGraph.addVertex(new Vertex('J'));//位置为9
		myGraph.addVertex(new Vertex('K'));//位置为10
		myGraph.addEdge(0, 1);
		myGraph.addEdge(0, 2);
		myGraph.addEdge(0, 3);
		myGraph.addEdge(1, 4);
		myGraph.addEdge(1, 5);
		myGraph.addEdge(3, 7);
		myGraph.addEdge(3, 10);
		myGraph.addEdge(4, 6);
		myGraph.addEdge(5, 6);
		myGraph.addEdge(5, 9);
		myGraph.addEdge(7, 8);
		myGraph.addEdge(8, 10);
		myGraph.displayGraph();
		
		System.out.println("深度优先迭代遍历:");
		for (Iterator iterator = myGraph.dfsIterator(); iterator.hasNext();) {
			vertex = (Vertex) iterator.next();
			System.out.println(vertex.toString());
		}

		System.out.println("广度优先迭代遍历:");
		for (Iterator iterator = myGraph.bfsIterator(); iterator.hasNext();) {
			vertex = (Vertex) iterator.next();
			System.out.println(vertex.toString());
		}
	}
}

 

 

 

package linkListGraph;
import java.util.ArrayList;
/**
 * @ClassName:   Vertex
 * @Description: 顶点类,表示图中存储的顶点
 * @author       zhoupengcheng
 * @version      2015年5月17日下午4:31:54
 */
public class Vertex {
	public char label;
	public boolean wasVisted;
	public int indexId;//顶点的标号
	//由于采用"邻接表"方式表示图,所以每个顶点对象持有一个邻接表adjList
	private ArrayList<Vertex> adjacentList = null;

	public Vertex(char lab) // constructor
	{
		this.label = lab;
		this.wasVisted = false;
	}

	// 为节点添加邻接点
	public void addAdj(Vertex ver) {
		if (adjacentList == null)
			adjacentList = new ArrayList<Vertex>();
		adjacentList.add(ver);
	}

	//返回一个顶点的邻接表,在遍历图时需根据邻接表找下一个节点
	public ArrayList<Vertex> getAdj() {
		return this.adjacentList;
	}

	public void setIndex(int index) {
		this.indexId = index;
	}

	public String toString() {
		return "顶点 :" + label+" ";
	}
}

 

 

 

 

 

 

package linkListGraph;
/*
 * 深度优先遍历需要借助栈保存当前访问过的顶点
 */
public class StackX {
	//private int size=20;
	private Vertex[] stackArray;//用数组实现栈的存储(理论上链栈效率更高)
	private int top;
	public StackX(int size){
		stackArray=new Vertex[size];
		top=-1;
	}

	public Vertex pop(){
		return stackArray[top--];
	}
	
	public Vertex peek(){
		return stackArray[top];
	}
	
	public boolean isEmpty(){
		return top==-1;
	}

	public void push(Vertex vertex) {
		// TODO Auto-generated method stub
		stackArray[++top]=vertex;
	}
}

 

package linkListGraph;
/*
 * 广度优先需要借助队列保存当前已经访问过的顶点
 */
public class Queue {
	private int maxSize=20;
	private int front;//队头指针
	private int rear;//队尾指针
	private Vertex[] queArray;//用数组实现队列的存储(理论上链队列效率更高)

	public Queue(int size) {
		this.maxSize=size;
		queArray = new Vertex[maxSize];
		front = 0;
		rear = -1;
	}

	public void insert(Vertex value) {
		if (rear == maxSize - 1)
			rear = -1;
		queArray[++rear] = value;
	}

	// 返回被删除的元素
	public Vertex remove() {
		if (front == maxSize)
			front = 0;
		Vertex temp = queArray[front++];
		return temp;
	}

	public boolean isEmpty() {
		return (rear+1==front||(front+maxSize-1==rear));
	}
}

 

 

 

 

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程猿薇茑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值