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).
Related
I was wondering if someone could help explain how to reverse a singly linked list without creating new nodes or changing data in the existing nodes. I am trying to study for finals and we had this question on a previous test. They don't release answers to the coding portions of the test and I haven't been able to figure it out.
They told us the best way to reverse it was by using a "runner technique" which I believe I understand what that is. They described it as using two pointers or counters to run through a list and gather information but I'm not sure how to use that to reverse a singly liked list. I was able to brute-force code to reverse a list of length 2, 3, and 4 but I was unable to make a loop or do it recursively. Any code or an explanation on how to go about this would be appreciated, thank you.
You can derive the code by starting with the idea of merely - one by one - popping elements off the input list and pushing them onto an initially empty result list:
NODE reverse(NODE list) {
NODE result = null;
while (list != null) {
NODE head = <pop the first node off list>
<push head onto result>
}
return result;
}
The result will be the reverse of the input. Now substitute Java for the missing pieces
NODE reverse(NODE list) {
NODE result = null;
while (list != null) {
// pop
NODE head = list;
list = list.next;
// push
head.next = result;
result = head;
}
return result;
}
And you're done...
It depends on your implementation of the list, but I would recurse to the end and then reverse the references.
void Reverse(List pList) {
Reverse(pList, null, pList.First); // initial call
}
void Reverse(List pList, Node pPrevious, Node pCurrent) {
if (pCurrent != null)
Reverse(pList, pCurrent, pCurrent.Next); // advance to the end
else { // once we get to the end, make the last element the first element
pList.First = pPrevious;
return;
}
pCurrent.Next = pPrevious; // reverse the references on all nodes
}
I am trying to reverse a linked list which works, but when I try to print the original, it fails (only prints the head). My question is, why would reversing affect the original. Below is my code. LinkedList is my own class, so is Node. Before reversing, if I try to print my list, that works.
public static void main(String[] args) {
LinkedList list;
...
Node head = list.getHead();
Node rev = reverse(head);
Node temp = rev;
while (temp != null) {
System.out.println(temp);
temp = temp.next;
}
temp = head;
while (temp != null) {
System.out.println(temp);
temp = temp.next;
}
}
private static reverse(Node head) {
// Reversing the linked list
}
EDIT::
This seems to be a Java thing. Java passes an object by reference. When I pass head as a parameter, it's passed by reference and any change made to it is reflected in the calling function.
Doing Node h = head and then passing h as a parameter won't work either since h will be the same object as head.
The only option I can think of is to create a new object, copy the linked list over and pass that as a parameter.
My question becomes, is there a better solution?
To understand it, picture your list looks like this
list (list.head =a) --> a (a.next=b) --> b (b.next= c) -> c (c.next = null)
If you get the head, then you are getting object 'a'.
Then you are modifying object 'a'.
So you can see you are editing the list by doing this.
What you need to do is:
Get the head
Create a copy
Reverse the copy
Get the next item
Copy it
Reverse it
Join it to the last
And so on
Since you are using your own classes not java collections classes, the easiest way is for you to make sure that reverseNode() only edits a copy of the one you pass it, and returns the copy.
First make sure your Node class has a constructor that copies another Node, then do something like this:
private static Node reverse(Node original)
{
Node retval = new Node(original);
// or you could use clone () as Bhavik suggested, if your Node class implements it
// modify retval
// I haven't shown code to reverse it as I assume you already have that and you didnt specify if it was a bidirectional list or just one direction.
return retval;
}
Or you might add a static method in your Node class that constructs a new node that is reversed:
static Node createReverse(Node n)
{
return new Node(n.data,n.next,n.prior);
}
Or a non static method of the node class which returns a reversed copy of itself;
Node createReverse()
{
return new Node(this.data,this.next,this.prior);
}
But you should consider this can get very ugly because your copies will still have pointers pointing into the existing list!
A better technique might be to create a new empty list, and then start from the end of your original, make a copy, and add it to the start of your new list.
You can use recursion to do this but might easily run out of memory.
But rather than do this manually, you might look at the java.util packages and switch to using one of their LinkedList and list item types. These classes have already solved all the problems with doing this stuff.
Then you could (if you need to keep the original list unmodified):
- Make a copy of your entire list.
- reverse the copy as below
If you don't care about keeping the original, then just use this method(below) on your list, no need then to make a copy.
From java.util.Collections:
Collections.reverse(List a_list);
The Collections class will choose an efficient way to reverse the list, depending on whether it is bidirectional, single directional, etc.
Chunko's answer is right in that you should be creating copies of your Nodes instead of just passing references to them.
However, I think you might be overthinking this:
LinkedList reversedList = new LinkedList();
for (int i = originalList.size()-1; i >= 0; i--) {
reversedList.add(list.get(i));
}
Java's LinkedList doesn't have a getHead() method, so I guess you're using some homework-related custom implementation of a linked list. Still, your implementation should have an add() method that appends a new Node to the list, as well as a get(int) method that returns the item in a given position.
You can use those methods to create a new list and populate it with the original list's items in reversed order.
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;
}
}
My Node class, representing a node of a linked list, is defined like this:
public class Node
{
Node next;
String data;
public Node (String data)
{
this.data = data;
}
}
and I'm using it like this:
Node node, head, tail;
String name; // name to be entered
int count = 0;
// initialize the head to null
head = null;
do
{
System.out.print ("Enter a name. Type q to end.");
name = stdin.readLine ();
// create a new node if the user doesn't type q
if (!name.equals ("q"))
{
node = new Node (name);
node.next = head;
count++;
// update the head to point to the new front of the list
head = node;
}
}
while (!name.equals ("q")); // loop continues until "quit" selected
node = head;
Suppose I wanted to back the names up to a method in case I modify the original list. How can I do this? Without writing it to a file.
Name is the variable that gets stored in the linked list and after the user presses q I want to modify the list while keeping what the user stored as a back up in case he/she wants to backtrack or see the original list.
It would be better to make the Node immutable. So every time when you want to modify the node, you create a new node. And store the old one in the linklist history.
So it sounds as though you want to keep a history of the prior names for each element in the linked list. I would suggest that you store an array or linked list within each node of the linked list that shows the prior history of that item. For instance:
public class Node
{
Node next;
String data;
LinkedList<String> history;
public Node (String data)
{
this.data = data;
}
}
You could populate this in many ways, that all really depend upon your use case.
Also, why implement your own linked list? Java already comes with a linked list implementation (java.util.LinkedList). I'd suggest using this if you need an ordered list of the linked list variety. If you did this, then create a new data structure to be contained within it that has a name and history, then just maintain the history within that, such as:
public class DataItem
{
String data;
LinkedList<String> history = new LinkedList<>();
public DataItem (String data)
{
this.data = data;
}
public void setData (String data)
{
this.history.add(0, this.data);
this.data = data;
}
}
Ultimately, remember that strings are immutable in Java. So, a string cannot be modified. You only need to keep a reference to the prior string somewhere, you don't need to copy the value.
To ultimately copy a tree of objects, you need to do what's called a deep copy, basically going through the full structure and all collections, and cloning each object into a new object.
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.