Java: Sorting an array from least to greatest - java

This is my first question on the site. I am in a CS class and part of one of my assignments involved sorting the scores column of an array from least to greatest and printing out the array in its new least-to-greatest form. I cannot seem to get the scores from the array to do so, for whatever reason, and I am very confused as to why it will not work. If any of you could help me, that would be awesome. Thanks! Here is the array I am working with. The two columns are the id (on the left) and the score (on the right):
365 265
222 223
306 262
003 559
004 560
203 224
113 243
208 242
213 229
115 257
302 242
223 230
001 599
311 256
323 245
321 245
123 253
104 239
002 513
112 239
207 228
325 246
116 246
218 243
110 238
And here is my code so far:
import java.io.*;
import java.util.*;
public class RankingTestScoresDriver
{
public static void main(String args[])
{
System.out.println("ID Score");
File file = new File("prog408a.dat");
int[] id = new int[24];
int[] score = new int[24];
try
{
Scanner kbReader = new Scanner(file);
while (kbReader.hasNextInt())
{
for (int i = 0; i < 25; i++)
{
id[i] = kbReader.nextInt();
score[i] = kbReader.nextInt();
}
}
}
catch (Exception e)
{
}
//From here down is the part which is giving me trouble.
int max;
max = score[0];
int index;
int maxScoreIndex = 0;
for (int k = 0; k < 25; k++)
{
for (index = 0; index < score.length; index++)
{
if (score[index] > max)
{
max = score[index];
maxScoreIndex = index;
}
}
System.out.println(maxScoreIndex + " " + max);
score[maxScoreIndex] = ((-1)*(max));
}
}
}
Currently it is producing this as the output:
ID Score
12 599
12 599
12 599
12 599
12 599
12 599
12 599
12 599
12 599
12 599
12 599
12 599
12 599
12 599
12 599
12 599
12 599
12 599
12 599
12 599
12 599
12 599
12 599
12 599
12 599
The final output should be the scores of the array but in least-to-greatest order.
Any help would be greatly appreciated in helping me fix the bit of code I am struggling on.

You can write a class that implements Comparable to do it simple.
class Score implements Comparable<Score> {
private int id, score;
Score(int id, int score) {
this.id = id;
this.score = score;
}
#override
public int compareTo(Score o) {
return score - o.score;
}
}
then after you create an array of Score, you can use sort() method.
Score[] scores = /* put data */
Arrays.sort(scores);
will work

In the section where you are trying to sort, I'd recommend calling Arrays.sort() on your array like this:
Arrays.sort(score);
Once you have the array sorted, print out each element from the beginning using a loop of some kind:
for(int i = 0; i < 25; i++)
{
System.out.println(i + " " + score[i]);
}
That should do the trick for you. If you don't need a fancy new sorting algorithm, just use one that's already coded for you :)

You need to sort the array. Right now your code doesn't do it, it just keeps track of the biggest value.
I'm assuming you don't have to worry about execution time here. In other words, if the algorithm is going to take a long time to execute for a large input it doesn't matter to your professor.
There are many ways to sort an array. One way to do it called Bubble Sort. It is not very effective but will do the trick for you, and it's probably what your professor wants for now.
The idea is pretty simple: you discover the lowest value you hold on the entire array and swap the value with your current position. Imagine you have the following array:
[2, 4, 3, 5, 1]
Your current index is 0. You're going to go through the entire array to find the lowest value of them all. You will find out that the index 4, that holds the value 1 contains the lowest value. So you swap your current index (index 0, value 2). Now the array looks like this:
[1, 4, 3, 5, 2]
Now you move on to the next index, which is 1. You don't need to look at index 0 anymore since you already found out he is the lowest value and now you want the second lowest value. You do the same thing you did before: find the lowest value from index 1 to index 4 and swap them. You're going to do it until you get to the last index, where, you can guess by now, it will always be the biggest value.
Start by making sure you get the first value right. Once you get it, then move to the loop that iterates through the other values.

