Java Recursive MergeSort for ArrayLists - java

I have been having a problem with my mergesort function, as I am not able to sort a series of integers or strings whenever inputting it into the program. I have an outside class that calls items into it, however it simply doesn't sort the numbers/strings. The two methods are below, I don't know where the problem is. Numbers are randomly inputted.
CODE:
/**
* Takes in entire vector, but will merge the following sections together:
* Left sublist from a[first]..a[mid], right sublist from a[mid+1]..a[last].
* Precondition: each sublist is already in ascending order
*
* #param a
* reference to an array of integers to be sorted
* #param first
* starting index of range of values to be sorted
* #param mid
* midpoint index of range of values to be sorted
* #param last
* last index of range of values to be sorted
*/
private void merge(ArrayList<Comparable> a, int first, int mid, int last) {
int x;
int i;
ArrayList<Comparable> left = new ArrayList<Comparable>();
ArrayList<Comparable> right = new ArrayList<Comparable>();
mergeSort(a,first,mid);
for(i = 0; i < a.size() - mid; i++){
left.add(i,a.get(i));
a.remove(i);
}
mergeSort(a,mid,last);
for (x = mid; x < a.size(); x++) {
right.add(x,a.get(x));
a.remove(x);
}
if ((left.get(i).compareTo(right.get(x))) > 0) {
i++;
a.add(i);
} else if (i < x) {
x++;
a.add(x);
}
System.out.println();
System.out.println("Merge");
System.out.println();
}
/**
* Recursive mergesort of an array of integers
*
* #param a
* reference to an array of integers to be sorted
* #param first
* starting index of range of values to be sorted
* #param last
* ending index of range of values to be sorted
*/
public void mergeSort(ArrayList<Comparable> a, int first, int last) {
int mid = (first + last)/2;
if(first == last){
}else if(last - first == 1){
merge(a,first, mid ,last);
}else{
last = mid;
}
}

I have an outside class that calls items into it, however it simply doesn't sort the numbers/strings. The two methods are below, I don't know where the problem is.
The first problem is that if you call your mergeSort method with first = 0 and last = a.size() you won't sort anything as you only call merge if last-first == 1 :
public void mergeSort(ArrayList<Comparable> a, int first, int last) {
int mid = (first + last)/2;
if(first == last){
}else if(last - first == 1){
// you only merge if last - first == 1...
merge(a,first, mid ,last);
}else{
last = mid;
}
}
Appart from this point, I don't get how you're trying to implement the Merge Sort algorithm. It's neither a top down, nor a bottom up implementation. You're splitting inside the merge method which is also really odd. It would have been easier to help you if you had provided your pseudo code + the way you call your public method. IMHO you have a real issue with your algorithm.
In fact the merge sort algorithm is really simple to implement. To illustrate this, I wrote this top down implementation of the merge sort algorithm using Deque instead of List objects:
import java.util.Deque;
import java.util.LinkedList;
public class Example {
private LinkedList<Comparable> merge(final Deque<Comparable> left, final Deque<Comparable> right) {
final LinkedList<Comparable> merged = new LinkedList<>();
while (!left.isEmpty() && !right.isEmpty()) {
if (left.peek().compareTo(right.peek()) <= 0) {
merged.add(left.pop());
} else {
merged.add(right.pop());
}
}
merged.addAll(left);
merged.addAll(right);
return merged;
}
public void mergeSort(final LinkedList<Comparable> input) {
if (input.size() != 1) {
final LinkedList<Comparable> left = new LinkedList<Comparable>();
final LinkedList<Comparable> right = new LinkedList<Comparable>();
// boolean used to decide if we put elements
// in left or right LinkedList
boolean logicalSwitch = true;
while (!input.isEmpty()) {
if (logicalSwitch) {
left.add(input.pop());
} else {
right.add(input.pop());
}
logicalSwitch = !logicalSwitch;
}
mergeSort(left);
mergeSort(right);
input.addAll(merge(left, right));
}
}
}
I used Deque because peek()/ pop() is ways prettier IMHO than get(0) and remove(0) but it's up to you. If you absolutely want to use ArrayList here follows the corresponding implementation.
import java.util.ArrayList;
import java.util.List;
public class Example {
private List<Comparable> merge(final List<Comparable> left, final List<Comparable> right) {
final List<Comparable> merged = new ArrayList<>();
while (!left.isEmpty() && !right.isEmpty()) {
if (left.get(0).compareTo(right.get(0)) <= 0) {
merged.add(left.remove(0));
} else {
merged.add(right.remove(0));
}
}
merged.addAll(left);
merged.addAll(right);
return merged;
}
public void mergeSort(final List<Comparable> input) {
if (input.size() != 1) {
final List<Comparable> left = new ArrayList<Comparable>();
final List<Comparable> right = new ArrayList<Comparable>();
boolean logicalSwitch = true;
while (!input.isEmpty()) {
if (logicalSwitch) {
left.add(input.remove(0));
} else {
right.add(input.remove(0));
}
logicalSwitch = !logicalSwitch;
}
mergeSort(left);
mergeSort(right);
input.addAll(merge(left, right));
}
}
}
Both implementation work with Integerand String or other Comparable.
Hope it helps.

