I have a Stack<String> defined in Java that I use for navigation through a workflow.
What I would like to do is ensure that all values in the stack are unique: when a transition to a "previous" state occurs, I want to remove everything off the stack AFTER the first occurrence of the previous state in the stack.
Is there an easy way to do this?
Edit: More information was requested. Here's an example of the contents of a stack:
[state2, state3, state2, state1, startState]
I need the ability to accept a String, check the stack and see if there are multiple occurrences of it, then pop elements until the "bottommost" occurrence of that String. "Truncate" was probably a bad description of what I wanted to do... "pop until I hit an arbitrary index" is probably closer to what I need.
Consider using deque. Below is the link which explains why should you use it over stack.
Why should I use Deque over Stack?
Stack implements List (among various other interfaces). Get a ListIterator for the last element, and move it backwards until you find an occurrence of the new state, counting how many elements along the way, and then pop that many elements. (If you don't find the new state, then of course you don't pop anything, and you push the new state onto the stack instead).
This might not be particularly efficient, but it will certainly work. If you also want it to be efficient, you probably need to use another data structure (either instead of or as well as the stack). One possibility is to use a Map (in addition to the stack) to keep track of which states are on the stack together with the index at which they occur, or at least a Set to keep track of which states are on the stack (you can then just pop states until you find the one you are looking for). You would maintain the stack and the map or set in parallel.
Or if you were serious about:
"pop until I hit an arbitrary index" is probably closer to what I need.
... then surely this would suffice:
int numberToPop = stack.size() - arbitraryIndex - 1;
while (numberToPop-- > 0) {
stack.pop();
}
Would it simplify your overall code if you created your own container that is basically a set that's a stack? Something like (not a complete implementation):
public class StackSet<T> {
private final Set<T> set;
private final Deque<T> queue;
public StackSet(){
set = new HashSet<>();
queue = new ArrayDeque<>();
}
public void push(T value){
if(set.add(value)){
queue.push(value);
}
}
public T pop(){
return queue.pop();
}
}
That should guarantee no duplicates.
Here's an example of a truncate method with Deque instead of Stack.
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Collection;
import java.util.Deque;
public class ExampleDeque
{
public static void main(String[] args)
{
Deque<String> deque = new ArrayDeque<String>();
deque.offer("startState");
deque.offer("state1");
deque.offer("state2");
deque.offer("state3");
deque.offer("state2");
System.out.println("Before");
print(deque);
deque = truncate(deque, "state2");
System.out.println("After");
print(deque);
}
static Deque<String> truncate (Deque<String> deque, String value)
{
if(!deque.contains(value)) return deque;
String[] array = deque.toArray(new String[deque.size()]);
for(int i = 0; i < array.length; i++)
{
if(array[i] == value)
{
String[] truncated = Arrays.copyOfRange(array, 0, i + 1);
Collection<String> collection = Arrays.asList(truncated);
return new ArrayDeque<>(collection);
}
}
return null;
}
static void print(Deque<String> deque)
{
for(String s : deque)
System.out.println(s);
System.out.println();
}
}
Related
I'm trying to figure out how I can get an output of remaining slots available when 1 object is removed.
ListOfMembers = new ArrayList<>(100); which caps my list at 100.
Whenever I delete 1 from the list, I need to print out the remaining space in the ArrayList.
public boolean DeleteMember() {
Scanner in = new Scanner(System.in);
System.out.println("Enter the membership number: ");
String pno = in. nextLine();
for(int i=0;i<ListOfMembers.size();++i) {
if(ListOfMembers.get(i).getMembershipNumber().equals(pno)) {
ListOfMembers.remove(i);
System.out.println("Space available: " +?????);
return true;
}
}
System.out.println("Numbership number does not exist");
return false;
}
Using System.out.println("Space available: " +ListOfMembers.size()) will provide the count of entries and I'm trying to have the opposite.
You seem to misunderstand how arraylist works.
new ArrayList<>(100) does not cap the list. The 100 is merely a hint.
ArrayList is defined as allowing infinite* growth, and it has no facilities to limit how many items can be in them.
ArrayList works 'under the hood' by having an array that holds your elements. The problem is, java does not allow arrays to grow or shrink. ArrayList solves this problem with two tricks:
By keeping track of the length of the ArrayList internally, the ArrayList impl can use an array that is 'too large'.
If you've filled up your arraylist to have as many items in it as the 'backing array is large', and you add another item, arraylist has a problem - the backing array is out of room. ArrayList will then make a new, larger array, copy over all the elements from the old array, now add the new item (as there is room; this new array is larger), and then get rid of the old array.
The only thing that 100 does in your constructor is serve as a hint: How large should the backing array be made initially. Out of the box (just new ArrayList<>()), you get the default hint of 10.
Try it! run this:
List<String> list = new ArrayList<String>(100);
for (int i = 0; i < 200; i++) list.add("" + i);
System.out.println(list.size());
That code will compile fine, run fine, and print 200. Thus proving that the '100' has absolutely nothing to do with capping the size of this list.
So, how DO you cap a size of an arraylist?
You don't. Arraylist cannot do that. Instead, you wrap, or extend. For serious code bases, I strongly recommend wrapping, but for a simple exercise, extending can make your code a little shorter:
public class LimitedList<T> extends ArrayList<T> {
private final int limit;
public LimitedList(int limit) {
this.limit = limit;
}
#Override public boolean add(T in) {
if (size() >= limit) throw new IllegalStateException("List is full");
super.add(in);
}
#Override public boolean addAll(Collection<T> in) {
// left as an exercise for the reader
}
#Override public boolean addAll(int index, Collection<T> in) {
// left as an exercise for the reader
}
#Override public boolean add(int idx, T in) {
// left as an exercise for the reader
}
#Override public List<T> subList(int from, int to) {
// this one gets complicated!
// let's just not allow it.
throw new UnsupportedOperationException();
}
public int available() {
return limit - size();
}
}
NB: As you can see, you have to be very careful and override every method that may grow the list; this is why making a new type that doesn't extend ArrayList at all, and instead has 1 field of type ArrayList (and 1 field of int for the limit, of course), can be better: Now you explicitly have to think about every method list has, instead of praying you covered all the ones that add things.
*) well, pragmatically speaking, you can't have more than 2^31-1 elements.
Reading the specification of List, it says that implementations can simply not implement add; or refuse to add elements based on type, or some property of the element; but it doesn't say that a list can refuse to add an element based on the list's current size. Placing a cap on the size thus violates Liskov Substitutability.
You can define a LimitedSizeList implements Collection, but it can't be a true implementation of java.util.List.
You can easily implement LimitedSizeList by extending AbstractCollection:
class LimitedSizeList<E> extends AbstractCollection<E> {
private final List<E> list = new ArrayList<>();
private final int capacity;
LimitedSizeList(int capacity) {
this.capacity = capacity;
}
// Fill in the methods described in the Javadoc:
#Override
public Iterator<E> iterator() { return list.iterator(); }
#Override
public int size() { return list.size(); }
#Override
public boolean add(E element) {
// Collection.add does allow you to throw an IllegalStateException
// https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html#add-E-
if (remainingCapacity() <= 0) throw new IllegalStateException("Full");
return list.add(element)
}
// You don't have to, but you might want to consider overriding
// addAll, in order to make trying to add too-large a collection
// failure atomic (that is, it fails to add any rather than some).
// And then provide a method to report the free capacity:
int remainingCapacity() {
return capacity - size();
}
}
This is a far cleaner way to approach the problem than attempting to extend ArrayList (not just because of the contract violation, but also for all the reasons to prefer composition over inheritance).
Of course, if you really want it to be an invalid List (or you can guarantee that it won't need to be treated as a general-purpose List), you can instead extend AbstractList: the methods you need to implement are different, but there are relatively few, and they're quite easy. However, violating contracts is a good way to get surprising bugs in surprising places in your code.
Capacity is an internal metric that is used to dynamically increase the available space used by the ArrayList<>() Usually, it is of no consequence to the user how this is managed since it is an internal issue.
However, being able to set the capacity allows the user to specify a value indicative of the initial contents that the list will hold. The advantage is that it allows the list to fill the backing array without having to continually readjust the capacity resulting in a lot of copying of objects.
Adjust capacity
At any time you can also increase the capacity by using the ensureCapacity() method.
Reduce capacity
And you can also release unused capacity by using trimToSize() method. This may free up memory within the JVM.
But none of the above will prevent you from adding addtional entries to the list. They simply allow one to make optimum choices based on a priori knowledge of the data.
You can use reflection to achieve this task to get the capacity first, then subtract the actual size
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");
list.add("h");
try {
Field field = list.getClass().getDeclaredField("elementData");
field.setAccessible(true);
int cap = Array.getLength(field.get(list));
System.out.println("The capacity: " + cap);
System.out.println("The size: " + list.size());
System.out.println("The remaining capacity: " + (cap - list.size()));
} catch (Exception e) {
e.printStackTrace();
}
}
, output
The capacity: 10
The size: 6
The remaining capacity: 4
I'm trying to write an operation that can enumerate all the combinations of a set of N elements. In other words, the N is unknown and depends on user input. On receiving the N, the function should be able to give all the possible combination of an N-item set, with all elements from a set U. Say, U={A,B,C...J}, 10 elements in total.
One more example of what I need, the function enumerate(3) should tell me all the possible combinations like {A,B,C},{A,D,J} etc., using elements picked from U.
I tried to do this in a way using for loops(initializing an integer since the size of U happen to be 10 in this case, so I can use 123 to denote {A,B,C}...). But the code smells bad and I'd like to know how this can be done in a more elegant with using recursive calls.
Java/Groovy are both acceptable (because I'm trying in them too). If anybody could provide ideas how to do this with closures in Groovy it'll be even more appreciated.
Also please don't use integers to denote the combination as I did, because I think this only applies to a certain U with no generality.
Thanks!
I believe I have the solution.
import java.util.HashSet;
import java.util.Set;
public class Generator<T> {
Set<T> source;
Set<Set<T>> combinations;
public Generator(Set<T> source) {
this.source = source;
}
public static void main(String[] args) {
final Set<String> source = new HashSet<>();
for (char character = 'A'; character <= 'Z'; character++){
source.add(String.valueOf(character));
}
final Generator<String> stringGenerator = new Generator<>(source);
stringGenerator.generate(3);
}
public void generate(int size){
if (size == 0){
return;
}
Set<Set<T>> newCombinations = new HashSet<>();
for (T element : source) {
if (combinations == null || combinations.isEmpty()){
final HashSet<T> set = new HashSet<>();
set.add(element);
newCombinations.add(set);
} else {
for (Set<T> combination : combinations) {
final HashSet<T> newCombination = new HashSet<>(combination);
if (newCombination.add(element)) {
newCombinations.add(newCombination);
}
}
}
}
combinations = newCombinations;
generate(size - 1);
}
}
It was fast dirty implementation, so probably it misses some cases, but it generally demonstrates the idea with at least one working case.
In the code below I pushed 1,5,3 into the stack respectively means the top 3 is located at the top of stack and 1 at the bottom( which is the case) however when i use iterator to display the contents of the stack, the iterator apparently treats stack like queue and
instead of displaying
3<-5<-1<-Bottom!
it outputs:
1<-5<-3<-Bottom!
why does the iterator do this?
If that's natural behavior of iterator then how can i display the contents of a Stack without using pop?
import java.util.Iterator;
import java.util.Stack;
public class MyStack{
Stack<Integer> stack = new Stack<>();
public void display(){
Iterator <Integer> it = stack.iterator();
while(it.hasNext()){
System.out.print(it.next()+"<-");
}
System.out.println("Bottom!");
}
void pushAll(int [] data){
for(int i:data){
stack.push(i);
}
}
public static void main(String [] org){
MyStack stak= new MyStack();
stak.pushAll(new int [] {1,5,3});
stak.display();
}
}
Console:
1<-5<-3<-Bottom!
while it should output:
3<-5<-1<-Bottom!
The hacky way would be to use a listIterator and start it from the end :
ListIterator<Integer> it = stack.listIterator(stack.size());
while(it.hasPrevious()){
System.out.print(it.previous()+"<-");
}
System.out.println("Bottom!");
You ... don't. The iterator only goes one way (specifically, the same way as in Vector which is where it comes from since Stack is a subclass of Vector).
Technically you can get around this with the ListIterator but really this is one of the reasons the javadoc recommends not using the Stack class anymore.
Use a class with the Deque interface (such as an ArrayDeque) as recommended and you then have the descendingIterator() call.
Iterator<Integer> it = arrayDeque.descendingIterator();
while(it.hasNext()){
System.out.print(it.next()+"<-");
}
So I have a null pointer exception when run. I am supposed to create a generic class that implements a list with chunks of arrays added as needed. Each time I add an element it is to check if there is space in the tail chunk array and if so add the element. Else it needs to add a chunk, adjust the pointers and add the element. My problem so far is that when I go to add the first element it is throwing a null pointer exception. I believe I have instantiated and object and assigned it where needed. If anyone has any insight please feel free to let me know what I am doing wrong or maybe its right in front of my face.
"myChunk.chunk_.add(element);////////////error" is where I am getting the error.
package ChunkList;
import java.util.*;
import java.io.*;
public class chunkList<T> {
public static void main(String[] args) {
chunkList<Integer> myList=new chunkList<Integer>();
for(int i=1; i<24; i++)
{
myList.add(i);//////////////////////////////////
System.out.println("Adding number: "+ i);
}
System.out.println("");
myList.display();
}
private chunk head;//changed T to chunk
private chunk tail;//changed T to chunk
private int array_size=8;
private int list_size;
public chunkList()//Default Constructor
{
head=null;
tail=null;
list_size=0;
}
//public chunkList(chunkList copy){}// a copy constructor.... don't think I need.
class chunk// added <T>
{
//T[] chunk_arr = new T[array_size];// illegal operation
//ArrayList<T> chunk_ = new ArrayList<T>(array_size);
ArrayList<T> chunk_;
private int chunk_size; //may need to change to public
chunk nextChunk;//changed T to chunk
chunk prevChunk;//changed T to chunk
public chunk()//default constructor
{
chunk_ = new ArrayList<T>(array_size);
chunk_size=0;
nextChunk=null;
prevChunk=null;
}
}
public void add(T element)
{
if(this.tail==null)//empty chunk list
{
chunk myChunk=new chunk();//instantiate
//myChunk.prevChunk=null;//changed from head to null
//myChunk.nextChunk=null;//changed from tail to null
head=myChunk;
tail=myChunk;
//head.nextChunk=null;
//head.prevChunk=null;
myChunk.chunk_.add(element);////////////error
list_size++;
myChunk.chunk_size=1;
}
else if (this.tail.chunk_size<array_size)//adds the element to the last chunk in list
{
this.tail.chunk_.add(element);//add element
list_size++;
this.tail.chunk_size++;//increase individual chunk array size
}
else// create new chunk, relink chunks, add element
{
chunk myChunk=new chunk();
myChunk.chunk_size=1;
list_size++;
myChunk.chunk_.add(element);
tail.nextChunk=myChunk;
myChunk.prevChunk=tail;
tail=myChunk;
}}
public int size()
{return list_size;}
public void display()
{
chunk my_chunk=head;
if(my_chunk==null)
{
System.out.print("Empty Chunk List");
return;
}
for(int i=0;i<list_size; )
{
for(int j=0; j<my_chunk.chunk_size; j++)
{
System.out.println(my_chunk.chunk_.get(j));
i++;
}
if(my_chunk.nextChunk!=null)
my_chunk=my_chunk.nextChunk;
}
}
}
So thanks Olivier Jacot-Descombes , I fixed one problem with the code and it now adds the first chunk BUT it is throwing NPE when it tries to create the next chunk. I will look at it and be back if i need more help. Thanks All.
P.S. The add method on this was incorrectly linked together in the last else statement.
Your code is very strange
There is a public static void main(String[] args) inside the class chunkList<T>. This makes no sense.
You declare a chunkList<Integer> instead of chunkList<int>.
You re-declare a chunk<T> head and chunk<T> tail in the constructor. The code should simply be head = null; without chunk<T>.
In the constructor of chunk you do the same thing again with ArrayList<T> chunk_ = ....
I could tell more things; however, I think that you should start by fixing these things to begin with.
NAMING STANDARDS PLEASE!
You will immediately benefit from adhering to industry naming standards, because your code will be more easily read by others when you ask for their help. Also, you'll be able to read other's code more easily too.
In java, convention is that:
all names are camelCase
all names start with a lowercase letter, except class names start with a capital letter
constants are all-capitals with underscore separation (eg MY_CONSTANT)
tend not to abbreviate names
don't use hungarian notation
To apply this to your code, make the following changes:
Rename chunkList to ChunkList
Rename array_size to arraySize
Rename my_chunk to myChunk
Rename chunk_ tochunk`
Now, to answer your question, just use a java.util.LinkedList and stop trying to reinvent the wheel!
For my data structure class, I am trying to write a program that simulates a car wash and I want to give fancy cars a higher priority than regular ones using a priority queue. The problem I am having has something to do with Java not being able to type cast "Object" as an "ArrayQueue" (a simple FIFO implementation). What am I doing wrong and how can I fix it?
public class PriorityQueue<E>
{
private ArrayQueue<E>[] queues;
private int highest=0;
private int manyItems=0;
public PriorityQueue(int h)
{
highest=h;
queues = (ArrayQueue<E>[]) new Object[highest+1]; <----problem is here
}
public void add(E item, int priority)
{
queues[priority].add(item);
manyItems++;
}
public boolean isEmpty( )
{
return (manyItems == 0);
}
public E remove()
{
E answer=null;
int counter=0;
do
{
if(!queues[highest-counter].isEmpty())
{
answer = queues[highest-counter].remove();
counter=highest+1;
}
else
counter++;
}while(highest-counter>=0);
return answer;
}
}
EDIT
Thank you both for the quick answer to this question. I solved the problem by following your advice and one other bit of code:
public PriorityQueue(int h)
{
highest=h;
queues = new ArrayQueue[highest+1];
for(int i = 0; i <= highest; i++)
{
queues[i] = new ArrayQueue();
}
}
An Object is an Object and (in most cases) not an ArrayQueue. So indeed the cast is not possible.
Creation of generic arrays is a problem too, but in your case, this should work:
public PriorityQueue(int h)
{
highest=h;
queues = new ArrayQueue[highest+1]; // Gives an ignorable warning
}
EDIT
The way it is explained in your textbook is incorrect, the book needs a new revision cycle ;) The suggested cast is not allowed in Java, it's like an attempt to do
String forEverUseless = (String) new Object(); // this will not give an empty String
// but an ouch-that-hurts-Exception
which is more obvious. You can never cast a class to one of its subtypes (derived classes). This is true for all classes, including arrays and generic classes.
EDIT 2
Two more suggestions:
The 'add' method should get a check whether 'priority' is in the valid range of priorities, otherwise add will throw an exception (like in: queue.add(entry, -1))
A remove method usually has an argument - you might want to call it with the element that shall be removed from the queue. (Or - if you're intention is something else, i suggest using the common queue operation names pop, push and peek)
The problem is almost exactly what you said -- you're making something of type Object[] and trying to cast it to ArrayQueue[], and those aren't compatible types. You should just do:
queues = new ArrayQueue[highest+1];