如何修改Dijkstra算法以适合C ++中的A *搜索算法

问题描述

我正在尝试在Dijkstra算法中实现A *搜索算法。 (最好不使用STL)

例如,对于每个顶点,我都有一个X和Y值

VERTEX | X-VALUE | Y-VALUE
1        13        42
2        22        25
3        73        98

我研究了一些A *搜索算法,例如GeeksForGeeks之类的A *搜索算法有600多个行实现,而我发现需要更改的只是价格函数Dijkstra算法。但是,我不确定如何为A *搜索算法计算成本函数

我有以下Dijkstra算法。

#include<iostream>
#include<stdio.h>
using namespace std;
#define INFINITY 9999
#define max 5
void dijkstra(int G[max][max],int n,int startnode);

int main()
{
    int G[max][max]= {{0,1,3,10},{1,5,0},{0,2,1},{3,6},{10,6,0}};
    int n=5;
    int u=0;
    dijkstra(G,n,u);
    return 0;
}

void dijkstra(int G[max][max],int startnode)
{
    int cost[max][max],distance[max],pred[max];
    int visited[max],count,mindistance,nextnode,i,j;

    for(i=0; i<n; i++)
        for(j=0; j<n; j++)
            if(G[i][j]==0)
                cost[i][j]=INFINITY;
            else
                cost[i][j]=G[i][j];

    for(i=0; i<n; i++)
    {
        distance[i]=cost[startnode][i];
        pred[i]=startnode;
        visited[i]=0;
    }

    distance[startnode]=0;
    visited[startnode]=1;
    count=1;
    while(count<n-1)
    {
        mindistance=INFINITY;
        for(i=0; i<n; i++)
            if(distance[i]<mindistance&&!visited[i])
            {
                mindistance=distance[i];
                nextnode=i;
            }
        visited[nextnode]=1;
        for(i=0; i<n; i++)
            if(!visited[i])
                if(mindistance+cost[nextnode][i]<distance[i])
                {
                    distance[i]=mindistance+cost[nextnode][i];
                    pred[i]=nextnode;
                }
        count++;
    }
    for(i=0; i<n; i++)
        if(i!=startnode)
        {
            cout<<"\ndistance of node"<<i<<"="<<distance[i];
            cout<<"\nPath="<<i;
            j=i;
            do
            {
                j=pred[j];
                cout<<"<-"<<j;
            }
            while(j!=startnode);
        }
}

谢谢您的任何帮助。

解决方法

我建议您的代码中包含结构。 您需要具有另一个A *节点结构(在顶点节点的内部结构中进行构建),该结构将保存“ f,g,h”值。 图的每个顶点都将具有此A *节点结构。

我完成了类似的任务,我不得不在JAVA中找到最短和第二条最短路径。

import java.util.*;

// Class to hold each vertex in our graph
class Vertex {

    private String label;
    private int xCoordinate;
    private int yCoordinate;

    private AStarNode aStarNode;

    AStarNode getAStarNode() {
        return aStarNode;
    }

    class AStarNode{

        double f,g,h;

        AStarNode() {
            f= g=h = Double.MAX_VALUE;
        }
    }

    private AdjacencyList adjacencyList;

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
    }

    public int getxCoordinate() {
        return xCoordinate;
    }

    public void setxCoordinate(int xCoordinate) {
        this.xCoordinate = xCoordinate;
    }

    public int getyCoordinate() {
        return yCoordinate;
    }

    public void setyCoordinate(int yCoordinate) {
        this.yCoordinate = yCoordinate;
    }

    public AdjacencyList getAdjacencyList() {
        return adjacencyList;
    }

    public Vertex(String label,int xCoordinate,int yCoordinate) {
        this.label = label;
        this.xCoordinate = xCoordinate;
        this.yCoordinate = yCoordinate;
        adjacencyList = new AdjacencyList();
        aStarNode = new AStarNode();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Vertex vertex = (Vertex) o;
        return label.equals(vertex.label);
    }

    @Override
    public int hashCode() {
        return label.length();
    }
}

// Class to hold the final result of each algorithm
class Result {
    private String shortestPath;
    private int distance;
    private int numberOfNodesTraversed;

    public Result(String shortestPath,int distance,int numberOfNodesTravesed) {
        this.shortestPath = shortestPath;
        this.distance = distance;
        this.numberOfNodesTraversed = numberOfNodesTravesed;
    }

    public String getShortestPath() {
        return shortestPath;
    }

    public int getDistance() {
        return distance;
    }

    public int getNumberOfNodesTraversed() {
        return numberOfNodesTraversed;
    }
}

// An edge having the destination label and the weight associated
class Edge {
    private String vertexLabel;
    private int weight;

    private boolean isActive;

    public String getVertexLabel() {
        return vertexLabel;
    }

    public void setVertexLabel(String vertexLabel) {
        this.vertexLabel = vertexLabel;
    }

    public int getWeight() {
        return weight;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }

    public boolean isActive() {
        return isActive;
    }

    public void setActive(boolean active) {
        isActive = active;
    }

    public Edge(String vertexLabel,int weight) {
        this.vertexLabel = vertexLabel;
        this.weight = weight;
        isActive = true;
    }
}

// List of edges for a particular vertex
class AdjacencyList {

    private Node first,last;

    AdjacencyList() {
        first = last = null;
    }
    public void addNode(Edge edge) {
        Node newNode = new Node(edge);
        if(first == null) {
            first = last = newNode;
        } else {
            last.next = newNode;
            last = newNode;
        }
    }


    public void printAdjacencyLabels() {
        Node start = first;
        while(start!=null) {
            System.out.print(start.edge.getVertexLabel()+"("+start.edge.getWeight()+")  ");
            start = start.next;
        }
    }