Working code : sort a two-dimensional array on column values in java.
Here we are using overloaded sort method in java.util.Arrays class which takes two arguments : the array to sort and a java.util.Comparator object.
import java.util.Arrays;
import java.util.Comparator;
public class SortArray {
Integer array[][] = { { 365, 265 }, { 222, 223 }, { 306, 262 },
{ 003, 559 }, { 004, 560 }, { 203, 224 }, { 113, 243 },
{ 208, 242 }, { 213, 229 }, { 115, 257 }, { 302, 242 },
{ 223, 230 }, { 001, 599 }, { 311, 256 }, { 323, 245 },
{ 321, 245 }, { 123, 253 }, { 104, 239 }, { 002, 513 },
{ 112, 239 }, { 207, 228 }, { 325, 246 }, { 116, 246 },
{ 218, 243 }, { 110, 238 } };
SortArray() {
System.out.println("Before sorting");
// show the contents of array
displayArray();
// sort array on score(second column)
Arrays.sort(array, new Comparator<Integer[]>() {
#Override
public int compare(Integer[] o1, Integer[] o2) {
Integer v1 = o1[1];
Integer v2 = o2[1];
// reverse sort on quantity
return v1.compareTo(v2);
}
});
// display array after sort
System.out.println("After sorting on score in ascending order");
displayArray();
}
public void displayArray() {
System.out.println("-------------------------------------");
System.out.println(" Index \t\t score");
for (int i = 0; i < array.length; i++) {
Integer[] sorted = array[i];
System.out.println(sorted[0] + "\t\t" + sorted[1]);
}
System.out.println("-------------------------------------");
}
public static void main(String[] args) {
new SortArray();
}
}
Explanation
A two dimensional array named array is created and initialized with default values.
First column of the array consists of Index values and second column is its Score.
For sorting the array, sort method of java.util.Arrays is used which takes 2 arguments : the array to be sorted and a java.util.Comparator object.
We pass an anonymous Comparator object(anonymous object means an object which has no name and which is created at its place of use only).
As 2d array in java is an array of arrays, thus, for sorting a 2d array on a column, we have to sort an integer array, therefore the generic type of this Comparator object should be Integer[ ].
Inside Comparator object, we implement its compare method which takes two objects of Integer[ ] type. These Integer objects represent the arrays to be compared.
For sorting the array on second column(score), the values at index 1 of the Integer[ ] objects are retrieved and compared.
Also read about Comparators and sort()
public static <T> void sort(T[] a,
Comparator<? super T> c)
Sorts the specified array of objects according to the order induced by the specified comparator. All elements in the array must be mutually comparable by the specified comparator (that is, c.compare(e1, e2) must not throw a ClassCastException for any elements e1 and e2 in the array).
This sort is guaranteed to be stable: equal elements will not be reordered as a result of the sort.
Implementation note: This implementation is a stable, adaptive, iterative mergesort that requires far fewer than n lg(n) comparisons when the input array is partially sorted, while offering the performance of a traditional mergesort when the input array is randomly ordered. If the input array is nearly sorted, the implementation requires approximately n comparisons. Temporary storage requirements vary from a small constant for nearly sorted input arrays to n/2 object references for randomly ordered input arrays.
The implementation takes equal advantage of ascending and descending order in its input array, and can take advantage of ascending and descending order in different parts of the the same input array. It is well-suited to merging two or more sorted arrays: simply concatenate the arrays and sort the resulting array.
The implementation was adapted from Tim Peters's list sort for Python ( TimSort). It uses techiques from Peter McIlroy's "Optimistic Sorting and Information Theoretic Complexity", in Proceedings of the Fourth Annual ACM-SIAM Symposium on Discrete Algorithms, pp 467-474, January 1993.
Parameters:
a - the array to be sorted
c - the comparator to determine the order of the array. A null value indicates that the elements' natural ordering should be used.

Related

How to get the top M values from a Map?

