搜索树的定义
/** SearchTree类 */
public class SearchTree {
private int root; // The root of the tree
private int[] parent; // Store the parent of each vertex 存储每个顶点的父对象 存储对应的边
private List<Integer> searchOrder; // Store the search order 存储搜索顺序
/** Construct a tree with root, parent, and searchOrder */
public SearchTree(int root, int[] parent, List<Integer> searchOrder){
this.root = root;
this.parent = parent;
this.searchOrder = searchOrder;
}
/** Return the root of the tree */
public int getRoot(){
return root;
}
/** Return the parent of vertex v */
public int getParent(int v){
return parent[v];
}
/** Return an array representing search order */
public List<Integer> getSearchOrder(){
return searchOrder;
}
/** Return number of vertices found 输出当前构建的搜索树的节点的个数 */
public int getNumberOfVerticesFound(){
return searchOrder.size();
}
/** Return the path of vertices from a vertex to the root 返回从顶点到根的顶点路径 */
// 这样是 从index 到 根节点
public List<V> getPath(int index){
ArrayList<V> path = new ArrayList<>();
do {
// 先将index位置的顶点 存入
path.add(vertices.get(index));
// 后对 index顶点的 父顶点进行下标获取 从下向根进行获取
index = parent[index];
}
while (index != -1);
return path;
}
/** Print a path from the root to vertex v */
public void printPath(int index){
List<V> path = getPath(index); // index到根节点的路径
System.out.print("A path from " + vertices.get(root) + " to " + vertices.get(index) + ": ");
// path.size() i-- 反过来,从根节点 到index节点的路径
for (int i = path.size() - 1; i >= 0; i--)
System.out.print(path.get(i) + " ");
}
/** Print the whole tree 打印整个树 打印树中所有的边 */
public void printTree(){
System.out.println("Root is: " + vertices.get(root));
System.out.print("Edges: ");
for (int i = 0; i < parent.length; i++){
if (parent[i] != -1){
System.out.print("(" + vertices.get(parent[i]) + ", " + vertices.get(i) + ") ");
}
}
System.out.println();
}
}
dfs 深度搜索遍历(树)
@Override
/** 得到从v开始的 一棵深度优先搜索树 */
public SearchTree dfs(int v) {
// 搜索过的顶点存储,在一个线性表searchOrder中 这里存储的顶点的位置 如:顶点0
List<Integer> searchOrder = new ArrayList<>();
// 每个顶点的父节点存储,在数组parent中
int[] parent = new int[vertices.size()];
// 初始化父节点的存储
for (int i = 0; i < parent.length; i++)
parent[i] = -1;
// Mark visited vertices 使用数组isVisited来表示已经被访问过的顶点
boolean[] isVisited = new boolean[vertices.size()];
// Recursively search 调用辅助方法 dfs(v, parent, searchOrders, isVisited)来完成深度优先搜索
dfs(v, parent, searchOrder, isVisited);
return new SearchTree(v, parent, searchOrder);
}
/** Recursive method for DFS search */
private void dfs(int v, int[] parent, List<Integer> searchOrder, boolean[] isVisited){
searchOrder.add(v);
isVisited[v] = true;
for (Edge e: neighbors.get(v)){ // e.u is v
int w = e.v; // e.v is w 这里是获取V点的边的信息,并用于下面的判断
if (!isVisited[w]){ // 判断 这个顶点 是否访问过了
parent[w] = v; // The parent of vertex w is v w的父节点是v
dfs(w, parent, searchOrder, isVisited); // Recursive search 进行回溯
}
}
}
利用栈来进行书写的深度搜索树
/** 利用栈来建立深度优先搜索树 */
private SearchTree dfs_stack(int v){
int[] parent = new int[vertices.size()];
for (int i = 0; i < parent.length; i++)
parent[i] = -1;
List<Integer> searchOrder = new ArrayList<>();
// 利用isVisited约束 这个点我们是否走过
boolean[] isVisited = new boolean[vertices.size()];
// 利用stack来进行 进栈与出栈的选择,也就是进行深度优先遍历
Stack<Integer> stack = new Stack<>();
// 先将初始点 推入栈中
stack.push(v);
// 修改我们的 searchOrder 搜索路径
searchOrder.add(v);
// 修改isVisited
isVisited[v] = true;
while (!stack.isEmpty()){
// 将点 推出来
int u = stack.pop();
// 获取与这个点相连的 边
for (Edge e: neighbors.get(u)){ // e.u
int w = e.v;
if (!isVisited[w]){
stack.push(w);
isVisited[w] = true;
}
}
}
return new SearchTree(v, parent, searchOrder);
}
bfs 广度搜索遍历(树)
@Override
/** 得到从v开始的 一棵广度优先搜索树 */
public SearchTree bfs(int v) {
// 搜索过的顶点存储,在一个线性表searchOrder中 这里存储的顶点的位置 如:顶点0
List<Integer> searchOrder = new ArrayList<>();
// 每个顶点的父节点存储,在数组parent中
int[] parent = new int[vertices.size()];
for (int i = 0 ; i < parent.length; i++)
parent[i] = -1;
// list used as a queue 使用队列 来进行 广度的判断
java.util.LinkedList<Integer> queue = new java.util.LinkedList<>();
boolean[] isVisited = new boolean[vertices.size()];
// 下面就是BFS的主要代码
queue.offer(v); // Enqueue v
isVisited[v] = true; // Mark it visited
while (!queue.isEmpty()){
int u = queue.poll(); // Dequeue to u
searchOrder.add(u); // u searched
for (Edge e:neighbors.get(u)){ // Note that e.u is u
int w = e.v; // e.v is w
if (!isVisited[w]){
queue.offer(w);
parent[w] = u;
isVisited[w] = true;
}
}
}
return new SearchTree(v, parent, searchOrder);
}
最小生成树
最小生成树 的树的构建
/** MST is an inner class in WeightedGraph */
public class MST extends SearchTree {
private double totalWeight;
public MST(int root, int[] parent, List<Integer> searchOrder, double totalWeight) {
super(root, parent, searchOrder);
this.totalWeight = totalWeight;
}
public double getTotalWeight(){
return totalWeight;
}
}
最小生成树的遍历代码
public MST getMinimumSpanningTree(int startingVertex){
// cost[v] stores the cost by adding v to the tree cost[v]通过将v添加到树中来存储成本 cost
// 用于存储 与当前连接的点的 对应的点的 权重
double[] cost = new double[getSize()];
// for (int i = 0; i < cost.length; i++){
// cost[i] = Double.POSITIVE_INFINITY; // Initial cost
// }
// Initial cost
Arrays.fill(cost, Double.POSITIVE_INFINITY);
// 刚开始的 那个点的权重 设置为0 用于刚进去的时候 的点的添加
cost[startingVertex] = 0; // cost of source is 0
int[] parent = new int[getSize()]; // Parent of a vertex
parent[startingVertex] = -1; // startingVertex is the root
double totalWeight = 0; // Total weight of the tree thus far
// 这里面存储的 就是路线,也就是最小的那些连接线
// 使用线性表而不是集合 是因为要记录加入到T的顶点的次序
List T = new ArrayList<>();
// Expand T
while (T.size() < getSize()){
// Find smallest cost u in V - T
int u = -1; // Vertex to be detemrined 要确定的顶点
double currentMinCost = Double.POSITIVE_INFINITY;
for (int i = 0; i < getSize(); i++){
// 这里查看 T路径中有没有当前的顶点 与 当前顶点的权重和 当前最小的权重做比较
if (!T.contains(i) && cost[i] < currentMinCost){
currentMinCost = cost[i];
u = i;
}
}
// 如果点全部添加进去 推出while循环 ,没有添加 顶点u到T路径中
if (u == -1) break; else T.add(u); // Add a new Vertex to T
// 添加权重
totalWeight += cost[u]; // Add cost[u] to the tree
// Adjust cost[v] for v that is adjacent to u and v in V - T
// 遍历当前的顶点 连接的边
for (Edge e: neighbors.get(u)){
// e.u = u e.v = v 就是与u 连接的顶点
// 找到没有存在 T路径中的与u 连接的顶点 并且这个顶点如果是无穷大的 也就是大于 这条边的权重
// 这里就是寻找 如果出现了 比之前还要小的权重,要刷新一哈 给cost[e.v]赋值过去, 并确定父亲节点
if (!T.contains(e.v) && cost[e.v] > ((WeightedEdge)e).weight){
// 直接将这表边的权重 赋值给 该顶点对应cost中的值
cost[e.v] = ((WeightedEdge)e).weight;
// 将u赋值为 e.v顶点的父节点
parent[e.v] = u;
}
}
}
return new MST(startingVertex, parent, T, totalWeight);
}
最短路径
最短路径生成树
/** ShortestPathTree is an inner class in WeightedGraph ShortestPathTree是WeightedGraph中的一个内部类 */
public class ShortestPathTree extends SearchTree{
// cost[v] is the cost from v to source
// cost数组是 将 从v根源顶点出发的 存储所有节点(最短)路径和
private double[] cost;
/** Construct a path */
public ShortestPathTree(int root, int[] parent, List<Integer> searchOrder, double[] cost) {
super(root, parent, searchOrder);
this.cost = cost;
}
/** Return the cost for a path from the root to vertex v 返回从root到 节点v的 cost的值(最短路径) */
public double getCost(int v){
return cost[v];
}
/** Print paths from all vertices to the source 打印所有的路径 从根源点 出发的 */
public void printAllPaths(){
System.out.println("All shortest paths from " + vertices.get(getRoot()) + " are: ");
for (int i = 0; i < cost.length; i++){
printPath(i); // Print a path from i to the source
System.out.println("(cost: " + cost[i] + ")"); // Path cost
}
}
}
最短路径的代码
/** Find single-source shortest paths 返回所有的单元最短路径 */
public ShortestPathTree getShortestPath(int sourceVertex){
// cost[v] stores the cost of the path from v to the source
// cost[v]存储从v到源的路径的成本
double[] cost = new double[getSize()];
// 初始化最大值 方便判断 获取 最小值
Arrays.fill(cost, Double.POSITIVE_INFINITY);
// Cost of source is 0
cost[sourceVertex] = 0;
// parent[v] stores the previous vertex of v in the path
int[] parent = new int[getSize()];
parent[sourceVertex] = -1;
// T stores the vertices whose path found so far
List T = new ArrayList<>();
// Expand T
while (T.size() < getSize()){
// Find smallest cost u in V-T
int u = -1; // 当前节点
double currentMinCost = Double.POSITIVE_INFINITY; // 当前节点对应的 权重
for (int i = 0; i < getSize(); i++){
if (!T.contains(i) && cost[i] < currentMinCost){
currentMinCost = cost[i];
u = i;
}
}
if (u == -1) break; else T.add(u);
// Adjust cost[v] for v that is adjacent to u and v in V-T
for (Edge e: neighbors.get(u)){
if (!T.contains(e.v) && cost[e.v] > cost[e.u] + ((WeightedEdge)e).weight){
cost[e.v] = cost[e.u] + ((WeightedEdge)e).weight;
parent[e.v] = u;
}
}
}
return new ShortestPathTree(sourceVertex, parent, T, cost);
}