Algorithms, 4th Edition: do not understand an example about aliasing/reference - java

Counter c1 = new Counter("ones");
c1.increment();
Counter c2 = c1;
c2.increment();
StdOut.println(c1);
class code link: https://introcs.cs.princeton.edu/java/33design/Counter.java
public class Counter implements Comparable<Counter> {
private final String name; // counter name
private final int maxCount; // maximum value
private int count; // current value
// create a new counter with the given parameters
public Counter(String id, int max) {
name = id;
maxCount = max;
count = 0;
}
// increment the counter by 1
public void increment() {
if (count < maxCount) count++;
}
// return the current count
public int value() {
return count;
}
// return a string representation of this counter
public String toString() {
return name + ": " + count;
}
// compare two Counter objects based on their count
public int compareTo(Counter that) {
if (this.count < that.count) return -1;
else if (this.count > that.count) return +1;
else return 0;
}
// test client
public static void main(String[] args) {
int n = Integer.parseInt(args[0]);
int trials = Integer.parseInt(args[1]);
// create n counters
Counter[] hits = new Counter[n];
for (int i = 0; i < n; i++) {
hits[i] = new Counter(i + "", trials);
}
// increment trials counters at random
for (int t = 0; t < trials; t++) {
int index = StdRandom.uniform(n);
hits[index].increment();
}
// print results
for (int i = 0; i < n; i++) {
StdOut.println(hits[i]);
}
}
}
The book says it will print "2ones", and the process is shown in the picture above.
But I can't get it. In my opinion, c1 adds so its object adds, so we get "2";then copy c1 to c2, c2 gets "2" as well. As c2 adds, the object will turn to the unknown next grid.
When printing c1, I think we should get "2" rather than "2ones". So what's wrong with my process?
Thanks in advance.

Counter c1 = new Counter("ones");
c1.increment();
Counter c2 = c1;
c2.increment();
StdOut.println(c1);
I think this demonstration should just show Referencing.
Since you are creating just 1 object of type counter.
And assigning the value of c1, to the variable (Counter) c2 and then use the method .increment() on the variable c2 , c1 will change .
Since c2 and c1 are both referencing to the same object in memory .
So changes to c1 and c2 will both affect the same object.

Related

how to construct an array of 100 elements containing the numbers 1 -100 for which shellsort, with the increments 1 4 13 40 (The worst case)?

This is the original question
"Shell Sort worst case. Construct an array of 100 elements containing the numbers 1 through 100 for which shellsort, with the increments 1 4 13 40, uses as large a number of compares as you can find."
There are 100! permutations for an array of 100 elements, it's terrifying to go through each permutation and find which one has the maximum number of compares. Is there any smarter way to approach this problem? My approach this problem is through violence, but only randomly shuffle the array 100000000 time which is less than 100! and it take me half an hour to get the final output.
I pasted my code below. I appreciate any suggestions from you guys!
`
package ch_2_1;
import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.StdRandom;
import java.util.Arrays;
public class exer_19
{
public static void main(String[] args)
{
// initial permutation
int[] array = new int[100];
for ( int i = 1; i < 101; i++)
{
array[i-1] = i;
}
// find the worst case and the number of compares
worst_input(array);
}
private static void worst_input(int[] array)
{
int max_count = 0;
int[] copy = new int[100];
int[] worst_case = new int[100];
for ( int i = 0; i < 100000000; i++)
{
int[] temp = generate(array);
for (int j = 0; j < 100; j++){ copy[j] = temp[j];}
Shell_sort operation = new Shell_sort();
operation.shell_sort(temp);
if (operation.compare() > max_count)
{
max_count = operation.compare();
worst_case = copy;
}
System.out.println(i);
}
for ( int s : worst_case){ System.out.print(s + " ");}
System.out.println();
System.out.println(max_count);
System.out.println();
}
private static int[] generate( int[] array)
{
StdRandom.shuffle(array);
return array;
}
private static class Shell_sort // it's necessary to create a private class to hold the shell sort method
// b/c the method must record the # of compares to sort the array, and this # count need to be returned
// to the worst_input method. Therefore, having a class to encapsulate the two methods is very helpful
{
private int count = 0;
private void shell_sort(int[] test)
{
int N = test.length;
int h = 1;
while (h < N/3) h = 3*h + 1; // 1, 4, 13, 40, 121...
while ( h > 0)
{
for ( int i = h; i < N; i++) // starting from the largest h-value th element of the array (simplified: ith element)
{
// if ith element is less than i-h th element, swap the two, continue this process until the condition is not met
for ( int j = i; j >= h && less( test[j], test[j-h]); j = j - h)
{
exchange( test, j, j-h);
count++;
}
}
// when reached the end of the array, update h value
h = h/3;
}
}
private int compare()
{
return count;
}
}
private static boolean less( int current, int previous)
{
return current < previous;
}
private static void exchange(int[] array, int cur_index, int pre_index)
{
int temp = array[pre_index];
array[pre_index] = array[cur_index];
array[cur_index] = temp;
}
}
`

