I am beginner in Java and trying to write a StackArray. I have a tester to test my code. I have run it several times but it does not pass my push method and my search method. Can anyone give me an idea where I am doing wrong? Thank you so much in advance!
import java.util.Arrays;
import java.util.NoSuchElementException;
public class Stack<E> implements StackADT<E>{
private E a[];
private int head, size;
public Stack(){
}
/*Adds the specified element to the top of the stack.
Returns the item added.*/
public E push(E element){
if (a.length == size){
throw new IllegalStateException("Cannot add to full stack");
}
// Since the remainder of the stack is to the RIGHT of the stack,
// adding a new element pushes the head to the LEFT (+ wrap around)
//head = (head - 1 + a.length) % a.length;
return a[head++] = element;
// return element;
}
/*Removes and returns the element from the top of the stack*/
public E pop(){
if (empty()){
throw new java.util.EmptyStackException();
}
// We need to get a copy of the old head before we advance to the
// new head. We want to return the old head, not the new head.
E rval = a[head];
// Why DON'T we need to add a.length here like we did in push?
head = (head + 1) % a.length;
return rval;
}
/*Returns without removing the element at the top of the stack*/
public E peek(){
if (empty()){
throw new java.util.EmptyStackException();
}
return a[head];
}
/*Returns true if the stack is empty, false otherwise*/
public boolean empty(){
return size == 0;
}
/*Returns the 1-based position where an object is on this stack
This means If the object o occurs as an item in this stack, this
method returns the distance FROM THE TOP OF THE STACK of the
occurrence nearest the top of the stack - the topmost item on
the stack is considered to be at distance 1.*/
public int search(Object o){
// i is the LOGICAL index
for (int i = 0; i < size; i++){
// p is the PHYSICAL index
int p = (head + i) % a.length;
E e = a[p];
// e == o Are the items (null or non-null the same?)
// if they are not the same, then at least one of them
// is non-null and can be compared to the other.
if (e == o || e != null && e.equals(o)){
// Distance = logical index + 1 as per the above description
return i + 1;
}
}
// No match was made
throw new NoSuchElementException();
}
/*Returns a string representation of the queue*/
public String toString(){
// Output should look like: [e_0, e_1, ..., e_n-1]
// Empty stack: []
if (empty())
return "[]";
// We know that there is at least one element in this stack
// since we didn't return
StringBuilder b = new StringBuilder();
b.append("[").append(a[head]);
// Start on the SECOND logical index
for (int i = 1; i < size; i++){
int p = (head + i) % a.length;
E e = a[p];
b.append(", ").append(e);
}
b.append("]");
return b.toString();
}
}
The most prominent error is that you do not instantiate the instance variables of Stack. Java uses default values for non-initialized values: primitive numbers are set to 0, booleans are set to false and all reference-types (i.e., Arrays and Objects) are set to null. This means that head and size are both initialized to 0 while a is initialized to null. The latter yields a NullPointerException when dereferencing its content.
Assuming you want to keep an array as your internal representation, you'd have to initialize an instance of E[] somehow. Unfortuantely, you cannot call new E[size]. See this other question on how to instantiate a generic array.
As for the initial value of head, which seems to be supposed to point to the top of the stack, you are not consistent in how you want to use it: In push, you use head as the index of the next free element in a and increment its value after adding the element. In toString, peek and pop, you use head as the index of the element that you want to return. Either representation is okay, but you must not mix them up.
Assuming you want head to always point to the last element, you would initialize it to -1 and increment its value in the push-method before accessing the index in a. Note the difference between head++ and ++head:
int i = head++;
is equivalent to
int i = head;
head = head + 1;
while
int i = ++head;
is equivalent to
head = head + 1;
int i = head;
so as a fix, you could change
return a[head++] = element;
to
return a[++head] = element;
but it is probably better to add a few lines of code and make the logic more explicit by incrementing the value of head first.
Now that we covered initialization, there's also a bug regarding the value of size: push should increment the size of the stack while pop should decrement it: However, in your code, size is never modified, hence empty is always true.
Also, I don't quite understand the idea behind the line
// Why DON'T we need to add a.length here like we did in push?
head = (head + 1) % a.length;
in pop. As an element is removed (and not added) I'd say this should simply be head = head - 1 or head-- if you prefer postfix-operators.
Putting it all together
Initialize the Stack properly, e.g.,
private E a[];
private int head = -1;
private int size = 0;
public Stack(Class<E> c, int maxSize){
#SuppressWarnings("unchecked")
final E[] a = (E[]) Array.newInstance(c, maxSize);
this.a = a;
}
Update the value of size in push and fix the update to head:
public E push(E element){
if (a.length == size){
throw new IllegalStateException("Cannot add to full stack");
}
size++;
return a[++head] = element;
}
Update the value of size and head in pop:
public E pop(){
if (empty()){
throw new java.util.EmptyStackException();
}
size--;
return a[head--];
}
Fixing toString
Remark: I kind of ignored the comments, as comments tend to lie as code gets refactored; but I just noticed that you wrote in a comment:
// Since the remainder of the stack is to the RIGHT of the stack,
// adding a new element pushes the head to the LEFT (+ wrap around)
which is actually the opposite of what the next line in your code tells: return a[head++] = element;. The proposed bugfixes are based on the code, not the comment, hence the remainder of the stack is to the LEFT of head. Because of that, the implementation of toString must be changed to print the array from right to left instead of left to right:
public String toString(){
if (empty())
return "[]";
StringBuilder b = new StringBuilder();
b.append("[").append(a[head]);
for (int i = head - 1; i >= 0; i--){
E e = a[i];
b.append(", ").append(e);
}
b.append("]");
return b.toString();
}
Related
I am trying to build the following method for my extended stack ADT implemented using a doubly linked list method is called
public T pop(int i) throws InvalidItemException.
It should remove and return the i-th data item from the top of the stack. for example if i = 1 it would return and remove the top item of the stack, if i = 3 then it would take the third item from the top.
this is my code it is a bit of a mess but I think I am somewhat on the right track. Can anyone help with this?
public T pop(int i) throws InvalidItemException {
int node = size() + 1; // my logic is that if i take the length and add 1
int nodeRemove = node - i; // and then minus the length by i then i will know which item to take
DoubleLinkedNode<T> temp = top;
T result = null;
if (i > numItems || i <= 0) {
throw new InvalidItemException("invalid items");
}
if (i == 1) {
top = top.getNext();
result = top.getElement();
}else {
while (temp != null && nodeRemove > 1) {
temp = temp.getNext();
result = temp.getElement();
nodeRemove--;
}
}
return result;
I have a program where I am creating an arrayList. One method randomly removes an item from the list. I also have a method that resizes the array if a certain amount of elements are added to make space for more elements to be added if wanted.
I am receiving a NullPointerExceptionError when the lists are resized and then the method tries to remove one of the null spaces in the newly resized array.
Without using a for loop and keeping a constant time, I'm trying to find a way to make my int value of choice just the number of non null elements in the array. I hope that makes sense - can anyone help?
remove method:
public T remove() {
if (isEmpty()) {
return null;
}
Random rand = new Random();
int choice = rand.nextInt(size);
size--;
elements[choice] = elements[size];
elements[size] = null;
return elements[choice];
}
This question boils down to "Given an array with null elements scattered throughout, how can I return the nth non-null element?" The answer is iterate through the array, which doesn't uphold the constant time constraint your're looking for.
But wait, how can array lists work in that case?!?
Here is how java.util.ArrayList does it:
#Override
public E get(int location) {
if (0 <= location && location < (lastIndex - firstIndex)) {
return (E) array[firstIndex + location];
}
throw new IndexOutOfBoundsException(Messages.getString("luni.0A",
location, lastIndex - firstIndex));
}
Note that there are no null checks, the Arraylist always maintains its elements in a contiguous block so gets are super fast. So some magic must happen when removing elements so there won't be nulls scattered about...
#Override
public E remove(int location) {
E result;
int localLastIndex = lastIndex;
int size = localLastIndex - firstIndex;
if (0 <= location && location < size) {
if (location == size - 1) {
result = (E) array[--localLastIndex];
array[localLastIndex] = null;
} else if (location == 0) {
result = (E) array[firstIndex];
array[firstIndex++] = null;
} else {
int elementIndex = firstIndex + location;
result = (E) array[elementIndex];
if (location < size / 2) {
System.arraycopy(array, firstIndex, array, firstIndex + 1,
location);
array[firstIndex++] = null;
} else {
System.arraycopy(array, elementIndex + 1, array,
elementIndex, size - location - 1);
array[--localLastIndex] = null;
}
}
if (firstIndex == localLastIndex) {
firstIndex = localLastIndex = 0;
}
} else {
throw new IndexOutOfBoundsException(Messages.getString("luni.0A",
location, localLastIndex - firstIndex));
}
lastIndex = localLastIndex;
modCount++;
return result;
}
There is the key! When removing an element the JDK impl doesn't leave a gap, nor does it move all the elements over to close the gap. It calls a native method that copies a chunk of array around as an atomic operation: https://docs.oracle.com/javase/7/docs/api/java/lang/System.html#arraycopy(java.lang.Object,%20int,%20java.lang.Object,%20int,%20int)
public int size(){
node n = head;
node m = tail;
int size = 0;
While(n!=m){
size++;
n=n.getNext();
}
return size;
}
Is this code correct? I'm not so sure and I'm asking for you guys opinion
The problem with your code logic is that you never check the last element of the list. Therefore, your method will return the number of elements of the linked list minus one. To fix this, initialize size to 1 instead of 0. And if you're concerned about linked lists of size 0, then use an if statement to check if the head or tail is null. Here's what it should look like,
public int size(){
node n = head;
node m = tail;
if(n == null){
return 0;
}
int size = 1;
While(n!=m){
size++;
n=n.getNext();
}
return size;
}
No this code is not correct. It will return the size one less than the actual size. The while loop will stop working as soon as condition n!=m is false. This will result in incorrect size. So I suggest you start either as int size=1; or you can do size++ once before you return, outside the while block
Your code will return size less than actual size , i.e. say your Head and Tail are pointing on same node which means you have only one node in list. Your code returns 0 where someone would accept 1.
do{
//your stuff
} while();
this should work.
I wanna implement a uniformly random access to a certain collection with N numbers, like each item in the collection will be accessed at uniformly 1/N chances. I put all the items in a modified double linked-list. then circular shift it with random times, remove the last item then add it as first. finally pick the first item. I used it to test how many number of calls it will take to cover all the item without moving the item out of the list. Mine total number needed is consistently units less than expected. Wondering if the implementation is truly uniformly random? do you think my implementation is truly random?I have been debugging this for quite some time, still no clue.
public Item callout(){
for (int j=0; j<StdRandom.uniform(N); j++)
{
this.addFirst(this.removeLast());
// circular shift the queue by StdRandom.uniform(N)times, always return the first item;
}
return first.item;
}
public void addFirst(Item item){
Node<Item> oldfirst = first;
first = new Node<Item>();
first.item = item;
first.previous = null;
if (last == null)
{last = first; first.next = null;} //if it's the first element added. if last.next = null == last = null;!!!!
else
{
first.next = oldfirst;
oldfirst.previous = first;
}
N++;
}
public Item removeLast(){
if (last == null) throw new RuntimeException();
Item item = last.item;
// if right now only one element exists in the container
if (first == last)
{
first=null;
last=null;
}
else{
last =last.previous;
last.next = null;
// old first becomes first; optional operation, easy way to tell if it's the header.
}
N--;
return item;
}
The following class computes the number of calls needed to reach comprehensive call, it receives a RandomCollection with n items in it. Basically, It's a collection with Integers from 1-N, I use an array int[] of flag to tag if the item has previously been called.
private static int getNumberOfCallsForComprehensiveCallout(RandomCollection<Integer> test, int n){
// create an array of the same number of items in collection, each with a Flag indicating whether it has beeen called
int calltimes =0; // calltimes stands for the numofcalls needed to reach a comprehensive call
int flag = 1; // flag used to indicate if this item has been called
int [] c = new int [n];
Arrays.fill(c, flag);
int NumberOfFlags = n;
while(NumberOfFlags != 0){
int numbercalled = test.callout();
if (c[numbercalled-1]==1) {NumberOfFlags--; c[numbercalled-1]=0;}
else; // indicate this item has been called earlier.
calltimes++;
// System.out.println(calltimes);
}
return calltimes; // return the number of calls for comprehensive callout each time this method is called.
}
The overall logic seems to be correct, but -
Firstly, the number of calls to cover all the items (with replacement) can be greater than size of the collection. Infact it will be greater most of the times.
Secondly, in callout(), call the StdRandom.uniform(N) method outside the loop only once. try the following change -
public Item callout(){
int randomRotate = StdRandom.uniform(N);
for (int j = 0; j < randomRotate; j++)
{
this.addFirst(this.removeLast());
}
return first.item;
}
I ran some simulations and the number of rotations are not uniformly distributed if the call to StdRandom.uniform(N) is made inside the for loop. Histogram results for a collection of size 10 -
0 1 2 3 4 5 6 7 8 9
1001 1813 2074 2043 1528 902 454 144 37 4
I am using array based MinHeap in java. I am trying to create a custom method which can remove any element not only root from the heap but couldn't. Below is MinHeap code-
public class MinHeap {
/** Fixed-size array based heap representation */
private int[] h;
/** Number of nodes in the heap (h) */
private int n = 0;
/** Constructs a heap of specified size */
public MinHeap(final int size) {
h = new int[size];
}
/** Returns (without removing) the smallest (min) element from the heap. */
public int peek() {
if (isEmpty()) {
throw new RuntimeException("Heap is empty!");
}
return h[0];
}
/** Removes and returns the smallest (min) element from the heap. */
public int poll() {
if (isEmpty()) {
throw new RuntimeException("Heap is empty!");
}
final int min = h[0];
h[0] = h[n - 1];
if (--n > 0)
siftDown(0);
return min;
}
/** Checks if the heap is empty. */
public boolean isEmpty() {
return n == 0;
}
/** Adds a new element to the heap and sifts up/down accordingly. */
public void add(final int value) {
if (n == h.length) {
throw new RuntimeException("Heap is full!");
}
h[n] = value;
siftUp(n);
n++;
}
/**
* Sift up to make sure the heap property is not broken. This method is used
* when a new element is added to the heap and we need to make sure that it
* is at the right spot.
*/
private void siftUp(final int index) {
if (index > 0) {
final int parent = (index - 1) / 2;
if (h[parent] > h[index]) {
swap(parent, index);
siftUp(parent);
}
}
}
/**
* Sift down to make sure that the heap property is not broken This method
* is used when removing the min element, and we need to make sure that the
* replacing element is at the right spot.
*/
private void siftDown(int index) {
final int leftChild = 2 * index + 1;
final int rightChild = 2 * index + 2;
// Check if the children are outside the h bounds.
if (rightChild >= n && leftChild >= n)
return;
// Determine the smallest child out of the left and right children.
final int smallestChild = h[rightChild] > h[leftChild] ? leftChild
: rightChild;
if (h[index] > h[smallestChild]) {
swap(smallestChild, index);
siftDown(smallestChild);
}
}
/** Helper method for swapping h elements */
private void swap(int a, int b) {
int temp = h[a];
h[a] = h[b];
h[b] = temp;
}
/** Returns the size of heap. */
public int size() {
return n;
}
}
How can i design a method to remove any element from this MinHeap?
If you know the index of the element to be removed,
private void removeAt(int where) {
// This should never happen, you should ensure to call it only with valid indices
if (n == 0) throw new IllegalArgumentException("Trying to delete from empty heap");
if (where >= n) throw new IllegalArgumentException("Informative error message");
// Now for the working cases
if (where == n-1) {
// removing the final leaf, trivial
--n;
return;
}
// other nodes
// place last leaf into place where deletion occurs
h[where] = h[n-1];
// take note that we have now one element less
--n;
// the new node here can be smaller than the previous,
// so it might be smaller than the parent, therefore sift up
// if that is the case
if (where > 0 && h[where] > h[(where-1)/2]) {
siftUp(where);
} else if (where < n/2) {
// Now, if where has a child, the new value could be larger
// than that of the child, therefore sift down
siftDown(where);
}
}
The exposed function to remove a specified value (if present) would be
public void remove(int value) {
for(int i = 0; i < n; ++i) {
if (h[i] == value) {
removeAt(i);
// assumes that only one value should be removed,
// even if duplicates are in the heap, otherwise
// replace the break with --i to continue removing
break;
}
}
}
Summarising, we can remove a node at a given position by replacing the value with the value of the last leaf (in the cases where the removal is not trivial), and then sifting up or down from the deletion position. (Only one or none sift needs to be done, depending on a comparison with the parent and/or children, if present.)
That works because the heap invariant is satisfied for the parts of the tree above and below the deletion position, so if the new value placed there by the swap is smaller than the parent, sifting up will place it in its proper position above the deletion position. All elements moved are smaller than any element in the children, so the heap invariant is maintained for the part below (and including) the deletion position.
If the new value is larger than one of the direct children, it's basically a removal of the root from the sub-heap topped at the deletion position, so the siftDown restores the heap invariant.
The fix for the mentioned flaw in the siftDown method is to set smallestChild to leftChild if rightChild >= n:
final int smallestChild = (rightChild >= n || h[rightChild] > h[leftChild]) ? leftChild
: rightChild;