JAVA数据结构基础--图的两种创建方式

JAVA数据结构基础–图的两种创建方式

图的邻接矩阵表示在这里插入图片描述
如图示一个有向图转为矩阵表示的例子(矩阵中空格表示无穷大,即无路径到达)。矩阵的行表示起始点,列表示终止点。对角线元素表示自己到自己,全为0。
图左侧的权值(道路长度)为1的路径,由1出发,指向0。在矩阵中表示为Edge[1][0]=1;表示1到0路径长度为1
在这里插入图片描述

以下我分析的是无向图的矩阵表示代码,若改成有向图,改动插入边的函数即可。

完整代码

import java.util.LinkedList;
import java.util.Queue;

public class Graph {
	private String[] Vertex;// 存储顶点名字
	private int[][] Edge;// 存储边信息
	private int numOfVertex;// 顶点个数
	private int maxOfVertex;// 最大顶点个数
	private int MAX = Integer.MAX_VALUE / 2;//无穷大表示值

	public Graph(int maxOfVertex) {//构造函数
		numOfVertex = 0;
		this.maxOfVertex = maxOfVertex;
		Vertex = new String[maxOfVertex];
		Edge = new int[maxOfVertex][maxOfVertex];

		inti(maxOfVertex);
	}

	public void inti(int maxOfVertex) {//初始化
		maxOfVertex = this.maxOfVertex;
		for (int i = 0; i < maxOfVertex; i++) {
			for (int j = 0; j < maxOfVertex; j++) {
				if (i != j) {
					Edge[i][j] = MAX;
				} else {
					Edge[i][j] = 0;
				}
			}
		}
	}

	public int getNumOfVertex() {// 获取顶点个数
		return numOfVertex;
	}

	public boolean insertVertex(String name) {// 插入顶点
		if (numOfVertex >= maxOfVertex) {
			return false;
		}
		Vertex[numOfVertex++] = name;
		return true;
	}

	public boolean insertEdge(String v1, String v2, int weight) {// 插入边
		int v_1 = findByName(v1);
		int v_2 = findByName(v2);

		if (v_1 < 0 || v_2 < 0) {
			return false;
		}

		Edge[v_1][v_2] = weight;
		Edge[v_2][v_1] = weight;

		return true;
	}

	public int getWeight(int s, int e) {//获得权重,即道路长度
		return Edge[s][e];
	}

	public int findByName(String name) {// 通过名字查找下标
		for (int i = 0; i < numOfVertex; i++) {
			if (Vertex[i].equals(name)) {
				return i;
			}
		}
		return -1;
	}

	public boolean deleteVertex(String name) {// 删除顶点
		int v = findByName(name);

		if (v < 0) {
			return false;
		}

		Vertex[v] = Vertex[numOfVertex - 1];

		for (int i = 0; i < numOfVertex; i++) {
			Edge[v][i] = Edge[numOfVertex - 1][i];
			Edge[i][v] = Edge[i][numOfVertex - 1];
			Edge[numOfVertex - 1][i] = MAX;
			Edge[i][numOfVertex - 1] = MAX;
		}

		Vertex[--numOfVertex] = null;

		return true;
	}

	public boolean deleteEdge(String v1, String v2) {// 删除边
		int v_1 = findByName(v1);
		int v_2 = findByName(v2);

		if (v_1 < 0 || v_2 < 0) {
			return false;
		}

		Edge[v_1][v_2] = MAX;
		Edge[v_2][v_1] = MAX;

		return true;
	}

	public int getEdge(String v1, String v2) {//获取权重
		int v_1 = findByName(v1);
		int v_2 = findByName(v2);
		if (v_1 < 0 ||v_2 < 0) {
			return -1;
		}
		return Edge[v_1][v_2];
	}
}

函数解析

一、图类结构

public class Graph {
	private String[] Vertex;// 存储顶点名字
	private int[][] Edge;// 存储边信息
	private int numOfVertex;// 顶点个数
	private int maxOfVertex;// 最大顶点个数
	private int MAX = Integer.MAX_VALUE / 2;//无穷大表示值
	}

一、Vertex数组:存储图顶点的名字,下标与名字一 一对应;
二、Edge二维数组:图的表示矩阵,即上面图片中矩阵的实例;
三、maxOfVertex:添加顶点总和的最大值;
四、numOfVertex:当前已顶点的个数;
五、MAX:表示无穷大,代表两顶点不通。(这里取整数最大值的一半);

二、初始化:


	public void inti(int maxOfVertex) {//初始化
		maxOfVertex = this.maxOfVertex;
		for (int i = 0; i < maxOfVertex; i++) {
			for (int j = 0; j < maxOfVertex; j++) {
				if (i != j) {
					Edge[i][j] = MAX;
				} else {
					Edge[i][j] = 0;
				}
			}
		}
	}

当i!=j时,Edge[i][j]=MAX;(在未添加边时,所有顶点都不通)
当i==j时,Edge[i][j]=0;(自己到自己距离为0)

