How to modify array without its modification in previously added deque? - java

I faced the next problem.
The simplified view of my code is:
class Board{
Cell[][] cells = new Cell[9][9]
Deque<Cell[][]> cellsReserved = new ArrayDeque<>();
public static void main(){
cells[5][4] = new Cell(5);
cellsReserved.add(cells);
cells[5][4].setValue(10);
cellsReserved.add(cells);
while(!cellsReserved.isEmpty()){
System.out.println(cellsReserved.poll()[5][4].getValue());
}
}
}
class Cell{
private int value;
public Cell(int value){
this.value = value;
}
public void setValue(int value){
this.value = value;
}
public int getValue() {
return value;
}
}
I want to get next result:
5
10
But the result is
10
10
I researched this issue and found that the core problem is that collections in Java save not values but references so modifying objects after setting its to collections causes their modification in collections.
I found the solution for adding lists to deque:
deque.addLast(list.stream().toList())
or
deque.addLast(new ArrayList<>(list));
But such approach doesn't work with arrays because
cellsReserved.add(Arrays.stream(cells).toArray(Cell[][]::new))
doesn't solve problem and value in deque is modified after modification of value of Cell not in deque.
I would be grateful if you help me with this problem.

There is only a single instance of Cell[][] cells here, so no matter how many times it is added to the Deque it is still the same reference to same instance. Moreover cells[5][4].setValue(10); overrides the value inside the selected Cell instance, so you need to create a new Cell each time.
It is not very clear from the question what is the overall purpose of this code. If the goal is to have a "history" per board cell, consider using an array of Deques instead. Since arrays of generics are not directly supported (possible with Array.newInstance() but won't get into this now), the array-of-arrays can be replaced by a flat ArrayList, but you will have to calculate the coordinates explicitly.
It can be something like this:
List<Deque<Cell>> cellsReserved = new ArrayList<>(9 * 9);
for (int i = 0; i < 9 * 9; i++) {
cellsReserved.add(new ArrayDeque<>());
}
Deque<Cell> dequeOf5_4 = cellsReserved.get(5 + 4 * 9);
dequeOf5_4.add(new Cell(5));
dequeOf5_4.add(new Cell(10));
while(!dequeOf5_4.isEmpty()){
System.out.println(dequeOf5_4.poll().getValue());
}
Update following #Ensei's comment:
For the case you need snapshot of the entire array/matrix in each Deque element, you can deep copy the matrix before each change. This may look like this:
public static void main(String[] args){
Deque<Cell[][]> cellsReserved = new ArrayDeque<>();
Cell[][] cells = new Cell[9][9];
cells[5][4] = new Cell(5);
cellsReserved.add(cells);
cells = deepCopy(cells);
cells[5][4].setValue(10);
cellsReserved.add(cells);
while(!cellsReserved.isEmpty()){
System.out.println(cellsReserved.poll()[5][4].getValue());
}
}
private static Cell[][] deepCopy(Cell[][] cells) {
Cell[][] copy = new Cell[cells.length][cells[0].length];
for (int i = 0; i < cells.length; i++) {
for (int j = 0; j < cells[i].length; j++) {
Cell source = cells[i][j];
if (source != null) {
copy[i][j] = new Cell(source.getValue());
}
}
}
return copy;
}
Note that the deep copy method creates a new instance of the array and a new instance of each Cell object.

Related

Declaring a new Array with a larger size within a method that does not return

I am currently filling in a section of code and in it one of the methods I have to make a new array double the size and fill it in with the old values, which I did, but how do I make it so that the new array is the one that is used from now on if the method doesn't return anything?
private void upSize()
{
String[] biggerArr = new String[theArray.length*2];
for( int i = 0; i < theArray.length; i++)
biggerArr[i] = theArray[i];
}
So obviously this code is built to not return anything, but when it gets called somewhere like here, how do I actually increase the size of that array so that it can fit the new "Added" element.
public boolean add( T element ){
if (size() == theArray.length) upSize();
theArray[count++] = element;
return true;
}
I'm sorry if this was something that already has an answered thread, I did a lot of searching through and couldn't find anything that touched on this specifically.
You have to return new array and assign it to the existing reference, like this:
private String[] upSize()
{
String[] biggerArr = new String[theArray.length*2];
for( int i = 0; i < theArray.length; i++)
biggerArr[i] = theArray[i];
return biggerArr;
}
public boolean add( T element ){
if (size() == theArray.length) theArray = upSize();
theArray[count++] = element;
return true;
}
But look at java.util.ArrayList, you won't have to reinvent the wheel :)

Linked List in a Array

I am currently doing a online Java course and am having a bit of trouble with a assignment. The assignment is to essentially create a Hashmap using just Arrays but no other Java Data Structures or methods. This is my code:
public class test {
static String[] array = new String[10];
class Cell<T> {
T first;
Cell<T> next;
Cell(T h, Cell<T> t) {
first = h;
next = t;
}
}
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 arraySetter(String a) {
int position = hashFunction(a);
if (array[position] == null) {
array[position] = a;
} else {
//Need a Linked List here for when there is already a item in the array at the same index.
}
}
public static void printArray() {
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
}
public static void main(String[] args) {
arraySetter("abc");
printArray();
}
}
My code essentially creates a list of lists. At each position in the Array I now need to create a list which is only initialised when there are two items with the same value for the hashFunction. I haven't written that function yet but my problem now is I don't know how to create a linkedList at each position in the array. Can someone help me out here?
This is the data structure in which you should store your data:
Cell[] array
When using an array such as String[] you will never be able to add any else than instances of String into that array.
When you get a new hashCode, you should create a new one:
array[position] = new Cell<>(a, null);
As it is the first element from the linkedList we will call it the head.
Every time a value with the same hashcode is provided, you will need to iterate from the head until a Cell whose next value is null, then you define it with a new instance of Cell.
This is generally called addLast method, and you ca find a good example here:
https://www.cs.cmu.edu/~adamchik/15-121/lectures/Linked%20Lists/linked%20lists.html
If you want a linked list to avoid collision then you have to declare array which will contain head of the linked list.
Node<K,V>[] table;
Sample code not fully implemented.
class Node<K,V> {
K key;
V value;
Node<K,V> next;
}
Node will contain current key and value .if key is same then you have to override and also next value if you want to use linked list.If you want to use array to avoid collision that time also use node which will contain key and value key is required to check equality and no next variable.

Creating an Array List from scratch

I was wondering if anyone would be able to point me in the correct direction in regards to creating my own array list methods. For instance, the current project I am assigned to does not allow for me to use the methods given to me for free like in the following example.
package com.tutorialspoint;
import java.util.ArrayList;
public class ArrayListDemo {
public static void main(String[] args) {
// create an empty array list with an initial capacity
ArrayList<Integer> arrlist = new ArrayList<Integer>(5);
// use add() method to add elements in the list
arrlist.add(15);
arrlist.add(22);
arrlist.add(30);
arrlist.add(40);
// adding element 25 at third position
arrlist.add(2,25);
// let us print all the elements available in list
for (Integer number : arrlist) {
System.out.println("Number = " + number);
}
}
}
This example shows the add() method. For my project I have to create this method myself and call it from a different file within my package.
I find this as an interesting problem. I am always curious about how things work at the raw level.
If you think about it, an ArrayList is basically just an array that you can expand. So you can either have a really big array (which would take a lot of memory for one ArrayList) or every time you add something, you make a new bigger array and copy the contents and add the new item (which I think the performance is O(N)).
This is my attempt without using any libraries:
public class MyArrayList<T>
{
private T[] asArray;
#SuppressWarnings("unchecked")
public MyArrayList()
{
asArray = (T[]) new Object[0];
}
public void add(T t)
{
#SuppressWarnings("unchecked")
T[] temp = (T[]) new Object[asArray.length + 1];
// copy everything over to the new array
for (int i = 0; i < asArray.length; i++)
{
temp[i] = asArray[i];
}
// add the new element
temp[asArray.length] = t;
asArray = temp;
}
public void remove(int index)
{
if (index < 0 || index >= asArray.length) return;
#SuppressWarnings("unchecked")
T[] temp = (T[]) new Object[asArray.length - 1];
boolean found = false;
// copy everything over to the new element
for (int i = 0; i < asArray.length; i++)
{
// don't copy if the indices are the same
if (i == index)
{
found = true;
continue;
}
temp[i - (found ? 1 : 0)] = asArray[i]; // it's i - 1 after the removed object so then it doesn't leave a gap and it doesn't go over the array's length
}
asArray = temp;
}
public T get(int index)
{
return asArray[index];
}
}
I am quite proud of this code. :) I consider Short_Teeth's code cheating because the class is a subclass and, well, doesn't add anything. I hope I helped.
This is very easy to understand; However, I explained a little bit in comments.
public class MyArrayList<E extends Object> {
private static int initialCapacity = 5;
private static int currentSize;
private Object[] myArrayList = {}, temp = {};
private static int currentIndex = 0;
public static void main(String[] args) {
MyArrayList arrList = new MyArrayList();
arrList.add("123"); //add String
arrList.printAllElements();
arrList.add(new Integer(111)); //add Integer
arrList.printAllElements();
arrList.add(new Float("34.56")); //add Integer
arrList.printAllElements();
arrList.delete("123");
arrList.printAllElements();
arrList.delete(123);
arrList.printAllElements();
arrList.delete(123);
arrList.printAllElements();
}
public MyArrayList() { //creates default sized Array of Objects
myArrayList = new Object[initialCapacity]; //generic expression
/* everytime I cross my capacity,
I make double size of Object Array, copy all the elements from past myObject Array Object
*/
}
public MyArrayList(int size) { //creates custom sized Array of Objects
myArrayList = new Object[size];
}
public void add(Object anyObj) {
//add element directy
myArrayList[currentIndex] = anyObj;
currentSize = myArrayList.length;
currentIndex++;
if (currentIndex == currentSize) {
createDoubleSizedObjectArray(currentSize);
}
}
//print all elements
public void printAllElements() {
System.out.println("Displaying list : ");
for (int i = 0; i < currentIndex; i++) {
System.out.println(myArrayList[i].toString());
}
}
private void createDoubleSizedObjectArray(int currentSize) {
temp = myArrayList.clone();
myArrayList = new MyArrayList[2 * currentSize]; //myObject pointer big size data structure
// myObject = temp.clone(); //probably I can do this here as well. Need to check this
System.arraycopy(temp, 0, myArrayList, 0, currentSize);
}
void delete(Object object) {
//if already empty
if (currentIndex == 0) {
System.out.println("Already empty!");
return;
}
//you don't need to delete anything. I can simply override the storage
currentIndex--;
}
}
import java.util.ArrayList;
public class MyArrayList<E> extends ArrayList<E>{
private static final long serialVersionUID = -5164702379587769464L;
public void newMethod(){
// No implementation
}
}
This is a class which extends from ArrayList and a method called newMethod() was added to this class.
Below we are calling this newly created method in your case you must implement the add to this newly created method.
public class Hello {
public static void main(String args[]) {
MyArrayList<Integer> myList = new MyArrayList<Integer>();
// It has the ArrayList add() method as this new class extends from ArrayList (all the ArrayList methods are included)
myList.add(2);
// The newly created method in your case you need to implement the add yourself
myList.newMethod();
}
}
This could also be a good link for what you need.
http://www.java2novice.com/java-interview-programs/arraylist-implementation/
I also recomend that you try to implement and solve your problems first and then ask questions about a specific problem, and only after you done a good research about what may be causing this problem (There are lots of resources out there). If you done some research before you asked this question, I'm pretty sure that you would have been able to solve everything on your own.
Hope you find this information useful. Good luck.

