was wondering if i could get some quick help with a heapsort implementation. I have it working and sorting fine but in the output it is always everything is sorted except the first number. It's probably just a check somewhere but i have gone over my code and tried changing values but nothing produced the results i needed. Any advice to where i went wrong?
here is my source code:
code removed, problem was solved!
thanks guys!
private static void movedown(double [] a, int k, int c) {
while (2*k <= c-1) {
int j = 2*k+1;
if (j <= c-1 && less(a[j], a[j+1])) j++;
if (!less(a[k], a[j])) break;
exch(a, k, j);
k = j;
}
}
public static void heapsort(double [] a, int count) {
for (int k = count/2; k >= 0; k--)
movedown(a, k, count);
while (count >= 1) {
exch(a, 0, count--);
movedown(a, 0, count);
}
}
I have fixed your bug and tested it on my machine. It should work. Just a couple minor changes in these two methods.
To summarize what you didn't get right:
In heapsort method, the count you passed in is zero-based index. However, when you built the heap you only looped to k = 1, i.e., one more iteration to go.
In movedown method, you should have known the left child index is 2*k+1 while the right child index is 2*k+2.
That you didn't keep consistent with your indexing choices(i.e., 0-based vs. 1-based) resulted in the bug I guess.
Related
This question already has answers here:
Why is processing a sorted array *slower* than an unsorted array? (Java's ArrayList.indexOf)
(3 answers)
Closed 9 months ago.
I've been solving one algorithmic problem and found solution, as I thought. But unexpectedly I bumped into a weird problem.
Let's assume i have the following code on java 8/17(replicates on both), intel 11th gen processor:
import java.util.Arrays;
import java.util.concurrent.ThreadLocalRandom;
public class DistanceYandex{
static class Elem implements Comparable<Elem>{
int value;
int index;
long dist;
public Elem(int value, int index){
this.value = value;
this.index = index;
}
#Override
public int compareTo(Elem o){
return Integer.compare(value, o.value);
}
}
public static void main(String[] args){
int n = 300_000;
int k = 3_000;
Elem[] elems = new Elem[n];
for(int i = 0; i < n; i++){
elems[i] = new Elem(ThreadLocalRandom.current().nextInt(), i);
}
solve(n, k, elems);
}
private static void solve(int n, int k, Elem[] elems){
Arrays.sort(elems); // interesting line
long time = System.nanoTime();
for(int i = 0; i < n; i++){
elems[i].dist = findDistForIth(elems, i, k);
}
// i omit output, because it's irrelevant
// Arrays.sort(elems, Comparator.comparingInt(elem -> elem.index));
// System.out.print(elems[0].dist);
// for(int i = 1; i < n; i++){
// System.out.print(" " + elems[i].dist);
// }
System.out.println((System.nanoTime() - time)/1_000_000_000.0);
}
private static long findDistForIth(Elem[] elems, int i, int k){
int midElem = elems[i].value;
int left = i - 1;
int right = i + 1;
long dist = 0;
for(int j = 0; j < k; j++){
if(left < 0){
dist += elems[right++].value - midElem;
}else if(right >= elems.length){
dist += midElem - elems[left--].value;
}else{
int leftAdd = midElem - elems[left].value;
int rightAdd = elems[right].value - midElem;
if(leftAdd < rightAdd){
dist+=leftAdd;
left--;
}else{
dist+=rightAdd;
right++;
}
}
}
return dist;
}
}
Point your eyes at solve function.
Here we have simple solution, that calls function findDistForIth n times and measures time it takes(I don't use JMH, because testing system for my problem uses simple one-time time measures). And before it captures start time, it sorts the array by natural order using built-in Arrays.sort function.
As you could notice, measured time doesn't include the time the array gets sorted. Also function findDistForIth's behaviour does not depend on whether input array is sorted or not(it mostly goes to third else branch). But if I comment out line with Arrays.sort I get significantly faster execution: instead of roughly 7.3 seconds, it takes roughly 1.6 seconds. More that 4 times faster!
I don't understand what's going on.
I thought maybe it is gc that's messing up here, I tried to increase memory I give to jvm to 2gb(-Xmx2048M -Xms2048M). Didn't help.
I tried to pass explicit comparator to Arrays.sort as second argument(Comparator.comparingInt(e -> e.value)) and deimplementing Comparable interface on Elem class. Didn't help.
I launched the profiler(Intellij Profiler)
With Arrays.sort included:
With Arrays.sort excluded:
But it didn't give me much information...
I tried building it directly to .jar and launching via java cmd(before i did it via intellij). It also didn't help.
Do anybody know what's goind on?
This problem also replicates in online compiler: https://onlinegdb.com/MPyNIknB8T
May be you need to sort your data using red black tree sorting algo which implemented in SortedSet, Arrays.sort use mergesort sorting algo which works well for small number of data
I am working on a Merge Sort method which sorts elements in-place without allocating extra memory. However, it isn't working as of now and I was wondering if anyone could help me, as I understand it is a relatively simple operation. Thank you in advance.
My merge sort method:
RegisterClass[] runMergeSort()
{
RegisterClass[] mergeSorted = new RegisterClass[capacity];
for (int counter = 0; counter < size; counter++)
{
mergeSorted[counter] = registerArray[counter];
}
runMergeSortHelper(mergeSorted, 0, size - 1);
return mergeSorted;
}
My helper method, which uses recursion:
private void runMergeSortHelper(RegisterClass[] workingArray,
int lowIndex,
int highIndex)
{
int midIndex = (lowIndex + highIndex) / 2;
if (lowIndex < highIndex)
{
runMergeSortHelper(workingArray, lowIndex, midIndex);
runMergeSortHelper(workingArray, midIndex+1, highIndex);
runMerge(workingArray, lowIndex, midIndex, highIndex);
}
}
And finally, my Merge method, which SHOULD be putting everything into order, however, it only does this partially.
private void runMerge(RegisterClass[] workingArray,
int lowIndex,
int midIndex,
int highIndex)
{
int counterJay = midIndex;
int counterAye = lowIndex;
int counterKay = lowIndex - 1;
while (counterAye < midIndex && counterJay <= highIndex)
{
counterKay++;
if (workingArray[counterAye].compareTo(workingArray[counterJay]) <= -1)
{
counterAye++;
}
else
{
swapValues(workingArray, counterAye, counterJay);
counterJay++;
counterAye++;
}
}
while (counterAye < midIndex)
{
counterKay++;
swapValues(workingArray, counterAye, counterKay);
counterAye++;
}
while (counterJay <= highIndex)
{
counterKay++;
swapValues(workingArray, counterJay, counterKay);
counterJay++;
}
}
Any advice at all would much be appreciated. I've looked online but nothing seems to help. Please do not refer me to a solution which is NOT an in-place solution.
Swapping isn't going to work with the logic used by the merge function. When a swap occurs, the element that is swapped from the left side to the right side is now out of order, and will be less than (or equal to) all of the remaining elements on the left side.
Whenever an element on the right side is found to be less than an element on the left side, a right rotate of that part of the array is needed to put the right side element into place.
Without resorting to a more complicated implementation, a small optimization can be made by scanning the right side for k = number of leading elements less than the current element on the left side, then do a rotate right by k elements. For random data, this won't help much, but for reverse sorted data, it would help quite a bit.
I have this recursive sorting algorithm I'm using for an assignment, and my teacher said that there's an easy way to improve the running time of my algorithm... But I can't figure out what it is, at all. Unless I'm mistaken, the complexity for the algorithm is O(n)? I'm not sure since we didn't learn how to calculate the complexity of recursive methods in class. Here's the code:
public static void MyAlgorithm(int[] A, int n){
boolean done = true;
int j = 0;
while (j <= n - 2){
if (A[j] > A[j + 1]) {
swap(A,j,j+1);
done= false;
}
j++;
}
j = n - 1;
while (j >= 1){
if (A[j] < A[j - 1]) {
swap(A,j-1,j);
done=false;
}
j--;
}
if (!done)
MyAlgorithm(A, n);
else
return;
}
The only thing I can think of would be adding a if(done) return; after the first loop but it only saves the program from doing a few other operations. Oh and the swap method is basically just:
public static void swap(int[] arr, int pos1, int pos2){
int temp = arr[pos1];
arr[pos1] = arr[pos2];
arr[pos2] = temp;
}
Thank you in advance.
To start, no sorting algorithm can be performed in O(n) using comparisons. As a general rule, all sorting algorithms take AT LEAST O(n*log(n)) time.
The sort you appear to be using is something akin to the cocktail shaker sort, or bidirectional bubble sort. It runs in O(n^2) time. You should definitely research the methods you use and consider why you use them, and also learn how to properly classify things in big O notation.
I imagine your teacher means that you should call the sort as MyAlgorithm(a, n-1). Notice how in your first loop it goes through the entire array? This means that the last element will already be sorted when that loop exits. Similarly, you could add a start index and increment it each time. For example, revised code:
public static void MyAlgorithm(int[] A, int start, int n){
boolean done = true;
int j = start;
while (j <= n - 2){
if (A[j] > A[j + 1]) {
swap(A,j,j+1);
done= false;
}
j++;
}
j = n - 1;
while (j >= start+1){
if (A[j] < A[j - 1]) {
swap(A,j-1,j);
done=false;
}
j--;
}
if (!done)
MyAlgorithm(A, start+1, n-1);
else
return;
}
Then you can call this using: MyAlgorithm(my_array, 0, my_array.length)
Keep in mind that this is still not a fantastic sorting algorithm, and if you ever need to sort large amount of data, you should consider using something faster.
I have a task to write quicksort (on only posivite numbers) algorythm in Java (I can't use any imports but Scanner) but without recursion and without stack.
I have two question about it :
I do understeand iterative quicksort with stack and recursive version but i cannot imagine how to do it without it.
I have heard about some 'in place' implementation but i dont really get it - is it solution for my problem?
I would appreciate if anyone could show me a way to do it ( dont post implementation if you can, I just want to understeand it not copy someone's code) or recommend some book where I can find it ( or some similar problem ).
Is implementing sort by insertion for some small arrays a good idea? If so how big should be N in this code :
if (arraySize < N)
insertionSort
else
quickSort
fi
Apparently my task was to find only posivite numbers, here is my solution:
public static void quickSort(final int size) {
int l = 0;
int r = size - 1;
int q, i = 0;
int tmpr = r;
while (true) {
i--;
while (l < tmpr) {
q = partition(l, tmpr);
arr[tmpr] = -arr[tmpr];
tmpr = q - 1;
++i;
}
if (i < 0)
break;
l++;
tmpr = findNextR(l, size);
arr[tmpr] = -arr[tmpr];
}
}
private static int findNextR(final int l, final int size) {
for (int i = l; i < size; ++i) {
if (arr[i] < 0)
return i;
}
return size - 1;
}
private static int partition(int l, int r) {
long pivot = arr[(l + r) / 2];
while (l <= r) {
while (arr[r] > pivot)
r--;
while (arr[l] < pivot)
l++;
if (l <= r) {
long tmp = arr[r];
arr[r] = arr[l];
arr[l] = tmp;
l++;
r--;
}
}
return l;
}
My array to sort is an static array in my class.
It is based on finding and creating negative numbers.
Partition is created by using middle element in array but using median is also good (it depends on array).
I hope someone will find this usefull.
Just as a reference the Java8 implementation of Arrays.sort(int[]) uses a threshold of 47, anything less than that is sorted using insertion. Their quick sort implementation is however very complex with some initial overhead, so look upon 47 as an upper limit.
A Google of "non-recursive quicksort" produced a slew of answers ... including this one: Non recursive QuickSort "Your language may vary," but the basic principle won't.
I personally think that, if you're going to sort something, you might as well use Quicksort in all cases . . .
Unless, of course, you can simply use a sort() function in your favorite target-language and leave it to the language implementors to have chosen a clever algorithm (uhhhh, it's probably Quicksort...) for you. If you don't have to specify an algorithm to do such a common task, "don't!" :-)
We have a collection of Comparables held in a bag and have to find the kth largest element. I copied the collection to a HashSet to remove duplicates, then converted the HashSet to an array to be sorted and consequently the kth element accessed. The code compiles, but fails the testing, and I can't figure out what's wrong. Any ideas?
public E kth(int k) {
uniqueSet();
Object[] uniqueArr = hashSet.toArray();
startQuick(uniqueArr);
return (E) uniqueArr[k - 1];
}
private void startQuick(Object[] uniqueArr) {
int i = 0, j = uniqueArr.length;
quickSort(uniqueArr, 0, j);
}
private void quickSort(Object[] uniqueArr, int i, int j) {
int index = partition(uniqueArr, i, j);
if (i < index - 1) {
quickSort(rankBagArr, index - 1, j);
}
if (index < j) {
quickSort(rankBagArr, i, index - 1);
}
}
private int partition(Object[] uniqueArr, int i, int j) {
E tmp;
E pivot = (E) rankBagArr[(i + j) / 2];
while (i <= j) {
while (rankBagArr[i].compareTo(pivot) < 0) {
i++;
}
while (rankBagArr[j].compareTo(pivot) > 0) {
j--;
}
if (i <= j) {
tmp = (E) rankBagArr[i];
rankBagArr[i] = rankBagArr[j];
rankBagArr[j] = tmp;
i++;
j--;
}
}
return i;
}
For a start this part is highly suspect:
if (i < index - 1)
quickSort(rankBagArr, index-1 ,j);
if (index < j)
quickSort(rankBagArr, i, index-1);
Don't you mean:
if (i < index - 1)
quickSort(rankBagArr, i, index-1);
if (index + 1 < j)
quickSort(rankBagArr, index + 1, j);
?
I'm not familiar with your approach to partitioning, so I don't know whether that's correct or not. I think I understand it, and it looks okay on inspection, but it's very easy to get off-by-one errors which are hard to see without careful study.
Here's a partition method I wrote in C# recently - you should be able to translate it into Java quite easily if you want to.
private static int Partition<T>(T[] array, int left, int right,
IComparer<T> comparer) {
// Pivot on the rightmost element to avoid an extra swap
T pivotValue = array[right];
int storeIndex = left;
for (int i = left; i < right; i++) {
if (comparer.Compare(array[i], pivotValue) < 0) {
Swap(array, i, storeIndex);
storeIndex++;
}
}
Swap(array, right, storeIndex);
return storeIndex;
}
static void Swap<T>(T[] array, int x, int y) {
T tmp = array[x];
array[x] = array[y];
array[y] = tmp;
}
Any reason for not just using Arrays.sort though?
If you want to solve the problem by sorting, then
Use sorting methods from API (Arrays.sort or Collections.sort). Reinventing the wheel is pointless.
Sort contents of your collection once, not every time you look for k-th element.
The quicksort partitioning is good for finding k-th element without sorting entire collection - you partition, if lowest range is larger then k, you recurrently go with partition to lower range, if it's smaller then k, you go to higher range and look for (k - size of lower range)-th element. It has better complexity than sorting whole collection. You can read more about it here
Anyway, your methods have parameter named uniqueArr, but some operations you perform on rankBagArr. Is it a typo? There is no definition of rankBagArr in your code.
May you could have a bit less of manipulations (and improve performance), and correct the default you are seeing...
Starting with a List (ArrayList), you could ask to sort it (using the comparator, and Collections.sort(list)). Then you could loop down and:
memorizing the last element
if you find the new element is not equals, increment a counter
when your counter reaches the k value, the current element is your target