Linked List in my Array not working - java

I am trying to create a program to store words in a Array. I have a hashFunction which computes a Integer value. This value is used to put the Word in a Node if that position in the array is null. If there is already a Cell there, it should create a new Cell with the word as its data type, and it should then point to the old Cell with all the other data. However this dosen't seem to be working - I have added a few words and although it adds the first word to the Cell the other words aren't being added. I'm not sure why this is happening - can someone show my why?
public class test2{
public static class Node<T>{
public T data;
public Node<T> next;
public Node(T data, Node<T> next)
{
this.data = data;
this.next = next;
}
}
static Node[] array = new Node[10];
public static void add(String word){
int position = hashFunction(word);
if(array[position] == null){
array[position] = new Node(word, null);
}else{
new Node(word, array[position]);
}
}
public static int hashFunction(String a){
int sum = 1;
for(int i = 0; i<a.length(); i++){
char b = a.charAt(i);
int value = (int) b;
sum *= value;
}
return sum % array.length;
}
public static void main(String[] args) {
add("abc");
add("acb");
add("bca");
add("bac");
add("cba");
System.out.println(array[4].next);
}
}

Instead of
new Node(word, array[position])
You should do the following:
array[position] = new Node(word, array[position]);
With the original line of code you are correctly creating an new instance of Node to which you assigned the current array[position] as its next value.
But array[position] is still the same, you need to change it to the newly created instance of Node.

You're adding the word as a new node in your linked list, but you're never storing a reference to the new node. When you add a node at the beginning of a linked list, you have to store the new node as the new head of the list.
In your case, you could accomplish that with the following:
public static void add(String word){
int position = hashFunction(word);
if(array[position] == null){
array[position] = new Node(word, null);
}else{
Node newHead = new Node(word, array[position]);
array[position] = newHead;
}
}
Now your linked list will have all of the words you're expecting. You could also iterate over the linked list in array[position] and add the new node at the end of the list if that's more appropriate for your use case.

Related

Remove item from LinkedList

Small problem i am having with a program here. I am trying to create a program that adds Words to Linked Lists within a Array depending on their hashCode, determined by my hashFunction. If they have the same value for their hashCode they get added into a Linked List. I have a small count method that counts how many times a word is in the List. It works by computing the value for their hashFunction. It then goes to that value in the array, and iterates through the LinkedList until it reaches a Null value. It has a count variable which is incremented each time it finds the word in the list. This is my code:
public class test{
public static class Node<T>{
public T data;
public Node<T> next;
public Node(){
}
public Node(T data, Node<T> next)
{
this.data = data;
this.next = next;
}
}
static Node[] array = new Node[512];
public static void add(String word){
int position = hashFunction(word);
if(array[position] == null){
array[position] = new Node(word, null);
}else{
Node newHead = new Node(word, array[position]);
array[position] = newHead;
}
}
public static void remove(String word){
int remove = hashFunction(word);
Node head = array[remove];
if(head.data == word){
head = head.next;
System.out.println("Found");
}else if(head.data != word){
for(; array[remove] != null; array[remove] = array[remove].next){
if(array[remove].data == word){
array[remove] = array[remove].next;
}
}
System.out.println("Yusuf");
}
}
public static int count(String word){
int number = 0;
int position = hashFunction(word);
for(; array[position] != null; array[position] = array[position].next){
if(array[position].data == word){
number++;
}
}
System.out.println(number);
return number;
}
public static int hashFunction(String a){
int sum = 1;
for(int i = 0; i<a.length(); i++){
char b = a.charAt(i);
int value = (int) b;
sum *= value;
}
return sum % array.length;
}
public static void addthings(String word, int n){
for(int i = 0; i<n; i++){
add(word);
}
}
public static void main(String[] args) {
addthings("abc", 500000);
count("abc");
count("abc");
count("abc");
count("abc");
}
}
My issue is the first time I add values in it and check how many times it occurs it works fine, but any more calls to the Count method after that returns 0 for some reason.
I have another issue too which is my remove method isn't removing the items from the Linked List I want it too. The code iterates through the List, and when it finds the item which is meant to be removed, it removes the pointer from there and points it to the next value. This isn't working however.
Can someone show me how to fix these two issues please?
Thanks.
In your function if you write something Node head it means you are creating some local instance for a Node. If you set head = head.next this will simply change the state of your local instance variable not the state of your array.
You are checking if the first node contains the data which you are looking and trying to remove it then you have to remove it from your source Array(Array in which your references reside).So you can write something like this:
if(head.data == word)
array[remove] = head.next;
This was an example. The point is that you are not chaning things in your array but in your local variable.
public static void remove(String word){
int remove = hashFunction(word);
Node head = array[remove];
if(head.data == word){
head = head.next;
System.out.println("Found");
}else if(head.data != word){
for(; array[remove] != null; array[remove] = array[remove].next){
if(array[remove].data == word){
array[remove] = array[remove].next;
}
}
System.out.println("Yusuf");
}
}
A second mistake is in second clause where you just set array[remove] = array[remove].next;
It will break your linkedlist into two different linkedlist. Suppose you have 4 elements in linkedlist A,B,C,D and you remove B and there were pointers like this A->B->C->D then you are adding no pointers from A -> C. Here you break your linkedlist.
You can use while loop that will work easily.

