How does this delete an element from an array? - java

I am using this book data structures and algorithms in java to learn about (you guessed it) - data structures and algorithms. This piece of code confuses me. I have tested it and it works but i don't see where in the code we specify to delete 55 exactly?
I see that we search for it in the array and move data elements up the index but don't see where we tell the compiler to delete 55.
searchKey = 55; // delete item with key 55
for(j=0; j<nElems; j++) // look for it
if(arr[j] == searchKey)
break;
for(int k=j; k<nElems-1; k++) // move higher ones down
arr[k] = arr[k+1];
nElems--; // decrement size

To be precise, this code does not delete an array element; it overrides it.
Note how j is declared outside the first loop, and used in the second loop to initialize the value of k. The first loop walks j through the array, until j "points" to the element with the value of 55. When this happens, the code exits the loop through break, so when the second loop reads j, it still points to the location in the array where 55 is stored. Now the second loop copies elements from k+1-st location into k-th, "overriding" the value of 55 on the first iteration, and then moving the rest of the values in the consecutive iterations.
Consider this example:
Index: 0 1 2 3 4 5
Value: 30 40 55 60 70 80
After the first loop j is set to 2. Each iteration of the second loop changes the array as follows:
Index: 0 1 2 3 4 5
Iteration 0: 30 40 55 60 70 80
Iteration 1: 30 40 60 60 70 80
Iteration 2: 30 40 60 70 70 80
Iteration 3: 30 40 60 70 80 80
At this point nElems is decremented, making sure that the last element (i.e. 80) is disregarded if the program runs again.

For the sake of example, suppose:
searchKey = 3
arr = {1,2,3,4,0,0,0}
nElems = 4
This means we have an array with seven slots, but the last three elements of the array are unused by the surrounding data structure.
The first for loop is simply looking for the index, j, that contains searchKey (searchValue would have been a better name, but alas). Once it finds the correct index, it breaks, leaving j set. In our example, j = 2 at the end of the first loop. Nothing has been changed yet, we've just found the index we want to clear.
The second for loop does the actual leg work by shifting everything after our found element down one index (and overwriting the found index in the process), so arr[2] is set to arr[3] and arr[3] is set to arr[4] and so on. At the end of the second loop we have
arr = {1,2,4,4,0,0,0}
Finally, we decrement nElems by one, so that there are now only three elements in the data structure. The last four elements in the array (4,0,0,0) are all now garbage that will get written over if more elements are added.

It is overwritten by the first iteration of the second for loop.

Related

When to use set and add methods in list

cutDeck() does the last step of shuffling -- cutting the deck. This should move the first cutLocation number of cards ("first" meaning at the lowest index) from cards and add them to the back of the List. Make certain that you add cards in the same (relative) order that they were originally stored.
public List<PlayingCard> cutDeck(int cutLocation) {
for (int i = 0; i < cutLocation; i++) {
cards.add(cards.get(i));
}
for (int i = 0; i < cutLocation; i++) {
cards.remove(cards.get(i));
}
return cards;
}
This is the error message i am getting
cutDeck(133) did not correctly cut when cards had 208 cards. At index 0 expected 5H but was 3C expected:<[5H]> but was:<[3C]>
I can't see how I am doing something wrong, is it my logic should I be using the cards.set() instead of cards.add()?
Your removal is wrong. Imagine cards has five cards in it and we're splitting it after the first two cards.
1 2 3 4 5
After your first loop terminates, you get:
1 2 3 4 5 1 2
Now, your second loop starts and removes the first card at i = 0, which is 1
2 3 4 5 1 2
Now, your second loop removes the first card at i = 1, which is 3, and NOT 2!
This is where your mistake is. You could simplify the whole logic to a single for loop:
for(int i = 0; i < cutLocation; i++) {
cards.add(cards.remove(0));
}
When you removed the first card in your second for loop all your cards will have been shifted to the front by one position. But your loop variable i is still increasing and you use it in your cards.get(i) call. This means that when you are in the second iteration of your loop you will call cards.get(1), but this would be the original third card to remove. After that you try to remove the next card with cards.get(2), but it would delete the original fifth card and so on.
You might want to use cards.removeAt(0) to (always) remove the card at the beginning until you reached the limit cutLocation.

Deleting from Indexed Priority Queue (java)