There are several problems but an important one is that you should not iterate over a list while modifying the list, i.e. in:
for (i = 0; i < a.size() - mid; i++){
left.add(i,a.get(i));
a.remove(i);
}
because once you remove an element, indexes for others are not the same... So you add in left elements of a that are not what you think.
A working code is the following (with some comments) :
private static void merge(ArrayList<Comparable> a) {
if (a.size()<=1) return; // small list don't need to be merged
// SEPARATE
int mid = a.size()/2; // estimate half the size
ArrayList<Comparable> left = new ArrayList<Comparable>();
ArrayList<Comparable> right = new ArrayList<Comparable>();
for(int i = 0; i < mid; i++) left.add(a.remove(0)); // put first half part in left
while (a.size()!=0) right.add(a.remove(0)); // put the remainings in right
// Here a is now empty
// MERGE PARTS INDEPENDANTLY
merge(left); // merge the left part
merge(right); // merge the right part
// MERGE PARTS
// while there is something in the two lists
while (left.size()!=0 && right.size()!=0) {
// compare both heads, add the lesser into the result and remove it from its list
if (left.get(0).compareTo(right.get(0))<0) a.add(left.remove(0));
else a.add(right.remove(0));
}
// fill the result with what remains in left OR right (both can't contains elements)
while(left.size()!=0) a.add(left.remove(0));
while(right.size()!=0) a.add(right.remove(0));
}
It has been tested on some inputs... Example:
[4, 7, 1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11]
[0, 1, 1, 2, 3, 4, 4, 5, 6, 7, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
For efficiency you may use subList method to avoid constructing too much sub lists explicitly, it will need to take care about indices.

A WARNING about Kraal's implementation that got the checkmark. It's a great implementation, but Kraal's Merge sort doesn't preserve the relative order of items that have the same value, which in some cases, when sorting objects for instance, is an important strength that merge sort has that other sorting algorithms, like quicksort, do not have. I modified Kraal's code to preserve relative orders.
private static List<Object> merge(final List<Object> left, final List<Object> right) {
printArr("left", left);
printArr("Right", right);
final List<Object> merged = new ArrayList<>();
while (!left.isEmpty() && !right.isEmpty()) {
if(left.get(0).getValue()-right.get(0).getValue() <= 0){
merged.add(left.remove(0));
} else {
merged.add(right.remove(0));
}
}
merged.addAll(left);
merged.addAll(right);
return merged;
}
public static void mergeSort(final List<Object> input) {
if (input.size() > 1) {
final List<Object> left = new ArrayList<Object>();
final List<Object> right = new ArrayList<Object>();
boolean logicalSwitch = true;
while (!input.isEmpty()) {
if (logicalSwitch) {
left.add(input.remove(0));
} else {
right.add(input.remove(input.size()/2));
}
logicalSwitch = !logicalSwitch;
}
mergeSort(left);
mergeSort(right);
input.addAll(merge(left, right));
}
}

If you want to sort an array using Merge sort, and not to implement a sorting algorithm by yourself,
I recommend using standard Java sorting algorithms because it implements "Merge sort" algorithm for non primitive types.
Collections.sort();
If you would like to implement your own version of Merge sort then you should look first at this implementation.
And if you are interested in better understanding sorting algorithms I recommend this book.

public class MergeSort{
public void sort(List<Integer> list){
sortAndMerge(list, 0, list.size()-1);
}
public void sortAndMerge(List<Integer> list, int start, int end){
if((end - start) >= 2){
int mid = (end - start)/2;
sortAndMerge(list, start, start + mid);
sortAndMerge(list, start + mid +1, end);
int i=start;
int j=start + mid +1;
while(i<j && j<=end){
if(list.get(i) > list.get(j)){
list.add(i, list.remove(j));
i++;
j++;
}else if(list.get(i) == list.get(j)){
list.add(i+1, list.remove(j));
i++;
j++;
}else{
i++;
}
}
}else{
if(end > start){
if(list.get(start) > list.get(end)){
int endValue = list.remove(end);
list.add(start, endValue);
}
}
}
}

Related

Find the minimum of a sorted and shifted array with better than O(n) time complexity

We have an assignment to search for the minimum element of a sorted array that is shifted to the right afterwards. For example: [1, 5, 6, 19, 56, 101] becomes [19, 56, 101, 1, 5, 6]. The method should be implemented using a divide and conquer algorithm and it should have a better asymptotic time complexity than O(n).
EDIT: I forgot to add that the elements int the array are unique.
I already implemented a method and wanted to ask if this is better than O(n) and if there are ways to improve my method.
public class FindMinimum {
public void findMinimum(int[] arr) {
// the recursive method ends when the length of the array is smaller than 2
if (arr.length < 2) {
return;
}
int mid = arr.length / 2;
/*
* if the array length is greater or the same as two, check if the middle
* element is smaller as the element before that. And print the middle element
* if it's true.
*/
if (arr.length >= 2) {
if (arr[mid - 1] > arr[mid]) {
System.out.println("Minimum: " + arr[mid]);
return;
}
}
/*
* separate the array in two sub-arrays through the middle and start the method
* with those two arrays again.
*/
int[] leftArr = new int[mid];
int[] rightArr = new int[arr.length - mid];
for (int i = 0; i < mid; i++) {
leftArr[i] = arr[i];
}
for (int i = mid; i < arr.length; i++) {
rightArr[i - mid] = arr[i];
}
findMinimum(leftArr);
findMinimum(rightArr);
}
}
In Java you could use a List because than you can create a Sublist.
private Integer findMinimum(List<Integer> list) {
if (list.size() < 2)
return list.get(0);
int mid = list.size() / 2;
// create left and right list
List<Integer> leftList = list.subList(0, mid);
List<Integer> rightList = list.subList(mid, list.size());
if (leftList.get(leftList.size() - 1) <= rightList.get(rightList.size() - 1))
return findMin(leftList);
else
return findMin(rightList);
}
When you create a Sublist with Java there is no copy. So to create a new Sublist takes a complexity of O(1).
So the function has a complexity of O(logn).
This is my new solution, without copying the array anywhere.
public class FindMinimum {
public void findMinimum(int[] arr) {
findMinimumSub(arr, 0, arr.length - 1, 2);
}
private void findMinimumSub(int[] arr, int start, int end, int size) {
// the recursive method ends when the length of the array is smaller than 2
if ((end - start) < 2) {
if (arr[end] > arr[start])
System.out.println("Minimum: " + arr[start]);
else
System.out.println("Minimum: " + arr[end]);
return;
}
int mid = arr.length / size;
if (arr[start] > arr[end]) {
// right side
start += mid;
findMinimumSub(arr, start, end, size * 2);
}
else {
// left side
findMinimumSub(arr, start, mid, size * 2);
}
}
}

sort array using recursive method

I am working on trying to write a program where a user will enter 6 strings and then it will sort the array in reverse alphabetical order using a recursive method. This is one concept I do not understand despite multiple videos, readings and attempts. Any support and insight is greatly appreciated. Thank you.
import java.util.Arrays;
import java.util.Scanner;
public class SRecusion {
public static void sort2 (String[] sort2) {
int i;
int min = 0;
int max;
for (i = 0; i <sort2.length -1; i++) {
if (sort2[i].charAt(0)> sort2[i=1].charAt(0)) {
sort2[i] = sort2[min];
}
else {
min = (sort2(sort2[i-1]));
}
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
String [] test = new String[6];
Scanner scnr = new Scanner(System.in);
String userEntry = "";
for(int i = 0; i <= test.length - 1; i++) {
System.out.println("Please enter a word:");
test[i] = scnr.nextLine();
}
sort2(test);
System.out.println("your list is" + Arrays.asList(test));
System.out.println();
}
}
Sorting is a pretty broad topic as there are many different sorting methods (quicksort, merge sort, etc.) However, a pretty basic and simple sorting method is bubble sort. Although it isn't the fastest one, it's pretty easy to understand and code using recursion.
Essentially, bubble sort with iterate through the elements in pairs of 2 and swap the two elements if they're in the wrong order.
For example, let's sort (3, 2, 5, 4, 1) using bubble sort.
(2, 3, 5, 4, 1) First, it'll look at the first two elements swap them if needed. Since 3 is greater than 2, it'll swap them.
(2, 3, 5, 4, 1) Next, it'll look at 3 and 5. Since 3 is less than 5, there is no need to swap
(2, 3, 4, 5, 1) It now looks at 5 and 4 and swaps them.
(2, 3, 4, 1, 5) Finally, it looks at 5 and 1 and swaps them.
Now start from the beginning and repeat the whole process. The sorting ends if exactly 0 swaps are made during an iteration.
If you're still a bit confused, try watching a tutorial on bubble sort or visit this link.
So from what I was asking above as to why you need a recursive sorting algorithm Here it goes I will try to explain how recursive sorting works. It took my some time to figure it out as I am sure it does for most people who first come in contact with it.
public static void Qsort(int[] array, int start, int end)
{
//find the current center of the whole or parital array part I am working on.
int center = (start+end)/2;
///System.out.println("\n This is the center : " + center);
int pivot, i, pivotplace;
i = 0;
pivot = 0;
pivotplace = 0;
//if start = end then we are at a single element. just return to the previous iterative call.
if(start == end)
{
// System.out.println("\n Inside base case return :");
return;
}
//find the pivot value we are using. using a 3 prong selection we are assured to at least get some type of median value and avoid the N^2 worst case.
pivot = getpivot(array[start], array[center], array[end]); //gets median value of start, center and end values in the array.
// System.out.println("\n pivotvalue is : " + pivot);
//find where the current pivot is located and swap it with the last element in the current portion of the array.
if(array[start] == pivot)
{
//System.out.print("\n Inside pivot at start");
swap(array, start, end);
}
else
{
if(array[center] == pivot)
{
//System.out.print("\n Inside pivot at center");
swap(array, center, end);
}
}
//due to iteration the pivot place needs to start at the passed in value of 'start' and not 0.
pivotplace = start;
//due to iteration the loop needs to go from the passed in value of start and not 0 and needs to go
//until it reaches the end value passed in.
for(i = start; i < end; i++)
{
//if the current slot of the array is less than then pivot swap it with the current pivotplace holder
//since the pivotplace keeps getting iterated up be each swap the final place of pivot place
//is where the pivot will actually be swapped back to after the loop cpompletes.
if(array[i] < pivot)
{
//System.out.print("\n Swapping");
swap(array, i, pivotplace);
pivotplace++;
}
}
//loop is finished, swap the pivot into the spot it belongs in.
swap(array, pivotplace, end);
//there are 2 cases for recursive iteration.
//The first is from the start to the slot before the pivot
if(start < pivotplace){Qsort(array, start, pivotplace-1);}
//the second is from the slot after the pivot to the end.
if(pivotplace+1 < end){Qsort(array, pivotplace+1, end);}
}
public static int getpivot(int a, int b, int c)
{
if((a > b) && (a < c))
{
return a;
}
if((b > a) && (b < c))
{
return b;
}
return c;
}
public static void swap(int[] array, int posa, int posb)
{
int temp;
temp = array[posa];
array[posa] = array[posb];
array[posb] = temp;
}
This is a basic Quick Sort or recursive sort I wrote this while in programming classes. You will probably not need to use the getpivot code as you are dealing with a small set of strings, but if you do some research you will see using a possible sample of 3 drastically speeds up the recursion due to balanced work load of the recursion tree.
Sort Array using recursion in kotlin
fun main() {
print(sortArray(arrayListOf(1,3,2,6,8,3)))
}
fun sortArray(arr: MutableList<Int>): MutableList<Int>{
if(arr.size==1) {
return arr
}
val lastValue = arr.last()
arr.removeLast()
sortArray(arr)
insert(arr, lastValue)
return arr
}
fun insert (arr: MutableList<Int>, value: Int): MutableList<Int> {
if(arr.size == 0 || arr.last() < value) {
arr.add(value)
return arr
}
val lastValue = arr.last()
arr.removeLast()
insert(arr, value)
arr.add(lastValue)
return arr
}

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;
}

Fixed-size collection that keeps top (N) values in Java

I need to keep top N(< 1000) integers while trying to add values from a big list of integers(around a million sized lazy list). I want to be try adding values to a collection but that needs to keep only the top N(highest values) integers. Is there any preferred data structure to use for this purpose ?
I'd suggest to use some sorted data structure, such as TreeSet. Before insertion, check the number of items in the set, and if it reached 1000, remove the smallest number if it's smaller than the newly added number, and add the new number.
TreeSet<Integer> set = ...;
public void add (int n) {
if (set.size () < 1000) {
set.add (n);
} else {
Integer first = set.first();
if (first.intValue() < n) {
set.pollFirst();
set.add (n);
}
}
}
Google Guava MinMaxPriorityQueue class.
You can also use custom sorting by using a comparator (Use orderedBy(Comparator<B> comparator) method).
Note: This collection is NOT a sorted collection.
See javadoc
Example:
#Test
public void test() {
final int maxSize = 5;
// Natural order
final MinMaxPriorityQueue<Integer> queue = MinMaxPriorityQueue
.maximumSize(maxSize).create();
queue.addAll(Arrays.asList(10, 30, 60, 70, 20, 80, 90, 50, 100, 40));
assertEquals(maxSize, queue.size());
assertEquals(new Integer(50), Collections.max(queue));
System.out.println(queue);
}
Output:
[10, 50, 40, 30, 20]
One efficient solution is a slightly tweaked array-based priority queue using a binary min-heap.
First N integers are simply added to the heap one by one or you can build it from array of first N integers (slightly faster).
After that, compare the incoming integer with the root element (which is MIN value found so far). If the new integer is larger that that, simply replace the root with this new integer and perform down-heap operation (i.e. trickle down the new integer until both its children are smaller or it becomes a leaf). The data structure guarantees you will always have N largest integers so far with average addition time of O(log N).
Here is my C# implementation, the mentioned method is named "EnqueueDown". The "EnqueueUp" is a standard enqueue operation that expands the array, adds new leaf and trickles it up.
I have tested it on 1M numbers with max heap size of 1000 and it runs under 200 ms:
namespace ImagingShop.Research.FastPriorityQueue
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
public sealed class FastPriorityQueue<T> : IEnumerable<Tuple<T, float>>
{
private readonly int capacity;
private readonly Tuple<T, float>[] nodes;
private int count = 0;
public FastPriorityQueue(int capacity)
{
this.capacity = capacity;
this.nodes = new Tuple<T, float>[capacity];
}
public int Capacity => this.capacity;
public int Count => this.count;
public T FirstNode => this.nodes[0].Item1;
public float FirstPriority => this.nodes[0].Item2;
public void Clear()
{
this.count = 0;
}
public bool Contains(T node) => this.nodes.Any(tuple => Equals(tuple.Item1, node));
public T Dequeue()
{
T nodeHead = this.nodes[0].Item1;
int index = (this.count - 1);
this.nodes[0] = this.nodes[index];
this.count--;
DownHeap(index);
return nodeHead;
}
public void EnqueueDown(T node, float priority)
{
if (this.count == this.capacity)
{
if (priority < this.nodes[0].Item2)
{
return;
}
this.nodes[0] = Tuple.Create(node, priority);
DownHeap(0);
return;
}
int index = this.count;
this.count++;
this.nodes[index] = Tuple.Create(node, priority);
UpHeap(index);
}
public void EnqueueUp(T node, float priority)
{
int index = this.count;
this.count++;
this.nodes[index] = Tuple.Create(node, priority);
UpHeap(index);
}
public IEnumerator<Tuple<T, float>> GetEnumerator()
{
for (int i = 0; i < this.count; i++) yield return this.nodes[i];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void DownHeap(int index)
{
while (true)
{
int indexLeft = (index << 1);
int indexRight = (indexLeft | 1);
int indexMin = ((indexLeft < this.count) && (this.nodes[indexLeft].Item2 < this.nodes[index].Item2))
? indexLeft
: index;
if ((indexRight < this.count) && (this.nodes[indexRight].Item2 < this.nodes[indexMin].Item2))
{
indexMin = indexRight;
}
if (indexMin == index)
{
break;
}
Flip(index, indexMin);
index = indexMin;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void Flip(int indexA, int indexB)
{
var temp = this.nodes[indexA];
this.nodes[indexA] = this.nodes[indexB];
this.nodes[indexB] = temp;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void UpHeap(int index)
{
while (true)
{
if (index == 0)
{
break;
}
int indexParent = (index >> 1);
if (this.nodes[indexParent].Item2 <= this.nodes[index].Item2)
{
break;
}
Flip(index, indexParent);
index = indexParent;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
The basic implementation is taken from "Cormen, Thomas H. Introduction to algorithms. MIT press, 2009."
In Java 1.7 one may use java.util.PriorityQueue. To keep the top N items you need to use reverse comparator, e.g. for integers you order them descending. In this manner the smallest number is always on top and could be removed if to many items in queue.
package eu.pawelsz.example.topn;
import java.util.Comparator;
import java.util.PriorityQueue;
public class TopN {
public static <E> void add(int keep, PriorityQueue<E> priorityQueue, E element) {
if (keep == priorityQueue.size()) {
priorityQueue.poll();
}
priorityQueue.add(element);
}
public static void main(String[] args) {
int N = 4;
PriorityQueue<Integer> topN = new PriorityQueue<>(N, new Comparator<Integer>() {
#Override
public int compare(Integer o1, Integer o2) {
return o1 - o2;
}
});
add(N, topN, 1);
add(N, topN, 2);
add(N, topN, 3);
add(N, topN, 4);
System.out.println("smallest: " + topN.peek());
add(N, topN, 8);
System.out.println("smallest: " + topN.peek());
add(N, topN, 5);
System.out.println("smallest: " + topN.peek());
add(N, topN, 2);
System.out.println("smallest: " + topN.peek());
}
}
// this Keep Top Most K Instance in Queue
public static <E> void add(int keep, PriorityQueue<E> priorityQueue, E element) {
if(priorityQueue.size()<keep){
priorityQueue.add(element);
}
else if(keep == priorityQueue.size()) {
priorityQueue.add(element); // size = keep +1 but
Object o = (Object)topN.toArray()[k-1];
topN.remove(o); // resized to keep
}
}
The fastest way is likely a simple array items = new Item[N]; and a revolving cursor int cursor = 0;. The cursor points to the insertion point of the next element.
To add a new element use the method
put(Item newItem) { items[cursor++] = newItem; if(cursor == N) cursor = 0; }
when accessing this structure you can make the last item added appear at index 0 via a small recalculation of the index, i.e.
get(int index) { return items[ cursor > index ? cursor-index-1 : cursor-index-1+N ]; }
(the -1 is because cursor always point at the next insertion point, i.e. cursor-1 is the last element added).
Summary: put(item) will add a new item. get(0) will get the last item added, get(1) will get the second last item, etc.
In case you need to take care of the case where n < N elements have been added you just need to check for null.
(TreeSets will likely be slower)
Your Question is answered here:
Size-limited queue that holds last N elements in Java
To summerize it:
No there is no data structure in the default java sdk, but Apache commons collections 4 has a CircularFifoQueue.

Is it possible to split a Java list into three without looping?

Given a Java List with 21 elements.
What is the best way to create three new lists with:
A = 0, 3, 6, ... indexed elements from source
B = 1, 4, 7, ...
C = 2 ,5, 8, 11, 14, 17, 20
Is it possible without looping?
Well you could write a wrapper class which is able to provide a read-only "view" onto a list given a multiple (3 in this case) and an offset (0, 1 and 2). When asked for the item at a particular index, it would have to multiply by the "multiple" and add the offset, then look into the original list. (Likewise for the other operations.)
It would be simpler to loop though... what's the context here? What are you really trying to achieve?
Here's an example of what Jon mentioned (if of course you really don't want to just loop). The name isn't great... I'm not sure what a good name for such a thing would be.
public class OffsetList<E> extends AbstractList<E> {
private final List<E> delegate;
private final int offset;
private final int multiple;
public static <E> OffsetList<E> create(List<E> delegate, int offset, int multiple) {
return new OffsetList<E>(delegate, offset, multiple);
}
private OffsetList(List<E> delegate, int offset, int multiple) {
this.delegate = delegate;
this.offset = offset;
this.multiple= multiple;
}
#Override public E get(int index) {
return delegate.get(offset + (index * multiple));
}
#Override public int size() {
int offsetToEnd = delegate.size() - offset;
return (int) Math.ceil(offsetToEnd / (double) multiple);
}
}
Example use:
List<Integer> numbers = // the numbers 0 to 21 in order
List<Integer> first = OffsetList.create(numbers, 0, 3);
List<Integer> second = OffsetList.create(numbers, 1, 3);
List<Integer> third = OffsetList.create(numbers, 2, 3);
System.out.println(first); // [0, 3, 6, 9, 12, 15, 18, 21]
System.out.println(second); // [1, 4, 7, 10, 13, 16, 19]
System.out.println(third); // [2, 5, 8, 11, 14, 17, 20]
Creating each list is O(1) since they're views. Iterating each list is O(n) where n is the size of the actual view list, not the size of the full list it's based on. This assumes the original list is a random access list... this approach, like index-based iteration, would be very inefficient with a linked list.
Given you saying you're used to functional programming, I'm going to assume you want to split up the lists because you want to do something different to each. If that's the case I would put the filtering logic at the Iterator level.
You could have a wrapping Iterator instead of a wrapping List. It might look something like this:
public <T> Iterable<T> filter(final Iterable<T> allElements, final int offset, final int multiple) {
return new Iterable<T> {
public Iterator<T> iterator() {
return new Iterator<T> {
int index = 0;
Iterator<T> allElementsIt = allElements.iterator();
public boolean hasNext() {
while (allElementsIt.hasNext()) {
if ( isDesiredIndex(index) ) {
return true;
} else {
allElementsIt.next();
index++;
}
}
return false;
}
private boolean isDesiredIndex(int index) {
return (index - offset) % multiple == 0;
}
public T next() {
if ( hasNext() ) {
return allElementsIt.next();
} else {
throw NoSuchElementException();
}
}
public void remove() {...}
}
}
}
}
Then to use it:
for ( ElementType element : filter(elements, 2, 3) ) {
//do something to every third starting with third element
}
Next try :)
class Mod3Comparator implements Comparator<Integer> {
public int compare(Integer a, Integer b) {
if (a % 3 < b % 3 || (a % 3 == b % 3 && a < b)) {
return -1;
}
if (a % 3 > b % 3 || (a % 3 == b % 3 && a > b)) {
return 1;
}
return 0;
}
}
First sort the list taking into consideration the modulo rule, then use the Arrays.copyOfRange method.
Collections.sort(list, new Mod3Comparator());
Integer[] array = new Integer[list.size()];
list.toArray(array);
List<Integer> A = Arrays.asList(Arrays.copyOfRange(array, 0, 7));
List<Integer> B = Arrays.asList(Arrays.copyOfRange(array, 7, 14));
...
Also see this example.
Unfortunately, I can't think of a way of doing so without pretending the arrays are lists are doing the following.
String[] twentyOne = new String[21];
String[] first = new String[3];
first[0] = twentyOne[0];
first[1] = twentyOne[3];
first[2] = twentyOne[6];
// And so on
String[] second = new String[3];
second[0] = twentyOne[1];
second[1] = twentyOne[4];
second[2] = twentyOne[7];
String[] third = new String[15];
third[0] = twentyOne[2];
// You get the picture
I only used arrays in the example because I'm more confident with them, and know them without needing to look at something.
May I ask why you want to avoid looping?

Categories