简体   繁体   中英

IndexOutOfBoundsException when running Dijkstra's algorithm implementation

Not particularly sure what's causing this IndexOutOfBoundsException to occur. The code works perfectly find if I hard code all of the addFlightPath() parameters, but as soon as I attempt to use a for loop to populate the flightPaths arrayList an IndexOutOfBoundsException is thrown. I'm probably missing something small but I'm not sure what it could be.

The exception is thrown on the call to flightPaths.add(path) within the addFlightPath method

public class DijkstrasController
{
    private FlightDatabase flightDatabase;
    private List<Vertex> nodes;
    private List<Edge> flightPaths;

    public DijkstrasController(FlightDatabase flightDatabase)
    {
        this.flightDatabase = flightDatabase;
        populateDijkstrasGraph(flightDatabase);
    }

    public String[] runDijkstras(String sourceAirport, String destinationAirport)
    {
        //Removed for visibility
    }

    public void populateDijkstrasGraph(FlightDatabase fdb)
    {
        nodes = new ArrayList<Vertex>();
        flightPaths = new ArrayList<Edge>();
        for (int i = 0; i < (fdb.getDatabaseSize()); i++)
        {
            Vertex location = new Vertex("Node_" + i, nodeNumberToNodeLetter(i));
            nodes.add(location);

         //This block of code throws an IndexOutOfBounds error
            AirJourney journey = fdb.getFlightDetails(i);
            String pathId = "Path_" + journey.getOriginAirport() + journey.getDestinationAirport();
            int sourceAirport = nodeLetterToNodeNumber(journey.getOriginAirport());
            int destinationAirport = nodeLetterToNodeNumber(journey.getDestinationAirport());
            int distance = journey.getNumberOfMilesToTravel();
            addFlightPath(pathId, sourceAirport, destinationAirport, distance);
        }

// Uncommenting this section of code allows the program to function normally
//      addFlightPath("Path_AB", 0, 1, 800);
//      addFlightPath("Path_BC", 1, 2, 900);
//      addFlightPath("Path_CD", 2, 3, 400);
//      addFlightPath("Path_BF", 1, 5, 400);
//      addFlightPath("Path_DE", 3, 4, 300);
//      addFlightPath("Path_EB", 4, 1, 600);
//      addFlightPath("Path_CE", 2, 4, 200);
//      addFlightPath("Path_DC", 3, 2, 700);
//      addFlightPath("Path_EB", 4, 1, 500);
//      addFlightPath("Path_FD", 5, 3, 200);
//      addFlightPath("Path_DE", 3, 4, 400);
//      addFlightPath("Path_CE", 2, 4, 300);

    }

    private void addFlightPath(String pathId, int sourceAirport, int destAirport, int distance)
    {
        Edge path = new Edge(pathId, nodes.get(sourceAirport), nodes.get(destAirport), distance);
        flightPaths.add(path); //IndexOutOfBounds exception is thrown here
    }

}

Stack Trace

Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 1, Size: 1
    at java.util.ArrayList.rangeCheck(ArrayList.java:657)
    at java.util.ArrayList.get(ArrayList.java:433)
    at core.dijkstras2.DijkstrasController.addFlightPath(DijkstrasController.java:83)
    at core.dijkstras2.DijkstrasController.populateDijkstrasGraph(DijkstrasController.java:63)
    at core.dijkstras2.DijkstrasController.<init>(DijkstrasController.java:19)
    at core.dijkstras2.DDriver.main(DDriver.java:10)

So, the reason for this IndexOutOfBounds was being caused by the fact that the for loop in question prevented the nodes ArrayList from being populated properly.

To fix this, I simply changed this code:

for (int i = 0; i < (fdb.getDatabaseSize()); i++)
        {
            Vertex location = new Vertex("Node_" + i, nodeNumberToNodeLetter(i));
            nodes.add(location);

         //This block of code throws an IndexOutOfBounds error
            AirJourney journey = fdb.getFlightDetails(i);
            String pathId = "Path_" + journey.getOriginAirport() + journey.getDestinationAirport();
            int sourceAirport = nodeLetterToNodeNumber(journey.getOriginAirport());
            int destinationAirport = nodeLetterToNodeNumber(journey.getDestinationAirport());
            int distance = journey.getNumberOfMilesToTravel();
            addFlightPath(pathId, sourceAirport, destinationAirport, distance);
        }

And moved the second block into a separate for loop, this allows the first for loop to populate the arraylist first, before the flight paths are added.

