图
- 实现有向图、无向图、有权图、无权图的邻接矩阵和邻接表表示方法
- 实现图的深度优先搜索、广度优先搜索
- 实现 Dijkstra 算法
图结构
public interface Graph<E> {
int getNumOfVertex();
boolean insertVex(E v);
boolean deleteVex(E v);
int indexOfVex(E v);
E valueOfVex(int v);
boolean insertEdge(int v1, int v2, int weight);
boolean deleteEdge(int v1, int v2);
int getEdge(int v1, int v2);
String depthFirstSearch(int v);
String breadFirstSearch(int v);
public int[] dijkstra(int v);
}
邻接矩阵
package graph;
import java.lang.reflect.Array;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;
public class GraphAdjMatrix<E> implements Graph<E> {
private E[] vexs;
private int[][] edges;
private int numOfVexs;
private int maxNumOfVexs;
private boolean[] visited;
@SuppressWarnings("unchecked")
public GraphAdjMatrix(int maxNumOfVexs, Class<E> type) {
this.maxNumOfVexs = maxNumOfVexs;
edges = new int[maxNumOfVexs][maxNumOfVexs];
vexs = (E[]) Array.newInstance(type, maxNumOfVexs);
}
public int getNumOfVertex() {
return numOfVexs;
}
public boolean insertVex(E v) {
if (numOfVexs >= maxNumOfVexs)
return false;
vexs[numOfVexs++] = v;
return true;
}
public boolean deleteVex(E v) {
for (int i = 0; i < numOfVexs; i++) {
if (vexs[i].equals(v)) {
for (int j = i; j < numOfVexs - 1; j++) {
vexs[j] = vexs[j + 1];
}
vexs[numOfVexs - 1] = null;
for (int col = i; col < numOfVexs - 1; col++) {
for (int row = 0; row < numOfVexs; row++) {
edges[col][row] = edges[col + 1][row];
}
}
for (int row = i; row < numOfVexs - 1; row++) {
for (int col = 0; col < numOfVexs; col++) {
edges[col][row] = edges[col][row + 1];
}
}
numOfVexs--;
return true;
}
}
return false;
}
public int indexOfVex(E v) {
for (int i = 0; i < numOfVexs; i++) {
if (vexs[i].equals(v)) {
return i;
}
}
return -1;
}
public E valueOfVex(int v) {
if (v < 0 || v >= numOfVexs)
return null;
return vexs[v];
}
public boolean insertEdge(int v1, int v2, int weight) {
if (v1 < 0 || v2 < 0 || v1 >= numOfVexs || v2 >= numOfVexs)
throw new ArrayIndexOutOfBoundsException();
edges[v1][v2] = weight;
edges[v2][v1] = weight;
return true;
}
public boolean deleteEdge(int v1, int v2) {
if (v1 < 0 || v2 < 0 || v1 >= numOfVexs || v2 >= numOfVexs)
throw new ArrayIndexOutOfBoundsException();
edges[v1][v2] = 0;
edges[v2][v1] = 0;
return true;
}
public int getEdge(int v1, int v2) {
if (v1 < 0 || v2 < 0 || v1 >= numOfVexs || v2 >= numOfVexs)
throw new ArrayIndexOutOfBoundsException();
return edges[v1][v2];
}
@Override
public String depthFirstSearch(int v) {
if (v < 0 || v >= numOfVexs)
throw new ArrayIndexOutOfBoundsException();
visited = new boolean[numOfVexs];
StringBuilder sb = new StringBuilder();
Stack<Integer> stack = new Stack<Integer>();
stack.push(v);
visited[v] = true;
while (!stack.isEmpty()) {
v = stack.pop();
sb.append(vexs[v] + ",");
for (int i = numOfVexs - 1; i >= 0; i--) {
if ((edges[v][i] != 0 && edges[v][i] != Integer.MAX_VALUE)
&& !visited[i]) {
stack.push(i);
visited[i] = true;
}
}
}
return sb.length() > 0 ? sb.substring(0, sb.length() - 1) : null;
}
@Override
public String breadFirstSearch(int v) {
if (v < 0 || v >= numOfVexs)
throw new ArrayIndexOutOfBoundsException();
visited = new boolean[numOfVexs];
StringBuilder sb = new StringBuilder();
Queue<Integer> queue = new LinkedList<Integer>();
queue.offer(v);
visited[v] = true;
while (!queue.isEmpty()) {
v = queue.poll();
sb.append(vexs[v] + ",");
for (int i = 0; i < numOfVexs; i++) {
if ((edges[v][i] != 0 && edges[v][i] != Integer.MAX_VALUE)
&& !visited[i]) {
queue.offer(i);
visited[i] = true;
}
}
}
return sb.length() > 0 ? sb.substring(0, sb.length() - 1) : null;
}
@Override
public int[] dijkstra(int v) {
if (v < 0 || v >= numOfVexs)
throw new ArrayIndexOutOfBoundsException();
boolean[] st = new boolean[numOfVexs];
int[] distance = new int[numOfVexs];
for (int i = 0; i < numOfVexs; i++)
for (int j = i + 1; j < numOfVexs; j++) {
if (edges[i][j] == 0) {
edges[i][j] = Integer.MAX_VALUE;
edges[j][i] = Integer.MAX_VALUE;
}
}
for (int i = 0; i < numOfVexs; i++) {
distance[i] = edges[v][i];
}
st[v] = true;
for (int i = 0; i < numOfVexs; ++i) {
int min = Integer.MAX_VALUE;
int index=-1;
for (int j = 0; j < numOfVexs; ++j) {
if (st[j]==false) {
if (distance[j] < min) {
index = j;
min = distance[j];
}
}
}
if(index!=-1)
st[index] = true;
for (int w = 0; w < numOfVexs; w++)
if (st[w] == false) {
if (edges[index][w] != Integer.MAX_VALUE
&& (min + edges[index][w] < distance[w]))
distance[w] = min + edges[index][w];
}
}
return distance;
}
}
邻接表
package graph;
import java.lang.reflect.Array;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;
public class GraphAdjList<E> implements Graph<E> {
private static class ENode {
int adjvex;
int weight;
ENode nextadj;
public ENode(int adjvex, int weight) {
this.adjvex = adjvex;
this.weight = weight;
}
}
private static class VNode<E> {
E data;
ENode firstadj;
}
;
private VNode<E>[] vexs;
private int numOfVexs;
private int maxNumOfVexs;
private boolean[] visited;
@SuppressWarnings("unchecked")
public GraphAdjList(int maxNumOfVexs) {
this.maxNumOfVexs = maxNumOfVexs;
vexs = (VNode<E>[]) Array.newInstance(VNode.class, maxNumOfVexs);
}
public int getNumOfVertex() {
return numOfVexs;
}
public boolean insertVex(E v) {
if (numOfVexs >= maxNumOfVexs)
return false;
VNode<E> vex = new VNode<E>();
vex.data = v;
vexs[numOfVexs++] = vex;
return true;
}
public boolean deleteVex(E v) {
for (int i = 0; i < numOfVexs; i++) {
if (vexs[i].data.equals(v)) {
for (int j = i; j < numOfVexs - 1; j++) {
vexs[j] = vexs[j + 1];
}
vexs[numOfVexs - 1] = null;
numOfVexs--;
ENode current;
ENode previous;
for (int j = 0; j < numOfVexs; j++) {
if (vexs[j].firstadj == null)
continue;
if (vexs[j].firstadj.adjvex == i) {
vexs[j].firstadj = null;
continue;
}
current = vexs[j].firstadj;
while (current != null) {
previous = current;
current = current.nextadj;
if (current != null && current.adjvex == i) {
previous.nextadj = current.nextadj;
break;
}
}
}
for (int j = 0; j < numOfVexs; j++) {
current = vexs[j].firstadj;
while (current != null) {
if (current.adjvex > i)
current.adjvex--;
current = current.nextadj;
}
}
return true;
}
}
return false;
}
public int indexOfVex(E v) {
for (int i = 0; i < numOfVexs; i++) {
if (vexs[i].data.equals(v)) {
return i;
}
}
return -1;
}
public E valueOfVex(int v) {
if (v < 0 || v >= numOfVexs)
return null;
return vexs[v].data;
}
public boolean insertEdge(int v1, int v2, int weight) {
if (v1 < 0 || v2 < 0 || v1 >= numOfVexs || v2 >= numOfVexs)
throw new ArrayIndexOutOfBoundsException();
ENode vex1 = new ENode(v2, weight);
if (vexs[v1].firstadj == null) {
vexs[v1].firstadj = vex1;
}
else {
vex1.nextadj = vexs[v1].firstadj;
vexs[v1].firstadj = vex1;
}
ENode vex2 = new ENode(v1, weight);
if (vexs[v2].firstadj == null) {
vexs[v2].firstadj = vex2;
}
else {
vex2.nextadj = vexs[v2].firstadj;
vexs[v2].firstadj = vex2;
}
return true;
}
public boolean deleteEdge(int v1, int v2) {
if (v1 < 0 || v2 < 0 || v1 >= numOfVexs || v2 >= numOfVexs)
throw new ArrayIndexOutOfBoundsException();
ENode current = vexs[v1].firstadj;
ENode previous = null;
while (current != null && current.adjvex != v2) {
previous = current;
current = current.nextadj;
}
if (current != null)
previous.nextadj = current.nextadj;
current = vexs[v2].firstadj;
while (current != null && current.adjvex != v1) {
previous = current;
current = current.nextadj;
}
if (current != null)
previous.nextadj = current.nextadj;
return true;
}
public int getEdge(int v1, int v2) {
if (v1 < 0 || v2 < 0 || v1 >= numOfVexs || v2 >= numOfVexs)
throw new ArrayIndexOutOfBoundsException();
ENode current = vexs[v1].firstadj;
while (current != null) {
if (current.adjvex == v2) {
return current.weight;
}
current = current.nextadj;
}
return 0;
}
public String depthFirstSearch(int v) {
if (v < 0 || v >= numOfVexs)
throw new ArrayIndexOutOfBoundsException();
visited = new boolean[numOfVexs];
StringBuilder sb = new StringBuilder();
Stack<Integer> stack = new Stack<Integer>();
stack.push(v);
visited[v] = true;
ENode current;
while (!stack.isEmpty()) {
v = stack.pop();
sb.append(vexs[v].data + ",");
current = vexs[v].firstadj;
while (current != null) {
if (!visited[current.adjvex]) {
stack.push(current.adjvex);
visited[current.adjvex] = true;
}
current = current.nextadj;
}
}
return sb.length() > 0 ? sb.substring(0, sb.length() - 1) : null;
}
public String breadFirstSearch(int v) {
if (v < 0 || v >= numOfVexs)
throw new ArrayIndexOutOfBoundsException();
visited = new boolean[numOfVexs];
StringBuilder sb = new StringBuilder();
Queue<Integer> queue = new LinkedList<Integer>();
queue.offer(v);
visited[v] = true;
ENode current;
while (!queue.isEmpty()) {
v = queue.poll();
sb.append(vexs[v].data + ",");
current = vexs[v].firstadj;
while (current != null) {
if (!visited[current.adjvex]) {
queue.offer(current.adjvex);
visited[current.adjvex] = true;
}
current = current.nextadj;
}
}
return sb.length() > 0 ? sb.substring(0, sb.length() - 1) : null;
}
public int[] dijkstra(int v) {
if (v < 0 || v >= numOfVexs)
throw new ArrayIndexOutOfBoundsException();
boolean[] st = new boolean[numOfVexs];
int[] distance = new int[numOfVexs];
for (int i = 0; i < numOfVexs; i++) {
distance[i] = Integer.MAX_VALUE;
}
ENode current;
current = vexs[v].firstadj;
while (current != null) {
distance[current.adjvex] = current.weight;
current = current.nextadj;
}
distance[v] = 0;
st[v] = true;
for (int i = 0; i < numOfVexs; i++) {
int min = Integer.MAX_VALUE;
int index = -1;
for (int j = 0; j < numOfVexs; j++) {
if (st[j] == false) {
if (distance[j] < min) {
index = j;
min = distance[j];
}
}
}
if (index != -1)
st[index] = true;
for (int w = 0; w < numOfVexs; w++)
if (st[w] == false) {
current = vexs[w].firstadj;
while (current != null) {
if (current.adjvex == index)
if ((min + current.weight) < distance[w]) {
distance[w] = min + current.weight;
break;
}
current = current.nextadj;
}
}
}
return distance;
}
}
- A* 算法
- 实现拓扑排序的 Kahn 算法、DFS 算法
- 对应的 LeetCode 练习题
- Number of Islands(岛屿的个数)