java数据结构之图

图是一种很复杂的数据结构,为了描述图创造了邻接矩阵的方式来描述它,图和树不一样,构建图,首先必须要有节点,然而树的根节点可以为空,构建图需要先将图描述起来

1.图的节点个数

2.图的节点矩阵

3.图的邻接矩阵

构建一个图

/*
 * 1.图的构成(顶点数量,顶点数组,顶点的邻接矩阵)
 * 2.图的遍历
 * 深度优先遍历和广度优先遍历
 * 深度优先算法:类似于树的前序遍历,一个布尔型数组存储是否已经遍历过,然后根据第一个节点不断地寻找他的下一个邻接节点,找到它的下一个邻接节点后在将起始节点换为它的邻接节点的下一个节点
 * 广度优先算法:类似于树的层序遍历,用一个队列来保存它的所有邻接节点,然后不断的根据他邻接节点的下一个节点来继续遍历它的下下个邻接节点
 * 3.图的最小生成树,普林姆算法,克鲁斯卡尔算法,迪杰斯特拉算法
 * 普林姆算法:精髓在于他有两个数组,一个数组用来存放当前情况下的最优解,然后根据当前情况下的最优数组找到最小值,置为0,遍历完及找到它的最优路径权值
 * 克鲁斯卡尔算法:将图存放为,起始顶点   终止顶点  和权值的数组,通过不断删除回环路径来确定最优解
 * 迪杰斯特拉算法:
 */
public class Graph{
	private int verterSize;//顶点数量
	private int[] verterArray;//顶点数组
	private int[][] materix;//邻接矩阵
	private boolean[] isvisited;
	//private int[][] matrix;
	public static final int MAX_WEIGHT=1000;
	
