Is there a space efficient implementation of mergesort? - java

I just coded up this working version of mergesort:
static int[] merge(int[] first, int[] second){
int totalsize = first.length + second.length;
int[] merged_array = new int[totalsize];
int i = 0, firstpointer = 0, secondpointer = 0;
while(i < totalsize){
if(firstpointer == first.length){
merged_array[i] = second[secondpointer];
++secondpointer;
}
else if(secondpointer == second.length){
merged_array[i] = first[firstpointer];
++firstpointer;
}
else if(first[firstpointer] < second[secondpointer]){
merged_array[i] = first[firstpointer];
++firstpointer;
}
else{
merged_array[i] = second[secondpointer];
++secondpointer;
}
++i;
}
return merged_array;
}
static int[] mergesort(int[] array){
if(array.length == 1){
return array;
}
else{
int length = array.length;
int[] first = Arrays.copyOfRange(array, 0, (int) length / 2);
int[] second = Arrays.copyOfRange(array, (int) length / 2, length);
return merge(mergesort(first), mergesort(second));
}
}
However, if you notice, I use the copyOfRange function which creates a new array that is a copy of a certain portion of the parent array. Is there a mergesort implementation in java that is more space efficient than this?

Duplicate of: How to sort in-place using the merge sort algorithm?
Summary: Yes, there are memory-efficient merge-sorts, but they are either a) very complicated, or b) not time-efficient: O(n^2 log n)
Basically, don't bother. It's not actually that much memory that you're saving, and if you really want to, just use quicksort instead.

Related

Sorting ArrayList of bytes array

I have some code in python which does the following:
for day in server_message.keys():
for epoch in server_message[day].keys():
assert sorted(server_message[day][epoch]) == server_message[day][epoch]
I need to write that code in Java. The problem is that the structure of server_message is as such:
Map<Integer, Map<Integer, ArrayList<byte[]>>>
How can sort ArrayList of bytes? Both Arrays.sort() and Collections.sort() don't return a new sorted array instead the work on the provided array.
Is there anything in Java that I can do to solve this problem, or do I need to write my own sorting algorithm for this kind of sort? How can I compare two bytes array?
Array.sort() uses quick algorithm at back-end and I'm surprised to see why Array.sout() is not working but you can use quick sort for this.
public class QuickSort {
public static void main(String[] args) {
int i;
int[] arr={90,23,101,45,65,23,67,89,34,23};
quickSort(arr, 0, 9);
System.out.println("\n The sorted array is: \n");
for(i=0;i<10;i++)
System.out.println(arr[i]);
}
public static int partition(int a[], int beg, int end)
{
int left, right, temp, loc, flag;
loc = left = beg;
right = end;
flag = 0;
while(flag != 1)
{
while((a[loc] <= a[right]) && (loc!=right))
right--;
if(loc==right)
flag =1;
elseif(a[loc]>a[right])
{
temp = a[loc];
a[loc] = a[right];
a[right] = temp;
loc = right;
}
if(flag!=1)
{
while((a[loc] >= a[left]) && (loc!=left))
left++;
if(loc==left)
flag =1;
elseif(a[loc] <a[left])
{
temp = a[loc];
a[loc] = a[left];
a[left] = temp;
loc = left;
}
}
}
returnloc;
}
static void quickSort(int a[], int beg, int end)
{
int loc;
if(beg<end)
{
loc = partition(a, beg, end);
quickSort(a, beg, loc-1);
quickSort(a, loc+1, end);
}
}
}
I think your problem is to sort an array of bytes (byte[]) and not a list of arrays of bytes (List<byte[]>) which doesn't make any sense.
If you want to get a sorted array of bytes without modifying the existing one you can clone the original array before :
byte[] bytes = {0, 23, 127, -12 };
byte[] clone = bytes.clone();
Arrays.sort(clone);

Java method to recursively add each integer in an array to all of the elements following it?

