Getting a Vertex by its Value - java

I'm implementing a Graph in Java.
The Graph class uses a LinkedList for the vertices. And each vertex also contains a LinkedList of adjacent vertices.
I'm still working on my methods. I just need a quick clarification with a getVertex() method which accepts a String label and returns a Vertex that matches that label.
public class Graph
{
private class Vertex
{
private String label;
private LinkedList links;
private boolean visited;
Vertex(String label)
{
this.label = label;
LinkedList links = new LinkedList();
visited = false;
}
private void addEdge(Vertex vertex)
{
links.insertLast(vertex);
}
private String getLabel()
{
return label;
}
private LinkedList getAdjacent()
{
return links;
}
private boolean isVisited()
{
return visited;
}
private void visit()
{
visited = true;
}
private void unvisit()
{
visited = false;
}
}
/* Classfields for Graph Class */
private LinkedList vertices; //Linked List for the vertices in the graph
private int vCount;
private int eCount;
public Graph()
{
LinkedList vertices = new LinkedList();
vCount = 0;
eCount = 0;
}
public void addVertex(String label)
{
Vertex newVertex = new Vertex(label);
vertices.insertLast(newVertex);
vCount++;
}
public int getVertexCount()
{
return vCount;
}
public Vertex getVertex(String label)
{
// what to return?
}
It should be very simple, but I can't understand how I'm going to import this label but return a Vertex, working with a LinkedList. Would appreciate any tips!

If you are working on assignment on an assignment, and you are expected to use LinkedList that's fine, but it's the best choice of collection that serves as a storage of all vertices in the graph and also as the adjacency list of vertex
I suggest you addressing these issues:
Firstly, don't use row types LinkedList links, you should always specify a generic type parameter List<Vertex>.
Write your code against interfaces, not against implementations. I.e. use List<Vertex> instead of LinkedList<Vertex>. It makes your code more flexible.
In order to be able to retrieve a particular vertex by label, you can use a Map<String, Vertex> to store all vertices of the graph. With that time complexity of the getVertex() will be reduced to constant time, it's way faster than iterate over the list. And the code is a single line vertexByLabel.get(label).
Maintaining a variable that hold a count of vertices is redundant because you can check the size of collection of vertices to get this value.
ArrayList performs than LinkedList and has a better memory consumption. For that reason, it considered to be a general purpose implementation of the List interface and it's a preferred choice if you don't expect use cases like removal of elements by the means of Iterator while iterating over the list (which will be done in constant time, here LinkedList really shines). Also, HashSet might be useful in a role of the collection of adjacencent vertices because it will all you to ensure that there will be no duplicates.
So in regard to getVertex() method, if you'll agree with the suggestion to use map, the code will look like this:
private Map<String, Vertex> vertexByLabel = new HashMap<>(); // it is advisable to initialise collections, if you are not passing argument with collection that holds values to the constructor, but just assigning a new collection
public Vertex getVertex(String label) {
return vertexByLabel.get(label);
}
I also advise you to make changes to the methods addVertex() and addEdge(). Firstly, I would rather expect to a method called addVertex() inside the Vertex class (we are adding a new vertex to the adjacency list of this vertex) and a method addEdge() inside the Graph (we are connecting vertices inside the graph).
And if order to connect the vertices method addEdge() of the graph will expect a vertex label as its first argument, and labes of the adjacent vertices as a variable arity argument (varargs).
In case if you have a strong requirement to utilize LinkedLinked exclusively and not allowed to use generic types. But frankly spiking, it doesn't seem a bright idea to disallow student to use generics. It doesn't reduce complexity a lot because instead you have to deal with manual down-casts, and it's a very bad practice.
Your method might look like this:
public Vertex getVertex(String label) {
Vertex result = null;
for (Object next: vertices) { // all elements in the collection of row type a treated by the compiler as being of type Object
Vertex vertex = (Vertex) next; // you need to cast the element into the Vertex type in order to be able to access its field `label`
if (vertex.label.equals(label)) {
result = vertex;
break;
}
}
return result;
}

Related

ArrayList Error

I'm trying to make an ArrayList of my own type to store some values. However, I'm getting an error "x cannot be resolved or is not a field", where is source for example.
Here is a snippet of my code:
public class myClass {
public static void main(String args[]){
addEdge("a","b", 10);
}
private static void addEdge(String source, String destination, int cost) {
List<Edge> add = new ArrayList<Edge>();
add.source = source; //error: source cannot be resolved or is not a field
add.destination = destination; //error: destination cannot be resolved or is not a field
add.cost = cost; //error: cost cannot be resolved or is not a field
}
}
class Edge{
String source;
String destination;
int cost;
}
As you can see I get errors in my addEdge method. I'm
In your code
List<Edge> add = ...
add.source = ...
you are trying to access source field via add reference which is of type List but List doesn't have source field (which is what error message is trying to say). You need to access this fields from Edge, not from List.
So try something more like
Edge edgeInstance = new Edge();
edgeInstance.source = source;
edgeInstance.destination = destination;
edgeInstance.cost = cost;
...
listOfEdges.add(edgeInstance);
Anyway you should avoid making your fields accessible from outside of your class. They should be private and you should initialize them via constructor or via setters.
Also it seems that each time you are calling your method you are creating new List
List<Edge> add = new ArrayList<Edge>();
and you are not reusing it anywhere outside of this method which seems kind of pointless.
Assuming the List and ArrayList types you are referencing in your addEdge method are Java's own java.util.List etc., they don't have accessible properties named source, destination or cost.
If the ArrayList is your own implementation, it does not feature source, destination or cost fields.
The idiom you want to use here is reference an Edge instance and mutate its fields.
To do so, you would do:
add.get(x).setSource("some source");
That implies:
Your List is not null nor empty
x is a valid index
The Edge element at index x is not null
You implemented setters/getters for your Edge fields
By defining list of type Edge, you dont get field's defined within edge. It's a list where you could add/remove/iterate elements within it.
In your case, List can only add object of type Edge. So you need to create Edgle like:
List<Edge> add = new ArrayList<Edge>();
Edge edge = new Edge(source, destination, cost);//add constructor to your edge class like public Edge(Source source... ){ this.source = source;.. }
add.add(edge);//rename list to meaningful name like edgeList

Graph implementing a comparable node java

For one of my projects in my computer science class, I have to implement a directed, weighted graph. Since we are only allowed to use an adjacency list and not an adjacency matrix, I decided to create a Node class that will contain my data, as well as a treeset to hold all of its edges, since the project stipulates that the edges must be sorted using the natural ordering of whatever data my graph is instantiated with. My Node class looks like this:
private class Node<V extends Comparable<V>> {
private V data;
private TreeSet<Edge> edges = new TreeSet<Edge>();
public Node(V data) {
this.data = data;
}
}
My graph itself is also a treeset that contains objects of type Node. I cannot, however, add to the graph using my add method which is as follows:
private boolean addVertex(V vertex) {
Iterator iter = graph.iterator();
Node check;
while (iter.hasNext()) {
check = (Node) iter.next();
if (check.data.compareTo(vertex) == 0)
return false;
}
Node n = new Node(vertex);
graph.add(n);
return true;
}
How can I make it so that my code adds Nodes to my graph class using the natural ordering of the data that the Node class is instantiated with?
**Edit
So based on what Peter said, I was able to come up with a solution (sort of) to my problem. Since my edges, per project stipulation, must be iterated over in the natural order of the data held in the nodes, I created a compareTo method in my edge class that works by using the data's compareTo method. It looks something like this:
private class Edge<V extends Comparable<V>> implements Comparable<V> {
private int weight;
private boolean visited;
//This is the data held in the node the edge ends at
private V endNode;
public Edge(V dest, int weight) {
visited = false;
endNode = dest;
this.weight = weight;
}
public int compareTo(Edge<V> e) {
if (endNode.compareTo((V) e.endNode) < 0)
return -1;
else if (endNode.compareTo((V) e.endNode) == 0)
return 0;
else
return 1;
}
}
Unfortunately, when I try and do this, I get two errors. one of them says "the type parameter V is hiding the type V" and the other says I must implement the Comparable.compareTo(V) method even though I explicitly do it in my code. I was able to find some information on the first error, which said that I could be getting that error because I used V as a concrete type somewhere in my code, however, that does not really help me much since I don't fully understand it. I did that in my Node class and nothing happened, so why am I getting errors in my Edge class? Any help would be greatly appreciated.
Also the class that both Node and Edge are declared in is defined as
public class Graph<V extends Comparable<V>>
if that helps anyone
The wikipedia page http://en.wikipedia.org/wiki/Adjacency_list is a good starting point.
Also, google for this "Goodrich and Tamassia adjacency".
This is a good starting point too.
Because your Graph is weighted and directed, it means you can/should associate with each Vertex the list of its outgoing (or alternatively incoming) Edges. An Edge is then an ordered couple of its two vertices (start vertex and end vertex) and whatever additional information you may want to store in it (e.g. its weight). That's what you need here.
Seems to me the natural ordering you're referring to is about the Edges, not about the Vertices. But you can have some ordering the vertices too.
You can also have a Graph class. The Graph can be just your top-level container class which gives you fast access to e.g.: 1) a Vertex given its id/name (or whatever piece of data you use to identify it), 2) an Edge given e.g. its start and end vertices, other methods, etc.
In general your code so far looks OK btw. I mean you seem to be on the right track.

