Vector of linked list - java

How to create vector of linked list in Java using Collections?
So far I have written the following code:
Vector <LinkedList <Integer> > adj = new Vector<>();
However I am unable to figure out how to initialize the vector with head nodes of the linked list.
What I want is given an integer N, I wish to initialize the vector with the values 0 to N-1 as the head nodes:
e.g given N = 4
vector ---> 0
1
2
3
So that later I can add members to the list when needed like :
vector ---> 0->2->3
1->3
2->0->1
3->1

With the code you have written, you have created an empty vector - you have to fill it with desired number of LinkedList instances (I am guessing you are a C++ programmer, where the vector would initialize "automatically"?). E.g. initialize your vector like this:
int N = 4;
Vector<LinkedList<Integer>> adj = new Vector<>(N); // N here isn't really needed, but it sets the initial capacity of the vector
for (int i = 0; i < 4; i++) {
ajd.add(new LinkedList<>());
}
Also, as Turing85 pointed out, you should use ArrayList if you don't need the synchronization.

Related

Representing a directed acyclic graph as a 2-dimensional array in Java

How can I represent a directed acyclic graph as a 2-dimensional array if each row contains the immediate out-neighbours of a particular node. For example, if I have an array int [] [] edges, edges[0] = {1,2,3} means there are edges from node 0 to nodes 1, 2 and 3.
If you have to use a 2D array - given that a 2D array at least in Java can't be sparse - then you need to allocate an NxN array: boolean[][] edges = new boolean[n][n];
You need to allow for the degenerate case where all the nodes are
in a single chain, hence you need n-1 rows.
You need to allow for a star rooted on any node, hence n-1 columns.
It's vastly more complicated to store addresses in an array - given that the size has to be so large anyway - than to simple store "yes" at row j, position k for an edge from j -> k. And it's a lot faster to update the latter.
Obviously the sensible approach would be a HashMap from source node to a HashSet of target nodes, but that's apparently not what you're looking for.
int n;
List<Integer>[] adj;
AdjacencyLists(int n) {
adj = (List<Integer>[])new List[n];
for (int i = 0; i < n; i++)
adj[i] = new ArrayList<Integer>(Integer.class);
}
.....
adj[a].add(b); // a -> b edge

How to add / remove different class instances from arrayList stored inside a mulitidimentional array in java

My overall thought process may be off here so if there is a more logical solution to this feel free to suggest. The problem is this, I have a 2 dimensional array that I am treating as an x,y grid system. I would like to be able to store multiple class instances inside a single array index. my thought was to instead store an array list inside each array index as a sort of container for the objects. The problem is that I'm not sure how to address the list that is inside a given index at array[i][j].
One solution I considered is to create a templist and set tempList = array[i][j] edit tempList set array[i][j] = tempList. Sort of a switcheroo. Is there a better way to do this?
You can edit the lists directly, without any need for temporary variables.
To set a list:
array[0][0] = new ArrayList<>();
So you can fill the entire array with something along these lines:
int width = 100;
int height = 100;
List[][] array = new List[width][height];
for(int x = 0; x < width; x++){
for(int y = 0; y < height; y++){
array[x][y] = new ArrayList<Object>();
}
}
The array will have all it's elements set to null by default, so you will have to create a list at every index.
The above code will create an ArrayList at every position in the array, which you can then use just like any other list:
array[0][0].add(element); //Adds the element to the list at [0,0]
Object obj = array[0][0].get(0); //Gets the element we just added

What is the best way to represent a tree in this case?