For example if I have an array of ints as a parameter to my method, my method needs to return an array of ints where each element is the sum of all the elements following it.
Example:
parameter is [5, 6, 7, 2, 3, 1] I need to return [24, 19, 13, 6, 4, 1]
I have a written a helper method that correctly adds an index to all of the ones after it here:
public static int sum(int[] array, int index) {
if (index == array.length) {
return array[array.length-1];
} else {
return array[index] + sum(array, index + 1);
}
}
This all works as it should, but I'm having trouble with the original method here:
public int[] reverseCumulative(int[] numbers) {
int[] temp = new int[numbers.length];
if (numbers.length == 0) {
return temp;
}
else {
temp[numbers.length-1] = sum(numbers, numbers.length);
numbers = Arrays.copyOf(numbers, numbers.length - 1);
reverseCumulative(numbers);
return temp;
}
}
The output here is [0, 0, 0, 0 , 0, 1]. I understand that this is most likely due to the fact I'm creating a new int[] temp every time I call the reverseCumulative method within itself, but I am completely lost and any push in the right direction would be appreciated.
Edit: Forgot to add, I am not allowed to use any loops.
Since you are creating a new array each time you call the reverseCumulative method, you should use the sum method as a helper method inside the reverseCumulative method so that you are still using recursion. For example,
public int[] reverseCumulative(int[] numbers) {
int[] temp = new int[numbers.length];
if (numbers.length == 0) {
return temp;
}
else {
for(int i = 0; i < numbers.length; i++){
temp[i] = sum(numbers,i);
}
return temp;
}
}
This way, each element in temp equals a sum of integers in the numbers array depending on which iteration it is currently on. In the first iteration, temp[0] = the sum of all the ints in numbers. In the second iteration, temp[1] = the sum of all the ints in numbers except the first int and so on. However, the way the sum method is written right now, it adds the last element twice so here's a simple fix,
public static int sum(int[] array, int index) {
if (index == array.length-1) {
return array[array.length-1];
} else {
return array[index] + sum(array, index + 1);
}
}
Maybe something like this?
public static int sum(final int[] target, final int[] source, int index) {
if (index >= source.length - 1)
return source[index];
return target[index] = source[index] + sum(target, source, index + 1);
}
public static int[] reverseCulmulative(final int[] array) {
final int[] target = array.clone();
sum(target, array, 0);
return target;
}

Finding the K-th largest element in an array using a tournament tree

Below, I have designed a function tournamentTreeKSelection which simulates a tree like structure using arrays and returns the largest element in the array. For example, given an input array [10,9,8,7,6,5,4,3,2,1] the following steps are performed to return 10.
[10, 8, 6, 4, 2, -1]
[10, 6, 2, -1]
[10, 2]
[10] //Max element of array found
My goal is to now add a second parameter int k requesting that the function return the k-th largest element such that tournamentTreeKSelection(data, 2) returns 9.
I'm having a lot of difficulty in modifying my algorithm to perform this task because my assumption is that i'm going to have to keep track of all elements that the max element beats ? Any help is appreciated.
import java.util.ArrayList;
import java.util.Arrays;
public class TournamentTree {
public static int tournamentTreeKSelection(int[] data, int k) {
ArrayList<Integer> list = new ArrayList<>();
ArrayList<Integer> list2 = new ArrayList<>();
for(int i = 0; i < data.length - 1; i += 2) {
list.add(max(data[i] , data[i + 1]));
}
for(int i = 0; i < data.length - 1; i++) {
list2.add(min(data[i], data[i + 1]));
}
if(list.size() == 1) return list.get(0);
if(list.size() % 2 != 0) list.add(-1);
if(k == 1) return tournamentTreeKSelection(listToArray(list),k);
else return tournamentTreeKSelection(listToArray(list2), --k);
}
public static int max(int a, int b) {
return a > b ? a : b;
}
public static int min(int a, int b) {
return a > b ? b : a;
}
public static int[] listToArray(ArrayList<Integer> arr) {
int[] arr2 = new int[arr.size()];
for(int i = 0; i < arr.size(); i++)
arr2[i] = arr.get(i);
return arr2;
}
}
I have now modified the code but it only works for k = 1 - 8, why does it break down ? tournamentTreeKSelection(data, 9) and tournamentTreeKSelection(data, 10) return 3 when they should be returning 2 and 1 respectively.
First of all, why your code is wrong:
When the size of the list is 2 or 3, your statement list.size() == 1 will be true even if K > 1.
Why do you do min(data[i], data[i + 1]), I have a feeling you just want to remove the maximum element but what with the case
[10,1,9,2,8,3,7,4,6,5], gives after 1 iteration [1,1,2,2,3,3,4,4,5] removing possible outcomes 9, 8, 7 and 6.
Some tips
Don't do useless computations. You are calculating the two lists, while you know in front you are only going to use one of them.
Use builtin methods whenever possible, see Math.max, Math.min
Note that you know the size of the resulting array in front. There is no need to create an ArrayList which causes a lot of overhead for you. Just create an array of the resulting size. For k==1, ((data.length+1)/2) else data.length-1
Still wondering
You say your tournament tree structure is a requirement, but you are looping over it in your code as it is an array. Why? You could determine the max value from the moment K==1 in 1 loop, instead of taking half of the maxes and doing it over and over again.
Alternative approach
As already suggested the sorting approach, or the quick find methods can be used. I was thinking how you could still use your tournament tree approach. And the best I came up with is how merge sort works. I slightly edited because you only need max K elements to return.
public static int find(int[] a, int k) {
int[] max = find(a, 0, a.length - 1, k);
return max[k-1];
}
private static int[] find(int[] a, int lo, int hi, int k) {
if (hi < lo){
return new int[]{};
}
if(lo == hi){
return new int[]{a[lo]};
}
int mid = lo + (hi - lo) / 2;
int[] left = find(a, lo, mid, k);
int[] right = find(a, mid + 1, hi, k);
return merge(left, right, k);
}
private static int[] merge(int[] left, int[] right, int k) {
int[] res = new int[Math.min(k, left.length+right.length)];
int l = 0, r = 0;
for (int i = 0; i<res.length;i++) {
if (l == left.length)
res[i] = right[r++];
else if (r == right.length)
res[i] = left[l++];
else if (left[l] > right[r])
res[i] = left[l++];
else
res[i] = right[r++];
}
return res;
}