三、插入顶点:

public boolean insertVertex(String name) {// 插入顶点
		if (numOfVertex >= maxOfVertex) {
			return false;
		}
		Vertex[numOfVertex++] = name;
		return true;
	}

一、 if (numOfVertex >= maxOfVertex):判断当前已添加顶点是否达到最大值。

二、Vertex[numOfVertex++] = name:Vertex数组的第numOfVertex个存入该顶点名字。(该顶点名字与顶点下标存在关联)

四、通过顶点名字找下标:

	public int findByName(String name) {// 通过名字查找下标
		for (int i = 0; i < numOfVertex; i++) {
			if (Vertex[i].equals(name)) {
				return i;
			}
		}
		return -1;
	}

循环次数为已添加顶点个数,即每个顶点依次遍历寻找。
若Vertex数组中存储的顶点信息匹配,返回下标值。

五、插入边

	public boolean insertEdge(String v1, String v2, int weight) {// 插入边
		int v_1 = findByName(v1);
		int v_2 = findByName(v2);

		if (v_1 < 0 || v_2 < 0) {
			return false;
		}

		Edge[v_1][v_2] = weight;
		Edge[v_2][v_1] = weight;

		return true;
	}

一、 先找到俩顶点的下标。
二、if (v_1 < 0 || v_2 < 0):若不存在两个顶点,返回false;
三、改变表示矩阵中的值。(这里是表示无向图,改变两处。有向图改变一处)
Edge[v_1][v_2] = weight;
Edge[v_2][v_1] = weight;

六、删除顶点:

public boolean deleteVertex(String name) {// 删除顶点
		int v = findByName(name);

		if (v < 0) {
			return false;
		}

		Vertex[v] = Vertex[numOfVertex - 1];

		for (int i = 0; i < numOfVertex; i++) {
			Edge[v][i] = Edge[numOfVertex - 1][i];
			Edge[i][v] = Edge[i][numOfVertex - 1];
			Edge[numOfVertex - 1][i] = MAX;
			Edge[i][numOfVertex - 1] = MAX;
		}

		Vertex[--numOfVertex] = null;

		return true;
	}

图例示范:
在这里插入图片描述
七、删除边

	public boolean deleteEdge(String v1, String v2) {// 删除边
		int v_1 = findByName(v1);
		int v_2 = findByName(v2);

		if (v_1 < 0 || v_2 < 0) {
			return false;
		}

		Edge[v_1][v_2] = MAX;
		Edge[v_2][v_1] = MAX;

		return true;
	}

一、先判断顶点是否存在
二、将表示矩阵中【v1到v2】和【v2到v1】的地方改为MAX。

图的邻接表表示:

在这里插入图片描述
链表存储可以只存出存在的边,节约了空间。

完整代码:

import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;

public class Graph {

	class Vertex {// 顶点
		protected String name;//顶点名

		Vertex(String N) {
			name = N;
		}
	}

	class Edge {// 边
		protected Vertex Start;// 起始边
		protected Vertex End;// 结束边
		private int weight;// 权重

		Edge(Vertex S, Vertex E, int W) {
			Start = S;
			End = E;
			weight = W;
		}

		protected int getWeight() {
			return weight;
		}
		
		protected Vertex getStart() {
			return Start;
		}
		
		protected Vertex getEnd() {
			return End;
		}
	}

	int maxSize;//最大顶点数
	int numVertex;//当前顶点个数
	int numEdge;//边个数
	Vertex vertex[]; //顶点信息集
	public LinkedList<Edge>[] Edges;//存放顶点相邻边链表的数组


	Graph(int maxSize) {//构造函数
		this.maxSize = maxSize;
		numVertex = 0;
		numEdge = 0;
		Edges = new LinkedList[maxSize+1];
		vertex = new Vertex[maxSize+1];
		for(int i=0;i<maxSize+1;i++){
			Edges[i]=new LinkedList();
		}
	}

	public boolean addEdge(String start, String end, int W) {//添加边
		if(findNum(start)<0||findNum(end)<0) {
			return false;
		}
		Vertex S = vertex[findNum(start)];
		Vertex E = vertex[findNum(end)];
		
		numEdge++;
		Edge edge = new Edge(S, E, W);
		Edges[findNum(S.name)].add(edge);
		return true;
	}

	public void addvertex(String name) {
		Vertex vertexs = new Vertex(name);
		vertex[numVertex] = vertexs;
		numVertex++;
	}

	public int findWeight(String v1, String v2) {
		int v_1 = findNum(v1);
		int v_2 = findNum(v2);
		if(v_1<0||v_2<0) {
			return -1;
		}
		for (int i = 0; i < Edges[v_1].size(); i++) {
			if (findNum(Edges[v_1].get(i).End.name) == v_2) {
				return Edges[v_1].get(i).getWeight();
			}
		}
		return Integer.MAX_VALUE/2;
	}
	