I am trying to solve this question: https://www.hackerrank.com/challenges/journey-to-the-moon I.e. a problem of finding connected components of a graph. What I have is a list of vertices (from 0 to N-1) and each line in the standard input gives me pair of vertices that are connected by an edge (i.e. if I have 1, 3) it means that vertex 1 and vertex 3 are in one connected component. My question is what is the best way to store the inpit, i.e. how to represent my graph? My idea is to use ArrayList of Arraylist - each position in the array list stores another arraylist of adgecent vertices. This is the code:
public static List<ArrayList<Integer>> graph;
and then in the main() method:
graph = new ArrayList<ArrayList<Integer>>(N);
for (int j = 0; j < N; j++) {
graph.add(new ArrayList<Integer>());
}
//then for each line in the standard input I fill the corresponding values in the array:
for (int j = 0; j < I; j++) {
String[] line2 = br.readLine().split(" ");
int a = Integer.parseInt(line2[0]);
int b = Integer.parseInt(line2[1]);
graph.get(a-1).add(b);
graph.get(b-1).add(a);
}
I'm pretti sure that for solving the question I have to put vertex a at position b-1 and then vertex b at position a-1 so this should not change. But what I am looking for is better way to represent the graph?
Using Java's collections (ArrayList, for example) adds a lot of memory overhead. each Integer object will take at least 12 bytes, in addition to the 4 bytes required for storing the int.
Just use a huge single int array (let's call it edgeArray), which represents the adjacency matrix. Enter 1 when the cell corresponds to an edge. e.g., if nodes k and m is seen on the input, then cell (k, m) will have 1, else 0. In the row major order, it will be the index k * N + m. i.e, edgeArray[k * N + m ] = 1. You can either choose column major order, or row major order. But then your int array will be very sparse. It's trivial to implement a sparse array. Just have an array for the non-zero indices in sorted order. It should be in sorted order so that you can binary search. The number of elements will be in the order of number of edges.
Of course, when you are building the adjacency matrix, you won't know how many edges are there. So you won't be able to allocate the array. Just use a hash set. Don't use HashSet, which is very inefficient. Look at IntOpenHashSet from fastutils. If you are not allowed to use libraries, implement one that is similar to that.
Let us say that the openHashMap variable you will be using is called adjacencyMatrix. So if you see, 3 and 2 and there are 10^6 nodes in total (N = 10^6). then you will just do
adjacencyMatirx.add(3 * 10000000 + 2);
Once you have processed all the inputs, then you can make the sparse adjacency matrix implementation above:
final int[] edgeArray = adjacencyMatrix.toIntArray(new int[adjacencyMatrix.size()]);
IntArrays.sort(edgeArray)
Given an node, finding all adjacent nodes:
So if you need all the nodes connected to node p, you would binary search for the next value that is greater than or equal to p * N (O(log (number of edges))). Then you will just traverse the array until you hit a value that is greater than or equal to (p + 1) * N. All the values you encounter will be nodes connected to p.
Comparing it with the approach you mentioned in your question:
It uses O(N*b) space complexity, where N (number of nodes) and b is the branching factor. It's lower bounded by the number of edges.
For the approach I mentioned, the space complexity is just O(E). In fact it's exactly e number of integers plus the header for the int array.
I used var graph = new Dictionary<long, List<long>>();
See here for complete solution in c# - https://gist.github.com/newton3/a4a7b4e6249d708622c1bd5ea6e4a338
PS - 2 years but just in case someone stumbles into this.

I am confused on copying 2D arrays

I was reading this post on Stack overflow: copy a 2d array in java and I am a little confused on how the clone method works here...
public int[][] CopyMap(int[][] Map)
{
int [][] copy = new int[Map.length][];
for(int i = 0; i < Map.length; i++)
copy[i] = Map[i].clone();
return copy;
}
I know how to copy using enhanced for loops but I would like to fully understand this way.
1) Why do we put the Map.length in the first set of square brackets but not Map[0].length in the second set of square brackets for int[][] copy = new int[Map.length][];? Don't we have to initialize the length of the columns as well? I'm guessing that we can't clone a 2D array but we can clone a row or column at a time.
2) By cloning the columns one column at a time and putting it into our 2D array it sets the length of the columns for us?
3) Could we reverse this code by doing this
public int[][] CopyMap(int[][] Map)
{
int [][] copy = new int[][Map[0].length];
for(int i = 0; i < Map[0].length; i++)
copy[i] = Map[i].clone();
return copy;
}
4) Also copy[i] ? This is a 2D array, so shouldn't it be copy[i][] ? Or something like that.
In Java a 2D array is essentially an array of arrays (possibly with different lengths). It is important to remember this. For example, this is OK:
int[][] ar = new int[2][];
ar[0] = new int[8]; // ar[0][0..7]
ar[1] = new int[4]; // ar[1][0..3]
The syntax new int[8][10] can be used as a convenience to create 8 separate arrays of 10 elements each.
If you are familiar with C: an int[][] in Java is more similar to an int** in C.
Note: Map is a terrible name for a variable in Java; variable names generally start with lowercase letters and there is also a very common base container interface of the same name.
1) Why do we put the Map.length in the first set of square brackets but not Map[0].length in the second set of square brackets for int [][] copy = new int[Map.length][]; ?
Because we are starting with an array of Map.length int[]'s, and then cloning those int[]s one at a time.
Don't we have to initialize the length of the columns as well?
No, because when we go through each int[] in Map, we just use clone() to copy it: copy[i] = Map[i].clone().
By cloning the columns one column at a time and putting it into our 2D array it sets the length of the columns for us?
A "column" is just a concept you made up that is only relevant to tabular data (column-major tabular data in your specific context). Anyways, "setting the length" isn't exactly accurate because it implied that something whose length is being set existed in the first place; but when you do int x[][] = new x[5][], x[0] is null until you assign it to something. By cloning the int[]s one at a time, we're just... cloning them one at a time. So, yes, each clone will be the same size as the original.
3) Could we reverse this code by doing this
public int[][] CopyMap(int[][] Map)
{
int [][] copy = new int[][Map[0].length];
for(int i = 0; i < Map[0].length; i++)
copy[i] = Map[i].clone();
return copy;
}
No; and hopefully the reason why is clear now that you know that an int[][] is an array of arrays. The expression new int[][size] doesn't make much sense; it says that we want each int[] in the array to have a given size, but it doesn't say how many int[]s are in the array. It's wrong for the same reason that int[] x = new int[] is wrong.
4) Also copy[i] ? This is a 2D array, so shouldn't it be copy[i][] ? Or something like that.
No, it should be copy[i]. I'll leave figuring out the reasons as an exercise.

