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;
}
}
`
I'm working on a code that should generate an array with a length of 100 and then separates numbers form the array to:
Numbers that are multiples of 4.
Numbers that are not multiples of 4.
Below is my code, however, I'm getting a weird output (lots of zeros). How can I identify the problem?
public class Assignment8 {
public static void main(String[] args) {
// Defined array to hold the values
int[] randomValueArray = new int[100];
int[] mod4ValueArray = new int[100];
int[] nonMod4ValueArray = new int[100];
// Initiate the randomValue Array
for (int i = 0; i < 100; ++i) {
// Generate a random number from the range 1 to 100
int randomValue = (int) (Math.random() * 100 + 1);
randomValueArray[i] = randomValue;
}
// Pass the array to the class method to separate mod4
// value and non mod4 value from the randomized array
mod4ValueArray = isMod4(randomValueArray);
nonMod4ValueArray = isNonMod4(randomValueArray);
// Print out the two result arrays
System.out.println("Randomly generated numbers that are multiples of four: ");
for (int i = 0; i < mod4ValueArray.length; ++i) {
System.out.println(mod4ValueArray[i]);
}
System.out.println("Randomly generated numbers that are not multiples of four: ");
for (int i = 0; i < nonMod4ValueArray.length; ++i) {
System.out.println(nonMod4ValueArray[i]);
}
}
// Mod4 Checker Method
public static int[] isMod4(int[] array) {
int[] resultArray = new int[array.length];
for (int i = 0; i < array.length; ++i) {
int itemValue = array[i];
if ((array[i] % 4) == 0) {
resultArray[i] = itemValue;
}
}
return resultArray;
}
// Non Mod 4 Checker Method
public static int[] isNonMod4(int[] array) {
int[] resultArray = new int[array.length];
for (int i = 0; i < array.length; ++i) {
int itemValue = array[i];
if ((itemValue % 4) != 0) {
resultArray[i] = itemValue;
}
}
return resultArray;
}
}
Try this.
int[] randomValueArray = new Random().ints(100, 1, 101).toArray();
int[] mod4ValueArray = IntStream.of(randomValueArray).filter(i -> i % 4 == 0).toArray();
int[] nonMod4ValueArray = IntStream.of(randomValueArray).filter(i -> i % 4 != 0).toArray();
try this:
new Random().ints(100, 1, 100).filter(n -> n % 4 == 0).toArray();
new Random().ints(100, 1, 100).filter(n -> n % 4 != 0).toArray();
Java 8 Stream-esque solution:
Map<Boolean, int[]> map = new Random().ints(10, 1, 100)
.mapToObj(i -> i)
.collect(partitioningBy(i -> i % 4 == 0, collectingAndThen(toList(), list -> list.stream()
.mapToInt(i -> i)
.toArray()
)));
This pulls 100 random integers from 1 to 100, then boxes all ints to Integers, then partitions by whether the number is dividable by 4. Then, the resulting List<Integer> is converted to an int[].
However, I think a plain old for loop is better. The only difficulty you have, is that you don't know how large each array will get. So at the end, you'll need to resize the arrays.
int[] fourMods = new int[100];
int[] nonFourMods = new int[100];
int fourModsCardinality = 0;
int nonFourModsCardinality = 0;
Random random = new Random();
for (int i = 0; i < 100; i++) {
int num = random.nextInt(100) + 1;
if (num % 4 == 0) {
fourMods[fourModsCardinality] = num;
fourModsCardinality++;
}
else {
nonFourMods[fourModsCardinality] = num;
nonFourModsCardinality++;
}
}
How to use multiple methods in a code? First it asks for the size of an array, then for the numbers of the element. One method is rounding numbers with a special rule.
Second method is a void method which modifies the array. Third method is making a new array with the modified values and returns to this array.
package tombtombbekerekit;
import java.util.Scanner;
public class TombTombbeKerekit {
public static int round(int osszeg)
{
int last_Digit = osszeg % 10;
if(last_Digit < 3)
return osszeg - last_Digit;
else if(last_Digit > 7)
return osszeg + (10 - last_Digit);
else
return osszeg - (last_Digit) + 5;
}
public static void roundSelf(int [] numbers)
{
int[] array = numbers;
for (int i = 0; i < array.length; i++)
return;
}
public static int [] roundNew(int [] numbers)
{
int [] newArray = new int[numbers.length];
return newArray;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("Kérem az összegek számát: ");
int size = sc.nextInt();
System.out.println("Kérem az összegeket: ");
int [] array = new int[size];
for (int i = 0; i < array.length; i ++)
{
array[i] = sc.nextInt();
}
int [] kerek = roundNew(array);
System.out.println("Kerekítve: ");
for (int i = 0; i < kerek.length; i++)
System.out.println(kerek[i]);
}
}
You should write your own function. Just find the rule for the rounding. You can use n%10 to get the last digit of an integer named n.
I've written something but haven't tested it, I believe it should work. Check it out:
public int weirdRounding(int n)
{
int last_Digit = n % 10;
if(last_Digit < 3)
return n - last_Digit;
else if(last_Digit > 7)
return n + (10 - last_Digit);
else // the last digit is 3,4,5,6,7
return n - (last_Digit) + 5;
}
Note: You should probably make this code more readable if you're going to use it. For example define int LOWER_BOUND = 3 and int UPPER_BOUND = 7 instead of using '3' and '7', you could also wrap the ugly expressions with functions (e.g. roundUp, roundToFive ..). #Magic_Numbers_Are_Bad
I have a function getNormalList() that must return a list with 3 random integers 0-5, not all the same. It's not working like I want it to work. Sometimes, despite the check, it outputs the same 3 numbers.
public class SpinResultGenerator {
public ArrayList<Integer> getNormalList() {
ArrayList<Integer> integerList = new ArrayList<Integer>();
Random r = new Random();
int Low = 0;
int High = 6;
for (int i = 0; i < 3; i++) {
int number = r.nextInt(High - Low) + Low;
integerList.add(number);
}
if (integerList.get(0) == integerList.get(1) && integerList.get(0) == integerList.get(2)
&& integerList.get(1) == integerList.get(2)) {
integerList.clear();
for (int i = 0; i < 3; i++) {
int number = r.nextInt(High - Low) + Low;
integerList.add(number);
}
}
return integerList;
}
public ArrayList<Integer> getJackpotList() {
ArrayList<Integer> integerList = new ArrayList<Integer>();
integerList.add(5);
integerList.add(5);
integerList.add(5);
return integerList;
}
}
If the result is, for example, [4,4,4], the for loop generates new numbers. Yet it is still able to output 3 of the same integers. Why?
You need a nested loop. Your for loop should repeat until 3 acceptable numbers are found. I used an array to make the code more compact, but the same can be done with ArrayList.
public List<Integer> getNormalList() {
Random r = new Random();
int[] arr = new int[3]; // initialized to 0s by default
int Low = 0;
int High = 6;
while (arr[0] == arr[1] && arr[1] == arr[2]) { // will repeat as long as the 3 number as
// all equal
for (int i = 0; i < arr.length; i++) {
arr[i] = r.nextInt(High - Low) + Low;
}
}
return Arrays.asList(arr);
}
Your current code fails because if it generates a list of duplicates, it just clears it and generates a new list, without checking if the new list contains duplicates. Here's my suggested alternate solution:
do {
List<Integer> result = ThreadLocalRandom.current().ints(0, 6).limit(3).boxed().collect(toList())
} while (result.get(0) == result.get(1) && result.get(0) == result.get(2))
return result;
I want to create a set of random numbers without duplicates in Java.
For example I have an array to store 10,000 random integers from 0 to 9999.
Here is what I have so far:
import java.util.Random;
public class Sort{
public static void main(String[] args){
int[] nums = new int[10000];
Random randomGenerator = new Random();
for (int i = 0; i < nums.length; ++i){
nums[i] = randomGenerator.nextInt(10000);
}
}
}
But the above code creates duplicates. How can I make sure the random numbers do not repeat?
Integer[] arr = {...};
Collections.shuffle(Arrays.asList(arr));
For example:
public static void main(String[] args) {
Integer[] arr = new Integer[1000];
for (int i = 0; i < arr.length; i++) {
arr[i] = i;
}
Collections.shuffle(Arrays.asList(arr));
System.out.println(Arrays.toString(arr));
}
A simple algorithm that gives you random numbers without duplicates can be found in the book Programming Pearls p. 127.
Attention: The resulting array contains the numbers in order! If you want them in random order, you have to shuffle the array, either with Fisher–Yates shuffle or by using a List and call Collections.shuffle().
The benefit of this algorithm is that you do not need to create an array with all the possible numbers and the runtime complexity is still linear O(n).
public static int[] sampleRandomNumbersWithoutRepetition(int start, int end, int count) {
Random rng = new Random();
int[] result = new int[count];
int cur = 0;
int remaining = end - start;
for (int i = start; i < end && count > 0; i++) {
double probability = rng.nextDouble();
if (probability < ((double) count) / (double) remaining) {
count--;
result[cur++] = i;
}
remaining--;
}
return result;
}
In Java 8, if you want to have a list of non-repeating N random integers in range (a, b), where b is exclusive, you can use something like this:
Random random = new Random();
List<Integer> randomNumbers = random.ints(a, b).distinct().limit(N).boxed().collect(Collectors.toList());
Achintya Jha has the right idea here. Instead of thinking about how to remove duplicates, you remove the ability for duplicates to be created in the first place.
If you want to stick with an array of ints and want to randomize their order (manually, which is quite simple) follow these steps.
create array of size n.
loop through and initialize each value at index i to the value i (or i+1 if you wish to have the numbers 1 to n rather than 0 to n-1).
finally, loop through the array again swapping each value for a value at a random index.
Your code could be modified to look like this:
import java.util.Random;
public class Sort
{
// use a constant rather than having the "magic number" 10000 scattered about
public static final int N = 10000;
public static void main(String[] args)
{
//array to store N random integers (0 - N-1)
int[] nums = new int[N];
// initialize each value at index i to the value i
for (int i = 0; i < nums.length; ++i)
{
nums[i] = i;
}
Random randomGenerator = new Random();
int randomIndex; // the randomly selected index each time through the loop
int randomValue; // the value at nums[randomIndex] each time through the loop
// randomize order of values
for(int i = 0; i < nums.length; ++i)
{
// select a random index
randomIndex = randomGenerator.nextInt(nums.length);
// swap values
randomValue = nums[randomIndex];
nums[randomIndex] = nums[i];
nums[i] = randomValue;
}
}
}
And if I were you I would likely break each of these blocks into separate, smaller methods rather than having one large main method.
Hope this helps.
If you need generate numbers with intervals, it can be just like that:
Integer[] arr = new Integer[((int) (Math.random() * (16 - 30) + 30))];
for (int i = 0; i < arr.length; i++) {
arr[i] = i;
}
Collections.shuffle(Arrays.asList(arr));
System.out.println(Arrays.toString(arr));`
The result:
[1, 10, 2, 4, 9, 8, 7, 13, 18, 17, 5, 21, 12, 16, 23, 20, 6, 0, 22, 14, 24, 15, 3, 11, 19]
Note:
If you need that the zero does not leave you could put an "if"
How about this?
LinkedHashSet<Integer> test = new LinkedHashSet<Integer>();
Random random = new Random();
do{
test.add(random.nextInt(1000) + 1);
}while(test.size() != 1000);
The user can then iterate through the Set using a for loop.
public class RandomNum {
public static void main(String[] args) {
Random rn = new Random();
HashSet<Integer> hSet = new HashSet<>();
while(hSet.size() != 1000) {
hSet.add(rn.nextInt(1000));
}
System.out.println(hSet);
}
}
If you're using JAVA 8 or more than use stream functionality following way,
Stream.generate(() -> (new Random()).nextInt(10000)).distinct().limit(10000);
Here we Go!
public static int getRandomInt(int lower, int upper) {
if(lower > upper) return 0;
if(lower == upper) return lower;
int difference = upper - lower;
int start = getRandomInt();
//nonneg int in the range 0..difference - 1
start = Math.abs(start) % (difference+1);
start += lower;
return start;
}
public static void main(String[] args){
List<Integer> a= new ArrayList();
int i;
int c=0;
for(;;) {
c++;
i= getRandomInt(100, 500000);
if(!(a.contains(i))) {
a.add(i);
if (c == 10000) break;
System.out.println(i);
}
}
for(int rand : a) {
System.out.println(rand);
}
}
Get Random number Returns a random integer x satisfying lower <= x <= upper. If lower > upper, returns 0. #param lower #param upper #return
In the main method I created list then i check if the random number exist on the list if it doesn't exist i will add the random number to the list
It is very slow but straight forward.
A simple stream solution:
new Random().ints(0, 10000)
.distinct()
.limit(10000)
.forEach(System.out::println);
public class Randoms {
static int z, a = 1111, b = 9999, r;
public static void main(String ... args[])
{
rand();
}
public static void rand() {
Random ran = new Random();
for (int i = 1; i == 1; i++) {
z = ran.nextInt(b - a + 1) + a;
System.out.println(z);
randcheck();
}
}
private static void randcheck() {
for (int i = 3; i >= 0; i--) {
if (z != 0) {
r = z % 10;
arr[i] = r;
z = z / 10;
}
}
for (int i = 0; i <= 3; i++) {
for (int j = i + 1; j <= 3; j++) {
if (arr[i] == arr[j]) {
rand();
}
}
}
}
}
HashSet<Integer>hashSet=new HashSet<>();
Random random = new Random();
//now add random number to this set
while(true)
{
hashSet.add(random.nextInt(1000));
if(hashSet.size()==1000)
break;
}