I am working on a project for my Data Structures class that asks me to write a class to implement a linked list of ints.
Use an inner class for the Node.
Include the methods below.
Write a tester to enable you to test all of the methods with whatever data you want in any order.
I have to create three different constructors. One of the constructors is a copy constructor. I have my code down below showing what I did but I'm not sure I wrote this constructor correctly. I also have a method called addToFront one of the many methods I need to implement in this project. Can someone let me know what I would need to write for the copy constructor? I have no idea what I need to write for a copy constructor. I've tried looking it up but the examples shown don't match with what I'm trying to write.
public class LinkedListOfInts {
Node head;
private class Node {
int value;
Node nextNode;
public Node(int value, Node nextNode) {
this.value = value;
this.nextNode = nextNode;
}
}
public LinkedListOfInts() {
}
public LinkedListOfInts(LinkedListOfInts other) {
}
public void addToFront(int x) {
head = new Node(x, head);
}
public String toString() {
String result = " ";
for (Node ptr = head; ptr != null; ptr = ptr.nextNode)
result += ptr.value + " ";
return result;
}
public static void main(String[] args) {
LinkedListOfInts list = new LinkedListOfInts();
for (int i = 0; i < 15; i++)
list.addToFront(i);
System.out.println(list);
}
}
You can iterate over the nodes of the other list and sequentially create new tail nodes based on their values.
public LinkedListOfInts(LinkedListOfInts other) {
Node tail = null;
for(Node n = other.head; n != null; n = n.nextNode){
if(tail == null) this.head = tail = new Node(n.value, null);
else {
tail.nextNode = new Node(n.value, null);
tail = tail.nextNode;
}
}
}
// ...
public static void main(String[] args) {
LinkedListOfInts list = new LinkedListOfInts();
for (int i = 0; i < 15; i++)
list.addToFront(i);
LinkedListOfInts copy = new LinkedListOfInts(list);
System.out.println(list);
System.out.println(copy);
}
This question already has answers here:
Cannot make a static reference to the non-static method
(8 answers)
Closed 2 years ago.
Im trying to work on some of the Queue methods, get some practice with them in a little bit so I chose a handful from the list on Oracle's documentation and gave them a shot. Everything in my code seems to be working smoothly except for this one hiccup that I have not been able to get over. I'm pretty new at programming and I am in college for it, but I am still learning the basics. Here is what I have for my code:
import java.util.NoSuchElementException;
public class Queue<E> {
private Object[] queue;
private int size = 0;
private int top;
private int bottom;
public Queue() {
queue = new Object[10];
}
public Queue(int capacity) {
queue = new Object[capacity];
}
#SuppressWarnings("unchecked")
public E elm() {
if (size == 0) {
throw new NoSuchElementException();
}
return (E) queue[top];
}
public boolean add(E elm) {
if (elm == null) {
throw new NullPointerException();
}
if (size == queue.length) {
int newCapacity = (int)Math.ceil(queue.length + 1.5);
Object[] newArr = new Object[newCapacity];
for (int i = 0; i < queue.length; i++) {
newArr[i] = queue[i];
}
}
if (bottom == -1) {
top = 0;
bottom = 0;
queue[bottom]= elm;
} else {
bottom = (bottom +1) % queue.length;
}
queue[bottom] = elm;
size++;
return true;
}
public boolean isEmpty() {
return size == 0;
}
#SuppressWarnings("unchecked")
public E remove() {
if (size == queue.length) {
throw new NoSuchElementException();
}
E elm = (E) queue[top];
top = (top +1) % queue.length;
size--;
if (size == 0) {
bottom = -1;
}
return elm;
}
public void clear() {
return;
}
public int size() {
for (int i = 0; i < queue.length; i++) {
size += 1;
}
return size;
}
boolean contains(Object o) {
if (Queue.contains(o)) {
return true;
} else {
return false;
}
}
}//end of file
the problem lies in the very last block of code. I keep getting the message in Eclipse, telling me "Cannot make a static reference to the non-static method contains(Object) from the type Queue" and it is suggesting I change contains() to static. I have tried this to no avail. When I do change it to static, I only get a repeating error upon running it that says "Exception in thread "main" java.lang.StackOverflowError" and gives the location of the error repeatedly. I am not sure what it is that I am doing wrong here? I'll put my driver below; I was using it to test some of my code but it doesnt have a whole lot in it.
public class Driver {
public static void main(String[] args) {
Queue<Integer> a1 = new Queue<>();
a1.add(10);
a1.add(79);
System.out.println(a1.size());
System.out.println(a1.contains(10));
}
}
Queue.contains is notation of calling a static method of the Queue class, which is why it is complaining.
On changing it to static, you are then just making the contains functions call itself recursively forever which is why it then stack overflows.
You will need to write the code yourself to compare each element for the contains function.
Let's say I have an implementation of the Herlihy-Wing Queue in Java :
public class HWQueue<T> {
AtomicReference<T>[] items;
AtomicInteger tail;
static final int CAPACITY = 1024;
public HWQueue() {
items =(AtomicReference<T>[])Array.newInstance(AtomicReference.class, CAPACITY);
for (int i = 0; i < items.length; i++) {
items[i] = new AtomicReference<T>(null);
// Each value in 'items' set to 'null'
// to indicate empty position for enqueue
}
tail = new AtomicInteger(0);
}
public void enq(T x) {
int i = tail.getAndIncrement();
items[i].set(x);
}
public T deq() {
while (true) {
int range = tail.get();
for (int i = 0; i < range; i++) {
T value = items[i].getAndSet(null);
if (value != null) {
return value;
}
}
}
}
}
I am using the type atomic<int *> data type for the items array. But in the enqueue method, I need to do something like items[i].store(&x) which is wrong obviously since it's a dangling reference. How to do this operation correctly? If I use heap, I don't know when to free that memory either. How can I achieve this?
I gotta create a program that, given a number N of threads, these threads can Insert or Remove an element from a queue, but there are conditions for the threads to access the queue:
if only one thread try to insert or remove an element, it will be able to;
if two or more threads are trying at the same time, one will be able to, and the next one will execute its operations when the first one finishes.
I made it using synchronized blocks, just like that:
import java.util.ArrayList;
import java.util.Random;
public class EditorThread extends Thread {
static int N = 10; // number of threads
static queue Q = new queue(); // shared queue
private int number; //number of the thread
public EditorThread(int n) {
number = n;
}
#Override
public void run() {
Random r = new Random();
while (true) {
int t = r.nextInt(2);
if (t == 1) {
int value = Q.get();
if (value == -1) {
System.out.println("The Thread " + number + " couldnt get any element (empty queue)");
}
else {
System.out.println("The Thread " + number + " got the element " + value );
}
}
else {
int n = r.nextInt(100);
Q.put(n);
System.out.println("The Thread " + number + " inserted the element " + n);
}
}
}
public static void main(String[] args) {
for (int i = 0; i < N; i++) {
Thread t = new EditorThread(i);
t.start();
}
}
}
class queue {
node head;
node tail;
queue() {
head = tail = null;
}
public synchronized int get() {
if (head == null)
return -1;
int r = head.value;
if (head != tail)
head = head.next;
else
head = tail = null;
return r;
}
public synchronized void put(int i) {
node n = new node(i);
if (head == null)
head = tail = n;
else {
tail.next = n;
tail = n;
}
}
}
class node {
int value;
node next;
public node(int value) {
this.value = value;
}
}
the run void is simple, it just loops forever while inserts or removes elements.
My question is, how can I follow that conditions without using synchronized?
How is it possible to guarantee mutual exclusion without the synchronized blocks?
EDIT: I cannot use things similar to synchronized (just like locks)
No, and yes.
Fundamentally you need to use some form of synchronization to do this. There is no way to do it yourself without.
However there are classes in the java.util.concurrent package that provide exactly the sort of behaviour you need and do it while minimizing locking and the cost of synchronization as much as possible.
For example LinkedBlockingQueue. https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/LinkedBlockingQueue.html
If you really want to understand how this stuff works though you should also read up on Non Blocking Algorithms. The wiki page is a good start. In general a lot of very smart people who know exactly what they are doing have worked on the concurrent package though. Threading is hard to get right.
https://en.wikipedia.org/wiki/Non-blocking_algorithm
I know references to objects in java are passed by copy , but the copy still points to the same memory in system , so after updating some data of the complex object in another function , the original data should me maintained. But interestingly something is going wrong here. I am working with Tries.
Here is my implementation of Trie, it's fairly custom implementation because of some custom rules:
public class Trie {
boolean isEnd;
Trie trie[] = new Trie[256];
ArrayList<Integer> indexNode;
public static Trie createTrieNode() {
Trie temp = new Trie();
temp.isEnd = false;
temp.indexNode = new ArrayList<Integer>();
for (int i = 0; i < temp.trie.length; i++) {
temp.trie[i] = null;
}
return temp;
}
public static void insertIntoTrie(Trie root, char[] alpha, int index, int i) {
if (root == null)
root = createTrieNode();
if (i < alpha.length)
insertIntoTrie(root.trie[alpha[i] - 'a'], alpha, index, i + 1);
else {
if (root.isEnd == true) {
root.indexNode.add(index);
} else {
root.isEnd = true;
root.indexNode.add(index);
}
}
}
}
Now my object root comes from this class and In the debugger I can see this statement being executed : root.isEnd = true;
Class:
public class AnagramsTogether {
public Trie root = new Trie();
public void printAnagrams(String[] anagrams){
char[] buffer;
for (int i = 0; i < anagrams.length; i++) {
buffer = anagrams[i].toCharArray();
Arrays.sort(buffer);
Trie.insertIntoTrie(root, buffer, i, 0);
}
AnagramsUtil.anagramUtil(root,anagrams);
}
}
But when when root is passed here AnagramsUtil.anagramUtil(root,anagrams);
public class AnagramsUtil {
public static void anagramUtil(Trie root, String[] anagrams) {
if (root.isEnd == true) {
for (Iterator<Integer> iterator = root.indexNode.iterator(); iterator
.hasNext();) {
Integer integer = (Integer) iterator.next();
System.out.println(anagrams[integer]);
}
} else {
for (int i = 0; i < root.trie.length; i++) {
if (root.trie[i] == null)
continue;
anagramUtil(root.trie[i], anagrams);
}
}
}
}
public class Anagram{
public static String string[] = {"cat", "dog", "god","act", "tac","gdo"};
public static void main(String args){
new AnagramsTogether().printAnagrams(Anagram.string);
}
}
This statement if (root.isEnd == true) in never executed and so is this is never executed anagramUtil(root.trie[i], anagrams); . The program just keep executing the continue statement.
Which should not be the case as I've already seen root.trie[i] receiving values.
Why does this happen?I am fairly new to java.
You have many Trie objects in your program and you are confusing them. If you check object identity (object number) with your debugger, you will see that they are not the same.
You are saying that you see in the debugger the statement root.isEnd = true; to be executed however you don't mention for which object is executing.
Your insertIntoTrie() method is called recursively so, that statement is probably executed for the Trie objects that the root has in its trie[] array but not for the root object itself.
Since the actual execution depends on the arguments you are using to call printAnagrams(String[] anagrams) please add those to your question if you need a more specific answer.
Update: Ok after you have edited your question it is clear that you are making the mistake to misuse object references even though you know that all "...references to objects in java are passed by copy". Your insertIntoTrie() is faulty. It seems that you intend to create a new object if the argument root is null however that new object will be lost because root argument is a copy. At the end of your method if you print the whole trie[] member of your original root object (the one in the AnagramsTogether class) you will see that all objects are null.
In Java, null is not an object, it is only a special type. Therefore null hasn't got a reference. So that, for example:
Trie root = null;
insertIntoTrie(root, alpha, index, i);
// after called this function, root = null
After called this function, root is still null because the variable root isn't yet an object before calling this function. So that there wasn't any reference of the variable root to be passed by copy in this calling.
Solution:
Change your function:
public static void insertIntoTrie(Trie root, char[] alpha, int index, int i) {
if (root == null)
root = createTrieNode();
if (i < alpha.length)
insertIntoTrie(root.trie[alpha[i] - 'a'], alpha, index, i + 1);
else {
if (root.isEnd == true) {
root.indexNode.add(index);
} else {
root.isEnd = true;
root.indexNode.add(index);
}
}
}
Into :
public static void insertIntoTrie(Trie root, char[] alpha, int index, int i) {
if (i < alpha.length) {
if (root.trie[alpha[i] - 'a'] == null) {
root.trie[alpha[i] - 'a'] = createTrieNode();
}
insertIntoTrie(root.trie[alpha[i] - 'a'], alpha, index, i + 1);
}
else {
if (root.isEnd == true) {
root.indexNode.add(index);
} else {
root.isEnd = true;
root.indexNode.add(index);
}
}
}
This solution make sure that the root is always an object before passing to the insertIntoTrie(...) function.