Java Priority Queue in Linked List Test Cases

So I'm trying to implement a priority queue with a linked list. I think I have the basics together, but for some reason my test cases aren't working. When I run it, the size show up fine, but none of the node values are showing (only an arrow "->" pops up once). If anyone could help me figure out why it isn't working, or suggest a better way to set up test cases in java (I've never done that before) it would be appreciated!
Node class:
public class Node { //Node class structure
int data; //data contained in Node; for assignment purposes, data is an int
Node next; //pointer to Next Node
//Node Constructor
public Node(int data) {
this.data = data;
next = null;
}
//Set Methods
public void setData(int data) { //set Node value
this.data = data;
}
public void setNext(Node next) { //set next Node value
this.next = next;
}
//Get Methods
public int getData() { //get Node value
return this.data;
}
public Node getNext() { //get next Node value
return this.next;
}
//Display the Node Value
public void displayNode() {
System.out.println(data + "urgh"); //display value as a string
}
}
Linked List Class:
import Question1.Node;
//basic set-up of a FIFO singly linked list
public class SLList{
protected Node head; //head of SLList
protected Node tail; //tail of SLList
int n; //number of elements in SLList
//SLList constructor
public SLList() {
head = null;
n = 0;
}
//check if list is empty
public boolean isEmpty() {
return head == null;
}
//return the size of the list
public int size() {
return n;
}
//add a new node to the end of the list
public boolean insert(int x){
Node y = new Node(x);
if (head == null){ //if head is null, thus an empty list
head = y; //assign head as y
}
else{ //if there is already a tail node
tail.next = y; //assign the tail's pointer to the new node
}
tail = y; //assign tail to y
this.n++; //increment the queue's size
return true; //show action has taken place
}
//remove and return node from head of list
public Node remove(){
if (n == 0){ //if the list is of size 0, and thus empty
return null; //do nothing
}
else{ //if there are node(s) in the list
Node pointer = head; //assign pointer to the head
head = head.next; //reassign head as next node,
n--; //decrement list size
return pointer; //return the pointer
}
}
//display SLList as string
public void displayList() {
Node pointer = head;
while (pointer != null) {
pointer.displayNode();
pointer = pointer.next;
}
System.out.println(" ");
}
}
Priority Queue Class:
import Question1.Node;
import Question1.SLList;
public class PriorityQueue extends SLList {
private SLList list; //SLList variable
public PriorityQueue(){ //create the official SLList
list = new SLList();
}
//add a new node; new add method that ensures the first element is sorted to be the "priority"
public boolean add(int x){
Node y = new Node(x);
if (n == 0){ //if there are 0 elements, thus an empty list
head = y; //assign head as y
}
else if (y.data < head.data){ //if new node y is the smallest element, thus highest priority
y.next = head; //assign y's next to be current head of queue
head = y; //reassign head to be actual new head of queue (y)
}
else{ //if there is already a tail node
tail.next = y; //assign the tail's pointer to the new node
}
tail = y; //assign tail to y
n++; //increment the queue's size
return true; //show action has taken place
}
//delete the minimim value (highest priority value) from the queue and return its value
public Node deleteMin(){
return list.remove(); //the list is sorted such that the element being removed in indeed the min
}
//return the size of the queue
public int size() {
return n;
}
//display Queue as string
public void displayQueue() {
System.out.println("->");
list.displayList();
}
}
Test Cases (so far, the delete one wasn't working so it's commented out):
import Question1.PriorityQueue;
public class TestQ1 { //Test code
public static void main(String[] args){
PriorityQueue PQueue1 = new PriorityQueue();
PQueue1.add(3);
PQueue1.add(2);
PQueue1.add(8);
PQueue1.add(4);
System.out.println("Test add(x): ");
PQueue1.displayQueue();
System.out.println("Test size(): " + PQueue1.size());
PriorityQueue PQueue2 = new PriorityQueue();
//Node node1 = PQueue1.deleteMin();
System.out.println("Test deleteMin():");
PQueue2.displayQueue();
System.out.println("Test size(): " + PQueue2.size());
}
}
Change list.displayList() to displayList(), and you'll see the expected output.
Why? Because your queue is already a list (that is, an instance of SLList). When a class A extends another class B, an instance of A is also an instance of B. This is inheritance.
You've also included an instance variable private SLList list within your PriorityQueue implementation, which is an example of composition. Generally you'll only do one or the other of these two options, depending on your situation. In this case it seems you're trying to use inheritance, so there's no reason to create a separate list instance variable. You're adding the data directly to the queue (using the fact that, intrinsically, it is a list in its own right).
You should remove the list instance variable, and all the usages of it should refer to the parent class' methods or variables.