Confusing regarding .get and .set in an ArrayList

(I'm new at Java, coming over from Python ---)
I'm going through a tutorial and they've created a program which counts how many times a number appears in a file, then returns that number. One particular part of the program is somewhat mysterious to me and deals with the ArrayList's .get and .set (methods? functions?). The program goes like this:
// (Scan a file with the numbers, say, 2 2 3 4, and put it into data1 variable.)
// (Make An Empty ArrayList with a bunch of 0's)
Scanner data1 = null;
ArrayList<Integer> count = new ArrayList<Integer>();
Integer idx;
while(data1.hasNextInt()){
idx = data1.nextInt();
System.out.println(idx);
System.out.println(count.get(idx)+1);
count.set(idx,count.get(idx)+1);
}
//Then prints out all the values; the ArrayList contains the number of times the number n occurs in the n-th index.
My question comes at the "while" part. For concrete, let's assume data1 has the numbers 2 2 3 4. It seems that it takes idx = 2, then puts a 1 in count[2], which is reasonable. It then takes idx = 2 again (the next integer in data1) and puts a 2 in count[2], which is also reasonable. At this point, the next number in data1 makes idx = 3, but it occurs at the index 2 in the ArrayList, so it should put a 3 in count[3], which is incorrect.
So, what is .get and .set doing here? Do they pop the elements off of the list when they're done with it? Am I overlooking something?
A .get() will not automagically get elements from a List which does not have that many elements. Note: list indices, like arrays, start at 0.
If you do:
final List<Integer> = new ArrayList<Integer>();
list.get(0);
this is a runtime error (IndexOutOfBoundsException) because your list has no elements.
You have to fill it:
list.add(1); // append an element
list.get(0); // returns element at index 0
list.get(1); // IndexOutOfBoundsException!
The .set() method takes an index and a value at an argument. In a similar vein, you cannot set an element which does not already exist, except at the very end of the list:
// start from an empty list
list.set(1, 32); // IndexOutOfBoundsException!
list.set(0, 32); // OK
Final note: try not to use list[i], bracket indices are used for arrays ;) Note that arrays are not resizabe in Java. Lists (which are an implementation of a Collection), however, are. But you must append to them.
So, what this line does:
count.set(idx, count.get(idx) + 1);
is take the value at index idx, add 1 to it, and sets back this value at the same index.
In your specific case, what you are looking for is a sparse array. In Java we use a HashMap<Integer, Integer> for that purpose. You don't need any initialization with zeros, but you do need to check for null:
final Integer curr = count.get(idx);
count.put(idx, curr == null? 1 : curr+1);
You are currently using an ArrayList, which acts like an array, but makes it easier to expand it - for example, add elements to it.
What you want is the java equivalent of the python dict, a key/value storage, in java, this is called a HashMap<K,V> (docs).
Scanner data1 = null;
HashMap<Integer, Integer> count = new HashMap<Integer, Integer>();
Integer idx;
while(data1.hasNextInt()) {
idx = data1.nextInt();
System.out.println(idx);
Integer g = count.get(idx)+1;
if(g == null) {
g = 0;
}
g++;
System.out.println(g);
count.put(idx, g);
}

Categories