Finding Max of an array using Recursion

So it's pretty simple to find the max of an array using a for loop or a while loop, but I wanted to try it out with recursion. For some reason, the substring doesn't work - it says "cannot find symbol". Why is this? My strategy is continue subdividing and comparing the two sides until there is only one left which should be the max....am I doing it right? Thanks
public static int max(int[] array) {
if (array.length == 1) {
return array[0];
} else {
int mid = (array.length) / 2;
int leftmax = max(array.substring(0, mid));
int rightmax = max(array.substring(mid, array.length));
if (leftmax > rightmax) {
return leftmax;
} else {
return rightmax;
}
}
}
You are going to want to use Arrays.copyOfRange. Substring isn't going to work on an array.
int[] firstHalf = Arrays.copyOfRange(original, 0, original.length/2);
int[] secondHalf = Arrays.copyOfRange(original, original.length/2, original.length);
I can't comment on your algorithm.
Since array is of type int[] not String, you cannot use substring(). Instead, keep track of which indexes you are searching through. Copying the array each iteration is a waste of both space and time.
int max( int[] array ){ return max( array, 0, array.length - 1 ); }
int max( int[] array, int low, int high )
{
if (low == high) {
return array[low];
}
else {
int mid = (high + low) / 2;
int leftmax = max(array, low, mid );
int rightmax = max(array, mid, high );
if (leftmax > rightmax) {
return leftmax;
}
else {
return rightmax;
}
}
}

How to sort an array of ints using a custom comparator?