I have an Indexed Minimum Priority Queue implemented as a heap. When deleting an indexed element, the code is:
public void delete(int i) {
if (i < 0 || i >= maxN) throw new IllegalArgumentException();
if (!contains(i)) throw new NoSuchElementException("index is not in the priority queue");
int index = qp[i];
exch(index, n--);
swim(index); // Why is this needed?
sink(index);
keys[i] = null;
qp[i] = -1;
}
The rest of the code can be found here: https://algs4.cs.princeton.edu/24pq/IndexMinPQ.java.html
Since pq[N] is the last element in pq[], and this is swapped with the element at pq[i] (which is to be deleted), wouldn't this mean that the value at pq[i] after the swap is larger or equal to pq[i] before the swap? The question is why do we have to call swim(i) at all and not just sink(i) alone? Under which specific conditions is there a need to call swim(i) after the swap?
(There are 3 arrays, qp[] and keys[] with corresponding indexes, and pq[] such that qp[pq[i]] = pq[qp[i]] = i.)
Since pq[N] is the last element in pq[], and this is swapped with the element at pq[i] (which is to be deleted), wouldn't this mean that the value at pq[i] after the swap is larger or equal to pq[i] before the swap?
No, that is not necessarily true. The only requirement for a valid min-heap is that a child cannot be smaller than its parent. While this means that the element in the first position is the smallest, it does not mean that the element in the last position is the largest. Consider the following heap:
1
10 2
15 18 5 3
16 17 19 20 7 8 6 4
pq[N] is 4 and yet there are lots of elements in that heap that are larger than it. Suppose we wanted to remove 15 by replacing it with 4. 4 is smaller than 10 and so would have to be moved up the tree (using swim).

Arrayelements as counters

I'm learning java and have some misunderstanding about array elements:
import java.util.Random;
class One {
public static void main (String[]args) {
Random R1 = new Random();
int mat [] = new int [6];
for ( int chance =0; chance<99; chance++ ) {
++mat[1+R1.nextInt(5)];
}
System.out.println("M\tNumber");
for(int M =1;M <mat.length;M++) {
System.out.println(M + "\t" + mat[M]);
}
}
}
And after running this code I got something like:
M Number
1 30
2 15
3 17
4 23
5 14
I did a lot of attempts and usually Number <=20, which is a bit confusing for me cause I assighn chance <99 hence I asume it should be a bigger number in general. Could you point on my mistake?
I think there is no mistake.
It is very likely that numbers will be about 20 because:
You repeat the following sequence 99 times:
1. Get one random(one of six) element from array.
2. Increase element value (plus one).
Let's assume (of course it doesn't) that random method works in the way it gets for 99 execution :
20 times value 0
20 times value 1
20 times value 2
20 times value 3
20 times value 4
19 times value 5
So we get:
20 in first array element
20 in second array element
and so on...
So, to get bigger number you need to decrease array length or change condition in for loop to bigger "chance" number (in your case: for ( int chance =0; chance<200; chance++ ) ).

Why does the output for my program always start with two consecutive zeros even though I wrote a code that doesn't produce zeros or repeated numbers?