How to protect arrays from changing?

I'm trying to get data from arrays that were used in method fifo and lifo. I have main array that fills from input by user. These array is used in methods fifo and lifo, the problem is that these two functions giving the same priceOfGoods, because while fifo using main array in process it changing data inside it. I want to prevent changing data in ```main array** and use it in two methods without changing data inside main array. Any ideas? Thanks!
public class Solution {
public static int[][] takingGoodsAndPrice(Scanner input, Integer m) {
final int[][] goodsAndPrice = new int[m][2];
// Taking goods and its price
for (int i = 0; i < m; i++) {
for (int j = 0; j < 2; j++) {
goodsAndPrice[i][j] = Integer.parseInt(input.next());
}
}
return goodsAndPrice;
}
public static int[] takingAmountOfSales(Scanner input, Integer k) {
final int[] amountOfSales = new int[k];
// Taking sale of goods
for (int i = 0; i < k; i++) {
amountOfSales[i] = Integer.parseInt(input.next());
}
return amountOfSales;
}
public static Integer fifo(Integer k, Integer m, int[][] goodsAndPrice, int[] amountOfSales) {
int priceOfRestGoods = 0;
int[][] goods = goodsAndPrice;
int[] amount = amountOfSales;
// Evaluates amount of goods that were not sold
for (int i = 0; i < k; i++) {
for (int j = 0; j < m; j++) {
if (amount[i] == 0)
break;
if (goods[j][0] > amount[i]) {
goods[j][0] = goods[j][0] - amount[i];
amount[i] = amount[i] - amount[i];
} else if (goods[j][0] <= amount[i]) {
amount[i] = amount[i] - goods[j][0];
goods[j][0] = 0;
}
}
}
// Evaluates price of goods that were not sold
for (int i = 0; i < m; i++) {
priceOfRestGoods = priceOfRestGoods + (goods[i][0] * goods[i][1]);
}
return priceOfRestGoods;
}
public static Integer lifo(Integer k, Integer m, int[][] goodsAndPrice, int[] amountOfSales) {
int priceOfRestGoods = 0;
// Evaluates amount of goods that were not sold
for (int i = 0; i < k; i++) {
for (int j = m-1; j >= 0; j--) {
if (amountOfSales[i] == 0)
break;
if (goodsAndPrice[j][0] > amountOfSales[i]) {
goodsAndPrice[j][0] = goodsAndPrice[j][0] - amountOfSales[i];
amountOfSales[i] = amountOfSales[i] - amountOfSales[i];
} else if (goodsAndPrice[j][0] <= amountOfSales[i]) {
amountOfSales[i] = amountOfSales[i] - goodsAndPrice[j][0];
goodsAndPrice[j][0] = 0;
}
}
}
// Evaluates price of goods that were not sold
for (int i = 0; i < m; i++) {
priceOfRestGoods = priceOfRestGoods + (goodsAndPrice[i][0] * goodsAndPrice[i][1]);
}
return priceOfRestGoods;
}
//
// public static Integer medium() {
//
// }
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
final int n = input.nextInt(); // n - total amount of goods
final int m = input.nextInt(); // m - total amount of goods that has been received
final int k = input.nextInt(); // k - total amount of goods that has been released
final int[][] goodsAndPrice = takingGoodsAndPrice(input, m);
final int[] amountOfSales = takingAmountOfSales(input, k);
System.out.println(fifo(k, m, goodsAndPrice, amountOfSales));
System.out.println(lifo(k, m, goodsAndPrice, amountOfSales));
}
}
At the moment, you're creating new variables to store the arrays, but they will reference the same array done like this, meaning that any changes made to them will also be present in the original parameters. You'll want to store a copy of the arrays in those variables instead. See here.
When you do the following
int[][] goods = goodsAndPrice;
you are still referencing the values referenced by goodsAndPrice i.e. both goods and goodsAndPrice will reference the same values. Therefore, any changes made using one of these references will be same for the other reference.
What you need to do is to create a copy of goodsAndPrice[][] and make changes to the copy. You can do create a copy of goodsAndPrice[][] as follows:
int[][] goods = Arrays.stream(goodsAndPrice).map(int[]::clone).toArray(int[][]::new);