Am I not understanding ArrayList or am I missing something?

I'm trying to create a very, very simple program.
I want my class called Text to simply print out a string, specifically, one letter.
Then in my second class called Window, I want to create an ArrayList of that class, iterate through the list and call the method of my Text class to print out the string. But it does not print anything.
What am I doing wrong?
public class Text {
private String a;
public void printA() {
a = "a";
System.out.print(a);
}
}
and the other class..
import java.util.ArrayList;
public class Window {
private ArrayList<Text> string = new ArrayList<Text>(5);
public Window() {
addText();
}
public void iterate() {
for (int i = 0; i < string.size() - 1; i++) {
string.get(i).printA();
}
}
public void addText() {
for (int i = 0; i <string.size() - 1; i++) {
string.add(new Text());
}
}
public static void main(String[] args) {
Window wind = new Window();
wind.iterate();
}
}
for(int i = 0; i <string.size()-1;i++){
string.add(new Text());
}
initialy the arraylist is empty, so string.size() == 0
the forlus wil not be executed, change to
public void addText(){
string.add(new Text())
}
or even better
public void addText(Text t){
string.add(t)
}
that way you can add Text-object created with different constructors
If you modify iterate to:
public void iterate(){
System.out.println(string.size()-1);
for(int i = 0; i < string.size()-1;i++){
string.get(i).printA();
}
}
You will get -1
Let me explain why:
Each ArrayList instance has a capacity. The capacity is the size of the array used to store the elements in the list. It is always at least as large as the list size. private ArrayList<Text>string = new ArrayList<Text>(5); merely sets the capacity of the underlying array that is the data structure that implement the ArrayList object. size() returns the number of objects inside of the ArrayList not the capcity
public void addText(){
for(int i = 0; i <string.size()-1;i++){
string.add(new Text());
}
}
The for loop's expression doesn't evaluate to true, and therefore you never add a single object to the loop which is why iterate would print -1 if you added the print statement there
The
new ArrayList<Text>(5);
Doesn't mean you have 5 elements array. It means that this is just initial capacity of internal array for storing elements. Due to this your init code:
public void addText(){
for(int i = 0; i <string.size()-1;i++){
string.add(new Text());
}
}
faces no elements in the list with string.size() = 0.
Use this instead (If you like to add 5 elements):
public void addText(){
for(int i = 0; i < 5;i++){
string.add(new Text());
}
}
There is no problem to add more elements (even if the initial capacity was only '5'). From docu "As elements are added to an ArrayList, its capacity grows automatically."
problem it this method.
public void addText(){
for(int i = 0; i <string.size()-1;i++){
string.add(new Text());
}
}
this doesn't add anything at all. because string.size() is 0.
may be you should change it to
public void addText(int size){
for(int i = 0; i <size-1;i++){
string.add(new Text());
}
}
Ps: new Arraylist<Text>(5) actually creates an empty list with initial capacity = 5 (not size). See it here
Well for stater your method in Text needs parameter so it KNOWS to take in 'a' and if you're variable in your parameter is going to be 'a' as well you need use "this." so that the compiler knows that the two are different.
public class Text {
private String a;
public void printA(String a) {
this.a = "a";
System.out.print(a);
}
}
What you are doing wrong is that you are creating the ArrayList with a capacity of 5, but it does not yet have 5 objects in it. Thus, the addText method does nothing. Here's a version that works:
public void addText(){
for(int i = 0; i < 4; i++){
string.add(new Text());
}
}
Note that string.size() - 1 has been changed to 4, becuase string.size() is 0, and you want to add 4 elements to the list. Also, your iterate method could use a little refactoring:
public void iterate(){
for(Text text : string){
string.get(i).printA();
}
}
Instead of a simple loop, an enhanced for is used instead. This is no more than a typing shortcut, but it improves efficiency for LinkedLists.

