I have some problems with my HeapSort implementation. For imstance, I don't know how to fix my IndexOutOfBoundsExcpetion. I have not only the HeapSort class in the file, but also the MinHeap class. Tell me if I should add the part of the other file, where the main method is. I use a counter in order to count the key comparisons. Because I was asked to, I add the main method at the bottom.
public class HeapSort {
int[] heap;
int size;
int count;
public HeapSort(int[] arr, int n, int counter) {
this.heap = arr;
this.size = n;
this.count = counter;
}
public int[] buildHeap(int[] arr) {
int[] build = new int[size];
for (int i = 0; i < size; ++i) {
build[i] = arr[i];
if (!MinHeap.isHeap(build)) {
int[] newBuild = new int[build.length];
newBuild = MinHeap.restoreHeap(i);
build = newBuild;
count();
}
}
return build;
}
//arr is already a Heap
public int[] sort(int[] arr) {
int[] sorted = new int[size];
int val = size;
for (int i = 0; size > 0; ++i) {
int[] newArr = new int[--size];
for (int j = 1; j < size; ++j) newArr[j - 1] = arr[j];
arr = newArr;
sorted[i] = MinHeap.pop();
MinHeap.restoreHeap(0);
count();
}
size = val;
return sorted;
}
public void count() {
++count;
}
#Override
public String toString() {
int arr[] = buildHeap(heap);
int[] array = sort(arr);
String str = "[";
for (int i = 0; i < size - 1; ++i) str += array[i] + ", ";
return str += array[size - 1] + "]";
}
}
class MinHeap {
static int[] heap;
static int size = 0;
public MinHeap() {
heap = new int[size];
}
static int[] restoreHeap(int index) {
// TODO Auto-generated method stub
int v; // current node
int l; // child child
int r; //right child
while (2 * index + 1 < size) {
v = heap[2 * index];
l = heap[2 * index + 1];
if (2 * index + 2 < size) r = heap[2 * index + 2];
else r = 0;
if (compare(l, v) || compare(r, v)) {
//Swap with left child
if (compare(l, r)) {
swap(index, index * 2 + 1);
index = index * 2 + 1;
}
//Swap with right child
else if (compare(r, l)) {
swap(index, index * 2 + 2);
index = index * 2 + 2;
}
}
else break;
}
return heap;
}
static void swap(int v1, int v2) {
int tmp = v1;
v1 = v2;
v2 = tmp;
}
//Remove the first element
static int pop() {
int min = heap[0];
heap[0] = heap[--size];
heap = restoreHeap(0);
return min;
}
static boolean compare(int left, int right) {
return left < right;
}
static boolean isHeap(int[] arr) {
// TODO Auto-generated method stub
int v = 0;
while (2 * v + 1 < size) {
if (2 * v + 2 < size) {
if (arr[v] > arr[2 * v + 1] || arr[v] > arr[2 * v + 2]) return false;
} else if (arr[v] > arr[2 * v + 1]) return false;
v *= 2;
}
return true;
}
static boolean isEmpty() {
return size == 0;
}
}
Main method (in another file):
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[] arr = new int[n];
for (int i = 0; i < n; ++i) arr[i] = scanner.nextInt();
int[] sort = sorted.sort(arr);
HeapSort sortHeap = new HeapSort(arr, n, 0);
int[] toSort = sortHeap.buildHeap(arr);
sort = sortHeap.sort(toSort);
int count = sortHeap.count;
if (count != 1) System.out.print("Heap Sort needed " + count + " key
comparisons for sorting the array to: ");
else System.out.print("Heap Sort needed " + count + " key comparison for
sorting the array to: ");
System.out.println(sortHeap.toString());
scanner.close();
}
}
Related
I'm confused on why tim sort which makes my suffix array implement O(nlognlogn) faster than LSD radix sort which should make the implementation O(nlogn). Perhaps is it that radix sort simply works better with larger string lengths?
here is my radix sort implementation in java and I don't know if I'm just not making it as efficient as it could be:
class Suffix {
int index;
int[] rank = new int[2];
public Suffix(int i, int r1, int r2){
index = i;
rank[0] = r1;
rank[1] = r2;
}
}
public class Main {
public static int getMax(Suffix[] suffixArray, int index){
int max = Integer.MIN_VALUE;
for(Suffix i : suffixArray){
if(i.rank[index] > max)max = i.rank[index];
}
return max;
}
public static void countingSort(Suffix[] suffixes, int exp, int index){
int[] count = new int[10];
Suffix[] sorted = new Suffix[suffixes.length];
for(Suffix i : suffixes)count[(i.rank[index]/exp) % 10]++;
for(int i = 1; i < 10; i++)count[i] += count[i - 1];
for(int i = suffixes.length - 1; i >= 0; i--){
Suffix current = suffixes[i];
int position = count[(current.rank[index]/exp) % 10] - 1;
sorted[position] = current;
count[(current.rank[index]/exp) % 10]--;
}
for(int i = 0; i < suffixes.length; i++)suffixes[i] = sorted[i];
}
public static void radixSort(Suffix[] suffixes, int index){
int max = getMax(suffixes, index);
for(int exp = 1; max/exp > 0; exp *= 10)countingSort(suffixes, exp, index);
}
public static void sort(Suffix[] suffixes){
int positiveCounter = 0;
for(Suffix i : suffixes){
if(i.rank[1] >= 0)positiveCounter++;
}
Suffix[] positives = new Suffix[positiveCounter];
int positivesIndex = 0;
int tempIndex = 0;
for(Suffix i : suffixes){
if( i.rank[1] >= 0){
positives[positivesIndex] = i;
positivesIndex++;
}
else {
suffixes[tempIndex] = i;
tempIndex++;
}
}
radixSort(positives, 1);
for(int i = 0; i < positives.length; i++){
suffixes[tempIndex] = positives[i];
tempIndex++;
}
radixSort(suffixes, 0);
}
You are given an array A of integers and an integer k. Implement an algorithm that determines, in linear time, the smallest integer that appears at least k times in A.
I have been struggling with this problem for awhile, coding in Java, I need to use a HashTable to find the smallest integer that appears at least k times, it also must be in linear time.
This is what I attempted but it does not pass any of the tests
private static int problem1(int[] arr, int k)
{
// Implement me!
HashMap<Integer, Integer> table = new HashMap<Integer, Integer>();
int ans = Integer.MAX_VALUE;
for (int i=0; i < arr.length; i++) {
if(table.containsKey(arr[i])) {
table.put(arr[i], table.get(arr[i]) + 1);
if (k <= table.get(arr[i])) {
ans = Math.min(ans, arr[i]);
}
}else{
table.put(arr[i], 1);
}
}
return ans;
}
Here is the empty code with all of the test cases:
import java.io.*;
import java.util.*;
public class Lab5
{
/**
* Problem 1: Find the smallest integer that appears at least k times.
*/
private static int problem1(int[] arr, int k)
{
// Implement me!
return 0;
}
/**
* Problem 2: Find two distinct indices i and j such that A[i] = A[j] and |i - j| <= k.
*/
private static int[] problem2(int[] arr, int k)
{
// Implement me!
int i = -1;
int j = -1;
return new int[] { i, j };
}
// ---------------------------------------------------------------------
// Do not change any of the code below!
private static final int LabNo = 5;
private static final String quarter = "Fall 2020";
private static final Random rng = new Random(123456);
private static boolean testProblem1(int[][] testCase)
{
int[] arr = testCase[0];
int k = testCase[1][0];
int answer = problem1(arr.clone(), k);
Arrays.sort(arr);
for (int i = 0, j = 0; i < arr.length; i = j)
{
for (; j < arr.length && arr[i] == arr[j]; j++) { }
if (j - i >= k)
{
return answer == arr[i];
}
}
return false; // Will never happen.
}
private static boolean testProblem2(int[][] testCase)
{
int[] arr = testCase[0];
int k = testCase[1][0];
int[] answer = problem2(arr.clone(), k);
if (answer == null || answer.length != 2)
{
return false;
}
Arrays.sort(answer);
// Check answer
int i = answer[0];
int j = answer[1];
return i != j
&& j - i <= k
&& i >= 0
&& j < arr.length
&& arr[i] == arr[j];
}
public static void main(String args[])
{
System.out.println("CS 302 -- " + quarter + " -- Lab " + LabNo);
testProblems(1);
testProblems(2);
}
private static void testProblems(int prob)
{
int noOfLines = prob == 1 ? 100000 : 500000;
System.out.println("-- -- -- -- --");
System.out.println(noOfLines + " test cases for problem " + prob + ".");
boolean passedAll = true;
for (int i = 1; i <= noOfLines; i++)
{
int[][] testCase = null;
boolean passed = false;
boolean exce = false;
try
{
switch (prob)
{
case 1:
testCase = createProblem1(i);
passed = testProblem1(testCase);
break;
case 2:
testCase = createProblem2(i);
passed = testProblem2(testCase);
break;
}
}
catch (Exception ex)
{
passed = false;
exce = true;
}
if (!passed)
{
System.out.println("Test " + i + " failed!" + (exce ? " (Exception)" : ""));
passedAll = false;
break;
}
}
if (passedAll)
{
System.out.println("All test passed.");
}
}
private static int[][] createProblem1(int testNo)
{
int size = rng.nextInt(Math.min(1000, testNo)) + 5;
int[] numbers = getRandomNumbers(size, size);
Arrays.sort(numbers);
int maxK = 0;
for (int i = 0, j = 0; i < size; i = j)
{
for (; j < size && numbers[i] == numbers[j]; j++) { }
maxK = Math.max(maxK, j - i);
}
int k = rng.nextInt(maxK) + 1;
shuffle(numbers);
return new int[][] { numbers, new int[] { k } };
}
private static int[][] createProblem2(int testNo)
{
int size = rng.nextInt(Math.min(1000, testNo)) + 5;
int[] numbers = getRandomNumbers(size, size);
int i = rng.nextInt(size);
int j = rng.nextInt(size - 1);
if (i <= j) j++;
numbers[i] = numbers[j];
return new int[][] { numbers, new int[] { Math.abs(i - j) } };
}
private static void shuffle(int[] arr)
{
for (int i = 0; i < arr.length - 1; i++)
{
int rndInd = rng.nextInt(arr.length - i) + i;
int tmp = arr[i];
arr[i] = arr[rndInd];
arr[rndInd] = tmp;
}
}
private static int[] getRandomNumbers(int range, int size)
{
int numbers[] = new int[size];
for (int i = 0; i < size; i++)
{
numbers[i] = rng.nextInt(2 * range) - range;
}
return numbers;
}
}
private static int problem1(int[] arr, int k) {
// Implement me!
Map<Integer, Integer> table = new TreeMap<Integer, Integer>();
for (int i = 0; i < arr.length; i++) {
if (table.containsKey(arr[i])) {
table.put(arr[i], table.get(arr[i]) + 1);
} else {
table.put(arr[i], 1);
}
}
for (Map.Entry<Integer,Integer> entry : table.entrySet()) {
//As treemap is sorted, we return the first key with value >=k.
if(entry.getValue()>=k)
return entry.getKey();
}
//Not found
return -1;
}
As others have pointed out, there are a few mistakes. First, the line where you initialize ans,
int ans = 0;
You should initialize ans to Integer.MAX_VALUE so that when you find an integer that appears at least k times for the first time that ans gets set to that integer appropriately. Second, in your for loop, there's no reason to skip the first element while iterating the array so i should be initialized to 0 instead of 1. Also, in that same line, you want to iterate through the entire array, and in your loop's condition right now you have i < k when k is not the length of the array. The length of the array is denoted by arr.length so the condition should instead be i < arr.length. Third, in this line,
if (k < table.get(arr[i])){
where you are trying to check if an integer has occurred at least k times in the array so far while iterating through the array, the < operator should be changed to <= since the keyword here is at least k times, not "more than k times". Fourth, k should never change so you can get rid of this line of code,
k = table.get(arr[i]);
After applying all of those changes, your function should look like this:
private static int problem1(int[] arr, int k)
{
// Implement me!
HashMap<Integer, Integer> table = new HashMap<Integer, Integer>();
int ans = Integer.MAX_VALUE;
for (int i=0; i < arr.length; i++) {
if(table.containsKey(arr[i])) {
table.put(arr[i], table.get(arr[i]) + 1);
if (k <= table.get(arr[i])) {
ans = Math.min(ans, arr[i]);
}
}else{
table.put(arr[i], 1);
}
}
return ans;
}
Pseudo code:
collect frequencies of each number in a Map<Integer, Integer> (number and its count)
set least to a large value
iterate over entries
ignore entry if its value is less than k
if entry key is less than current least, store it as least
return least
One line implementation:
private static int problem1(int[] arr, int k) {
return Arrays.stream(arr).boxed()
.collect(groupingBy(identity(), counting()))
.entrySet().stream()
.filter(entry -> entry.getValue() >= k)
.map(Map.Entry::getKey)
.reduce(MAX_VALUE, Math::min);
}
This was able to pass all the cases! Thank you to everyone who helped!!
private static int problem1(int[] arr, int k)
{
// Implement me!
HashMap<Integer, Integer> table = new HashMap<Integer, Integer>();
int ans = Integer.MAX_VALUE;
for (int i=0; i < arr.length; i++) {
if(table.containsKey(arr[i])) {
table.put(arr[i], table.get(arr[i]) + 1);
}else{
table.put(arr[i], 1);
}
}
Set<Integer> keys = table.keySet();
for(int i : keys){
if(table.get(i) >= k){
ans = Math.min(ans,i);
}
}
if(ans != Integer.MAX_VALUE){
return ans;
}else{
return 0;
}
}
I'm trying to implement a heapsort on an array of objects which has already been created. It is meant to be sorted according to their eventTime attribute, yet each eventTime attribute is set to the same as the others by the time the queue is sorted. Is there any way to fix this so that it creates a 'priorityqueue' in ascending order?
Main:
public static void main(String[] args) {
CustomerQueue cQ = new CustomerQueue(0, 0, false);
for (int i = 0; i < 10; i++) {
CustomerQueue cQ1 = new CustomerQueue(0, 0, false);
cQ.enqueue(cQ1);
System.out.println(cQ1.arrivalTime);
}
System.out.print("\n");
PriorityQueue pQ = new PriorityQueue(0, 0, 0, false);
while (!cQ.isEmpty()) {
for (CustomerQueue c : cQ.array) {
PriorityQueue pQ1 = new PriorityQueue(0, 0, 0, false);
pQ1.eventTime = c.arrivalTime;
pQ.enqueue(pQ1);
System.out.println(pQ1.eventTime);
cQ.dequeue();
}
}
pQ.sort(pQ.array);
System.out.println(Arrays.toString(pQ.array));
}
PriorityQueue:
class PriorityQueue {
PriorityQueue array[] = new PriorityQueue[10];
private int front;
private int rear;
private int count;
private int eventType;
double eventTime;
private double tallyTime;
private boolean paymentMethod;
public PriorityQueue(int evT, int eT, double tT, boolean pM) {
this.eventType = evT;
this.eventTime = eT;
this.tallyTime = tT;
this.paymentMethod = pM;
front = 0;
rear = -1;
count = 0;
}
public void enqueue(PriorityQueue pQ) {
if (isFull()) {
System.out.println("OverFlow\nProgram Terminated");
System.exit(1);
}
rear = (rear + 1);
array[rear] = pQ;
count++;
}
public void sort(PriorityQueue arr[]) {
int n = arr.length;
// Build heap (rearrange array)
for (int i = n / 2 - 1; i >= 0; i--) {
heapify(arr, n, i);
}
// One by one extract an element from heap
for (int i = n - 1; i >= 0; i--) {
// Move current root to end
int temp = (int) arr[0].eventTime;
arr[0] = arr[i];
arr[i].eventTime = temp;
// call max heapify on the reduced heap
heapify(arr, i, 0);
}
}
void heapify(PriorityQueue arr[], int n, int i) {
int largest = i; // Initialize largest as root
int l = 2 * i + 1; // left = 2*i + 1
int r = 2 * i + 2; // right = 2*i + 2
// If left child is larger than root
if (l < n && arr[l].eventTime > arr[largest].eventTime) {
largest = l;
}
// If right child is larger than largest so far
if (r < n && arr[r].eventTime > arr[largest].eventTime) {
largest = r;
}
// If largest is not root
if (largest != i) {
int swap = (int) arr[i].eventTime;
arr[i] = arr[largest];
arr[largest].eventTime = swap;
// Recursively heapify the affected sub-tree
heapify(arr, n, largest);
}
}
public void dequeue() {
if (isEmpty()) {
System.out.println("UnderFlow\nProgram Terminated");
System.exit(1);
}
front = (front + 1) % array.length;
count--;
}
public boolean isEmpty() {
return (size() == 0);
}
public int size() {
return count;
}
public boolean isFull() {
return (size() == array.length);
}
public PriorityQueue peek() {
if (isEmpty()) {
System.out.println("UnderFlow\nProgram Terminated");
System.exit(1);
}
return array[front];
}
#Override
public String toString() {
return eventType + " " + eventTime + " " + tallyTime + " " + paymentMethod;
}
}
I see two parts which are most likely wrong and the cause of your issue:
In the heapify method you have:
int swap = (int) arr[i].eventTime;
arr[i] = arr[largest];
arr[largest].eventTime = swap;
And in the sort method you have:
int temp = (int) arr[0].eventTime;
arr[0] = arr[i];
arr[i].eventTime = temp;
Assuming you want to switch the CustomerQueue objects around inside the array, they should be this instead:
// In the heapify:
CustomerQueue swap = arr[i];
arr[i] = arr[largest];
arr[largest] = swap;
// In the sort:
CustomerQueue temp = arr[0];
arr[0] = arr[i];
arr[i] = temp;
What your code currently does in pseudo-code is this:
CustomerQueue ith has for example name = "I", eventTime = 1
CustomerQueue largest has for example name = "largest", eventTime = 2
int temp = (int) arr[i].eventTime; // temp is now 1
arr[i] = arr[largest]; // Both arr[i] AND arr[largest] are now CustomerQueue largest (with name = "largest" and eventTime = 2)
arr[i].eventTime = temp; // Both arr[i] AND arr[largest] are now changed to eventTime temp (which is 1)
So now both arr[i] and arr[largest] will hold: name = "largest" and eventTime = 1, as well as referencing the same CustomerQueue-instance.
The purpose of this project is to create two arrays of random numbers and run a quick sort and heap sort of them. Keep track of the number of comparison's and then compare them. Both sorts work, but my heap sort wont keep track of the comparison's. it just says 0. My quick sort works and puts the comparisons in an array. How do i fix this?
package sorting;
import java.util.Arrays;
//import java.util.Random;
import java.util.*;
public class project2
{
static int [] heap_sort_comparison = new int[21];
static int [] quick_sort_comparison = new int[21];
static int [] array1 = new int [20];
static int [] array2 = new int [20];
static int compares = 0;
static int heap_compares = 0;
private static void quickSort(int[] array1, int l, int h) {
if(l < h ) {
compares++;
int position = partition(array1, l, h);
quickSort(array1,l, position -1);
quickSort(array1, position +1, h);
}
}
private static int partition(int[] array1, int i, int j) {
int pivot = array1[j] -1;
int small = i -1;
for(int k = i; k < j; k++) {
if(array1[k] <= pivot) {
compares++;
small++;
swap(array1, k, small);
}
}
swap(array1, j, small + 1);
//System.out.println("Pivot = " + array1[small + 1]);
print_quick_sort(array1);
return small + 1;
}
public static void swap(int[] array1, int a, int b) {
int temp;
temp = array1[a];
array1[a] = array1[b];
array1[b] = temp;
}
public static void print_quick_sort(int[] array1) {
for(int i = 0; i < array1.length; i++) {
System.out.print(array1[i] + " ");
}
System.out.println();
}
//HEAP SORT
public void build(int array2[]) {
int length = array2.length;
for(int i = length/2-2; i >=0; i--) {
bubble_down(array2, i, array2.length-1);
heap_compares++;
}
for(int i = length-1; i>= 0; i--) {
swap2(array2, 0,i);
bubble_down(array2,i,0);
heap_compares++;
}
}
void bubble_down(int[] array2, int parent, int size) {
int left = parent*2+1;
int right = 2*parent+2;
int largest = 0;
if(left <= size && array2[left] > array2[largest]) {
largest = left;
heap_compares++;
}
if(right <= size && array2[right] > array2[largest]) {
largest = right;
heap_compares++;
}
if(largest != parent) {
swap2(array2,parent, largest);
bubble_down(array2,largest,size);
heap_compares++;
}
}
public static void swap2(int[] array2, int a, int b) {
int temp = array2[a];
array2[a] = array2[b];
array2[b] = temp;
}
public static void print_heap_sort(int[] array2) {
for(int i = 0; i < array2.length; i++) {
System.out.print(array2[i] + " ");
}
System.out.println();
}
public static void main(String[] args) {
for(int x = 0; x < 20; x++) {
for(int y = 0; y < 20; y++) {
for(int i = 0; i < array1.length; i++) {
array1[i] = array2[i]= (int)(Math.random()*20 + 0);
}
System.out.println("Numbers Generated in Array 1: " + Arrays.toString(array1));
System.out.println("");
System.out.println("Numbers Generated in Array 2: " + Arrays.toString(array2));
System.out.println("");
//quickSort
print_quick_sort(array1);
quickSort(array1, 0, array1.length -1);
System.out.println("The number of comparisons in quick sort: "+ compares);
System.out.println("=============================");
quick_sort_comparison[x] = compares;
compares = 0;
System.out.println("Array of quick sort comparison's: ");
System.out.println(Arrays.toString(quick_sort_comparison));
System.out.println("=============================");
//Heap Sort
System.out.println("Before Heap Sort: ");
System.out.println(Arrays.toString(array2));
heap_sort_comparison[y] = heap_compares;
heap_compares = 0;
HeapSort ob = new HeapSort();
ob.sort(array2);
System.out.println("Sorted array is (heap Sort): ");
print_heap_sort(array2);
System.out.println("=============================");
System.out.println("Array of heap sort comparison's: " + heap_compares);
System.out.println(Arrays.toString(heap_sort_comparison));
}
}
}
}
You do not even call the HeapSort method that you've built.
look here...
HeapSort ob = new HeapSort();
ob.sort(array2);
I think you are trying to use a built in sorting method from HeapSort class, So how do you think the counter heap_compares will increase!
I have a simple rotation function which takes an array and a number to rotate the numbers left
e.g. [1,2,3,4,5] & 2 - output: [3,4,5,1,2].
I want to know the most efficient way of completing this function, whether it would be to convert the int array into a string a splice it or whether to copy the array or to convert to an List<Integer>.
If anyone wants additional information please ask!
my solution at the moment:
static int[] rotLeft(int[] a, int d) {
int lengthOfArray = a.length;
int[] temp = new int[lengthOfArray];
for(int i = 0; i < lengthOfArray; i++){
int newLocation = (i + (lengthOfArray - d)) % lengthOfArray;
temp[newLocation] = a[i];
}
return temp;
}
Simple way to do it with O(n) complexity is as below along with handling of valid shifts int[] arr: is an int array, n=length of an array, d=how many shifts required.
public int[] leftRotate(int[] arr, int n, int d) {
int rot = 0;
int[] marr = new int[n];
if (d < 0 || d == 0 || d>n) {
return arr;
}
else {
for (int i = 0; i < n; i++) {
if (i < n - d) {
marr[i] = arr[i + d];
} else {
marr[i] = arr[rot];
rot++;
}
}
return marr;
}
}
public void GetArray(int[] arr, int n, int d) {
int[] arr1 = leftRotate(arr, n, d);
for (int j : arr1) {
System.out.println(j);
}
}
public static void main(String args[]) {
int[] arr = { 1,2,3,4,5 };
int n = arr.length;
Test2 obj = new Test2();
obj.GetArray(arr, n, 2);
}
Why don't you try this one
void Rotate(int arr[], int d, int n)
{
for (int i = 0; i < d; i++)
leftRotatebyOne(arr, n);
}
void leftRotatebyOne(int arr[], int n)
{
int i, temp;
temp = arr[0];
for (i = 0; i < n - 1; i++)
arr[i] = arr[i + 1];
arr[i] = temp;
}
and to call this invoke method like below
int arr[] = { 1, 2, 3, 4, 5 };
Rotate(arr, 2, 5);