    Node getFirst() {
        return first;
    }

    Edge getParticularEdge(String label) {
        Node start = first;
        while(start!=null) {
            if(start.getEdge().getVertexLabel().equals(label)) {
                return start.getEdge();
            }
            start = start.next;
        }
        return null;
    }
}

// Class representing each node in adjancy list
// List will hold each edge details
class Node {
    Edge edge;
    Node next;
    Node(Edge edge) {
        this.edge = edge;
        next = null;
    }
    Edge getEdge() {
        return edge;
    }
    Node getNext() {
        return next;
    }
}

public class Main {

    // Data structure that will hold all the vertices details and there edges
    static Vertex[] graph;

    static String startLabel,goalLabel;

    // Function to get the index of a vertex based on the label
    private static int getVertexNo(String label) {
        for(int i=0;i<graph.length;i++) {
            if(graph[i].getLabel().equals(label)) {
                return i;
            }
        }
        return -1;
    }

    // Function to add an edge to a vertex
    private static void addEdge(String sourceLabel,Edge edge) {
        graph[getVertexNo(sourceLabel)].getAdjacencyList().addNode(edge);
    }


    // Function to print the result of shortest path algos
    private static void printResult(Result result) {
        System.out.println("Vertices on path : "+result.getShortestPath());
        System.out.println("Length of this path : "+result.getDistance());
    }

    // Function to find minimum f value of unvisited vertex
    static int findMinVertexAStar(boolean[] visited) {

        double minDistance = Double.MAX_VALUE;
        int minIndex =-1;

        for(int i=0;i<graph.length;i++) {
            if(!visited[i] && minDistance > graph[i].getAStarNode().f) {
                minDistance = graph[i].getAStarNode().f;
                minIndex = i;
            }
        }
        return minIndex;
    }

    // Function to compute eucledian distance between 2 vertices
    static double getEucledianDistance(Vertex first,Vertex second) {
        return Math.sqrt(Math.pow(first.getxCoordinate() - second.getxCoordinate(),2)
                + Math.pow(first.getyCoordinate() - second.getyCoordinate(),2));
    }

    // Function to get shortest path based on A star Algo
    static Result shortestPath() {

        int startVertex = getVertexNo(startLabel);
        int goalVertex = getVertexNo(goalLabel);
        Vertex finalVertex = graph[goalVertex];

        int[] parentArray = new int[graph.length];

        boolean[] visitedVertices = new boolean[graph.length];

        int totalNumberOfNodesVisited =0;

        // Initialise data structures
        for(int i=0;i<graph.length;i++) {
            visitedVertices[i] = false;
            parentArray[i] = -1;
            graph[i].getAStarNode().f = Double.MAX_VALUE;
        }

        graph[startVertex].getAStarNode().f =0;
        graph[startVertex].getAStarNode().g =0;
        graph[startVertex].getAStarNode().h =0;

        // Lopp over until goal vertex is found
        while(true) {

            totalNumberOfNodesVisited++;
            int currIndex = findMinVertexAStar(visitedVertices);
            visitedVertices[currIndex] = true;

            if(currIndex==goalVertex) {
                break;
            }

            Node startNode= graph[currIndex].getAdjacencyList().getFirst();

            // Traverse each edge of current vertex
            while (startNode!=null && startNode.getEdge().isActive()) {


                int edgeVertexIndex= getVertexNo(startNode.getEdge().getVertexLabel());

                if(!visitedVertices[edgeVertexIndex]) {

                    double parentG = graph[currIndex].getAStarNode().g;
                    double newG = parentG+startNode.getEdge().getWeight();
                    double newH =   getEucledianDistance(graph[edgeVertexIndex],finalVertex);

                    if((newG + newH) < graph[edgeVertexIndex].getAStarNode().f) {
                        graph[edgeVertexIndex].getAStarNode().f = newG + newH;
                        graph[edgeVertexIndex].getAStarNode().g = newG ;
                        graph[edgeVertexIndex].getAStarNode().h = newH;
                        parentArray[edgeVertexIndex] = currIndex;
                    }
                }
                startNode = startNode.getNext();
            }

        }
        String shortestPath ="";
        int currIndex = goalVertex;
        int distance = (int)graph[goalVertex].getAStarNode().g;

        // Computing the shortest path from parent array
        while(true) {
            int nextIndex = parentArray[currIndex];
            shortestPath = graph[currIndex].getLabel()+" "+shortestPath;
            if(nextIndex == -1) {
                break;
            }
            currIndex = nextIndex;
        }

        return new Result(shortestPath,distance,totalNumberOfNodesVisited);

    }

    // Function to get second shortest path based on A star Algo
    static Result secondShortestPath(String shortestPathStr) {

        String[] vertices = shortestPathStr.split("\\s+");
        Edge[] edgesOnShrtestPath = new Edge[vertices.length-1];

        // Fill up array of edges in shortest path
        for(int i=0;i<vertices.length-1;i++) {
            String startLabel = vertices[i];
            String endLabel = vertices[i+1];
            int startVertexNo = getVertexNo(startLabel);
            edgesOnShrtestPath[i] = graph[startVertexNo].getAdjacencyList().getParticularEdge(endLabel);
        }

        Result shortestAStarResult =null;
        // Lopp over each edge in shortest path
        for(int edge=0;edge<edgesOnShrtestPath.length;edge++) {

            edgesOnShrtestPath[edge].setActive(false);

            Result currResult = shortestPath();
            // Compute again shortest path with given edge inactive
            if(shortestAStarResult ==null || shortestAStarResult.getDistance() > currResult.getDistance()) {
                shortestAStarResult = currResult;
            }
            // Make edge active again
            edgesOnShrtestPath[edge].setActive(true);

        }
        return shortestAStarResult;
    }
}