I am trying to create a method that produces lottery numbers with a random number generator. There are two groups of numbers. Group one is supposed to have five different numbers that appear in sorted order, with a range of 1-56. Group two consists of a single number with a range of 1-46. When I run the program, group one always begins two consecutive zeros even though I tried to write the code in a way that doesn't allow group one to have zeros or repeating numbers. At first I thought that the problem must have something to do with the random number generator, so I tried debugging the project in NetBeans. As I stepped through the lines of code, I could see the values assigned to n, which is the variable that holds the numbers produced by the random generator. The values of n were 54, 50, 11, 49, and 28. In the program, the values of n are put into a sorted array. So the output for group one should have been 11, 28, 49, 50, 54, but instead it was 0, 0, 11, 28, 49.
Here is my code:
public static void MakeTickets(){
int [] Group1= new int [5];
int Group2;
int n;
Random rand= new Random ();
for (int j=0 ; j<5; j++){
//Here, I try to make sure that the range for n is 1-56
n= rand.nextInt(55)+1;
//Here, I try to make sure that a number isn't put into the group one
//array more than once
while (Arrays.binarySearch(Group1, n)>=0){
n= rand.nextInt(55)+1;
}
Group1[j]=n;
Arrays.sort(Group1);
}
Random r= new Random();
int num= r.nextInt(45)+1;
Group2=num;
System.out.print("Here is your ticket: Group One= ");
for(int number: Group1){
if (number==Group1[4]){
System.out.print(number);
} else {
System.out.print(number+", ");
}
}
System.out.println(" Group Two= "+Group2);
}
Here is the output:
Here is your ticket: Group One= 0, 0, 33, 45, 50 Group Two= 40
I've tried using ThreadLocalRandom instead, but I still had the same problem. Does anyone know what I am doing wrong? Any and all advice is much appreciated.
The Arrays.sort(Group1); is causing the problem.
I believe the Arrays.sort(Group1); should be placed after the first for loop (after generating the Group1 values).
Currently the values are sorted after adding every value.
Initially the values in the array are 0 0 0 0 0
1st Iteration
After generating the first number
n= rand.nextInt(55)+1; //lets assume the generated value is 43
the, array becomes 43 0 0 0 0
After calling the sort ,
Arrays.sort(Group1);
the array becomes 0 0 0 0 43
2nd Iteration.
After generating the second number
n= rand.nextInt(55)+1; //lets assume the generated value is 22
the, array becomes 0 22 0 0 43
After calling the sort ,
Arrays.sort(Group1);
the array becomes 0 0 0 22 43
3rd Iteration
After generating the third number
n= rand.nextInt(55)+1; //lets assume the generated value is 31
the, array becomes 0 0 31 22 43
After calling the sort ,
Arrays.sort(Group1);
the array becomes 0 0 22 31 43
The 4th and 5th iteration do not change the first two values in the array. This way the first 2 number get stuck as 0s, which explains your result.
You can't use Arrays.binarySearch on an unsorted array. In such case result of this operation is unpredictable.
Sort moves all zeros to the beginning of the array. But you are not rewriting them (cause j is being incremented).
Hello thereļ¼ŒAs far as I know, there are zero-digit situation, the general is the default allocation of zero is the compiler, that you did not initialize this variable.
I believe the problem is that the int array is being sorted every time. The int array is initialized with values of 0. By sorting the array every time you are changing where the new random number needs to be inserted. So sometimes you are accidentally overwriting one of the randomly generated numbers instead of the 0's.
Perhaps instead of using BinarySearch which requires the sorting just used contains and get rid of the sorting until all of the random numbers are generated. I don't know the exact syntax since I haven't coded in Java for 3 years, but you could do something like Arrays.asList(Group1).contains(n). So...
for (int j = 0; j < 5; j++) {
//Here, I try to make sure that the range for n is 1-56
n= rand.nextInt(55)+1;
while (Arrays.asList(Group1).contains(n)) {
n = rand.nextInt(55)+1;
}
Group1[j] = n;
}
Arrays.sort(Group1);

Strange output than my expected output using LinkedList

When the program runs it outputs 10 random numbers and each number stores into LinkedList list, then this list is being displayed there are only 4-5 numbers are shown instead of 10 from the original array. Here's the simple code:
import java.util.LinkedList;
import java.util.Random;
public class randomSum {
private static Random rand = new Random();
private static LinkedList<Integer> arr = new LinkedList<Integer>();
public static void main(String[] args) {
int num = 0;
System.out.println("Original List");
for(int i=0; i < 10; i++) {
num = rand.nextInt(1000);
arr.add(num);
System.out.println(num);
}
System.out.println("\nLinkedList List");
for(int j=0; j < arr.size(); j++)
System.out.println(arr.remove(j));
}
}
The output is like that, which is not exactly what I expected. They both should be the same. Why is that happening?
Original List
693
239
33
999
862
965
994
884
127
977
LinkedList List
693
33
862
994
127
Because on each iteration, you are removing the element you are printing. That will break up the indices. For e.g., when you remove element at index 0, the element at index 1 now moves to index 0, but the loop index moves to index 1 now. So the element just shifted to index 0, was never processed. This will happen to every alternate element, and hence you get that output.
You need to use get(j) instead of remove(j):
for(int j=0; j < arr.size(); j++)
System.out.println(arr.get(j));
or use enhanced for loop:
for (int val: arr) {
System.out.println(val);
}
If you really want to remove items while printing the LinkedList, you should use an Iterator. Removing elements like you're doing causes undefined behavior. Do something like that:
Iterator<Integer> it = arr.iterator();
while(it.hasNext()) {
int element = it.next();
System.out.println(element);
it.remove();
}
In this answer I want to illustrate what actually happens, so that you understand why remove(j) is probably not what you want, like Rohit Jain said.
In the beginning your list looks like this:
693 239 33 999 862 965 994 884 127 977
After the first iteration, in which you call remove(0) it will look like this
239 33 999 862 965 994 884 127 977
so when you call remove(1) in you next iteration you are removing the element 33, which was originally the third element. So each iteration you actually go forward by two elements, with respect to your original list.
You see the regulation the output comes? It's every other number in the original list.
every time you use arr.remove(j) , the list arr will shrink size by 1. so the loop ended while j==5, meantime arr.size()=5. And furthermore, you use arr.remove(j), then the jTH item is removed, and after j++, you skip the original (j+1)th,current jTH item. So comes to the regulation that every other number comes from the original list.
If you replace remove to get that would work as you expected.
And, you can replace remove(j) to remove(0) and change the loop ending condition to j<10, which works fine, too.

Categories