I need to sort an array of ints using a custom comparator, but Java's library doesn't provide a sort function for ints with comparators (comparators can be used only with objects). Is there any easy way to do this?
If you can't change the type of your input array the following will work:
final int[] data = new int[] { 5, 4, 2, 1, 3 };
final Integer[] sorted = ArrayUtils.toObject(data);
Arrays.sort(sorted, new Comparator<Integer>() {
public int compare(Integer o1, Integer o2) {
// Intentional: Reverse order for this demo
return o2.compareTo(o1);
}
});
System.arraycopy(ArrayUtils.toPrimitive(sorted), 0, data, 0, sorted.length);
This uses ArrayUtils from the commons-lang project to easily convert between int[] and Integer[], creates a copy of the array, does the sort, and then copies the sorted data over the original.
How about using streams (Java 8)?
int[] ia = {99, 11, 7, 21, 4, 2};
ia = Arrays.stream(ia).
boxed().
sorted((a, b) -> b.compareTo(a)). // sort descending
mapToInt(i -> i).
toArray();
Or in-place:
int[] ia = {99, 11, 7, 21, 4, 2};
System.arraycopy(
Arrays.stream(ia).
boxed().
sorted((a, b) -> b.compareTo(a)). // sort descending
mapToInt(i -> i).
toArray(),
0,
ia,
0,
ia.length
);
You can use IntArrays.quickSort(array, comparator) from fastutil library.
If you don't want to copy the array (say it is very large), you might want to create a wrapper List<Integer> that can be used in a sort:
final int[] elements = {1, 2, 3, 4};
List<Integer> wrapper = new AbstractList<Integer>() {
#Override
public Integer get(int index) {
return elements[index];
}
#Override
public int size() {
return elements.length;
}
#Override
public Integer set(int index, Integer element) {
int v = elements[index];
elements[index] = element;
return v;
}
};
And now you can do a sort on this wrapper List using a custom comparator.
You don't need external library:
Integer[] input = Arrays.stream(arr).boxed().toArray(Integer[]::new);
Arrays.sort(input, (a, b) -> b - a); // reverse order
return Arrays.stream(input).mapToInt(Integer::intValue).toArray();
By transforming your int array into an Integer one and then using public static <T> void Arrays.sort(T[] a,
Comparator<? super T> c) (the first step is only needed as I fear autoboxing may bot work on arrays).
java 8:
Arrays.stream(new int[]{10,4,5,6,1,2,3,7,9,8}).boxed().sorted((e1,e2)-> e2-e1).collect(Collectors.toList());
If you are interested with performance and reducing number of object created on the way consider using implementation from eclipse collections.
It uses custom IntComparator, which operates on primitives thus no boxing is required.
Here is some code (it's actually not Timsort as I originally thought, but it does work well) that does the trick without any boxing/unboxing. In my tests, it works 3-4 times faster than using Collections.sort with a List wrapper around the array.
// This code has been contributed by 29AjayKumar
// from: https://www.geeksforgeeks.org/sort/
static final int sortIntArrayWithComparator_RUN = 32;
// this function sorts array from left index to
// to right index which is of size atmost RUN
static void sortIntArrayWithComparator_insertionSort(int[] arr, IntComparator comparator, int left, int right) {
for (int i = left + 1; i <= right; i++)
{
int temp = arr[i];
int j = i - 1;
while (j >= left && comparator.compare(arr[j], temp) > 0)
{
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = temp;
}
}
// merge function merges the sorted runs
static void sortIntArrayWithComparator_merge(int[] arr, IntComparator comparator, int l, int m, int r) {
// original array is broken in two parts
// left and right array
int len1 = m - l + 1, len2 = r - m;
int[] left = new int[len1];
int[] right = new int[len2];
for (int x = 0; x < len1; x++)
{
left[x] = arr[l + x];
}
for (int x = 0; x < len2; x++)
{
right[x] = arr[m + 1 + x];
}
int i = 0;
int j = 0;
int k = l;
// after comparing, we merge those two array
// in larger sub array
while (i < len1 && j < len2)
{
if (comparator.compare(left[i], right[j]) <= 0)
{
arr[k] = left[i];
i++;
}
else
{
arr[k] = right[j];
j++;
}
k++;
}
// copy remaining elements of left, if any
while (i < len1)
{
arr[k] = left[i];
k++;
i++;
}
// copy remaining element of right, if any
while (j < len2)
{
arr[k] = right[j];
k++;
j++;
}
}
// iterative sort function to sort the
// array[0...n-1] (similar to merge sort)
static void sortIntArrayWithComparator(int[] arr, IntComparator comparator) { sortIntArrayWithComparator(arr, lIntArray(arr), comparator); }
static void sortIntArrayWithComparator(int[] arr, int n, IntComparator comparator) {
// Sort individual subarrays of size RUN
for (int i = 0; i < n; i += sortIntArrayWithComparator_RUN)
{
sortIntArrayWithComparator_insertionSort(arr, comparator, i, Math.min((i + 31), (n - 1)));
}
// start merging from size RUN (or 32). It will merge
// to form size 64, then 128, 256 and so on ....
for (int size = sortIntArrayWithComparator_RUN; size < n; size = 2 * size)
{
// pick starting point of left sub array. We
// are going to merge arr[left..left+size-1]
// and arr[left+size, left+2*size-1]
// After every merge, we increase left by 2*size
for (int left = 0; left < n; left += 2 * size)
{
// find ending point of left sub array
// mid+1 is starting point of right sub array
int mid = Math.min(left + size - 1, n - 1);
int right = Math.min(left + 2 * size - 1, n - 1);
// merge sub array arr[left.....mid] &
// arr[mid+1....right]
sortIntArrayWithComparator_merge(arr, comparator, left, mid, right);
}
}
}
static int lIntArray(int[] a) {
return a == null ? 0 : a.length;
}
static interface IntComparator {
int compare(int a, int b);
}
Here is a helper method to do the job.
First of all you'll need a new Comparator interface, as Comparator doesn't support primitives:
public interface IntComparator{
public int compare(int a, int b);
}
(You could of course do it with autoboxing / unboxing but I won't go there, that's ugly)
Then, here's a helper method to sort an int array using this comparator:
public static void sort(final int[] data, final IntComparator comparator){
for(int i = 0; i < data.length + 0; i++){
for(int j = i; j > 0
&& comparator.compare(data[j - 1], data[j]) > 0; j--){
final int b = j - 1;
final int t = data[j];
data[j] = data[b];
data[b] = t;
}
}
}
And here is some client code. A stupid comparator that sorts all numbers that consist only of the digit '9' to the front (again sorted by size) and then the rest (for whatever good that is):
final int[] data =
{ 4343, 544, 433, 99, 44934343, 9999, 32, 999, 9, 292, 65 };
sort(data, new IntComparator(){
#Override
public int compare(final int a, final int b){
final boolean onlyNinesA = this.onlyNines(a);
final boolean onlyNinesB = this.onlyNines(b);
if(onlyNinesA && !onlyNinesB){
return -1;
}
if(onlyNinesB && !onlyNinesA){
return 1;
}
return Integer.valueOf(a).compareTo(Integer.valueOf(b));
}
private boolean onlyNines(final int candidate){
final String str = String.valueOf(candidate);
boolean nines = true;
for(int i = 0; i < str.length(); i++){
if(!(str.charAt(i) == '9')){
nines = false;
break;
}
}
return nines;
}
});
System.out.println(Arrays.toString(data));
Output:
[9, 99, 999, 9999, 32, 65, 292, 433, 544, 4343, 44934343]
The sort code was taken from Arrays.sort(int[]), and I only used the version that is optimized for tiny arrays. For a real implementation you'd probably want to look at the source code of the internal method sort1(int[], offset, length) in the Arrays class.
I tried maximum to use the comparator with primitive type itself. At-last i concluded that there is no way to cheat the comparator.This is my implementation.
public class ArrSortComptr {
public static void main(String[] args) {
int[] array = { 3, 2, 1, 5, 8, 6 };
int[] sortedArr=SortPrimitiveInt(new intComp(),array);
System.out.println("InPut "+ Arrays.toString(array));
System.out.println("OutPut "+ Arrays.toString(sortedArr));
}
static int[] SortPrimitiveInt(Comparator<Integer> com,int ... arr)
{
Integer[] objInt=intToObject(arr);
Arrays.sort(objInt,com);
return intObjToPrimitive(objInt);
}
static Integer[] intToObject(int ... arr)
{
Integer[] a=new Integer[arr.length];
int cnt=0;
for(int val:arr)
a[cnt++]=new Integer(val);
return a;
}
static int[] intObjToPrimitive(Integer ... arr)
{
int[] a=new int[arr.length];
int cnt=0;
for(Integer val:arr)
if(val!=null)
a[cnt++]=val.intValue();
return a;
}
}
class intComp implements Comparator<Integer>
{
#Override //your comparator implementation.
public int compare(Integer o1, Integer o2) {
// TODO Auto-generated method stub
return o1.compareTo(o2);
}
}
#Roman:
I can't say that this is a good example but since you asked this is what came to my mind.
Suppose in an array you want to sort number's just based on their absolute value.
Integer d1=Math.abs(o1);
Integer d2=Math.abs(o2);
return d1.compareTo(d2);
Another example can be like you want to sort only numbers greater than 100.It actually depends on the situation.I can't think of any more situations.Maybe Alexandru can give more examples since he say's he want's to use a comparator for int array.

Categories