So I am writing this program, which calculates different things about the Collatz-conjucture.
So basically for a number I calculate a cycle and its length, like this:
For 8: [8, 4, 2, 1]
Length: 4
Now I want to calculate until 1000.
And for every number the length of the cycle is different.
So for example the length of the cycle for number 43 can be bigger than that for 45.
And I want to get the biggest lengths in ascending order.
Like this:
Number 1 2 3 6 7 9 1825 27 54 73 97 129 171 231 313 327 649 703 871
Length(N) 0 1 7 8 16 19 20 23 111 112 115 118 121 124 127 130 143 144 170 178
I put the numbers in HashMap with the numbers as keys and the lengths as values.
Now I have no clue how to get the biggest lengths in ascending order.
Is there a function that helps me with that?
Do I have to use a loop and more lists?
The Collections.Max is of no help, because it gets only one value, but I need more than one.
You should use any sorting algorithm, (like merge) and then pick the amount you'd like to get from the sorted map.
This amounts to essentially sorting a list composed of the map's values.
Returns the top m values of your Map, ascending:
public static List<Integer> topMValuesAscending(Map<?, Integer> map, int m){
final List<Integer> values = new ArrayList<Integer>(map.values());
Collections.sort(values);
final int valuesCount = values.size();
return values.subList(valuesCount - m, valuesCount);
}
I believe this is optimal, and is O[s*Log(s)] log-linear, where s is the size of the map.

how to create a Java List of two integers

Hello I am new to java and I am trying to create a list like
List<Int, Int> list = new List<Int, Int>();
the first int is the value and the second int is the finished time. I want to be able to read from a file and save in my list, So can I later get the finished time or value list in a sorted way. I am going to ue these two list together so when the first one is sorted the second one also needs to be sorted accordingly.
If I use HashMap I cant add duplicate values, can someone help me please?
I tried with TreeMap but it also didnt work.
You should create a class to wrap your values. Something like:
public class IntPair {
public int value;
public int time;
}
should do. You can then add a constructor, a compare method for sorting, and whatever other functionality you need.
Create the list as follows:
List<IntPair> list = new ArrayList<>();
Using java inbuilt Pair class. ArrayList or any List of pairs can be constructed. you need to import javafx.util.pair for that. Similarly for 3 values. Use java's Triplet class.
eg: Pair p=new Pair(1, 2);
ArrayList or any List of these pairs can be constructed easily now
The 'lazy' way you could create an ArrayList<Integer[]> at each index you add an array of 2 places holding the value and the time ex new Integer[]{val,time} and then you can sort the arraylist using the Collection.sort and with the help of a Comparator
Here is a small example :
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Random;
public class Test {
public static void main(String[] args) {
ArrayList<Integer[]> values = new ArrayList<>();
Random rand = new Random();
// just for testing I add random values but you
// should add your values you read from your file
for (int i = 0; i < 10; i++) {
values.add(new Integer[] { rand.nextInt(100), rand.nextInt(100) });
System.out.println(values.get(i)[0] + "\t" + values.get(i)[1]);
}
// Let's sort our ArrayList looking at the first index of each array
// which holds the value
Collections.sort(values, new Comparator<Integer[]>() {
public int compare(Integer[] array1, Integer[] array2) {
return array1[0].compareTo(array2[0]);
}
});
// Print the results
System.out.println();
System.out.println();
for (int i = 0; i < 10; i++) {
System.out.println(values.get(i)[0] + "\t" + values.get(i)[1]);
}
}
}
Output :
82 21
3 54
60 73
14 35
45 30
16 30
8 19
62 43
67 51
7 34
3 54
7 34
8 19
14 35
16 30
45 30
60 73
62 43
67 51
82 21

Using string vs byte[] as value, Memory usage in map