Java array NullPointerException

The code block is listed below:
public static Vertex[] computeSubGraph(Vertex[] AdjList, int[] retiming)
{
Vertex[] subGraph = new Vertex[AdjList.length];
for (int i = 0; i < AdjList.length; i++) {
System.out.println(i);
subGraph[i].nodeDelay = AdjList[i].nodeDelay;
subGraph[i].predecessor = AdjList[i].predecessor;
subGraph[i].mark = AdjList[i].mark;
subGraph[i].starTime = AdjList[i].starTime;
subGraph[i].finishTime = AdjList[i].finishTime;
for (int j = 0; j < AdjList[i].inArcList.size(); j++) {
ArcNode old = AdjList[i].inArcList.get(j);
ArcNode newNode = new ArcNode(old.adjVex, old.arcWeight);
subGraph[i].outArcList.add(newNode);
subGraph[old.adjVex].inArcList.add(newNode);
}
}
return subGraph;
}
This is the Vertex class:
public class Vertex implements Comparable<Vertex> {
public int arcWeight;
public int preDelay;
public boolean infinite = true;
public int nodeDelay = 0;
public Vertex predecessor = null;
public ArcNode firstArc = null;
public int mark = 0;
public int starTime;
public int finishTime;
public ArrayList<ArcNode> inArcList = new ArrayList<ArcNode>();
public ArrayList<ArcNode> outArcList = new ArrayList<ArcNode>();
}
Actually, I just want to copy the element in AdjList to a new array subgraph. But the error message shows that "java.lang.NullPointerException" and shows the problem lies in "subGraph[i].nodeDelay = AdjList[i].nodeDelay;" line.
I tested by printing to the console. And found the AdjList.length is 8 and the problem occurs in the very first round; And even when I only write "subGraph[i].nodeDelay;" without assigning any value to it, it also shows the wrong message.
Any idea on this? Thanks in advance.
Add it inside the loop:
subGraph[i] = new Vertex();
You first need to instantiate an object (subGraph[i] in your case) before accessing it.
The answer is: uninitialized variable. You did initialize subGraph to be an array, but you did not initialize subGraph[i].
When you create an object array in java, it's automatically initialized with null values. It's your responsibility to loop on the array an populate it with references to new objects.
In your case, you should assign Vertex objects to all array positions.
You need to create a Vertex instance and place it in the array prior to setting any fields.
Something like:
public static Vertex[] computeSubGraph(Vertex[] AdjList, int[] retiming)
{
Vertex[] subGraph = new Vertex[AdjList.length];
for (int i = 0; i < AdjList.length; i++) {
subGraph[i] = new Vertex(); // adding instance prior to setting fields.
System.out.println(i);
subGraph[i].nodeDelay = AdjList[i].nodeDelay;
subGraph[i].predecessor = AdjList[i].predecessor;
subGraph[i].mark = AdjList[i].mark;
subGraph[i].starTime = AdjList[i].starTime;
subGraph[i].finishTime = AdjList[i].finishTime;
for (int j = 0; j < AdjList[i].inArcList.size(); j++) {
ArcNode old = AdjList[i].inArcList.get(j);
ArcNode newNode = new ArcNode(old.adjVex, old.arcWeight);
subGraph[i].outArcList.add(newNode);
subGraph[old.adjVex].inArcList.add(newNode);
}
}
return subGraph;
}
On add
subGraph[i] = new Vertex();
before this line
subGraph[i].nodeDelay = AdjList[i].nodeDelay;
Because subGraph[i] is initially null . So subGraph[i].nodeDelay will obviously throw a NullPointerException, because you are trying to access or modify the field of a null object. Array of references will always be initialized with elements of null references by default.

Categories

Resources