My dequeue method currently does not delete the item I wish for it too, instead it deletes the last element from the collection. For example,
If I add in the elements: 1, 2, 3
My toString method will return 1, 2, 3 as expected.
Then when I use my driver to call dequeue, it should dequeue the 0th element, 1 in this case.
Although, the method says "Removed element 1 from the queue" prompting that the T result variable has embodied the correct value, although the method does not work as expected, as when calling the toString method after to print the contents, it will print: 1, 2
Then when I call the enqueue method again, on the same queue, if I enqueue the String 3, it will print this as the new queue: 3, 2, 3
I am confused as to where my logic error is, as I assume it is with the extreme case of the collection being filled, but I still run into errors with my dequeue method when the collection is not at max. I attached my code below.
public class QueueRA<T> implements QueueInterface<T> {
protected T[] items;
protected int front, back, numItems;
#SuppressWarnings("unchecked")
public QueueRA() {
front = 0;
numItems = 0;
back = 0;
items = (T[]) new Object[3];
}
#Override
public boolean isEmpty() {
return numItems == 0;
}
#Override
public void enqueue(T newItem) throws QueueException {
if(numItems == items.length) {
resize();
enqueue(newItem);
}
else {
items[back] = newItem;
back = (back + 1) % items.length;
numItems++;
}
}
#Override
public T dequeue() throws QueueException {
T result;
if(numItems != 0) {
result = items[front];
items[front] = null;
front = (front + 1) % items.length;
numItems--;
}
else {
throw new QueueException("The queue does not contain any elements.");
}
return result;
}
#SuppressWarnings("unchecked")
#Override
public void dequeueAll() {
back = 0;
front = 0;
numItems = 0;
items = (T[]) new Object[3];
}
#Override
public T peek() throws QueueException {
T result;
if(numItems != 0) {
result = items[front];
}
else {
throw new QueueException("The queue does not contain any elements.");
}
return result;
}
/**
*
*/
#SuppressWarnings("unchecked")
protected void resize() {
T[] newItems = (T[]) new Object[numItems+4];
for(int i = 0; i < numItems; i++) {
newItems[i] = items[i];
}
this.front = 0;
this.back = numItems;
this.items = newItems;
}
/**
*
*/
public String toString() {
String toReturn = "";
for(int i = 0; i < numItems; i++) {
if( (i+1) == numItems) {
toReturn = toReturn.concat(items[i] + " ");
}
else {
toReturn = toReturn.concat(items[i] + ", ");
}
}
return toReturn;
}
}
Your toString() and resize() methods are wrong.
In your example code, you created an arraySize of 3 initially and then added 1, 2, and 3. This occupies all the 3 slots in the array and your numItems is set to 3. The front is set to 0 and back is also set to 0 because after adding 3, your algorithm is:
back = (back+1)%items.length;
back was initially 2. Now it is calculated as:
-> (2+1)%3
-> 3%3
-> 0
So your back is 0 at this moment.
Now, when you call dequeue(), the front pops 1 out. So now your array looks like this:
items[0] -> empty
items[1] -> 2
items[2] -> 3
back = 0
front = 1
So, when you enque next and add 3, your enqueue() method checks that number of items in the system is less than size of the array (2 < 3) and adds 3 to the location pointed by back (which is 0 now) and increments it to 1. So, your array looks like this now:
items[0] -> 3
items[1] -> 2
items[2] -> 3
back = 1
front = 1
Now, in your toString() method, without considering the values of front and back, you start from 0 to end:
for(int i = 0; i < numItems; i++) {
.
.
.
}
What you need to be doing is start at i = front. if front < back, that means that you travel lineraly from "front" to "back" and print everything. If front > back then you do two loops:
for(int i=front; i < arr.length; i++) {
// Code to print arr[i]
}
for(int i=0; i < back; i++) {
// Code to print arr[i]
}
This way, it will print from front to end and then from 0 to back.
Also, your resize method is wrong for the same reason. You cannot copy from 0 to numItems, you need to start the copy at "front" and then progress like how I wrote for the toString(). Doing this will ensure that your queue's order is preserved across multiple resizes.
Adding to #Arun Subramanian's answer.
Your resize() method was simply copying all of the elements sequentially from items to newItems, then setting front = 0 and back = numItems. Which would have been fine if you had implemented the queue sequentially. However, your implementation of a queue is not sequential, it's a circular / ring implementation. Therefor you have to copy the elements in a circular way.
One way to do this is mentioned in #ArunSubramanian's answer, "If front < back, that means that you travel linearly from front to back and print everything. If front > back then you do two loops." Another way is to use a do-while loop with modular arithmetic, as in the following:
#SuppressWarnings("unchecked")
protected void resize() {
T[] newItems = (T[]) new Object[numItems + 4];
int i = 0; // index used to copy items to newItems
// do-while used in case the queue is full (i.e. front == back)
do {
newItems[i] = items[front];
// modular arithmetic used to circle back on items
front = (front + 1) % items.length;
i += 1;
} while(front != back);
this.front = 0;
this.back = numItems;
this.items = newItems;
}
Similarly your toString() method can be implemented in the following way:
#Override
public String toString() {
String toReturn = "";
// need this check, otherwise do-while will illegally access items[0]
if(!isEmpty()) {
int len = items.length;
int i = front;
// do-while used in case front == back
do {
String delim = ((i+1) % len == back) ? " " : ", ";
toReturn += items[i] + delim;
i = (i+1) % len; // modular arithmetic used to circle back
} while(i != back);
}
return toReturn;
}
Related
I must implement a recursive method merge(long[] arr, int i) which multiplies adjacent elements if they have the same value, starting at index i.
Example:
merge({1, 2, 2, 4}, 0)
should produce an array like this:
{1, 4, 4}
If there are multiple (n) occurrences of a number {1, 2, 2, 2, 2, 5}, all of these must be multiplied together: {1, 16, 5}.
A number which has already been merged can not be merged again {1, 4, 4, 16} -> {1, 16, 16}.
All this must be achieved by using only this one method merge and having exactly one recursive call per element in the original array.
This is a working implementation using recursion and loops:
public static long[] merge(long[] ns, int i) {
final long[] EMPTY_LONG_ARRAY = {};
if (i < 0) {
return merge(ns, 0, m); // if i negative, start at 0
} else if (i >= ns.length) {
return EMPTY_LONG_ARRAY; // if out of bounds, return empty array
} else if (i == ns.length - 1) {
return ns; // base case
} else { // recursion in here
if (ns[i] == ns[i + 1]) { // if next long is equal
int occurences = 1; // first occurence
for (int j = i; j < ns.length - 1; j++) {
if (ns[j] == ns[j + 1])
occurences++;
else
break;
} // add next occurences
long[] newArray = new long[ns.length - occurences + 1]; // new array is (occurences-1) shorter
for (int j = 0; j < newArray.length; j++) { // fill new array
if (j < i) {
newArray[j] = ns[j]; // left of i: values stay the same
} else if (j > i) {
newArray[j] = ns[j + occurences - 1]; // pull values right of i (occurences-1) to the left
} else {
int counter = occurences;
long mergedValue = ns[j];
while (counter > 1) {
mergedValue *= ns[j];
counter--;
}
newArray[j] = mergedValue; // at j: value is ns[j]^occurences
}
}
if (i == ns.length - 1)
return merge(newArray, i, m);
else
return merge(newArray, i + 1, m); // if bounds permit it, jump to next number
} else {
return merge(ns, i + 1, m); // nothing to merge, go one step forward
}
}
This implementation produces the correct result, however, the recursion depth is wrong (needs to be one recursive call per element in original array ns[]).
I'm sure there is a genius out here who can solve this using linear recursion.
Lets transform your loop into a recursive call. The only reason to do this is that the assignment asks for it - it is not more readable (at least to me), and it is actually slower. People usually want to go in the other direction for efficiency reasons: from recursion to loops.
First, an annotated version of your code:
public static long[] merge(long[] ns, int i) { // i not needed, but useful for recursion
long[] out = new long[ns.length]; // for result; allocate only once
for (int j = i; j < ns.length; j++) { // main loop, condition is "j == length"
int occurences = 0;
for (int k = i; k < ns.length; k++) { // inner loop - can avoid!
if (ns[j] == ns[k]) {
occurences++;
}
}
out[j] = (long) Math.pow(ns[j], occurences); // updating the result
}
// remove additional elements
return out; // this does not remove elements yet!
}
First, let me rewrite that to be more efficient. Since duplicates are only removed if they are next to each other, you do not need the inner loop, and can write this instead:
public static long[] merge(long[] ns) {
long[] out = new long[ns.length];
int oSize = 0; // index of element-after-last in array out
long prev = ns[0]; // previous element in ns; initial value chosen carefully
out[0] = 1; // this make the 1st iteration work right, not incrasing oSize
for (int i=0; i<ns.length; i++) {
long current = ns[i];
if (current == prev) {
out[oSize] *= current; // accumulate into current position
} else {
oSize ++; // generate output
out[oSize] = current; // reset current and prev
prev = current;
}
}
// generate final output, but do not include unused elements
return Arrays.copyOfRange(out, 0, oSize+1);
}
Assuming this works (and beware - I have not tested it), I will now transform it into tail recursion. There will be 2 parts: a driver code (everything not in the loop), and the recursive code (the loopy part).
public static long[] merge(long[] ns) {
long[] out = new long[ns.length];
int oSize = 0;
long prev = ns[0];
out[0] = 1;
int i=0;
recursiveMerge(ns, i, out, oSize, prev); // recursion!
return Arrays.copyOfRange(out, 0, oSize+1);
}
public static void recursiveMerge(long[] ns, int i, long[] out, int oSize, long prev) {
if (i == n) return; // check "loop" termination condition
// copy-pasted loop contents
long current = ns[i];
if (current == prev) {
out[oSize] *= current; // accumulate into current position
} else {
oSize ++; // generate output
out[oSize] = current; // reset current and prev
prev = current;
}
// next loop iteration is now a recursive call. Note the i+1
recursiveMerge(ns, i+1, out, oSize, prev);
}
The general idea is to pass all state as arguments to your recursive function, and check loop termination at the start, put the loop code in the middle, and at the very end, make a recursive call for the next iteration.
I'm building a sorting algorithm visualizer in processing (extension of java with extra libraries for visualization) and i'm very much stuck on this problem which I think others will be able to help me solve.
In processing there is a function called draw() that is being called 60 times each second. It's here that I want to execute, each time draw() is called, one step of the insertion algorithm. I already implemented it with a bubble sort. (see code below).
updateBubble() is being called in draw() and 'colors' is the name of the arraylist I use to keep the different values of colors to sort.
picture to get a better understanding:
[![visualisation algorithm preview][1]][1]
...
int j = 0
...
void updateBubble() {
bubble.sort(j);
j++;
if (i<bubble.colors.size()) {
if (j >= bubble.colors.size()-i-1) {
j = 0;
i++;
}
} else {
bubble.sorted = true;
}
}
and here is the function in the class BubbleSort (bubble is an object of this class)
void sort(int j) {
if (j<colors.size()-1) {
if (colors.get(j) > colors.get(j+1))
{
int temp = colors.get(j);
colors.set(j, colors.get(j+1));
colors.set((j+1), temp);
}
}
}
This way I was able to slow down the visualization process to the the pace of the framerate which I can control myself without using loops which would execute the sorting algorithm immediately. Now I also wanted to make a similar implementation for the insertion sort algorithm but i feel like i'm stuck because I don't seem to be able to use a similar implementation that works or there might be a better way to do this?
What I have at the moment executes it immediately as expected, without being able to see the process.
void updateInsertion() {
insertion.sort();
}
void sort() {
int n = colors.size();
for (int i = 1; i < n; ++i) {
int key = colors.get(i);
int j = i - 1;
while (j >= 0 && colors.get(j) > key) {
colors.set(j+1, colors.get(j));
j = j - 1;
}
colors.set(j+1, key);
}
}
this is what i got now: which is still wrong but is getting closer and clearifies what i'm trying to reach, making a function that only works with increments and if statements instead of whiles and fors so each different step is being executed with each call of the method.
// i resembles for loop variable
if (i<insertion.colors.size()) {
if (j<0 || insertion.colors.get(j) <= insertion.colors.get(i)) { // negative check to go out of while loop
insertion.colors.set(j+1, keap);
if(notSortedYet()){
i++;
keap = insertion.colors.get(i);
j = i - 1;
}
} else { // resembles being in the while loop
insertion.colors.set((j+1), insertion.colors.get(j));
j = j - 1;
}
}
}
EDIT: I fixed it and you can find my solution beneath :) everytime updateInsertion() is called, my code will execute exact one step in the algorithm! thanks to everyone who put effort into commenting, I dont know if this is best practise, so keep me updated on that if you want!
void updateInsertion() {
// i resembles for loop variable
if (i<insertion.colors.size()) {
if (j>=0 && insertion.colors.get(j) > firstUnsorted) {
int temp = insertion.colors.get(j+1);
insertion.colors.set((j+1), insertion.colors.get(j));
insertion.colors.set(j,temp);
j = j - 1;
} else {
insertion.colors.set(j+1, firstUnsorted);
if (i<insertion.colors.size()-1) {
i++;
}
firstUnsorted = insertion.colors.get(i);
j = i - 1;
}
}
}
I love this project.
Processing also have a millis() method which returns how many milliseconds were spent since you've started your sketch. I sometimes use it to time my animations, which could come in handy right here. Here's an implementation of a timer class:
class Delay {
int limit;
Delay (int l) {
limit = millis() + l;
}
boolean expired () {
return (millis() > limit);
}
}
I suggest that you use this class instead of tweaking the FPS. By using the Delay to slow down your implementation of the sort, you're letting the computer work at it's own rhythm and only draw a new frame when you need it. Like this (excuse the parts where I say "do stuff"):
Delay holdTheFrame = new Delay(1);
void draw() {
if(holdTheFrame.expired()) {
holdTheFrame = new Delay(500); // half a second before the next frame
// Advance one step forward in your sorting
// Draw the visualization of the data
}
}
You can fine tune at what pace your data is sorted and only paint it when it changes. It's win-win!
Have fun!
EDIT
To help you with the implementation, here's an example one. You can copy and paste this code in an empty Processing sketch and it'll run as-is. To make things easier on my side I print to console instead of using the graphical display, but you should be able to get what I'm doing.
The secret here is that my sorting algorithm have been subtly modified so they instead always run only ONE sorting step when I call them. See for yourself:
int _numberOfItems = 10;
int _sortingStep = 0;
IntList _bubbleList = new IntList();
boolean _bubbleListSorted = false;
IntList _selectionList = new IntList();
IntList _insertionList = new IntList();
Delay _delay = new Delay(1);
void setup() {
for (int i=0; i<_numberOfItems; i++) {
_bubbleList.append((int)random(10, 99));
}
for (int i=0; i<_numberOfItems; i++) {
_selectionList.append((int)random(10, 99));
}
for (int i=0; i<_numberOfItems; i++) {
_insertionList.append((int)random(10, 99));
}
}
void draw() {
if (_delay.expired()) {
_delay = new Delay(500);
// sort one step with every algo you want to display
if (!_bubbleListSorted) {
singleStepBubbleSort(_bubbleList);
}
if (_sortingStep < _numberOfItems) {
singleStepSelectionSort(_selectionList, _sortingStep);
singleStepInsertionSort(_insertionList, _sortingStep);
}
_sortingStep++;
// update the display (I'm printing to console instead for simplicity)
for (int i : _bubbleList) {
print(i + " ");
}
print(" | ");
for (int i : _selectionList) {
print(i + " ");
}
print(" | ");
for (int i : _insertionList) {
print(i + " ");
}
print("\n");
}
}
// An "single-step" implementation of Insertion Sort
void singleStepInsertionSort(IntList list, int step) {
int k = list.get(step);
int j = step - 1;
while (j >= 0 && list.get(j) > k) {
list.set(j+1, list.get(j));
j = j - 1;
}
list.set(j+1, k);
}
// An "single-step" implementation of Bubble Sort
void singleStepBubbleSort(IntList list) {
int temp;
boolean swapped = false;
for (int i=0; i<list.size()-1; i++)
{
if (list.get(i) > list.get(i + 1))
{
// swap arr[j] and arr[j+1]
temp = list.get(i);
list.set(i, list.get(i+1));
list.set(i+1, temp);
swapped = true;
}
}
if (!swapped) {
_bubbleListSorted = true;
}
}
// An "single-step" implementation of Selection Sort
void singleStepSelectionSort(IntList list, int step)
{
int min_idx = step;
for (int j = step+1; j < list.size(); j++) {
if (list.get(j) < list.get(min_idx)) {
min_idx = j;
}
}
int temp = list.get(min_idx);
list.set(min_idx, list.get(step));
list.set(step, temp);
}
class Delay {
int limit;
Delay (int l) {
limit = millis() + l;
}
boolean expired () {
return (millis() > limit);
}
}
Let me know if you have questions.
MORE EDITS:
Every swap of an insertion sort means many, many swaps. It's a real pain because this algorithm is kinda complicated to stop in it's tracks.
Luckily, I don't care. Thinking outside the box, I opted instead to create a class dedicated to sort an array while recording how to sort it, then be able to play it back "as if it was happening in real time". take a look:
int numberOfItems = 10;
int sortingStep = 0;
Delay delay = new Delay(1);
ManagedSelectionSort managedSelectionSort; // I created a class just to manage this madness
void setup() {
IntList list = new IntList();
for (int i=0; i<numberOfItems; i++) {
list.append((int)random(10, 99)); // some random numbers to sort later
}
managedSelectionSort = new ManagedSelectionSort(list); // take a look at the instantiation of this class
print("Step " + String.format("%02d", sortingStep) + ": ");
printArray(managedSelectionSort.list);
print("\n");
}
void draw() {
if (delay.expired()) {
delay = new Delay(100); // i put a very short delay, you'll probably want to tweak this
managedSelectionSort.sortOneStep(); // this is not what it seems
sortingStep++;
print("Step " + String.format("%02d", sortingStep) + ": ");
printArray(managedSelectionSort.list);
print("\n");
}
}
// this class is where the magic happens
// we'll sort the array all at once while recording every move
// then we'll play back those moves on a copy of the array
class ManagedSelectionSort {
IntList list, hiddenList; // list is the "official" list, while hiddenList is where the heavy lifting happens
ArrayList<SwapIndex> swapList; // this is where I record how to sort the array
ManagedSelectionSort(IntList baseList) { // this way I can instantiate several similar objects with the same list
list = new IntList();
hiddenList = new IntList();
swapList = new ArrayList<SwapIndex>();
for (int i : baseList) {
// both lists have the same initial numbers
list.append(i);
hiddenList.append(i);
}
// as soon as this object is instantiated, it knows how it'll sort the array
// because it already did...
hiddenSort();
}
// this method plays the moves which were recorded earlier according to the current sortingStep
// the swapList array was filled with every swap needed to sort the array, one by one
// now it's just a matter of playing them back on a copy of the initial array
void sortOneStep() {
if (sortingStep < swapList.size()) {
swap(list, swapList.get(sortingStep).index1, swapList.get(sortingStep).index2);
}
}
// this is the real implementation of the insertion sort
void hiddenSort()
{
for (int i=1; i<hiddenList.size(); i++) {
int j = i;
while (j>0 && hiddenList.get(j) < hiddenList.get(j-1)) {
swap(hiddenList, j, j-1, true); // swap is a class specific helper method, it swaps the numbers and also records the move
j--;
}
}
}
// this is an overload, i could have done without but it's confortable
void swap(IntList list, int index1, int index2) {
swap(list, index1, index2, false);
}
void swap(IntList list, int index1, int index2, boolean recordMove) {
// the swap first
int temp = list.get(index1);
list.set(index1, list.get(index2));
list.set(index2, temp);
// if the method is set on 'record', it adds this move to the swapList array
if (recordMove) {
swapList.add(new SwapIndex(index1, index2));
}
}
}
// this class could have been a struct, but I like to start in OOP right from the bat in case things gets complicated
class SwapIndex {
int index1;
int index2;
SwapIndex(int index1, int index2) {
this.index1 = index1;
this.index2 = index2;
}
}
// this method is just an helper method to print to console
void printArray(IntList list) {
for (int i : list) {
print(i + " ");
}
}
class Delay {
int limit;
Delay (int l) {
limit = millis() + l;
}
boolean expired () {
return millis() > limit;
}
}
This should solve your initial problem, if I understood it right this time!
One way to achieve this is via a some sort of stored state. Below is at a high level what I'm talking about.
// Starts the procedure. Must be called before draw().
void init() {
state = "forLoop";
i = 1;
n = colors.size();
}
// Single iteration of a loop.
void draw(){
switch(state) {
case "forLoop":
doForBody();
break;
case "whileLoop":
doWhileLoopBody();
break;
...
}
}
// Executes everything in the while loop and the one or two things
// just after it.
void doWhileLoopBody() {
if (isThisIterationOfWhileDone()) {
// Get out of the while loop and prepare for the next iteration of for.
// A better way to what I'm doing on the next couple lines here would
// be to introduce an additional state (ex: "postWhile") that would
// execute just after this method and would handle the colors.set(),
// incrementing i, etc.
state = "forLoop";
colors.set(j+1, key);
i++;
return;
}
// update colors, value of j, etc...
}
// Executes everything before the while loop.
void doForLoopBody() {
if (isThisIterationOfForDone()) {
state = "END";
return;
}
// update colors, get values of key and j initialized, etc
// switch to processing the body of the while loop
state = "whileLoop";
}
Implement a data type that supports insert an item, delete the item added least recently, and delete a random item. Each operation should take constant expected amortized time per operation and should use space (at most) proportional to the number of items in the data structure.
eg. 1 2 3 4 5 6 -> 1 2 4 5 6
I have already implemented the queue as below, but now I do not know how the delete a random item with amortized time, should I rearrange the array every time when there is a random remove like moving number after the random removed number one slot forward in array? is it a really bad practice? or should I implement the Queue using linked list? but my gut feeling tells me linked list also need average O(n) to reach the random node from the head of the linked list.
public class RandomQueue<Item> implements Iterable<Item> {
Item[] items;
int N;
int first;
int last;
public RandomQueue() {
items = (Item[]) new Object[2];
N = 0;
first = last = 0;
}
public static void main(String[] args) {
RandomQueue<Integer> rd = new RandomQueue<>();
}
public boolean isEmpty() {
return N == 0;
}
public String toString() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < N; i++) {
sb.append(items[(first + i) % items.length]).append(" ");
}
return sb.toString();
}
private void resize(int length) {
Item[] temp = (Item[]) new Object[length];
for (int i = 0; i < N; i++) {
temp[i] = items[(first + i) % items.length];
}
items = temp;
first = 0;
last = N;
}
public void enqueue(Item item) {
if (N == items.length)
resize(items.length * 2);
items[last++] = item;
if (last == items.length)
last = 0;
N++;
}
public Item dequeue() {
if (isEmpty())
throw new NoSuchElementException("Queue is empty");
Item first = items[first];
items[first] = null;
N--;
if (first == items.length)
first = 0;
else
first++;
if (N > 0 && N == items.length / 4)
resize(items.length / 2);
return first;
}
}
The key to this problem is that you are not removing a random item from the queue you are creating a queue that excludes a random item. You should have a function in your program that accepts a queue as input and does the following:
Create a second queue that will exclude the random deleted item.
Generate a random number less than or equal to the total length of the first queue.
Create a loop that will remove items from the first queue and add them to the second queue.
If the counter in your loop equals the random number, do not add it to the second queue.
Delete the first queue and return the second queue.
I have implemented a function which removes an element from an array list. I should not the ArrayList libraries! See my code below:
/**
* removes a LendItem at a specified (index) position.
* This functions returns the item removed from the list or null if no such item exists. This
* function leaves no gaps, that means all items after the removed item are shifted one position.
* #param list is the item to be removed
* #param n is the index of the item to be removed
* #return the removed item
*/
public static LendItem remove(LendItemArrayList list, int n) {
if (list.next == 0) {
return null;
}
if (n < 0 || n > list.INITIAL_SIZE) {
return null;
}
LendItem itemToBeRemoved = list.lendItems[n]; // itemToBeRemoved is the item which has the index n, which we want to remove from the list.
int i;
for (i = n; i < list.next - 1; i++) { // iterate through the list, starting where the index of the itemToBeRemoved is.
list.lendItems[i] = list.lendItems[i + 1];
}
list.lendItems[i] = null;
list.next--;
return itemToBeRemoved;
}
and here is the class :
public class LendItemArrayList {
int INITIAL_SIZE = 20;
boolean resizeable = false;
LendItem[] lendItems = new LendItem[INITIAL_SIZE];
int next = 0;
}
I have tested my functions with a few test methods which have been provided, and i am only failing one of them. Specifically the test is called:
removeNonExistingElement
and it fails like this:
java.lang.AssertionError: 10 elements have been added, next should be 10 (no changes) but found 9.
EDIT:
Added the add() function.
public static boolean add(LendItemArrayList list, LendItem p) {
if (list.next == list.lendItems.length) {
if (list.resizeable == false) {
return false;
}
}
if (list.next == list.lendItems.length) {
if (list.resizeable == true) {
LendItem[] resizedList = new LendItem[list.lendItems.length*2];
for (int i = 0; i < list.next; i++) {
resizedList[i] = list.lendItems[i];
}
list.lendItems = resizedList;
}
}
list.lendItems[list.next++] = p;
return true;
}
Leave this as it is, as it checks if the indices are out of range.
if (n < 0 || n >= list.INITIAL_SIZE) {
return null;
}
Next, add this line of code:
if (list.lendItems[n] == null) {
return null;
}
Afterwards, you may or may not add the if statement which checks if the given list is empty. It makes no difference unless it is required to be used.
if (list.next == 0){
return null;
}
Change this line:
if (n < 0 || n > list.INITIAL_SIZE) {
To this:
if (n < 0 || n >= list.INITIAL_SIZE) {
>= means greater or equal. If n == list.INITIAL_SIZE, then that item can't be removed either, because since indices start with 0, the last value in a list has an index of size - 1. It's one of those things that hurt your brain when you start programming.
I am working on a project in which I have to sort an array of Integer objects by using Comparable.
My add method takes an item of type E. If my size variable (which tracks the elements in my array theData[]) is = 0 (which it is initialized to), I simply put the item in theData[0].
If it is not, I use item.compareTo to compare the item against each item already in the array. If the result of compareTo is < 0 for a number in the array, I shift everything at that number and after to the right, and insert the item before it.
If compareTo returns a 0, meaning the item is equal to the number in the array, I do nothing as I don't want duplicates in the array.
If none of the compareTo statements in the loop return a -1 or a 0, I put the item in theData[size], the end of the array, as it must be larger than all the other numbers.
However, this doesn't work. Any time I make a new Set and add a few numbers to it, then try to print out the contents of my set using a for loop,I keep getting a java.lang.ArrayIndexOutOfBoundsException: 10 error for this line:
theData[j + 1] = theData[j];
I've tried starting from scratch and re-writing my loop with different logic, and each time I keep hitting this wall. I know I must either be shifting incorrectly or not increasing the size of the array correctly with my reallocate method, but I can't wrap my head around it.
import java.util.*;
public class Set<E extends Comparable<E>> {
String s;
String name;
private static final int INITIAL_CAPACITY = 10;
private E[] theData;
private int size = 0;
private int capacity = INITIAL_CAPACITY;
#SuppressWarnings("unchecked")
public Set() {
theData = (E[]) new Comparable[capacity];
}
public Set(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void add(E item) {
if (size == capacity) {
reallocate();
}
if (size == 0) { // If size is 0, add item to theData[0]
theData[size] = item;
size++;
return;
}
else { // Else compare the item to every item in loop.
for (int i = 0; i < size; i++) {
int result = item.compareTo(theData[i]);
if (result < 0) {
for (int j = 0; j < size; j++) { //If item is less than a number, shift everything
theData[j + 1] = theData[j]; //after that index to the right, and add item
theData[j] = item;
}
}
if (result == 0) {
return;
}
else { //If item is not less than or equal to any
theData[size] = item; //numbers in the array, add it to the end
size++;
}
}
}
}
/*
* if (size>=1){ int result = item.compareTo(theData[size-1]); if(result<0){
* E temp = theData[size-1]; theData[size-1] = item; theData[size] = temp; }
* if(result>1){ return; } }
*/
public E get(int index) {
if (index < 0 || index >= size) {
throw new ArrayIndexOutOfBoundsException(index);
}
return theData[index];
}
public int size() {
return size;
}
private void reallocate() {
capacity = 2 * capacity;
theData = Arrays.copyOf(theData, capacity);
}
}
Edit: The driver method I'm using to test it -
public class Driver {
String one = "two";
public static void main(String[] args){
Set<Integer> one = new Set<Integer>();
one.add(63);
one.add(20);
one.add(127);
one.add(10);
one.add(26);
one.add(15);
for(int i = 0; i < one.size(); i++){
System.out.println(one.get(i));
}
}
}
When j == size - 1, theData[j+1] will take you out of the array.
You want to loop to one before the end instead.
for (int j = 0; j < size - 1; j++) { //If item is less than a number, shift everything
theData[j + 1] = theData[j]; //after that index to the right, and add item
theData[j] = item;
}
So I've also taken a look at the logic you've got for the insertion, and it doesn't make a lick of sense. Why do you delay the insertion at all? If you've got the room, just add it!
Next, the double loops are essentially implementing bubble sort, but there's a fatal flaw with it: you don't ever complete the swap; you only overwrite your values repeatedly. You're also not comparing in the right direction; you want to swap if the value on the left is larger than the value on the right, since you're starting from the beginning of the array.
So, with that...this is what an implementation would have the form of...
public void add(E item) {
if (size == capacity) {
reallocate();
}
theData[size++] = item;
for (int i = 0; i < size - 1; i++) {
for (int j = 0; j < size - 1; j++) {
if (theData[j].compareTo(theData[j + 1]) > 0) {
// perform the swap (you need an extra variable!
}
}
}
}
I leave implementing the swap as an exercise for the reader.
First, in your shift loop, you are inserting the new item in every position instead of shifting then inserting in [i] because you copy theData[j] to the next position, but always assign item to theData[j], is that right?
Second, you are starting from the beginning of array since j starts with 0. J should start with i.
Third and main bug, you verify if result < 0 then you verify IF result == 0, change for a ELSE IF so the else don't get executed even when result < 0
shift elements to right can be done from right to left, like:
for (int j = size; j > i; j--) { // If item is less than a
// number, shift
// everything
theData[j] = theData[j - 1]; // after that index to the
// right, and add item
}
size++;
theData[i] = item;
break;// after insert the number, we can just break the for loop
once the new number is inserted, break the for loop, else, the size variable will not be correct
else { // If item is not less than or equal to any
theData[size] = item; // numbers in the array, add it to the end
size++;
break;
}