How can I best make a class hold something for another class?

I'm encountering a couple awkward situations that seem, in some sense, dual to each other, and was wondering if anyone had any thoughts about how to handle them cleanly.
External initialization
class Human {
Collection <Human> nextDoorNeighbors;
}
class Neighborhood {
Collection <Human> humans;
Neighborhood() {
// Make humans
// Then, let them all know who their neighbors are.
}
}
This is awkward because the humans (in this situation) never have to change their next-door neighbors once they've been set up (they are effectively write-once), but this setup can't be done in the Human constructor because the neighbors that need to be put in the nextDoorNeighbors collection don't all exist when the human is constructed.
Holding something for another
Suppose I want to be able to store Humans in a tree-based map. To do so, the Human has to hold a Comparable ID, even if that isn't logically significant to the concept of a Human. The Human constructs this ID, but it never uses it. Only the map uses it (or even should use it).
In the first case, maybe the awkwardness is an indication that neighbours shouldn't be a property of Human. Perhaps the Neighbourhood object should be a property of Human, and a method like human.getNeighbours() can be used to get the actual neighbours when they are needed. Then having a neighbours property becomes a private performance issue for the getNeighbours() method.
In the second case, how is your tree-based map providing a structure if the Human is inherently unstructurable? What's the map for if the ID is irrelevant to the human? Typically an ID is relevant, and is used by the class that has it to ensure that it's uniquely identifiable, but if it's genuinely not required, you can use a separate class, like a HumanKey, to wrap the Human for the map.
I don't really understant what your question is.. Because it's not explicit..
But for the id you can have a static variable in the human class that you will increment in the human constructor and another variable wich will contain the id
It would be something like this
class Human
{
private static int humansCounter=0;
final public int id;
public Human()
{
id=humansCounter++;
}
}
I have an approach that I think is rather clean if the objects themselves need to be aware of the networking. Note that this approach will not work if you concurrently instantiate instances (since each thread will have its own copy of the static fields).
class Foo {
// instance fields
public Foo(/* constructor args */) {
// set instance up
network(this);
}
public boolean isNeighbor(Foo that) {
return areNeighbors(this, that);
}
// static field for tracking edges between neighbors, maybe a
private static Map<Foo, List<Foo>> neighborhood = new HashMap<>();
private static void network(Foo me) {
myNeighbors = new ArrayList<>();
for (Map.Entry<Foo, List<Foo>> x : neighborhood.entrySet()) {
Foo n = x.getKey();
if (/* use me and n's fields to determine whether they are neighbors */) {
myNeighbors.add(n);
x.getValue().add(me);
}
}
neighborhood.put(me, myNeighbors);
}
public static boolean areNeighbors(Foo a, Foo b) {
return neighborhood.get(a).contains(b);
}
}
This approach makes it so that each instance can determine their neighbors without actually knowing their neighbors ahead of time and without using an external class. If an instance's neighbors cannot be inferred from internal state, this approach could be combined with the approach of generating unique IDs (hashes?) for each instance:
class Bar {
// instance fields
public Bar(/* constructor args */, int... neighborIndices) {
// set instance up
network(this, neighborIndices);
}
#Override
public int hashCode() {
return /* a unique value based upon this object's state */;
}
public boolean isNeighbor(Bar that) {
return areNeighbors(this, that);
}
private static Map<Integer, Bar> lookup = new HashMap<>();
private static Map<Bar, List<Integer>> neighbors = new HashMap<>();
private static void network(Bar me, int[] neighbors) {
lookup.put(me.hashCode(), me);
List<Integer> neighborList = new ArrayList<>();
for (int i : neighbors) {
neighborList.add(i);
}
neighbors.put(me, neighborList);
}
public static boolean areNeighbors(Bar a, Bar b) {
return neighbors.get(a).contains(b.hashCode());
}
}
Naturally, if the neighbor relationships are not associative, it is trivial to modify the first example to be a digraph.