	private int findNum(String name) {
		for(int i=0;i<numVertex;i++) {
			if(name.equals(vertex[i].name)) {
				return i;
			}
		}
		return -1;
	}
	
	public boolean deleteVertex(String name) {
		if(numVertex >= maxSize) {
			return false;
		}
		int v = findNum(name);
		
		vertex[v] = vertex[--numVertex];
		vertex[numVertex] = vertex[maxSize];
		
		Edges[v] = Edges[numVertex];
		Edges[numVertex] = Edges[maxSize];
		
		
		return true;
	}
	
	public boolean deleteEdge(String v1,String v2) {
		int v_1 = findNum(v1);
		int v_2 = findNum(v2);
		int i=0;
		while(findNum(Edges[v_1].get(i).getEnd().name)!=v_2){
			i++;
		}
		Edges[v_1].remove(i);
		numEdge--;
		return true;
	}
	
	
}

代码解析

三个类,图类,边类,定点类。

	class Vertex {// 顶点类
		protected String name;//存储顶点名,
		//与矩阵表示不同,改为顶点类与顶点数组下标对应
		
		Vertex(String N) {//构造函数,赋值顶点名字
			name = N;
		}
	}

	class Edge {// 边类
		protected Vertex Start;// 起始边
		protected Vertex End;// 结束边
		private int weight;// 权重

		Edge(Vertex S, Vertex E, int W) {
			Start = S;//起始顶点
			End = E;//结束顶点
			weight = W;//权重
		}
	}



public class Graph {
	int maxSize;//最大顶点数
	int numVertex;//当前顶点个数
	int numEdge;//边个数
	Vertex vertex[]; //顶点信息集
	public LinkedList<Edge>[] Edges;//存放顶点相邻边链表的数组
	}

LinkedList[] Edges:
首先它是一个数组,存储链表。而每个链表存储的都是边。(详细看边的添加)

构造函数:

Graph(int maxSize) {//构造函数
		this.maxSize = maxSize;
		numVertex = 0;
		numEdge = 0;
		Edges = new LinkedList[maxSize+1];
		vertex = new Vertex[maxSize+1];
		for(int i=0;i<maxSize+1;i++){//省略这步会出现空指针异常
			Edges[i]=new LinkedList();
		}
	}

初始化为maxSize+1的原因是,在删除边和顶点的时候,将删除顶点赋值为最后一个空的数组即可。避免了直接复制null产生空指针的问题。

通过名字寻找顶点下标

	private int findNum(String name) {
		for(int i=0;i<numVertex;i++) {
			if(name.equals(vertex[i].name)) {//与顶点数组中name属性配对返回下标
				return i;
			}
		}
		return -1;
	}

添加顶点

	public void addvertex(String name) {
		Vertex vertexs = new Vertex(name);//new一个顶点对象
		vertex[numVertex] = vertexs;//将顶点集的最后一个未赋值的赋值为新建的对象
		numVertex++;//当前顶点个数加一
	}

添加边

	public boolean addEdge(String start, String end, int W) {//添加边
		if(findNum(start)<0||findNum(end)<0) {//判断顶点是否存在
			return false;
		}
		Vertex S = vertex[findNum(start)];//获取顶点信息
		Vertex E = vertex[findNum(end)];
		
		numEdge++;//边数+1
		Edge edge = new Edge(S, E, W);//new一个边对象
		Edges[findNum(S.name)].add(edge);
		return true;
	}

Edges[findNum(S.name)].add(edge):
举个例子,0到1有条边,则为Edges[0].add(边对象);
即Edge下标对应起始顶点。Edge[1]存放所有以1为起始顶点的边。
Edge[]的是链表的数组,用add()函数添加边对象。

删除边

	public boolean deleteVertex(String name) {
		if(numVertex >= maxSize) {
			return false;
		}
		int v = findNum(name);
		
		vertex[v] = vertex[--numVertex];//将最后一个存在的顶点移动至删除顶点位置
		vertex[numVertex] = vertex[maxSize];//将移动结点赋值为空
		
		Edges[v] = Edges[numVertex];//顶点与顶点数组下标对应,边集也是如此
		Edges[numVertex] = Edges[maxSize];
		
		
		return true;
	}

删除边

	public boolean deleteEdge(String v1,String v2) {
		int v_1 = findNum(v1);
		int v_2 = findNum(v2);
		int i=0;
		while(findNum(Edges[v_1].get(i).getEnd().name)!=v_2){
			i++;
		}
		Edges[v_1].remove(i);//找到此边,删除
		numEdge--;//边条数减一
		return true;
	}

一、findNum(Edges[v_1].get(i).getEnd().name:
得到以v1为起始点的边,并获取此边结束顶点的顶点名字。
二、若头匹配,尾巴不匹配,i++,继续匹配下一条以v1为起始点的边。
直到匹配成功,退出while循环,得到下标边对应索引后删除此边。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值