I read it in multiple places that using byte[] instead of string would save you memory. I wanted to test it out using jol.
Here my test:
public static void main (String[] args) throws java.lang.Exception{
System.out.println(VMSupport.vmDetails());
String StrByte = GraphLayout.parseInstance(sizeOfStrByteMap(100000)).toFootprint();
String ByteByte = GraphLayout.parseInstance(sizeOfByteByteMap(100000)).toFootprint();
String StrStr = GraphLayout.parseInstance(sizeOfStrStrMap(100000)).toFootprint();
System.out.println(StrByte);
System.out.println(ByteByte);
System.out.println(StrStr);
}
public static HashMap<String, String> sizeOfStrStrMap(int size) {
String value = "this is the sample value";
HashMap<String, String> map = new HashMap<>();
for (int i = 0; i < size; i++) {
map.putIfAbsent(Integer.toString(i), value);
}
return map;
}
public static HashMap<String, byte[]> sizeOfStrByteMap(int size) {
byte[] value = "this is the sample value".getBytes();
HashMap<String, byte[]> map = new HashMap<>();
for (int i = 0; i < size; i++) {
map.putIfAbsent(Integer.toString(i), value);
}
return map;
}
public static HashMap<byte[], byte[]> sizeOfByteByteMap(int size) {
byte[] value = "this is the sample value".getBytes();
HashMap<byte[], byte[]> map = new HashMap<>();
for (int i = 0; i < size; i++) {
map.putIfAbsent(Integer.toString(i).getBytes(), value);
}
return map;
}
Here is my result:
Running 64-bit HotSpot VM.
Using compressed oop with 3-bit shift.
Using compressed klass with 3-bit shift.
Objects are 8 bytes aligned.
Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
// StrByteMap
java.util.HashMap#15327b79d footprint:
COUNT AVG SUM DESCRIPTION
1 184 184 [B
100000 31 3120000 [C
1 1048592 1048592 [Ljava.util.HashMap$Node;
100000 24 2400000 java.lang.String
1 48 48 java.util.HashMap
100000 32 3200000 java.util.HashMap$Node
300003 9768824 (total)
// ByteByteMap
java.util.HashMap#a9d12ad footprint:
COUNT AVG SUM DESCRIPTION
100001 24 2400184 [B
1 1048592 1048592 [Ljava.util.HashMap$Node;
1 48 48 java.util.HashMap
100000 32 3200000 java.util.HashMap$Node
200003 6648824 (total)
// StrStrMap
java.util.HashMap#716d90fad footprint:
COUNT AVG SUM DESCRIPTION
100001 31 3120344 [C
1 1048592 1048592 [Ljava.util.HashMap$Node;
100001 24 2400024 java.lang.String
1 48 48 java.util.HashMap
100000 32 3200000 java.util.HashMap$Node
300004 9769008 (total)
As you can see, memory usage between StrByteMap and StrStrMap is almost identical. Am I testing it wrong here?
UPDATE:
Please see #Amod Pandey's question below, I would also like to know why.
For Map test you are putting in the same value reference so it is not going to use much space. In the same way that you have a different key you need to make the values different or as you see, the choice of value type doesn't make much difference.
I find it strange.
// StrByteMap
java.util.HashMap#15327b79d footprint:
COUNT AVG SUM DESCRIPTION
1 184 184 [B
100000 31 3120000 [C
There is one instance of byte arrary and 100000 instances of char array. Which is 100001 char array in the StrStr case
// StrStrMap
java.util.HashMap#716d90fad footprint:
COUNT AVG SUM DESCRIPTION
100001 31 3120344 [C
So even if you have stored byte array the memory footprint is of char array!!
Another point is for ByteByte the the Avg size of byte array object is 24 which is less than byte array size of 184 (StrByteMap) and shouldn't the total count in all three cases be the same.

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.

Generating n-digit numbers sequenced by sum of individual digits (without recursion)

I'm looking to generate all possible values of n-digit number, in the following order, where the sequence is dictated by the sum of the individual digits.
For example, with n = 3:
111 sum = 3
112 sum = 4
121
211
122 sum = 5
212
221
113
131
311
114 sum = 6
141
411
:::
999 sum = 27
The order within the sum group is not important.
Any help, ideas would be appreciated
You can always turn a recursive problem into an iterative one if you maintain your own stack of important data - that's if the reason for avoiding recursion is that the language doesn't support it.
But, if the language does support it, then recursive solutions are far more elegant.
The only other reason I can think of for avoiding recursion is limited stack depth. In that case an iterative conversion of a recursive solution will mitigate the problem by not requiring as much stack space.
But you need to understand that the stack depth for processing n numbers only grows relative to log10n. In other words, you only get an extra stack frame per digit (only 10 stack frames to handle the full range of 32-bit integers).
Aside: by the time you get to that point, you're algorithm will be taking so long to run, stack frames will be the least of your problems :-)
Here's a recursive Python solution:
def recur (numdigits,sum,pref="",prefsum=0):
if numdigits == 0:
if prefsum == sum:
print "%s, sum=%d"%(pref,prefsum)
else:
for i in range (1,10):
recur (numdigits-1,sum,"%s%d"%(pref,i),prefsum+i)
def do (n):
for i in range (1,n*9+1):
recur (n,i)
do (2)
do (3)
which outputs (for 2 and 3):
11, sum=2 111, sum=3
12, sum=3 112, sum=4
21, sum=3 121, sum=4
13, sum=4 211, sum=4
22, sum=4 113, sum=5
31, sum=4 122, sum=5
14, sum=5 131, sum=5
23, sum=5 212, sum=5
32, sum=5 221, sum=5
41, sum=5 311, sum=5
15, sum=6 114, sum=6
: : : :
89, sum=17 989, sum=26
98, sum=17 998, sum=26
99, sum=18 999, sum=27
Keep in mind that solution could still be optimized somewhat - I left it in its initial form to show how elegant recursion can be. A pure-iterative solution follows, but I still prefer the recursive one.
Run the following program and use sort and awk under UNIX to get the desired order. For example:
go | sort | awk '{print $2}'
Note that this uses external tools to do the sorting but you could just as easily sort within the C code (memory permitting).
#include <stdio.h>
int main (void) {
int i, sum, carry, size;
int *pDigit;
// Choose your desired size.
size = 2;
// Allocate and initialise digits.
if ((pDigit = malloc (size * sizeof (int))) == NULL) {
fprintf (stderr, "No memory\n");
return 1;
)
for (i = 0; i < size; i++)
pDigit[i] = 1;
// Loop until overflow.
carry = 0;
while (carry != 1) {
// Work out sum, then output it with number.
// Line is sssssssssssssssssss ddddd
// where sss...sss is the fixed-width sum, zero padded on left (for sort)
// and ddd...ddd is the actual number.
sum = 0;
for (i = 0; i < size; i++)
sum += pDigit[i];
printf ("%020d ", sum);
for (i = 0; i < size; i++)
printf ("%d", pDigit[i]);
printf ("\n");
// Advance to next number.
carry = 1;
for (i = 0; i < size; i++) {
pDigit[size-i-1] = pDigit[size-i-1] + carry;
if (pDigit[size-i-1] == 10)
pDigit[size-i-1] = 1;
else
carry = 0;
}
}
return 0;
}
Can you use std::next_permutation?
The next_permutation() function
attempts to transform the given range
of elements [start,end) into the next
lexicographically greater permutation
of elements. If it succeeds, it
returns true, otherwise, it returns
false.
If a strict weak ordering function
object cmp is provided, it is used in
lieu of the < operator when comparing
elements.
See this: previous SO answer
If it doesn't matter what pattern you use so long as there is a pattern (it's not entirely clear from your post whether you have a specific pattern in mind) then for n=3, start with 111 and increment until you reach 999.
By the way, the term for what you're asking for isn't exactly "permutations".
You can try to reduce your problem to two buckets:
Two bucket splits are simple: Start with all minus one in bucket A and one in bucket B, then put one from A into B until A contains only one.
Three bucket splits are then just: Start with all minus two in bucket A and one each in B and C. Reduce A by one and collect all two bucket splits of three in B and C, repeat until A contains only one.

Categories