Setting Parameters for Random String from Array: Exception n <= 0

Edit: I am trying to pass the values of wG1...wG5, which are in the Main class, to rarityType(), which is expecting five parameters. I want these passed parameters to be used in int[], which defines the weight of the items in the rare[].
Hard-coding the values into the function (line 3) works as intended:
public String rarityType() {
String rare[] = {"Common", "Uncommon", "Rare", "Epic", "Legendary"};
int[] a = {64, 32, 24, 4, 1};
int sum = 0;
for (int i : a)
sum += i;
int s = r.nextInt(sum);
int prev_value = 0;
int current_max_value;
int found_index = -1;
for (int i = 0; i < a.length; i++) {
current_max_value = prev_value + a[i];
boolean found = (s >= prev_value && s < current_max_value);
if (found) {
found_index = i;
break;
}
prev_value = current_max_value;
}
rarityType() is not instanced in Main, it's value is retrieved via getter:
Weapon weapon = new Weapon();
String weaponRarity = weapon.getWeaponRarity();
And in the class:
private String weaponRarity = rarityType();
But I want to be able to modify those values from Main.
.
I am trying to set parameters in Main for a class that returns a weighted random string. When I have the parameters hard coded in the class, it works as expected.
The exception is telling me that the random generator returned null because it was not passed any parameters. I tried to create setters in the class and define them in Main, to no avail. My question is, how can I pass parameters to the function in the class that I instantiate in Main? Thank you for any guidance!
Note: I cannot have a constructor for this class in Main because their are other functions in the class that rely on the returned string from this function.
Main code snippet:
Weapon weapon = new Weapon();
weapon.wG1 = 1;
weapon.wG2 = 1;
weapon.wG3 = 1;
weapon.wG4 = 1;
weapon.wG5 = 1000;
Class code snippet:
public class Weapon {
public int wG1,wG2,wG3,wG4,wG5;
private Random r = new Random();
private String weaponRarity = rarityType(wG1,wG2,wG3,wG4,wG5);
public String rarityType(int w1, int w2, int w3, int w4, int w5) {
String rare[] = {"Common", "Uncommon", "Rare", "Epic", "Legendary"};
int[] a = {w1, w2, w3, w4, w5};
int sum = 0;
for (int i : a)
sum += i;
int s = r.nextInt(sum); //line 100
int prev_value = 0;
int current_max_value;
int found_index = -1;
for (int i = 0; i < a.length; i++) {
current_max_value = prev_value + a[i];
boolean found = (s >= prev_value && s < current_max_value);
if (found) {
found_index = i;
break;
}
prev_value = current_max_value;
}
String selection = "unknown";
if (found_index != -1) {
selection = rare[found_index];
}
return selection;
}
This version of the code throws an exception:
Caused by: java.lang.IllegalArgumentException: n <= 0: 0 at
net.zingrook.mobiloot.Weapon.rarityType(Weapon.java:100)
I think it happens because rarityType method is executed when you create weapon object but wG1,wG2,wG3,wG4,wG5 are not instantiated yet:
Weapon weapon = new Weapon();
probably it will make sense to create a constructor with all these parameters. Please let me know if you have any questions.

Sorting an array on more than one criterion

I have this method to sort an array of objects by the variable id, there's name & GPA, too. How would you go about sorting the entire array of objects? Im only getting the id's sorted but the names when outputted are mixed. This is what I have thus far.
private Student[] st;
private int count;
public ProcessStudents() {
st = new Student[5];
count = 0;
public void sortAscendingID() {
for (int n = 0; n < count - 1; n++) {
int min = st[n].getId();
int index = n;
for (int o = n + 1; o < count; o++) {
if (st[o].getId() < min) {
min = st[o].getId();
index = o;
}
}
if (st[n].getId() > min) {
int p = st[n].getId();
st[n].setId(min);
st[index].setId(p);
}
}
}
}
If I were writing code for a production system rather than say homework or whatever I'd do this:
List<Student> list = new ArrayList<Student>(Arrays.asList(st));
Collections.sort(list);
Would implement Comparable and override its method:
#Override
public int compareTo(Object arg0) {
// return -1, 0 or 1 depending on compared fields.
// if(this.GetId()>((Student)arg0).GetId())
// ...
return 0;
}
...
Collections.sort(collectionOfStudentObjects);

Java: Expanding array size, can't seem to keep all values in original locations

For my current homework, I'm trying to sort my array through a generic class as the user inserts values into its locations. When the size reads as fully loaded, the array class calls in an expansion method that increases the size of the array while retaining its values in proper locations, which I followed from my Professor's note. For some reason, all my values except for location[0] seem to either be misplaced or erased from the array. I'm leaning that the problem originates in the expansion method but I have no idea how to fix this.
For example, the initial size is currently set to 5 but increments by 3 when expansion method is called. The user can input values 1,2,3,4,5 perfectly. But expansion is called when user inputs new value 6 that outputs an array of 1, 6, null, null, null, null. Any further will lead to the error "Exception in thread "main" java.lang.NullPointerException"
Here is my Sorted Array class:
public class SortedArray {
private int size;
private int increment;
private int top;
Comparable[] a;
public SortedArray(int initialSize, int incrementAmount)
{
top = -1;
size = initialSize;
increment = incrementAmount;
a = new Comparable [size];
}
public int appropriatePosition(Comparable value)
{
int hold = top;
if(hold == -1)
{
hold = 0;
}
else
{
for(int i = 0; i <= top; i++)
{
if(value.compareTo(a[i]) > 0)
{
hold = i + 1;
}
}
}
return hold;
}
public Comparable smallest()
{
return a[0];
}
public Comparable largest()
{
return a[top];
}
public void insert(Comparable value)// the method that my driver calls for.
{
int ap = appropriatePosition(value);
//Expansion if full
if(full() == true)
{
expansion();
}
//Shifting numbers to top
for(int i = top; i >= ap ; i--)
{
{
a[i + 1] = a[i];
}
}
a[ap] = value;
top++;
}
public boolean full()
{
if(top == a.length -1)
{
return true;
}
else
{
return false;
}
}
public void expansion()//here's where the expansion begins
{
int newSize = a.length + increment;
Comparable[] tempArray = new Comparable[newSize];
for(int i= 0; i < a.length; i++)
{
tempArray[i]= a[i];
a = tempArray;
}
}
Here's my driver class that calls for the insert method in SortedArray class.
public class IntDriver {
public static void main(String[] args)
{
Scanner keyboard = new Scanner(System.in);
//Creating variables
int data;
boolean check = false;
int choice;
int size = 5;
int increment = 3;
SortedArray b = new SortedArray(size, increment);
//Creating Menu
System.out.println("Please choose through options 1-6.");
System.out.println("1. Insert\n2. Delete\n3. Clear\n4. Smallest\n5. Largest\n6. Exit\n7.Redisplay Menu");
while(check == false)
{
choice = keyboard.nextInt();
switch(choice)
{
case 1:
System.out.println("Type the int data to store in array location.");
data = keyboard.nextInt();
Integer insertObj = new Integer(data);
b.insert(insertObj);
System.out.println("The value " + data + " is inserted");
b.print();
break;
In the expansion method, you're replacing a too soon. The replacement should happen after the for loop:
public void expansion()//here's where the expansion begins
{
int newSize = a.length + increment;
Comparable[] tempArray = new Comparable[newSize];
for(int i= 0; i < a.length; i++)
{
tempArray[i]= a[i];
}
a = tempArray;
}

Categories