Keeping track of head of ListNode in Java

I am currently working on my own Java class called LString, which is meant to convert back and forth between linked lists of characters and Strings.
I am having issues with my toString() method, specifically keeping track of the "head" of the linked list in order to loop through it and concatenate the characters into a new string. While researching, I read that I am supposed to keep track of the head of the list somehow, but I can't figure out how to implement it.
Any help would be greatly appreciated!
Edit: The error message I am receiving is:
LString.java:79: error: cannot find symbol
ListNode current = this.front;
public class LString{
private static int length;
// ListNode constructors
// Creates a new ListNode with characters stored in variable "data" and
// Node named next
private class ListNode{
char item;
ListNode next;
private ListNode(){
}
// creates a new ListNode that has the value and links to the specified ListNode
private ListNode(char item, ListNode next){
this.item = item;
this.next = next;
}
// given a character, creates a new ListNode that doesn't link to anything
private ListNode(char item){
this.item = item;
this.next = null;
}
}
public LString(){
this.length = 0;
ListNode front = new ListNode();
}
//LString
// Takes in a String object and loops until it has added all characters to a new linked list
public LString(String original){
ListNode front;
this.length = 1; // length keeps track of number of nodes
if (original.charAt(0) == 0){ // creates a new ListNode if it is an empty string
front = new ListNode();
}
else {
front = new ListNode(original.charAt(0));
}
//System.out.println("this is happening " + front.item);
//ListNode current = front;
for (int index = 1; index < original.length(); index++) {
front.next = new ListNode(original.charAt(index), front.next);
front = front.next;
//System.out.println("strings: " + front.item);
length++;
}
//System.out.println("length: " + length);
}
// returns length of the LString object
public int length(){
return this.length;
}
// toString takes an LString object and converts it to a string
public String toString(){
StringBuilder newString;
ListNode current = this.front;
while (current.next != null){
newString.append(current.item);
current = current.next;
}
return newString.toString();
}
public static void main(String[] args){
LString stuffTest = new LString("hello");
int valueOf = stuffTest.length();
System.out.println(stuffTest.length());
String testMeWhy = stuffTest.toString();
}
}
The general pattern for building a linked list by appending to the end is:
At the beginning:
head = null;
tail = null;
To append newNode to the list:
if (head == null) {
head = newNode;
} else {
tail.next = newNode;
}
tail = newNode;
I think you're trying to do this by keeping just one pointer in the list class, which doesn't work very well. Also, doing things using this pattern means you don't have to have a "special" node at the front of the list, unless there's some other good reason to. It looks like you were trying to use new ListNode() with no arguments to create some kind of special node, but only sometimes. It's unnecessary and just makes things more complicated.
Your basic problem is that there should be only one front, and it should be a class member and not a local variable. That is how your LString class "keeps track" of the first node.
public class LString {
private ListNode front = null;
private int size = 0;
...
This will get you started and allow you to maintain the actual list. Your other LString methods will also need some work, but once you get past this problem you should be able to use your debugger to step through the code and solve the remaining issues yourself.

Adding an integer to an array inside a node

So the concept of my question is: Let's say we have nodes. Each node has an array of integers. Now, we must add an integer to end of the array. How do we do that?
Here's what I've done so far:
Created class Node:
public class Node {
private int[] data;
Node next;
public Node(int n, Node nxt) {
data = new int[n];
next = nxt;
}
}
Then the dynamic array list class:
public class DynamicArrayOfInts {
private Node head = null;
private int numOfElementsPerNode = 0;
public DynamicArrayOfInts(int elementsPerNode) {
numOfElementsPerNode = elementsPerNode;
}
public void add(int e) {
}
}
You should add an attribute in the Node class to know the current index you are for the current Node's array. I would also add an attribute in your DynamicArrayOfInts to keep a reference for the current node.
Then in your add method, check if the array that the current node have is not full (it can be done easily because you know the value of the index and the number of elements per node).
If it's not the case (or if the head is null for the first add call), create a new node and add the element in its array, otherwise just fill the next slot of the array for the current node.
This is how I would implement it.
class DynamicArrayOfInts {
private Node head, current;
private int numOfElementsPerNode;
public DynamicArrayOfInts(int elementsPerNode) {
if(elementsPerNode <= 0)
throw new IllegalArgumentException("elementsPerNode must be > 0");
numOfElementsPerNode = elementsPerNode;
}
public void add(int e) {
if(head == null){
head = new Node(numOfElementsPerNode, null);
head.data[head.index++] = e;
current = head;
return;
}
if(current.index == numOfElementsPerNode){
Node n = new Node(numOfElementsPerNode, null);
current.next = n;
current = n;
}
current.data[current.index++] = e;
}
#Override
public String toString(){
StringBuilder sb = new StringBuilder();
Node n = head;
while(n != null){
sb.append(Arrays.toString(n.data));
n = n.next;
}
return sb.toString();
}
private static class Node {
private int[] data;
private int index;
private Node next;
public Node(int n, Node nxt) {
data = new int[n];
index = 0;
next = nxt;
}
}
}
A small main to show how it behaves:
public static void main(String[] args){
int[] toAdd = {5,7,10,-1};
DynamicArrayOfInts d = new DynamicArrayOfInts(2);
for(int i : toAdd){
d.add(i);
System.out.println(d);
}
}
Output:
[5, 0]
[5, 7]
[5, 7][10, 0]
[5, 7][10, -1]
Unfortunately you have to create a new array in this case (yes, I feel your pain) which will have one more element than data. You will have to copy the content of data into your new array and set the last element to your int value. This is not too elegant, this is why Mureinik suggested that you should use an ArrayList of Node (ArrayList<Node>) instead. I can even enhance his suggestion to make your solution more general and tell you to use an AbstractList<Node> instead and instantiate it with ArrayList, but this might be too advanced compared to your current level (no offence, we all have been there). As of your exact question, I imagine a method like the following in your Node class to deal with this problem.
public void push(int newValue) {
int[] newData = new int[data.length + 1];
for (int i = 0; i < data.length; i++) {
newData[i] = data[i];
}
newData[data.length] = newValue;
data = newData;
}

Appending an object in an ArrayList in java

I am working on an exercise and I ran into a problem.
In NodeList, create a static method Node arrayToNode(String[] arr)
which converts a String array into a list. Your method should create a first Node,
and then go through the rest of the array, creating a Node at each step, and using
append to put the created Node at the end of the list. Test this method on the
command line arguments. What happens if the array is empty?
Currently my code is like this
public static Node arrayToNode(String[] arr) {
Node first = new Node(arr[0]);
ArrayList<Node> list = new ArrayList<Node>();
for(int i=1; i<arr.length;i++){
list.add(new Node(arr[i]));
}
}
as you can see there is no return statement YET.
I am not sure if the person who wrote the exercise made a mistake by writing Node instead of void but I cannot ask him.
The append method is
public void append(Node fin){
if(next==null)
next=fin;
else
append(next);
}
and the instance variables and the constructor is as follows:
public String value;
public Node next;
public Node(String s){
value =s;
next=null;
}
I am quite unsure what it means to put the node at the end of the list as the ArrayList keeps on expanding.
Also, I have questions about using the deploying the append method as in how to even use it in the TestNode class.
Thanks for the comment.
I have now realized what the problem was and have made appropriate changes.
public static Node arrayToNode(String[] arr){
Node first = new Node(arr[0]);
for(int i=1; i<arr.length;i++){
Node nd = new Node(arr[i]);
nd.append(nd);
first.next=nd;
}
return first;
}
could you see if this is correct?
Unless I'm missing something, your append method should be this:
public void append(Node fin) {
if (next == null)
next = fin;
else
next.append(fin); // <- this line changed
}
That will append fin down the line until it reaches the end of the list while the way you have it in your OP will give infinite recursion.
If it's supposed to be that way then creating the list is very simple. You can just append each value to the original one.
public class Node {
public static void main(String[] args) {
Node begin = arrToLL(new String[] {
"hello 1", "hello 2", "hello 3", "hello 4", "hello 5"
});
while (begin != null) {
System.out.println(begin.val);
begin = begin.next;
}
}
static Node arrToLL(String[] arr) {
if (arr == null) {
return null;
} else if (arr.length == 0) {
return new Node("null");
}
int ind = 0;
Node begin = new Node(arr[ind++]);
while (ind < arr.length) {
begin.append(new Node(arr[ind++]));
}
return begin;
}
/* instance */
String val;
Node next;
Node(String val) { this.val = val; }
void append(Node ap) {
if (next == null) {
next = ap;
} else {
next.append(ap);
}
}
}
Output is:
hello 1
hello 2
hello 3
hello 4
hello 5
Inside the "to list" loop you could also "shuffle ahead" by assigning next to a variable like in my println loop. That way you aren't taking advantage of the "pass through".
public static Node arrayToNode(String[] arr){
Node first = new Node(arr[0]);
for(int i=1; i<arr.length;i++){
Node nd = new Node(arr[i]);
nd.append(nd); // <- appends nd to itself
first.next=nd; // <- always assigns the new value to first
}
return first;
}
That's getting closer but I've commented the two lines that are in err. I think what you will end up with is:
First Node with the first array element linked to
A second Node with the last array element linked to
Itself (the second Node)
You can do this without append but you need another variable to shuffle:
public static Node arrayToNode(String[] arr){
Node first = new Node(arr[0]);
Node current = first;
for(int i=1; i<arr.length;i++){
Node nd = new Node(arr[i]);
current.next = nd; // <- append the new node to the last
current = nd; // <- shuffle ahead to the new one
}
return first;
}
Otherwise if I'm correct in thinking append had an error you can do something closer to my main example (including the shuffle if you want and a for loop works just as well).

Categories

Resources