	public int getVerterSize() {
		return verterSize;
	}
	public void setVerterSize(int verterSize) {
		this.verterSize = verterSize;
	}
	public int[] getVerterArray() {
		return verterArray;
	}
	public void setVerterArray(int[] verterArray) {
		this.verterArray = verterArray;
	}
	public int[][] getMaterix() {
		return materix;
	}
	public void setMaterix(int[][] materix) {
		this.materix = materix;
	}
	public boolean[] getIsvisited() {
		return isvisited;
	}
	public void setIsvisited(boolean[] isvisited) {
		this.isvisited = isvisited;
	}
	public static int getMaxWeight() {
		return MAX_WEIGHT;
	}
	public Graph(int verterSize)
	{
		this.verterSize=verterSize;
		this.verterArray=new int[verterSize];
		this.materix=new int[verterSize][verterSize];
	}
public void creatGraph()
	{
		this.verterSize=9;
		this.verterArray= new int[]{0,1,2,3,4,5,6,7,8};
		this.materix[0]=new int[] {0,10,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,11,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT};
		                         //0,10,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,11,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT
		this.materix[1]=new int[] {10,0,18,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,16,MAX_WEIGHT,12};
		                         //10,0,18,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,16,MAX_WEIGHT,12
		this.materix[2]=new int[] {MAX_WEIGHT,MAX_WEIGHT,0,22,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,8};
		                         //MAX_WEIGHT,MAX_WEIGHT,0,22,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,8
		this.materix[3]=new int[] {MAX_WEIGHT,MAX_WEIGHT,22,0,20,MAX_WEIGHT,MAX_WEIGHT,16,21};
		                         //MAX_WEIGHT,MAX_WEIGHT,22,0,20,MAX_WEIGHT,MAX_WEIGHT,16,21
		this.materix[4]=new int[] {MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,20,0,26,MAX_WEIGHT,7,MAX_WEIGHT};
		                         //MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,20,0,26,MAX_WEIGHT,7,MAX_WEIGHT
		this.materix[5]=new int[] {11,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,26,0,17,MAX_WEIGHT,MAX_WEIGHT};
		                          //11,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,26,0,17,MAX_WEIGHT,MAX_WEIGHT
		this.materix[6]=new int[] {MAX_WEIGHT,16,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,17,0,19,MAX_WEIGHT};
		                          //MAX_WEIGHT,16,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,17,0,19,MAX_WEIGHT
		this.materix[7]=new int[] {MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,16,7,MAX_WEIGHT,19,0,MAX_WEIGHT};
		                          //MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,16,7,MAX_WEIGHT,19,0,MAX_WEIGHT
		this.materix[8]=new int[] {MAX_WEIGHT,12,8,21,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,0};
		                          //MAX_WEIGHT,12,8,21,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,0
	}

图的深度优先遍历和广度优先遍历

//获取两个顶点之间的权值
	public int getWeight(int pos1,int pos2)
	{
		return this.matrix[pos1][pos2];
	}
	//插入一个顶点
	//删除一个顶点
	//图的深度优先遍历
	/*
	 * 获取某个顶点的第一个邻结点
	 * (给定一个index,通过index在矩阵中行遍历,返回它的第一个邻节点)
	 */
	//知道节点找他的第一个邻节点
	public int getFirstNeighbor(int index)
	{
		for(int j=0;j<verterSize;j++)
		{
			if(matrix[index][j]>0&&matrix[index][j]<MAX_WEIGHT)
			{
				return j;
			}
		}
		return -1;
	}
	/*
	 * 根据前一个邻节点下标来确定下一个邻结点
	 * (给定一个节点,和它的第一个邻节点,通过节点遍历找到,它的下一个邻节点)
	 * v1表示要找到顶点
	 * v2表示该顶点对应哪个邻结点
	 */
	//知道节点与第一个邻节点找下一个邻节点
	public int getNextNeighbor(int v,int index)
	{
		for(int j=index+1;j<verterSize;j++)
		{
			if(matrix[v][j]>0&&matrix[v][j]<MAX_WEIGHT)
			{
				return j;
			}
		}
		return -1;
	}
	/*
	 * 图的深度优先遍历(DFS)
	 */
	private void depthFirstSerch(int i)
	{
		isvisited[i]=true;//表示已经被遍历了
		int w=getFirstNeighbor(i);//拿到它的第一个邻节节点
		while(w!=-1)
		{
			if(!isvisited[w])
			{
				//需要遍历该节点
				System.out.println("访问到:"+w+"顶点");
				depthFirstSerch(w);
			}
			w=getNextNeighbor(i,w);//第一个相对于W的邻接节点
		}
	}
	/*
	 * 深度优先遍历
	 * 如果图是有向图,那么A有些地方它会到不了
	 */
	public void depthFirstSerch()
	{
		isvisited=new boolean[this.verterSize];
		for(int i=0;i<verterSize;i++)
		{
			if(!isvisited[i])
			{
				depthFirstSerch(i);
			}
		}
	}
	/*
	 * 图的广度优先算法(BFS)
	 * 类比树的层序
	 */
	//防止它非连通
	 public void broadFirstSerch()
	 {
		isvisited=new boolean[verterSize];
		for(int i=0;i<verterSize;i++)
		{
			if(!isvisited[i])
			{
				broadFirstSerch(i);
			}
		}
	 }
	private void broadFirstSerch(int i)
	{
		int u,w;
		LinkedList<Integer> queue=new LinkedList<Integer>();
		System.out.println("访问到:"+i+"顶点");
		isvisited[i]=true;
		queue.add(i);
		while(!queue.isEmpty())
		{
			u=(Integer)(queue.removeFirst()).intValue();
			w=getFirstNeighbor(u);
			while(w!=-1)
			{
				System.out.println("访问到:"+w+"顶点");
				isvisited[w]=true;
				queue.addLast(w);
			}
			w=getNextNeighbor(u, w);
		}
	}

图的最小生成树算法(普林姆算法和克鲁斯卡尔算法)

//普林姆算法

//图的最小生成树
	//普林母算法
	public void prim()
	{
		int [] lowcost=new int[verterSize];//最小代价顶点权值的数组,为0表示已经找到
		int []  adjvex=new int[verterSize];//放顶点权值
		int min,minID,sum=0;
		for(int i=1;i<verterSize;i++)
		{
			lowcost[i]=matrix[0][i];
		}
		for(int i=1;i<verterSize;i++)//每次只能拿一个,所以需要verterSize次
		{
			min=MAX_WEIGHT;
			minID=0;
			for(int j=1;j<verterSize;j++)//找到当前lowcost数组中最小的一个顶点
			{
				if(lowcost[j]<min&&lowcost[j]>0)
				{
					min=lowcost[j];
					minID=j;
				}
			}
			System.out.println("顶点:"+adjvex[minID]+"权值"+min);//此时minID指向最小的那个位置
			sum+=min;
			lowcost[minID]=0;//将这个顶点置为零
			for(int j=1;j<verterSize;j++)//把当前lowcost的值与minID这一列的值相比较,小的放进locast
			{
				if(matrix[minID][j]<lowcost[j]&&lowcost[j]!=0)
				{
					lowcost[j]=matrix[minID][j];
					adjvex[j]=minID;
				}
			}
		}
	}

克鲁斯卡尔算法

public class GraphKruskal {
	private Edge[]  edges;
	private int edgSize;
	public GraphKruskal(int edgSize)
	{
		this.edgSize=edgSize;
		this.edges=new Edge[edgSize];
	}
	class Edge
	{
		private int begin;
		private int end;
		private int weight;
		public Edge(int begin,int end,int weight)
		{
			this.begin=begin;
			this.end=end;
			this.weight=weight;
		}
	}
	public void creatEdgeArray()
	{
		Edge edge0=new Edge(4,7,7);
		Edge edge1=new Edge(2,8,8);
		Edge edge2=new Edge(0,1,10);
		Edge edge3=new Edge(0,5,11);
		Edge edge4=new Edge(1,8,12);
		Edge edge5=new Edge(3,7,16);
		Edge edge6=new Edge(1,6,16);
		Edge edge7=new Edge(5,6,17);
		Edge edge8=new Edge(1,2,18);
		Edge edge9=new Edge(6,7,19);
		Edge edge10=new Edge(3,4,20);
		Edge edge11=new Edge(3,8,21);
		Edge edge12=new Edge(2,3,22);
		Edge edge13=new Edge(3,6,24);
		Edge edge14=new Edge(4,5,26);
		edges[0]=edge0;
		edges[1]=edge1;
		edges[2]=edge2;
		edges[3]=edge3;
		edges[4]=edge4;
		edges[5]=edge5;
		edges[6]=edge6;
		edges[7]=edge7;
		edges[8]=edge8;
		edges[9]=edge9;
		edges[10]=edge10;
		edges[11]=edge11;
		edges[12]=edge12;
		edges[13]=edge13;
		edges[14]=edge14;
	}
	public void miniSpanTreeKurskal()
	{
		int m,n,sum=0;
		int[] parent=new int[edgSize];//以数组的下标为起点,值为终点
		for(int i=0;i<edgSize;i++)
		{
			parent[i]=0;//将数组初始化n 
		}
		for(int i=0;i<edgSize;i++)
		{
			n=find(parent,edges[i].begin);
			m=find(parent,edges[i].end);
			System.out.println("n的值为:"+n+"  m的值为:"+m);
			if(n!=m)
			{
				parent[n]=m;	
				System.out.println("起始顶点:"+edges[i].begin+"     结束顶点"+edges[i].end);
				sum+=edges[i].weight;
			}
		}
		System.out.println(sum);
	}
	/*
	 * 将parent数组进行查询获取非回环的值
	 */
	private int find(int[] parent, int f) {
		while(parent[f]>0)//当前位置有值
		{
			f=parent[f];
		}
		return f;
	}
	public static void main(String[] args)
	{
		GraphKruskal graphKruskal=new GraphKruskal(15);
		graphKruskal.creatEdgeArray();
		graphKruskal.miniSpanTreeKurskal();
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值