tags:

views:

76

answers:

2

I am inputting an adjacency list for a graph. There are three columns of data (vertex, destination, edge) separated by a single space. Here is my implementation so far:

         FileStream in = new FileStream("input1.txt");
         Scanner s = new Scanner(in);

         String buffer;
         String [] line = null;
        while (s.hasNext()) 
        {       
            buffer = s.nextLine();
            line = buffer.split("\\s+");     
            g.add(line[0]);
            System.out.println("Added vertex " + line[0] + ".");
            g.addEdge(line[0], line[1], Integer.parseInt(line[2]));
            System.out.println("Added edge from " + line[0] + " to " + line[1] + " with a weight of " + Integer.parseInt(line[2]) + ".");                  
         }

         System.out.println("Size of graph = " + g.size());

Here is the output:

Added vertex a.
Added edge from a to b with a weight of 9.
Exception in thread "main" java.lang.NullPointerException
    at structure5.GraphListDirected.addEdge(GraphListDirected.java:93)
    at Driver.main(Driver.java:28)

I was under the impression that

 line = buffer.split("\\s+");

would return a 2 dimensional array of Strings to the variable line. It seemed to work the first time but not the second. Any thoughts?

I would also like some feedback on my implementation of this problem. Is there a better way? Anything to help out a novice! :)

EDIT:

I tried this implementation earlier today and was unsuccessful. I did it again here:

FileStream in = new FileStream("input1.txt");
             Scanner s = new Scanner(in).useDelimiter("\\s+");

            while (s.hasNext()) 
            {       
                Scanner line = new Scanner(s.nextLine());
                String vertex = line.next();
                String destination = line.next();
                int weight = line.nextInt();     
                g.add(vertex);
                System.out.println("Added vertex " + vertex + ".");
                g.addEdge(vertex, destination, weight);
                System.out.println("Added edge from " + vertex + " to " + destination + " with a weight of " + weight + ".");                  
             }

             System.out.println("Size of graph = " + g.size()); 

Output:

Added vertex a.
Exception in thread "main" java.lang.NullPointerException
    at structure5.GraphListDirected.addEdge(GraphListDirected.java:93)
    at Driver.main(Driver.java:22)

Edit2:

Here is the addEdge function. This is not my own implementation I am using it to save the time of feebly writing my own at this beginning stage...

package structure5;
import java.util.Iterator;


abstract public class GraphList<V,E> extends AbstractStructure<V> implements Graph<V,E>
{
    protected Map<V,GraphListVertex<V,E>> dict; // label -> vertex

    protected boolean directed; // is graph directed?


    protected GraphList(boolean dir)
    {
        dict = new Hashtable<V,GraphListVertex<V,E>>();
        directed = dir;
    }

    public void add(V label)
    {
        if (dict.containsKey(label)) return; // vertex exists
        GraphListVertex<V,E> v = new GraphListVertex<V,E>(label);
        dict.put(label,v);
    }


    abstract public void addEdge(V v1, V v2, E label);
}

Graph.java:

package structure5;
import java.util.Iterator;

public interface Graph<V,E> extends Structure<V>
{
    public void add(V label);


    public void addEdge(V vtx1, V vtx2, E label);
}

Note: I am leaving out the rest of the methods that don't pertain to the program

Edit3: Here is GraphListDirected.java

public class GraphListDirected<V,E> extends GraphList<V,E>
{
    public GraphListDirected()
    {
        super(true);
    }
    public void addEdge(V vLabel1, V vLabel2, E label)
    {
        GraphListVertex<V,E> v1 = dict.get(vLabel1);
        GraphListVertex<V,E> v2 = dict.get(vLabel2);
        Edge<V,E> e = new Edge<V,E>(v1.label(), v2.label(), label, true);   //Line 93
        v1.addEdge(e);
    }
+2  A: 

String.split returns a String[], a one-dimensional array, never a two dimensional array. You can, of course, further split a String that was the result of a split (and so on).

Having said that, since you're already using Scanner, you should never need to use split and Integer.parseInt etc. Just create another Scanner to scan s.nextLine().

Scanner line = new Scanner(s.nextLine());
String from = line.next();
String to = line.next();
int weight = line.nextInt();

I'm not sure what caused the NullPointerException, although we know from your output that at least one edge was successfully added.

API links


On multiple Scanner

The little A-ha!! moment here is the realization that just as you can split on the result of a previous split, you can create a Scanner to scan strings returned from another Scanner.

    String inputText =
        "Line1 a b\n" +
        "Line2 d e f\n" +
        "Line3";
    Scanner input = new Scanner(inputText);
    while (input.hasNext()) {
        Scanner line = new Scanner(input.nextLine());
        System.out.println("[" + line.next() + "]");
        while (line.hasNext()) {
            System.out.println("  " + line.next());
        }
    }

The above snippet prints:

[Line1]
  a
  b
[Line2]
  d
  e
  f
[Line3]

This is just a simple example, but you can see the value of this technique when each line is more complex, e.g. when it contains numbers and regex patterns.


On the NullPointerException

You need to add both the starting and ending vertices, because of the way addEdge is implemented.

            Scanner line = new Scanner(s.nextLine());
            String vertex = line.next();
            String destination = line.next();
            int weight = line.nextInt();     
            g.add(vertex);
            g.add(destination); // <--- ADD THIS LINE!!
            g.addEdge(vertex, destination, weight);

This should fix the NullPointerException.

Hopefully the process of finding this bug has been educational: it took several revisions to the question to gather the relevant information, but finally the culprit of the error has been identified.

polygenelubricants
@polygenelubricants: Thank you for you patience! Everything seems to working fine now. I guess the hardest errors to figure it out is the error in your own logic :D
Nathan
A: 

As polygenelubricants mentioned, split() returns String[], not String[][].

Note that split() will recompile the regex pattern on every loop iteration. If your input is small, this won't matter, but if your input is large (maybe thousands of iterations), you would be better off using a second Scanner inside the loop, or using a Pattern that's compiled outside the loop.

To get to the bottom of the NullPointerException, I'd suggest using a debugger (like the one included in Eclipse) and setting a breakpoint at line 93 of GraphListDirected.java (the line reported in the stacktrace). Each time the breakpiont pauses your program at that line, double-check all your values to make sure they are what you would expect to see.

rob
He is using `nextLine()`. That should do what he wants.
jjnguy
Oops, missed that--thanks. :)
rob