This is a homework program I"m working on for an algorithms course. The task is to simulate an adjacency matrix for a graph using a matrix of Lists (this is Java btw). The element of the matrix is interpreted as the first node. Any nodes it is connected to in the graph are added to the list of that is that matrix element. I have constructed the matrix as such:
List<Node>[] weightedList = new List[size]
I understand that there are issues with Lists of Objects and type-checking. I then call a method initializeList() to construct the initial structure.
protected void initializeList() {
List<Node> list = new ArrayList<Node>();
for (int i = 1; i < Tester.size; i++){
weightedList[i] = list;
}
}
As I'm processing my input data I need to "construct" the graph based on given node values. My problem lies here, when I call addEdge() (effectively, connecting two nodes creates an Edge), the node I am trying to add gets added to every element of the matrix. Here is the method:
public static void putEdge(Edge e) {
Node node1 = e.getVertex1();
Node node2 = e.getVertex2();
int dim1 = node1.getNode();
if (dim1 < Tester.size){
weightedList[dim1].add(node2);
}
}
Is my issue related to the type-checking problems inherent in Lists of Objects or something else? Please advise.
-- JQK
You assign the same list instance to all the indices of the array.
You should instantiate each list inside the loop :
protected void initializeList() {
for (int i = 0; i < Tester.size; i++){
List<Node> list = new ArrayList<Node>();
weightedList[i] = list;
}
}
This way, each index in the array will contain a different ArrayList instance.
And you probably should iterate from 0, since that's the first index of the array.
You're running into the problem here of assignment only copying a reference to an object, not the object itself. #Eran's solution shows how to assign a different list to each matrix element.
Thank you #Eran. Your solution was correct. Simple mistake on my part. I cannot upvote yet and I'm not sure how to give you credit for the solution.
My error was the location of the assignment statement in initializeList()
This is the correct format provided by #Eran.
protected void initializeList() {
for (int i = 0; i < Tester.size; i++){
List<Node> list = new ArrayList<Node>();
weightedList[i] = list;
}
}
Related
I am trying to use array lists, and I have a row of coordinates. I would like to shift all the coordinates in this row to the front or to the back. I'm not sure if I am on the correct lines here with the code.
List<Coordinate> coordinates = new ArrayList<>();
void addCoordinateToList(Coordinate singleCoordinate) {
coordinates.add(singleCoordinate)
}
void addCoordinateToBackList(ArrayList<> coordinateList) {
for(int i = 0; i < coordinates.size(); i++) {
coordinateList.add(i, coordinateList(i));
}
}
void addCoordinateToFrontList(ArrayList<> coordinateList) {
for(int i = coordinates.size(); i > 0; i--) {
coordinateList.add(i, coordinatesList(i));
}
}
This is not final code, its just writing thoughts out at the moment.
Well, you don't need to use a for loop here.
You could instead utilize the addAll method to achieve what you want:
void addCoordinatesToBack(List<Coordinate> coordinateList) {
coordinates.addAll(coordinateList);
}
void addCoordinatesToFront(List<Coordinate> coordinateList) {
coordinates.addAll(0, coordinateList);
}
addAll has two forms:
addAll(Collection c) adds all elements of the specified Collection at the end of the list;
addAll(int position, Collection c) adds all elements of the specified Collection at the given position. Use position 0 to add them at the beginning of the list.
Also note that I have used List instead of ArrayList with your parameters, as this makes it more flexible.
Note that this is not quite the same as reversing lists.
This functionality is built into the List interface. You can use the following functions for that:
List<String> myList = new ArrayList<>();
//adds to the end of the list
myList.add("reading");
myList.addAll(List.of("the","documentation","first!"));
//adds to the front of the list
myList.add(0,"with");
myList.addAll(0,List.of("It","begins");
Your code
void addCoordinateToBackList(ArrayList<> coordinateList) {
for(int i = 0; i < coordinates.size(); i++) {
coordinateList.add(i, coordinateList.get(i));
}
}
will endlessly add the first element of the original list to beginning of itself. Note that I added the call to List.get(int).
Your last method will throw an ArrayIndexOutOfBounds exception as index i=coordinates.size() is out of bounds. You probably need to change
void addCoordinateToFrontList(ArrayList<> coordinateList) {
for(int i = coordinates.size() - 1; i >= 0; i--) {
coordinateList.add(i, coordinatesList.get(i));
}
}
But this will again add endlessly the last element of the list to itself.
Probably what you want to achieve is:
List<Object> coordinateList = new ArrayList<>();
...
java.util.Collections.reverse(coordinateList);
This will reverse the order of the elements in the list. Note that it will work on the given list and not return anything. This will work only on modifiable lists.
EDIT:
You probably mean to "rotate" the elements, right? There is also the method Collections.rotate(List input, int distance). The documentation:
Rotates the elements in the specified list by the specified distance. After calling this method, the element at index i will be the element previously at index (i - distance) mod list.size(), for all values of i between 0 and list.size()-1, inclusive. (This method has no effect on the size of the list.)
For example, suppose list comprises [t, a, n, k, s]. After invoking Collections.rotate(list, 1) (or Collections.rotate(list, -4)), list will comprise [s, t, a, n, k].
This works in both directions.
I am using graphviz with Java, and I need to loop data array and need to define relationship
Graph g = graph("example5").directed().with(node("abc")
.link(node("xyz")),node("abc")
.link(node("xyz")));
Graphviz viz = Graphviz.fromGraph(g);
viz.width(200).render(Format.SVG).toFile(new File("example/ex5.svg"));
I need to create array that should have multiple node("abc").link(node("xyz")) then pass it to with method
I think doing something like the following should work.
Here I am iterating and creating a node, calling link on the current node and assigning the the node, before reassigning current.
The entire list is then passed to with
List<Node> nodes = new ArrayList<>();
Node curr = node(String.valueOf(0));
for(int i = 0; i < 5; i++){
Node next = node(String.valueOf(i+1));
curr.link(next);
nodes.add(curr);
curr = next;
}
Graph g = graph("example5").directed().with(nodes);
just to start off, this is homework and thank you for your assistance ahead of time. I keep getting stuck on little problems so I am hoping you guys can help me with one. What I am trying to do is create a linked list that has multiples functions. The one I am having trouble with is sorting(I can do the other ones). Each node holds a string, an integer and a double. I need to be able to sort by each of these and by the order it was inputted, on the user's request. ***It is also important to mention that the variables in my object are private and my object is called list1. Basically, I have to make one linked list for the chronological order and one for each other order.
My plan is to insert the nodes in their correct order as the user inputs them. So as the user inputs a node, that node needs to go in the correct place in the chronological list and in the other lists. So, I need to copy the node to do this. However, I cannot simply just say
icopy(copy for integer) = newNode(node the user just inputted)
That only changes the address. When I went to my instructor he told me that I should say:
icopy.data = newNode.data;
("data" being the shortcut way of mentioning that I need to get the individual data types within the node.) So I wrote:
icopy.GetI() = newNode.GetI();
When I do this I encounter this error: unexpected type required:variable, found:value. I am not sure what to do. Any assistance would be appreciated and I would be happy to clarify anything.
*GetI: method in my object that gives access to the integer value in each node.
*p: pointer for the Chronological
*pi: pointer for the integer.
*fi: front of the integer linked list
public static void main(String args[])
{
String repeat = "y";
boolean inserted = false;
list1 fChr = null;
list1 p = fChr;
list1 icopy = null;
list1 scopy = null;
list1 dcopy = null;
list1 fd = fChr;//front of the double list
list1 fi = null;//front of the integer list
list1 fStr = fChr;//front of the string list~
while(repeat.equals("y"))//while the user agrees to adding a new node
{
if(fChr == null)// if the front is empty
{
fChr = new list1();//create a new node by calling object and sets it as the front
}
else
{
p = fChr;
while(p.next != null)//finds the end of the Linked list
{
p = p.next;//moves the pointer p down the list
}
list1 newNode = new list1();
icopy.GetI() = newNode.GetI();// make a copy of newNode
p.next = nexNode;//put in chronological order
while(p != null)
{
if(fi == null)
{
fi = n;
}
else if(n.GetI() < fi.GetI)//check at beginning
{
//put at beginning
}
else if(icopy.GetI() < p.next.GetI())//check in between nodes
{
//put in between
}
//does it go at the end
}
}
repeat = JOptionPane.showInputDialog("Would you like to add a node [y/n]");
}
PrintMenu(fChr, fi, fd, fStr);// sends the user to the menu screen
}
There are a few things here that you are not understanding. Firstly, in Java iCopy.getI() = ... makes no sense. When a method returns a value it needs to be assigned to a variable if you wish to change it. If you want to change the instance variable you need a separate method called something like iCopy.setI().
It sounds as though you're not asking for help with the sorting so I'll restrict my answer to creating copies of the list.
What your professor is getting at is that the easiest way to ensure the data is consistent in your several linked lists is to separate the class storing the data from the nodes of the list. So I would expect your class structure to end up looking something like:
class Data {
private final int intValue;
private final String strValue;
private final double doubleValue;
}
class Node {
private final Data data;
private Node next;
public Node(Data data) {
this.data = data;
this.next = null;
}
}
Now if you want to create a new linked list with the same data as the old one then you can add a constructor to Node that creates a reference to the original data:
class Node {
public Node copy() {
Node copy = new Node(data);
if (next != null)
copy.next = next.copy();
return copy;
}
}
Hopefully you can see what that does: it creates a new node referencing the same data as this one and then uses recursion to copy the rest of the list.
Now creating each of the sort orders could look like:
Node listByInt = list.copy();
/* code to sort listByInt according to data.intValue */
Add a comment if you want some hints on sorting as well but I suggest you get your code to the point of having equal copies of lists before attempting that.
As a final note, you don't necessarily need to have separate linked lists to solve this problem. An alternative would be to store the original insertion order in the node. You could then sort by any order (including original insertion order) before printing the list. Personally I'd prefer that as a solution unless there are performance issues (e.g. you need to use each sorted list many times).
This seems like basic question, but it has really confused me. I ma trying to represent the adjacency list of a graph. I have two questions :
public class Graph
{
private final int V;
private List<Integer>[] adj;
public Graph(int V)
{
this.V = V;
this.adj = (List<Integer>[]) new LinkedList[V]; // this works
}
}
Question 1: when I do the below, it gives an error saying
Array type expected; found: 'java.util.LinkedList<java.lang.Integer>'
this.adj = (List<Integer>[]) new LinkedList<Integer>()[V];
I am creating a List of Integer arrays, right ?
Question 2: when I do this, it again gives an error saying generic array creation:
this.adj = (List<Integer>[]) new LinkedList<Integer>[V];
What is the problem with the last two approaches ? i think the first one is more correct.
In (1), your expression is being parsed as
(new LinkedList<Integer>())[V]
which is attempting to index a freshly-created LinkedList, hence the error.
In (2), you are trying to make an array of generics. You can't do this. Instead, consider using some container type (like an ArrayList<List<Integer>>).
You are trying to create an array of list of integer. That means each index can have multiple count. So, you need to initialize each index.
public Graph(int v)
{
V = v;
adj = new List<int>[v];
for (int i = 0; i < v; ++i)
adj[i] = new List<int>();
}
I am creating a linked list function for homework that adds at any index except last, but I don't understand how to make a conditiontargetList.addToIndexAt(81,0); without sentinel nodes
EDIT Okay, I fixed all of the problems, except for one. This time, the code runs the code states that the result is 81,0,0,0,0, which means that after returns back to 0 every cycle of the code. How do i make the after=after.tail retain it's number?
public void addToIndexAt(int n, int index){
IntList addition = new IntList(n);
if(index==0){ //THIS IS MY PROBLEM
IntList beginning=this;
IntList after=this;
IntList current=this;
IntList temp=this;
while(after.tail!=null){
after=after.tail;
temp=after;
after.head=current.head;
}
beginning.head=n;
}
else{
IntList after = this;
IntList before = this;
int nafter = index;
int nbefore = index;
while(nafter>0){
after = after.tail;
nafter--;
}
addition.tail = after;
while(nbefore>1){
before = before.tail;
nbefore--;
}
before.tail= addition;
}
}
It seems you are treating the Node class the same as a List class. To me, these are different. I would suggest creating a class called List that holds a reference to the first node in the list.
Alternatively, you can try changing your code slightly where the insert method returns the new head of the list.