The purpose of this program is to find the kth smallest element in an array without sorting the array using a recursive and nonrecursive decrease and conquer type method.
I was hoping someone could look over my code and try to help me with my array out of bounds error(s).
The method that is throwing these errors is the recursive selection the non recursive selection works fine.
My driver is also attached and everything should compile if you want to test my code.
public class KthSmallest
{
private int counter;
private int term;
private int[] A;
int SelectionNonRecursive(int A[], int kthSmallest, int sizeOfA)
{
this.A = A;
if(kthSmallest == 1 || kthSmallest == sizeOfA)
{
return (LinearSearch(kthSmallest, sizeOfA));
}
else
{
for(int i = 0; i<sizeOfA; i++)
{
counter = 0;
for(int j = 0; j<sizeOfA; j++)
{
if(A[i] < A[j])
{
counter++;
}
}
if((sizeOfA - counter) == kthSmallest)
{
return A[i];
}
}
}
return 0;
}
int SelectionRecursive(int A[], int kthSmallest, int sizeOfA)
{
this.A = A;
return Selection_R(0, sizeOfA - 1, kthSmallest);
}
int Selection_R(int l, int r, int kthSmallest)
{
if(l<r)
{
if(kthSmallest == 1 || kthSmallest == A.length)
{
return (LinearSearch(kthSmallest, A.length));
}
else
{
int s = LomutoPartition(l, r);
if(s == kthSmallest - 1)
{
return A[s];
}
else if(s > (A[0] + kthSmallest - 1))
{
Selection_R(l, s-1, kthSmallest);
}
else
{
Selection_R(s+1, r, kthSmallest);
}
}
}
return 0;
}
int LomutoPartition(int l, int r)
{
int pivot = A[l];
int s = l;
for(int i = l+1; i<r; i++)
{
if(A[i] < pivot)
{
s += 1;
swap(A[s], A[i]);
}
}
swap(A[l], A[s]);
return s;
}
public void swap(int i, int j)
{
int holder = A[i];
A[i] = A[j];
A[j] = holder;
}
int LinearSearch(int kthSmallest, int sizeOfA)
{
term = A[0];
for(int i=1; i<sizeOfA; i++)
{
if(kthSmallest == 1)
{
if(term > A[i])
{
term = A[i];
}
}
else
{
if(term < A[i])
{
term = A[i];
}
}
}
return term;
}
}
public class KthDriver
{
public static void main(String[] args)
{
KthSmallest k1 = new KthSmallest();
int[] array = {7,1,5,9,3};
System.out.print(k1.SelectionRecursive(array, 3, array.length));
}
}
Inside your LomutoPartition method, you are passing the array elements in your swap method: -
swap(A[s], A[i]); // Inside for loop
and
swap(A[l], A[s]); // Outside for loop
And your swap method considers them as indices: -
public void swap(int i, int j) <-- // `i` and `j` are elements A[s] and A[i]
{
int holder = A[i]; <-- // You are accessing them as indices(A[i] -> A[A[s]])
A[i] = A[j];
A[j] = holder;
}
That is why you are getting that exception. Because, if any element in array is greater than size, it will blast out.
You should change your invocation to: -
swap(s, i); // Inside for loop
and
swap(l, s); // Outside for loop
respectively. And leave your method as it is.
Note that, you should pass array indices, and not array elements. If you pass array elements, then the swapping in the method will not be reflected in your array. Because, your method will have its own copy of your elements.
Related
I wish to implement a hybrid algorithm that switches from insertion sort to merge sort once the input array size becomes too big.
This is my main function (I fixed my input array size at 30 currently as I wish to test my merge sort function) :
public static void main(String[] args) {
int[] a = genrandarray(30);
long bgn, end;
bgn = System.currentTimeMillis();
imsort(a, 0, a.length, 30);
end = System.currentTimeMillis();
for(int i = 1; i < a.length; i++){
if(a[i-1] > a[i]){
System.out.println("failed");
break;
}
}
System.out.println("milliseconds " + (end-bgn));
}
Insertion sort is called when the array size is <20, else merge sort is called:
public static void imsort(int [] slot, int b, int e, int size) {
//if smaller than 20, use insertion sort
if (e-b<=20) {
insertionSort(slot, e); //e is the length of slot[]
System.out.println("imsort entered!");
}
else {
mergesort(b, e, slot);
System.out.println("mergesort entered!");
}
}
There is a Index 30 out of bounds error for my merge sort function currently.
public static int merge(int n, int m, int[] slot) {
int mid = (n+m)/2;
int a = n, b = mid+1, i, tmp, cmp=0, comp=0;
//sanity check
if (m-n <= 0) return -1000;
while (a <= mid && b <= m) {
cmp = compare(slot[a], slot[b]);
comp++;
if (cmp > 0) { //slot[a] > slot[b]
tmp = slot[b++];
for (i = ++mid; i > a; i--)
slot[i] = slot[i-1];
slot[a++] = tmp;
}
else if (cmp < 0) //slot[a] < slot[b]
a++;
else {
//slot[a] == slot[b]
if (a == mid && b == m) break;
tmp = slot[b++];
a++;
for (i = ++mid; i > a; i--)
slot[i] = slot[i-1]; slot[a++] = tmp;
}
} // end of while loop;
return comp;
} // end of merge
public static int mergesort(int s, int e, int[] slot) {
//int comp =0;
int mid = (s+e)/2;
int right=0, left=0;
if(e-s>0) {
//comp++;
left = mergesort(s,mid, slot);
//comp++;
right = mergesort(mid+1,e, slot);
}
return right + left + merge(s,e,slot);
}
I am unsure of the error in my merge / mergesort function. Can I get some further advice?
a.length returns you 30 which is the length of your random array from the genrandarray method i believe. And your array is indexed 0 through 29. Try changing the main method like this and it will work out
public static void main(String[] args) {
int[] a = genrandarray(30);
long bgn, end;
bgn = System.currentTimeMillis();
imsort(a, 0, a.length-1, 30);
end = System.currentTimeMillis();
for(int i = 1; i < a.length; i++){
if(a[i-1] > a[i]){
System.out.println("failed");
break;
}
}
System.out.println("milliseconds " + (end-bgn));
}
First, let me congratulate on a very good post for someone new. You didn't post the line of code where the error is happening and code isn't complete, so I filled in some blanks and executed it:
import java.util.Arrays;
import java.util.Random;
public class Test {
public static int[] genrandarray(int n)
{
int[] a = new int[n];
Random r = new Random();
for(int i=0;i<n;i++) a[i] = r.nextInt();
return a;
}
public static void main(String[] args) {
int[] a = genrandarray(30);
long bgn, end;
bgn = System.currentTimeMillis();
imsort(a, 0, a.length, 30);
end = System.currentTimeMillis();
for(int i = 1; i < a.length; i++){
if(a[i-1] > a[i]){
System.out.println("failed");
break;
}
}
System.out.println("milliseconds " + (end-bgn));
}
public static void imsort(int [] slot, int b, int e, int size) {
//if smaller than 20, use insertion sort
if (e-b<=20) {
Arrays.sort(slot, 0, e);
System.out.println("imsort entered!");
}
else {
mergesort(b, e, slot);
System.out.println("mergesort entered!");
}
}
public static int merge(int n, int m, int[] slot) {
int mid = (n+m)/2;
int a = n, b = mid+1, i, tmp, cmp=0, comp=0;
//sanity check
if (m-n <= 0) return -1000;
while (a <= mid && b <= m) {
cmp = slot[a] - slot[b];
comp++;
if (cmp > 0) { //slot[a] > slot[b]
tmp = slot[b++];
for (i = ++mid; i > a; i--)
slot[i] = slot[i-1];
slot[a++] = tmp;
}
else if (cmp < 0) //slot[a] < slot[b]
a++;
else {
//slot[a] == slot[b]
if (a == mid && b == m) break;
tmp = slot[b++];
a++;
for (i = ++mid; i > a; i--)
slot[i] = slot[i-1]; slot[a++] = tmp;
}
} // end of while loop;
return comp;
} // end of merge
public static int mergesort(int s, int e, int[] slot) {
//int comp =0;
int mid = (s+e)/2;
int right=0, left=0;
if(e-s>0) {
//comp++;
left = mergesort(s,mid, slot);
//comp++;
right = mergesort(mid+1,e, slot);
}
return right + left + merge(s,e,slot);
}
}
The error is caused by setting variable a to n in your merge function and then in the line cmp = slot[a] - slot[b]. Because arrays go from 0 to n-1, n will cause an out of bounds exception.
I have a quicksort algorithm that works fine, but when I try an parallelize it only the second half the array is being sorted, the other half is almost unchanged. And since I am new to parallel programming I have no idea why.
The solution I have is combined from different codes found online.
How do improve it so that he whole array is sorted?
public class foo {
private static final int N_THREADS = Runtime.getRuntime().availableProcessors();
private static final int FALLBACK = 2;
private static Executor pool = Executors.newFixedThreadPool(N_THREADS);
public static <T extends Comparable<T>> void sort(int[] numberArray){
if(numberArray == null && numberArray.length == 0){
return;
}
final AtomicInteger count = new AtomicInteger(1);
pool.execute(new QuicksortRunnable<T>(numberArray, 0, numberArray.length-1, count));
}
private static class QuicksortRunnable<T extends Comparable<T>> implements Runnable {
private final int[] values;
private final int left;
private final int right;
private final AtomicInteger count;
public QuicksortRunnable(int[] values, int left, int right, AtomicInteger count) {
this.values = values;
this.left = left;
this.right = right;
this.count = count;
}
#Override
public void run() {
quicksort(left, right);
synchronized (count) {
if (count.getAndDecrement() == 1)
count.notify();
}
}
private void quicksort(int pLeft, int pRight) {
int pivotIndex = (pRight - pLeft) / 2 + pLeft;
int pivot = values[pivotIndex];
int j = pRight;
int i = pLeft;
while (i < j) {
while (values[i] > pivot) {
i++;
}
while (values[j] < pivot) {
j--;
}
if (i <= j) {
int temp = values[i];
values[i] = values[j];
values[j] = temp;
i++;
j--;
}
}
if (count.get() >= FALLBACK * N_THREADS) {
if (pLeft < j)
quicksort(pLeft, j);
if (i < pRight)
quicksort(i, pRight);
} else {
if (pLeft < j) {
count.getAndAdd(1);
pool.execute(new QuicksortRunnable<T>(values, pLeft, j, count));
}
if (i < pRight) {
count.getAndAdd(1);
pool.execute(new QuicksortRunnable<T>(values, i, pRight, count));
}
}
}
}
~~~
My main function:
public static void main(String[] arg) {
Random rand = new Random();
int length = 1000;
int[] toSort = new int[length];
for(int i = 0; i<length; i++){
toSort[i] = rand.nextInt(length);
}
sort(toSort);
boolean sortedFH = true;
boolean sortedSH = true;
for(int i = 0; i<length/2; i++) {
if (toSort[i] < toSort[i + 1]) {
sortedFH = false;
}
}
for(int i = length/2; i<length-1; i++) {
if (toSort[i] < toSort[i + 1]) {
sortedSH = false;
}
}
System.out.println();
System.out.println("First half :" + sortedFH);
System.out.println("Second half :" + sortedSH);
}
}
Returns:
First half :false
Second half :true
EDIT: Removed a part of the program. I tried something, didn't work, forgot to remove it when posting the question.
Firstly I think the results you are seeing are mainly because you are printing out the results before the sorting threads have finished. You need to wait for all the threads to complete before you check the results.
Based on your code, you can do this easily enough using your AtomicInteger count to block the sort() returning until all the threads have finished.
public static <T extends Comparable<T>> void sort(int[] numberArray) {
if (numberArray == null || numberArray.length == 0) {
return;
}
final AtomicInteger count = new AtomicInteger(1);
pool.execute(new QuicksortRunnable<T>(numberArray, 0, numberArray.length - 1, count));
while (count.get() > 0) {
synchronized (count) {
count.wait();
}
}
}
As an aside, unless it is intentional, your algorithm looks like it is going to sort the array in descending order. I think you need to flip
while (values[i] > pivot) {
i++;
}
while (values[j] < pivot) {
j--;
}
to
while (values[i] < pivot) {
i++;
}
while (values[j] > pivot) {
j--;
}
The same applies to your checks at the end of the main method.
Your check on a null or empty array should be separated by an OR not an AND
if (numberArray == null || numberArray.length == 0) {
return;
}
I am trying to insert in a maxHeap in java and then bubble up the object. This is what I have done, I am not sure how I should approach the bubble up method.
I do understand the algorithm behind bubble up, which is as follows:
get parent node
see if L_childNode is less than parent Node. If Yes, then swap parent with L_child.
see if R_childNode is less than parent Node. If Yes, then swap parent with L_child.
Please point out what am I doing wrong?
private int getLeftChild(int n){
return x*2+1;
}
private int getRightChild(int n){
return x*2+2;
}
public void insert (E item) {
//Integer pos_lastEl= new Integer (heapArray.lastElement());
heapArray.add(item);
bubbleUp(item);
}
//To use to reheap up when item inserted at end of heap (complete tree)
private void bubbleUp(E x){
int place = heapArray.size()-1;
int parent=(place-1)/2;
if ((parent>=0) && (parent.compareTo(heapArray.get(getLeftChild))<0)){
swap(place,parent);
}else ((parent>=0 && (parent.compareTo(heapArray.get(getRightChild))<0))){
swap(place,parent);
}
}
//swaps two objects at index i and j
private void swap(int i, int j){
int max=heapArray.size();
if(i>=0 && i<max && j>=0 && j<max){
E temp=heapArray.get(i);
//put J item in I
heapArray.set(i,heapArray.get(j));
heapArray.set(j,temp);
}
}
Your major problem is using if instead of while to bubble up the newly added element to the proper position.
And there are also some other issues in your code, sorry I had to do some refactoring to make it clean enough:
public class MaxHeapTest<E extends Comparable<E>> {
List<E> heapArray = new ArrayList<>();
public static void main(String... args) {
int N = 13;
MaxHeapTest<Integer> maxHeap = new MaxHeapTest();
for (int i = 0; i < N; ++i) { // ascending;
maxHeap.insert(i);
}
while (!maxHeap.isEmpty()) { // descending now;
System.out.print(maxHeap.delMax() + " ");
}
}
public E delMax() {
E e = heapArray.get(0);
swap(0, heapArray.size() - 1);
heapArray.remove(heapArray.size() - 1);
sinkDown(0);
return e;
}
public void insert(E item) {
heapArray.add(item);
bubbleUp(item);
}
public boolean isEmpty() {
return heapArray.isEmpty();
}
private void bubbleUp(E x) {
int k = heapArray.indexOf(x);
int j = (k - 1) / 2;
while (j >= 0) {
if (heapArray.get(j).compareTo(heapArray.get(k)) < 0) {
swap(k, j);
k = j;
j = (j - 1) / 2;
} else break;
}
}
private void sinkDown(int k) {
int j = 2 * k + 1;
while (j < heapArray.size()) {
if (j < heapArray.size() - 1 && heapArray.get(j).compareTo(heapArray.get(j + 1)) < 0) j++;
if (heapArray.get(k).compareTo(heapArray.get(j)) < 0) {
swap(k, j);
k = j;
j = 2 * j + 1;
} else break;
}
}
private void swap(int i, int j) {
E temp = heapArray.get(i);
heapArray.set(i, heapArray.get(j));
heapArray.set(j, temp);
}
}
After the maxHeap, we can easily output the descending numbers as:
12 11 10 9 8 7 6 5 4 3 2 1 0
Hi all for an assignment we must count the number of comparisons for a number of algorithms. I'm using the code in the book "Algorithms" by Sedgewick & Wayne. I don't see where my code is wrong actually... As soon we going to compare something I count my comparison...
public long sort(Comparable[] a) {
if (a == null) {
throw new IllegalArgumentException("argument 'array' must not be null.");
}
int N = a.length;
for (int i = 0; i < N; i++) {
for (int j = i; j > 0; j--) {
this.comparisons++;
if(less(a[j], a[j-1]))
exch(a, j, j-1);
}
assert isSorted(a, 0, i);
}
assert isSorted(a);
return this.comparisons;
}
the less method which I use:
private boolean less(Comparable v, Comparable w) {
return (v.compareTo(w) < 0);
}
It must pass this test
Integer[] array = {4, 2, 1, 3, -1};
Comparable[] arrayClone1 = array.clone();
Comparable[] arrayClone2 = array.clone();
long nbCompares1 = i.sort(arrayClone1);
long nbCompares2 = i.sort(arrayClone2);
System.out.println("1" + nbCompares1);
System.out.println("2" + nbCompares2);
those two should be equal....
The isSorted methods:
private boolean isSorted(Comparable[] a) {
System.out.println("here");
return isSorted(a, 0, a.length - 1);
}
// is the array sorted from a[lo] to a[hi]
private boolean isSorted(Comparable[] a, int lo, int hi) {
System.out.println("here1");
for (int i = lo + 1; i <= hi; i++)
if (less(a[i], a[i-1])) return false;
return true;
}
Someone ideas about this? Help will be appreciated!
Number of comparisons should be exactly N*(N-1)/2. Maybe you mess with comparisons field in somewhere else, so I would advise to use local variable instead:
public long sort(Comparable[] a) {
if (a == null) {
throw new IllegalArgumentException("argument 'array' must not be null.");
}
int N = a.length;
int comparisonsCount = 0; // use this instead
for (int i = 0; i < N; i++) {
for (int j = i; j > 0; j--) {
comparisonsCount++; // edit here
if(less(a[j], a[j-1]))
exch(a, j, j-1);
}
assert isSorted(a, 0, i);
}
assert isSorted(a);
return comparisonsCount; // and here
}
There's a mergeSort code that I copied at class lesson, can you help me to find the errors?
When I run the main that use mergeSort the program enters in an infinite loop but doesn't display any error. I tried to run in debug mode but I am not very expert and I don't find what's wrong. However I think that the error is in mergeSort(int[] v, int inf, int sup) recursion.
public class CopyOfSortMethods {
private static void merge(int[] v, int inf, int med, int sup) {
int aux[] = new int[v.length];
int i = inf;
int j = med + 1;
int k = inf;
while ((i <= med) && (j <= sup)) {
if (v[i] < v[j]) {
aux[k] = v[i];
i++;
k++;
} else {
aux[k] = v[j];
j++;
k++;
}
}
while (i <= med) {
aux[k] = v[i];
i++;
k++;
}
while (j <= sup) {
aux[k] = v[j];
j++;
k++;
}
for (i = 0; i <= sup; i++) {
v[i] = aux[i];
}
}
public static void mergeSort(int[] v, int inf, int sup) {
int med;
while (inf < sup){
med = (inf + sup)/2;
mergeSort(v, inf, med);
mergeSort(v, med + 1, sup);
merge(v, inf, med, sup);
}
}
public static void mergeSort(int[] v) {
if(v!=null) {
mergeSort(v, 0, v.length - 1);
}
}
}
As Maverik points out, the issue is the while loop in mergeSort().
inf and sup are never modified, so inf is always less than sup. The loop never terminates.
The problems in your merge sort (based in the comments):
In mergeSort method, you're recursively calling the mergeSort inside a while loop and never changing the values of inf and sup. Change this for an if instead.
if (inf < sup) {
//code goes here...
}
In your merge sort, at the bottom of the method body, you're moving the items all the items from aux array to v array. You should only move the elements between inf and sup:
//for (i = 0; i <= sup; i++) {
for (i = inf; i <= sup; i++) {
//code goes here...
}