for (int i = 0; i < (fdb.getDatabaseSize()); i++)
        {
            Vertex location = new Vertex("Node_" + i, nodeNumberToNodeLetter(i));
            nodes.add(location);
        }

        for (int i = 0; i < fdb.getDatabaseSize(); i++)
        {
            AirJourney journey = fdb.getFlightDetails(i);
            String pathId = "Path_" + journey.getOriginAirport() + journey.getDestinationAirport();
            int sourceAirport = nodeLetterToNodeNumber(journey.getOriginAirport());
            int destinationAirport = nodeLetterToNodeNumber(journey.getDestinationAirport());
            int distance = journey.getNumberOfMilesToTravel();
            addFlightPath(pathId, sourceAirport, destinationAirport, distance);
        }

As mentioned in the comments, your exception seems to be stemming from the following line:

Edge path = new Edge(pathId, nodes.get(sourceAirport), nodes.get(destAirport), distance);

Let's go over your populateDijkstrasGraph() function (offending portion):

    for (int i = 0; i < (fdb.getDatabaseSize()); i++)
    {
        Vertex location = new Vertex("Node_" + i, nodeNumberToNodeLetter(i));
        nodes.add(location);

Here you add the location given by nodeNumberToNodeLetter(i) .

        int sourceAirport = nodeLetterToNodeNumber(journey.getOriginAirport());
        int destinationAirport = nodeLetterToNodeNumber(journey.getDestinationAirport());

Here, you are getting the integer values for the first two airport nodes. However, we've only added a single node! ( nodes.add(location) above).

Thus, if sourceAirport == 0 and destinationAirport == 1 , with nodes currently containing only a single Vertex , nodes.get(sourceAirport) will work, whereas nodes.get(destinationAirport) will throw an IndexOutOfBoundsException , as expected.

One way to fix this would be to populate the list of nodes before attempting to populate the edges between them.

Edit: If you haven't already, you should enable line numbers in your IDE. It makes debugging much easier. In addition, you should familiarize yourself with debugging and breakpoints - this would've allowed you to find the above error quite quickly.

A bit of guess work, but I assume that your working version of the code looks something like this:

public void populateDijkstrasGraph(FlightDatabase fdb)
{
    nodes = new ArrayList<Vertex>();
    flightPaths = new ArrayList<Edge>();
    for (int i = 0; i < (fdb.getDatabaseSize()); i++)
    {
        Vertex location = new Vertex("Node_" + i, nodeNumberToNodeLetter(i));
        nodes.add(location);

     //This block of code throws an IndexOutOfBounds error
     //   AirJourney journey = fdb.getFlightDetails(i);
     //   String pathId = "Path_" + journey.getOriginAirport() + journey.getDestinationAirport();
     //   int sourceAirport = nodeLetterToNodeNumber(journey.getOriginAirport());
     //   int destinationAirport = nodeLetterToNodeNumber(journey.getDestinationAirport());
     //   int distance = journey.getNumberOfMilesToTravel();
     //   addFlightPath(pathId, sourceAirport, destinationAirport, distance);
    }

// Uncommenting this section of code allows the program to function normally
   addFlightPath("Path_AB", 0, 1, 800);
   addFlightPath("Path_BC", 1, 2, 900);
   addFlightPath("Path_CD", 2, 3, 400);
// etc.

This will work fine since you have a fully populated nodes List. If you move addFlightPath into the for -loop though, nodes will only contain one element in the first iteration through the loop. Hence the call to nodes.get(1) will fail with the IndexOutOfBounds exception.

You will probably need to loop twice:

for (int i = 0; i < (fdb.getDatabaseSize()); i++)
{
    Vertex location = new Vertex("Node_" + i, nodeNumberToNodeLetter(i));
    nodes.add(location);
}

for (int i = 0; i < (fdb.getDatabaseSize()); i++)
{
    AirJourney journey = fdb.getFlightDetails(i);
    String pathId = "Path_" + journey.getOriginAirport() + journey.getDestinationAirport();
    int sourceAirport = nodeLetterToNodeNumber(journey.getOriginAirport());
    int destinationAirport = nodeLetterToNodeNumber(journey.getDestinationAirport());
    int distance = journey.getNumberOfMilesToTravel();
    addFlightPath(pathId, sourceAirport, destinationAirport, distance);
}

When you do a loop always start from 0 to size -1 of the list you use. If you have a list of 5 position, the loop goes from 0 to 4. Maybe its your problem?

Try to put:

for (int i = 0; i < (fdb.getDatabaseSize()-1); i++)
{}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM