ArrayQueue -> RandomQueue implementation: Issues excluding a random element - java

I'm attempting a problem from Pat Morin's Open Data Structures textbook, based on his ArrayQueue implementation:
https://opendatastructures.org/ods-java/2_3_ArrayQueue_Array_Based_.html
"Exercise 2..3 Design and implement a RandomQueue. This is an implementation of the Queue interface in which the remove() operation removes an element that is chosen uniformly at random among all the elements currently in the queue. (Think of a RandomQueue as a bag in which we can add elements or reach in and blindly remove some random element.) The add(x) and $ remove() operations in a RandomQueue should run in constant time per operation."
His code for remove():
T remove() {
if (n == 0) throw new NoSuchElementException();
T x = a[j];
j = (j + 1) % a.length;
n--;
if (a.length >= 3*n) resize();
return x;
}
Logically, what I'm trying to do is:
Swap a random element and the next element.
Return the next element (now swapped with another random element).
I must be missing something, because performing this operation returns some elements multiple times, and never returns others. My code (renamed variables for clarity):
public T remove() {
if (count == 0) throw new NoSuchElementException();
Random random = new Random();
int randIndex = random.nextInt(count);
T objTemp = array[nextElem];
array[nextElem] = array[randIndex];
array[randIndex] = objTemp;
T obj = array[nextElem];
// Increment next element:
nextElem = (nextElem + 1) % array.length;
// Decrement element count:
count--;
if (array.length >= (3 * count))
resize();
return obj;
}
What am I doing wrong, here? Why am I getting some elements multiple times, and others not at all?
(Note: This is for an online university course.)

Credit to Andreas for pointing out my silly mistake.
I needed to get my index based on the index of the head (of course!). This code works:
public T remove() {
if (count == 0) throw new NoSuchElementException();
Random random = new Random();
int randIndex = random.nextInt(count);
int safeRandomIndex = (headIndex + randIndex) % array.length;
// Swap that randomly chosen element with our nextElem:
T objTemp = array[headIndex];
array[headIndex] = array[safeRandomIndex];
array[safeRandomIndex] = objTemp;
T obj = array[headIndex];
headIndex = (headIndex + 1) % array.length;
count--;
if (array.length >= (3 * count))
resize();
return obj;
}

Related

FIFO Queue with random deletion

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.

Search a specific number in a sum of sublist Java

I want to know how to search a number, for instance T, exists if we addition the elements of a list.
For exemple, if I have a list L=[1,5,-2,6] and T= 3, T exists.
The list hits 20 to 30 elements, any ideas ?
Well, if someone wants to know one day here's what I found :
final nt TAB_SIZE = 30;
int[] tab = new int[TAB_SIZE];
for(int i = 0; i < TAB_SIZE; i++){
tab[i] = i;
}
int T = -1;
int n = tab.length;
if (isSubsetSum(tab, n, T))
System.out.println("Found");
else
System.out.println("Not found");
public boolean isSubsetSum(int tab[], int n, int T){
if (T == 0)
return true;
if (n == 0) //So T !=0
return false;
//If the last element is higher, we ignore it
if (tab[n-1] > T)
return isSubsetSum(tab, n-1, T);
//Otherwise, looking if the sum can be obtain bith adding ou excluding the last element
return isSubsetSum(tab, n-1, T) || isSubsetSum(tab, n-1, T-tab[n-1]);
}
This algorithm is really fast but will only works with positive values

Removing a element from an array list without using libraries. Java

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.

Creating a dequeue

I'm trying to create an array-based dequeue but I can't get the order of the output right.
Right now it is bounded but I will probably use unbounded once I figure out how to work the dequeue right.
Here is my code:
public class ArrayBndDequeue<T> implements BoundedDequeueInterface<T>
{
protected final int DEFCAP = 100; // default capacity
protected T[] queue; // array that holds queue elements
protected int numElements = 0; // number of elements n the queue
protected int front = 0; // index of front of queue
protected int rear; // index of rear of queue
public ArrayBndDequeue()
{
queue = (T[]) new Object[DEFCAP];
rear = DEFCAP - 1;
}
public ArrayBndDequeue(int maxSize)
{
queue = (T[]) new Object[maxSize];
rear = maxSize - 1;
}
public void enqueue(T element)
// Throws QueueOverflowException if this queue is full;
// otherwise, adds element to the front of this queue.
{
if (isFull())
throw new DequeueOverflowException("Enqueue attempted on a full queue.");
else
{
front = (front + 1) % queue.length;
queue[front] = element;
numElements = numElements + 1;
}
}
public T dequeue()
// Throws QueueUnderflowException if this queue is empty;
// otherwise, removes rear element from this queue and returns it.
{
if (isEmpty())
throw new DequeueUnderflowException("Dequeue attempted on empty queue.");
else
{
T toReturn = queue[rear];
queue[rear] = null;
rear = (rear + 1) % queue.length;
numElements = numElements - 1;
return toReturn;
}
}
public boolean isEmpty()
// Returns true if this queue is empty; otherwise, returns false
{
return (numElements == 0);
}
public boolean isFull()
// Returns true if this queue is full; otherwise, returns false.
{
return (numElements == queue.length);
}
}
And this is my main class:
public class Dequeue
{
public static void main(String[] args)
{
Scanner userInput = new Scanner(System.in);
String line;
BoundedDequeueInterface<String> queue;
queue = new ArrayBndDequeue<String>(3);
for (int i = 1; i <= 3; i++)
{
System.out.print("Enter a line of text > ");
line = userInput.nextLine();
queue.enqueue(line);
}
System.out.println("\nOrder is:\n");
while (!queue.isEmpty())
{
line = queue.dequeue();
System.out.println(line);
}
}
}
When I run the program, I usually type in:
1
2
3
And the output comes out as:
2
3
1
Any help? If you need anymore pieces of my code, just let me know!
During enqueue you are at first adding +1 to front, then set the object, but you need to do it the opposite order.
On the other hand it is a very bad idea to implement your own Queue class (unless you do it for learning of course), as Java already has a high-speed, reliable and well tested class for this. You can have a look at the source code of the Java queue class for ideas on how to do it properly.
The problem you describe stems from the following expression during insertion (equally applies to removal):
this.front = (this.front + 1) % this.queue.length;
This evalates to:
(0 + 1 % 3) = 1
(1 + 1 % 3) = 2
(2 + 1 % 3) = 0
Because as the third value is stored, due to the size of the queue being 3, you get 3 % 3 which is 0. So the value is stored at index 0.
Have a look at the definition of this algorithm in the ArrayDeque of the JDK. They do it like this:
public void addFirst(E e) {
if (e == null)
throw new NullPointerException();
elements[head = (head - 1) & (elements.length - 1)] = e;
if (head == tail)
doubleCapacity();
}
I think you meant the following (although your overall rational is correct)
Correction
(0+1) % 3 = 1
(1+1) % 3 = 2
(2+1) % 3 = 0
Instead of your example (since % operator has higher precedence order equivalent to multiplication or division from left to right):
(0 + 1 % 3) = 1 => 1
(1 + 1 % 3) = 2 => 2
(2 + 1 % 3) = 0 => 3

How to re-sort already sorted array where one element updates

I have array with constant size (size = 20 in real life), duplicates are allowed For example:
1 2 2 3 3 4 5 6 7 8 9
Now exactly one element updates:
1 5 2 3 3 4 5 6 7 8 9
I need to resort this array. Should I just use bubblesort?
update I don't know how to call what I wrote. But i suppose it is not possible to sort faster. comments are welcome!
// array is already almost sorted and INCREASING, element at pos need to be inserted to the right place
private void SortQuotes(List<Quote> quoteList, int pos)
{
var quoteToMove = quoteList[pos];
if (pos == 0 || quoteList[pos - 1].Price < quoteToMove.Price)
{
MoveElementsDown(quoteList, pos);
} else if (pos == quoteList.Count - 1 || quoteList[pos + 1].Price > quoteToMove.Price)
{
MoveElementsUp(quoteList, pos);
}
}
private void MoveElementsDown(List<Quote> quoteList, int pos)
{
var quoteToInsert = quoteList[pos];
var price = quoteToInsert.Price;
for (int i = pos - 1; i >= 0; i--)
{
var nextQuote = quoteList[i];
if (nextQuote.Price > price)
{
quoteList[i + 1] = quoteList[i];
if (i == 0) // last element
{
quoteList[i] = quoteToInsert;
}
}
else
{
quoteList[i + 1] = quoteToInsert;
break;
}
}
}
private void MoveElementsUp(List<Quote> quoteList, int pos)
{
var quoteToInsert = quoteList[pos];
var price = quoteToInsert.Price;
for (int i = pos + 1; i < quoteList.Count; i++)
{
var nextQuote = quoteList[i];
if (nextQuote.Price < price)
{
quoteList[i - 1] = quoteList[i];
if (i == quoteList.Count - 1) // last element
{
quoteList[i] = quoteToInsert;
}
}
else
{
quoteList[i - 1] = quoteToInsert;
break;
}
}
}
updated i do know which element is odd, i.e. it's position is known!
This solution shifts each element by one until the right position for the odd element is found. As it has been overwritten already in the first step, it is saved in a temporary variable 'h' and then written to the final position. It requires the minimum of comparisions and shift operations:
static void MoveOddElementToRightPosition(int[] a, int oddPosition)
{
int h = a[oddPosition];
int i;
if (h > a[oddPosition + 1])
for (i = oddPosition; i < a.Count()-1 && a[i+1] <= h; i++)
a[i] = a[i+1];
else
for (i = oddPosition; i > 0 && a[i-1] >= h; i--)
a[i] = a[i - 1];
a[i] = h;
}
Bubblesort will use n^2 time if the last element needs to get to the front. Use insertion sort.
As the array is small, insertion sort takes roughly ~O(n) time for small arrays and if you are just updating 1 value, insertion sort should fulfil your purpose in the best possible way.
It can be done in O(n). If you don't know the element then search for the element in O(n) and then You just need to compare and swap for each element and that would take O(n). So total 2n which means O(n).If you know the element which has been modified then compare and swap for each element.
If you're interested in replacing an element quickly, then you can also use a structure where deletion and insertion is fast, like for example a TreeSet in Java. That means O(log(n)) theoretically, but if you just manipulate arrays of 20 elements it may not be worth it
If the set of all different elements is finite, like in your example where you just use numbers for 1 to 9, then there is a solution in O(1). Instead of having a sorted list you just keep an array with the number of occurrences of your elements.
If you still want to keep everything in an array, then the fastest way is this
find the position A of of the element you're going to remove by bisection in O(log(n)).
find the position B of where your new element is going to end up in the same way. More precisely B is the smallest index where new_element < a[k] for every k > B
if A < B, move all elements between A + 1 and B to their left, then set the new element to position B. if B > A, you do the same thing but to the right. Now this step is in O(n), but there's no logic, it's just moving memory around. In C you'd use memmove for this and it's heavily optimized, but I don't know any Java equivalent.
You don't need to sort it again.
Only one element changes. So you just need to go through the list and put the changed number to appropriate place. This will be of O(n) complexity.
int a[] = {1, 5, 2, 3, 3, 4, 5, 6, 7, 8, 9};
int count = 0;
//find the odd element
for(int jj=1; jj< a.length; jj++){
if(a[jj] < a[count])
break;
else count++;
}
System.out.println(" Odd position " + count);
//put odd element to proper position
for(int k= count+1; k<a.length; k++){
if(a[count] > a[k]){
int t = a[count];
a[count] = a[k];
a[k] = t;
count++;
}
}
Above is the working code tested for given input.
Enjoy.
Bubblesort is quite OK in this case with 20 compares max.
But finding the new position with binary search is O(log(n)), that is 5 compares in this case.
Somewhat faster, if you need the last bit odd speed use the binary search otherwise you can stick with bubble sort.
Here is a naive implementation in plain C. Remove the fprintf(stderr, ... after testing. The ITEM can be anything, as long as a comparison function is possible. Otherwise: use pointers to ITEM, (and maybe add an extra sizeofelem argument, ala qsort)
#include <stdio.h>
#include <string.h>
typedef int ITEM;
int item_cmp(ITEM one, ITEM two);
unsigned one_bubble( ITEM *arr, unsigned cnt, unsigned hot , int (*cmp)(ITEM,ITEM) );
int item_cmp(ITEM one, ITEM two)
{
fprintf(stderr,"Cmp= %u to %u: %d\n", one, two, one-two);
if (one > two) return 1;
else if (one < two) return -1;
else return 0;
}
unsigned one_bubble( ITEM *arr, unsigned cnt, unsigned hot , int (*cmp)(ITEM,ITEM) )
{
unsigned goal = cnt;
int diff;
ITEM temp;
/* hot element should move to the left */
if (hot > 0 && (diff=cmp( arr[hot-1], arr[hot])) > 0) {
/* Find place to insert (this could be a binary search) */
for (goal= hot; goal-- > 0; ) {
diff=cmp( arr[goal], arr[hot]);
if (diff <= 0) break;
}
goal++;
fprintf(stderr,"Move %u LEFT to %u\n", hot, goal);
if (goal==hot) return hot;
temp = arr[hot];
/* shift right */
fprintf(stderr,"memmove(%u,%u,%u)\n", goal+1, goal, (hot-goal) );
memmove(arr+goal+1, arr+goal, (hot-goal) *sizeof temp);
arr[goal] = temp;
return goal; /* new position */
}
/* hot element should move to the right */
else if (hot < cnt-1 && (diff=cmp( arr[hot], arr[hot+1])) > 0) {
/* Find place to insert (this could be a binary search) */
for (goal= hot+1; goal < cnt; goal++ ) {
diff=cmp( arr[hot], arr[goal]);
if (diff <= 0) break;
}
goal--;
fprintf(stderr,"Move %u RIGHT to %u\n", hot, goal);
if (goal==hot) return hot;
temp = arr[hot];
/* shift left */
fprintf(stderr,"memmove(%u,%u,%u)\n", hot, hot+1, (goal-hot) );
memmove(arr+hot, arr+hot+1, (goal-hot) *sizeof temp);
arr[goal] = temp;
return goal; /* new position */
}
fprintf(stderr,"Diff=%d Move %u Not to %u\n", diff, hot, goal);
return hot;
}
ITEM array[10] = { 1,10,2,3,4,5,6,7,8,9,};
#define HOT_POS 1
int main(void)
{
unsigned idx;
idx = one_bubble(array, 10, HOT_POS, item_cmp);
printf("%u-> %u\n", HOT_POS, idx );
for (idx = 0; idx < 10; idx++) {
printf("%u: %u\n", idx, array[idx] );
}
return 0;
}

Categories