How to initialize Key Class in HashMap in Java

I have a question related to Key Type initialization in HashMap. For example, I have defined the below Node class with over-ridden equals() and hashCode() as follows:
public class Node implements Comparable<Node> {
private int Id;
public Node(int i) {
...
}
void setId(int i) {
Id = i;
}
int getId() {
return Id;
}
#Override
public boolean equals(Object o) {
if (o == null) {
throw new NullPointerException();
}
if (o instanceof Node && this != o) {
if (((Node) o).getId() == this.getId())
return true;
}
return false;
}
public int hashCode() {
return Id;
}
}
Now I am building a HashMap with key as type Node as follows:
public class AdjList {
public HashMap<Node,Double> adj;
public AdjList() {
adj = new HashMap<Node,Double>(maxSize);
}
...
}
As you can possibly figure out, I am trying to generate a graph adjacency list with the node class as HashMap.
Now, my question is when I call AdjList() constructor where I create a new HashMap with some maxSize, will it initialize the Node() class as key type? Or I need to separately initialize Node() clas for the key? If I need to initialize Node() in AdjList constructor, then how it can be possible?
Any suggestion will be valuable and useful suggestions will be rewarded.
Thanks,
Somnath
when I call AdjList() constructor where I create a new HashMap with some maxSize, will it initialize the Node() class as key type?
No! You are instantiate the Map with initialCapacity which is the loadFactor value not maxSize (See the documentation).
You may define a method in AddList that adds an entry.
public void add(int i,Double d)
{
adj.put(new Node(i),d);
}
Second, you've implemented Comparable so you must have to define the compareTo method.
There are a number of things that confuse me about your question (even after reading about adjacency lists which I had not heard of before). Firstly why is overriding equals and hash map important? Secondly how does this code form an adjacency list (reading http://en.wikipedia.org/wiki/Adjacency_list) I could not see the relationship between what you have and an adjacency list. I'm also not sure what you are asking when talking about initialising the Node class. It sounds like yoga re confused about some things, I'm just not sure what.
Finally, based on what I read about adjacency lists, I would simply use the following code:
Map<int, List<int>> adjList = new HashMap<int, List<int>>();
Then I can store node 1 with a adjacency list of nodes 2 and 3 as:
adjList.put(1, Arrays.aslist(2,3));
and retrieve then with:
adjList.get(1);
etc, etc. No need for any custom classes at all.

adding a full list of objects to every object in the list in JAVA

Hi I have 2 classes in Java, Gossip and Node, I want that Gossip will hold a list of all the objects of Node class and I want that each Node object will also have that list. I tried to write it in the following way:
public class Node {
private Boolean val = null;
private LinkedList<Node> list;
static Random rand = new Random();
public Node(LinkedList<Node> list) {
this.list=list;
}
... the rest of Node functions ...
}
and in the Gossip contractor:
public class Gossip {
private int count;
private int n;
private LinkedList<Node> list;
public Gossip (int n) {
this.count = 0;
this.n = n;
list = new LinkedList<Node>();
for (int i=0; i<n; i++){
list.add(new Node(list));
}
}
... the rest of Gossip functions ...
}
Since I'm used to C++ I am not sure how it works here and whether this will work like a pointer and each Node will have a full list or will each Node will only have a list with the Nodes created before it and itself. Also, I don't need to change the list on the program, just to read from it, but it's interesting, will a change that one Node does in the list will affect all other Nodes's lists?
There is only one list of nodes and all the nodes have references to this single list.
This is because in the Node constructor the assignment this.list=list; doesn't create a copy of the object - it simply makes this.list the same as list, but remember they both are references (on the stack) to the object (on the heap).
Therefore, if you change the list through one of the nodes, all other nodes will see the change.
There is only one list created in new LinkedList<Node>(); per one Gossip. Later it is passed by reference (pointer like), thus it same list everywhere.
Is the Node class used outside of the Gossip class? If not then you might want to consider making Node a private inner class of Gossip. That will simplify things because Node instances can access the list in Gossip without having to have their own reference to it. You'll have to define the list as final to do this.
All variables / fields in java that are derived from java.lang.Object are "references" and that is basically exactly the same as a pointer in C++. (Not to be mixed up with C++ references which are also only pointers but with a special semantic)
That means int, float and all other primnitives are values and not pointers/references, ofc.

Categories