Binary Search Symbol Table implementation going inside infinite loop - algorithm

I am trying to implement 'Binary Search in an ordered array' from the book 'Algorithms (fourth edition) by Robert Sedgewick & Kevin Wayne' (on page 381). However my code is going inside infinite loop. Please help. Below is the code:
public class BinarySearchST<Key extends Comparable<Key>, Value>{
private Key keys[];
private Value values[];
private int N;
public BinarySearchST(int capacity){
keys = (Key[]) new Comparable[capacity];
values = (Value[]) new Object[capacity];
}
public int size(){
return N;
}
public boolean isEmpty(){
return N == 0;
}
public int rank(Key key){
int lo = 0, hi = N-1;
while(lo <= hi){
int mid = (lo + (hi - lo))/2;
int comp = key.compareTo(keys[mid]);
if(comp < 0) hi = mid - 1;
else if(comp > 0) lo = mid + 1;
else return mid;
}
return lo;
}
public Value get(Key key){
if(isEmpty()) return null;
int rank = rank(key);
if(rank < N && key.compareTo(keys[rank]) == 0)
return values[rank];
else
return null;
}
public void put(Key key, Value value){
int rank = rank(key);
if(rank < N && key.compareTo(keys[rank]) == 0){//key already existing, just update value.
values[rank] = value;
return;
}
for(int i = N; i > rank; i--){
keys[i] = keys[i-1]; values[i] = values[i-1];
}
keys[rank] = key;
values[rank] = value;
N++;
}
public static void main(String[] args){
BinarySearchST<String, Integer> st = new BinarySearchST<String, Integer>(10);
st.put("A", 10);
st.put("B", 100);
st.put("C", 1000);
StdOut.println(st.get("A"));
}
}
This appears to be correct to me, but looks like some issue inside put() for loop.

use int mid = (lo + hi)/2.
You are using int mid = (lo+(hi-lo))/2 which reduces to hi/2. So, eventually your middle will be less than your lo and will not converge causing infinite loop.

Related

What is correct solution for this (Benny and Segments) question on Hackerearth?

How do i correctly solve this question Benny and Segments. The solution given for this question is not correct . According to editorial for this question, following is a correct solution.
import java.io.*; import java.util.*;
class Pair{
int a; int b;
public Pair(int a , int b){ this.a = a; this.b = b;}
}
class TestClass {
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static StringTokenizer st;
static void rl() throws Exception{st = new StringTokenizer(br.readLine());}
static int pInt() {return Integer.parseInt(st.nextToken());}
public static void main(String args[] ) throws Exception {
rl();
int T = pInt();
while(T-- > 0){
rl();
int N = pInt();
int L = pInt();
Pair[] p = new Pair[N];
for(int i = 0; i < N; i++){
rl();
int l = pInt();
int r = pInt();
p[i] = new Pair(l, r);
}
Arrays.sort(p, new Comparator<Pair>(){
#Override
public int compare(Pair o1, Pair o2)
{
return o1.a - o2.a;
}
});
boolean possible = false;
for(int i = 0; i < N; i++){
int start = p[i].a;
int curr_max = p[i].b;
int req_max = p[i].a + L;
for(int j = 0; j < N; j++){
if(p[i].a <= p[j].a && p[j].b <= req_max){
curr_max = Math.max(curr_max, p[j].b);
}
}
if(curr_max == req_max ){
System.out.println("Yes");
possible = true;
break;
}
}
if(!possible)
System.out.println("No");
}
}
}
But this will certainly fail for the following testcase. It will give "Yes" when it should have given "No", Because there is no continuous path of length 3.
1
3 3
1 2
3 4
4 5
As suggested by kcsquared. I modified my code.
It runs correctly. I think Question setters had set weak test case for this question.
As your test-case demonstrates, the error is that when adding new segments to extend the current segment, there's no test to check whether the new segment can reach the current segment or would leave a gap. To do so, compare the new segment's left end to your current segment's right end:
for(int j = i + 1; j < N; j++){
if(p[j].a <= curr_max && p[j].b <= req_max){
curr_max = Math.max(curr_max, p[j].b);
}
}

Can we have an if loop for the root section of Quick Union algorithm?

In the Quick Union algorithm imlementation below, inside the root method can we have an if loop (such as if(i != id[i]) instead of the while loop? I think it works just as well. Then why did they use the while loop?
public class QuickUnionUF {
private int []id;
public QuickUnionUF(int N){
id = new int[N];
for(int i=0; i<N; i++) id[i] = i;
}
private int root(int i){
while(i != id[i]) i = id[i];
return i;
}
public boolean connected(int p, int q){
return root(p) == root(q);
}
public void union(int p, int q){
int i = root(p);
int j = root(q);
id[i] = j;
}
}
A component may be represented by a tree higher than one level. To get the component id you need to go down all the way to the root. For example try
s = new QuickUnionUF(3);
s.union(0,1);
s.union(1,2);
System.out.println(s.connected(0,1)); // <== prints false when using 'if'

Optimizing quick sort

I am implementing quick sort algorithm in java and here is the code :
public class quickSort {
private int array[];
private int length;
public void sort(int[] inputArr) {
if (inputArr == null || inputArr.length == 0) {
return;
}
this.array = inputArr;
length = inputArr.length;
quickSorter(0, length - 1);
}
private void quickSorter(int lowerIndex, int higherIndex) {
int i = lowerIndex;
int j = higherIndex;
// calculate pivot number, I am taking pivot as middle index number
int pivot = array[lowerIndex+(higherIndex-lowerIndex)/2];
// Divide into two arrays
while (i <= j) {
while (array[i] < pivot) {
i++;
}
while (array[j] > pivot) {
j--;
}
if (i <= j) {
exchangeNumbers(i, j);
//move index to next position on both sides
i++;
j--;
}
}
// call quickSort() method recursively
if (lowerIndex < j)
quickSorter(lowerIndex, j);
if (i < higherIndex)
quickSorter(i, higherIndex);
}
private void exchangeNumbers(int i, int j) {
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
Then I implement it with (median of three)
public class quickSort {
private int array[];
private int length;
public void sort(int[] inputArr) {
if (inputArr == null || inputArr.length == 0) {
return;
}
this.array = inputArr;
length = inputArr.length;
quickSorter(0, length - 1);
}
private void quickSorter(int lowerIndex, int higherIndex) {
int i = lowerIndex;
int j = higherIndex;
int mid = lowerIndex+(higherIndex-lowerIndex)/2;
if (array[i]>array[mid]){
exchangeNumbers( i, mid);
}
if (array[i]>array[j]){
exchangeNumbers( i, j);
}
if (array[j]<array[mid]){
exchangeNumbers( j, mid);
}
int pivot = array[mid];
// Divide into two arrays
while (i <= j) {
while (array[i] < pivot) {
i++;
}
while (array[j] > pivot) {
j--;
}
if (i <= j) {
exchangeNumbers(i, j);
//move index to next position on both sides
i++;
j--;
}
}
// call quickSort() method recursively
if (lowerIndex < j)
quickSorter(lowerIndex, j);
if (i < higherIndex)
quickSorter(i, higherIndex);
}
private void exchangeNumbers(int i, int j) {
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
and the testing main :
public static void main(String[] args) {
File number = new File ("f.txt");
final int size = 10000000;
try{
quickSortOptimize opti = new quickSortOptimize();
quickSort s = new quickSort();
PrintWriter printWriter = new PrintWriter(number);
for (int i=0;i<size;i++){
printWriter.println((int)(Math.random()*100000));
}
printWriter.close();
Scanner in = new Scanner (number);
int [] arr1 = new int [size];
for (int i=0;i<size;i++){
arr1[i]=Integer.parseInt(in.nextLine());
}
long a=System.currentTimeMillis();
opti.sort(arr1);
long b=System.currentTimeMillis();
System.out.println("Optimaized quicksort: "+(double)(b-a)/1000);
in.close();
int [] arr2 = new int [size];
Scanner in2= new Scanner(number);
for (int i=0;i<size;i++){
arr2[i]=Integer.parseInt(in2.nextLine());
}
long c=System.currentTimeMillis();
s.sort(arr2);
long d=System.currentTimeMillis();
System.out.println("normal Quicksort: "+(double)(d-c)/1000);
}catch (Exception ex){ex.printStackTrace();}
}
The problem is that this method of optimization should improve performance by 5%
but, what happens actually is that I have done this test many times and almost always getting better result on normal quicksort that optimized one
so what is wrong with the second implementation
A median of three (or more) will usually be slower for input that's randomly ordered.
A median of three is intended to help prevent a really bad case from being quite as horrible. There are ways of making it pretty bad anyway, but at least avoids the problem for a few common orderings--e.g., selecting the first element as the pivot can produce terrible results if/when (most of) the input is already ordered.

unable to create second deck from same code for a queue

I have to set up a queue class that implements from a deque class. I need to use this to set up two deck cards with a random order. I have the code below, it works when the first deck is created but for some reason it does not work with the second deck, its the same code that im reusing.
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5
at prog.pkg4.Deque.insertOnBack(Prog4.java:93)
at prog.pkg4.Queue.insert(Prog4.java:153)
at prog.pkg4.Prog4.createDeck(Prog4.java:465)
at prog.pkg4.Prog4.topTrump(Prog4.java:444)
at prog.pkg4.Prog4.main(Prog4.java:287)
initiates the two decks
Queue player = new Queue();
Queue computer = new Queue();
player = createDeck(player, cards);
computer = createDeck(computer, cards);
code to create random deck
public static Queue createDeck(Queue queue, GreekHero[] cards){
Random rand = new Random();
int temp = 0;
int r;
for(int i = 0; i < 30; i++){
r = rand.nextInt(30);
cards[temp] = cards[i];
cards[i] = cards[r];
cards[r] = cards[temp];
}
for(int i = 0; i < 29; i++){
queue.insert(cards[i]);
System.out.println(queue.insertions());
System.out.println(queue);
}
return queue;
}
class Queue{
private Deque queue;
public Queue(){
queue = new Deque();
}
public void insert(Object o){
queue.insertOnBack(o);
}
public Object delete(){
return queue.deleteFromFront();
}
public boolean isEmpty(){
return queue.isEmpty();
}
public String toString(){
return queue.toString();
}
public int insertions(){
return queue.getInsertions();
}
}
i've tested out the deque code several times i know it works, as demonstrated by the first deck that is created, im just not sure what could be causing the problem for the second deck.
EDIT: I've added the Deque class code below, the way i have this set up is that if the number of insertions equals the size of the array, it should double in size, as mentioned before it works with the first deque but on the second deque it stops at size of array - 1. I've increased the size to test out and I could make it bigger to satisfy this project but I need to create a deque with an increasing array.
class Deque{
private Object[] arrayObject;
private int beggining; //tracks first element in array
private int insertions; //counts the items in the array
private static int SIZE = 30; //size of array
public Deque(){
arrayObject = new Object[SIZE];
beggining = 0;
insertions = 0;
}
// displays position of first element in circular array
public Object getBeggining(){
int temp = beggining + 1;
if(temp == SIZE)
temp = 0;
return temp;
}
public int getInsertions(){
return insertions;
}
public Object indexOne(){
int temp = beggining + 1;
if(temp == SIZE)
temp = 0;
return arrayObject[temp];
}
public String toString(){
if(isEmpty())
return "Empty";
int temp = beggining + 1;
if( temp >= SIZE)
temp = 0;
String s = "Current Index:\n[("+arrayObject[temp]+")";
int loops = 0;
for(int i = temp + 1; loops < insertions - 1; i++){
if(i >= SIZE)
i = 0;
s += ", ("+arrayObject[i]+")";
loops++;
}
s += "]";
return s;
}
public String toStore(){
String s = "Store Index:\n[(1: "+arrayObject[1]+")";
for(int i = 1; i <= SIZE - 1; i++)
s += ", ("+(i+1)+": "+arrayObject[i]+")";
s += "]";
return s;
}
public void insertOnFront(Object o){
if(insertions == SIZE)
arrayObject = increaseArray();
arrayObject[beggining] = o;
beggining--;
if(beggining < 0)
beggining = SIZE - 1;
insertions++;
}
public Object deleteFromFront(){
if(isEmpty())
return null;
int count = beggining + 1;
if(count >= SIZE)
count = 0;
Object temp = arrayObject[count];
beggining += 1;
insertions--;
if(insertions > 0)
insertions = 0;
return temp;
}
public void insertOnBack(Object o){
int temp = beggining + insertions + 1;
if(insertions == SIZE - 1)
arrayObject = increaseArray();
if(temp >= SIZE)
temp = 0 + (temp - SIZE);
arrayObject[temp] = o;
insertions++;
}
public Object deleteFromBack(){
if(isEmpty())
return null;
int count = beggining + insertions;
Object temp = arrayObject[count];
insertions--;
if(insertions >= 0)
insertions = 0;
return temp;
}
public boolean isEmpty(){
if(insertions > 0)
return false;
else
return true;
}
public Object[] increaseArray(){
SIZE *= 2;
int loops = 0;
int j = beggining;
Object[] newArray = new Object[SIZE];
for(int i = j; loops <= SIZE/2; i++){
if(j >= SIZE/2)
j = 0;
newArray[i] = arrayObject[j];
loops++;
j++;
}
return newArray;
}
}
I solved the issue by moving the SIZE variable as an instance variable of the class and removed static from it. I don't know why the issue popped in on the second iteration rather than on the first try, ill look it up later, if anyone knows please post it here.

MergeSort gives StackOverflow error

this is the code for the mergeSort,this gives an stackoverflow error in line 53 and 54(mergeSort(l,m); and mergeSort(m,h);)
Any help will be regarded so valuable,please help me out,i am clueless,Thank you.
package codejam;
public class vector {
static int[] a;
static int[] b;
public static void main(String[] args) {
int[] a1 = {12,33,2,1};
int[] b1 = {12,333,11,1};
mergeSort(0,a1.length);
a1=b1;
mergeSort(0,b1.length);
for (int i = 0; i < a1.length; i++) {
System.out.println(a[i]);
}
}
public static void merge(int l,int m,int h) {
int n1=m-l+1;
int n2 = h-m+1;
int[] left = new int[n1];
int[] right = new int[n2];
int k=l;
for (int i = 0; i < n1 ; i++) {
left[i] = a[k];
k++;
}
for (int i = 0; i < n2; i++) {
right[i] = a[k];
k++;
}
left[n1] = 100000000;
right[n1] = 10000000;
int i=0,j=0;
for ( k =l ; k < h; k++) {
if(left[i]>=right[j])
{
a[k] = right[j];
j++;
}
else
{
a[k] = left[i];
i++;
}
}
}
public static void mergeSort(int l,int h) {
int m =(l+h)/2;
if(l<h)
{
mergeSort(l,m);
mergeSort(m,h);
merge(l,m,h);;
}
}
}
Following is the recursive iterations table of the mergeSort function with argument l=0 and h=4
when the value of l is 0 and value of h is 1 , expression calculate m value which turn out to be 0 but we are checking condition with h which is still 1 so 0<1 become true , recursive calls of this mergeSort function forms a pattern , this pattern doesn't let the function to terminate , stack runs out of memory , cause stackoverflow error.
import java.lang.*;
import java.util.Random;
public class MergeSort {
public static int[] merge_sort(int[] arr, int low, int high ) {
if (low < high) {
int middle = low + (high-low)/2;
merge_sort(arr,low, middle);
merge_sort(arr,middle+1, high);
arr = merge (arr,low,middle, high);
}
return arr;
}
public static int[] merge(int[] arr, int low, int middle, int high) {
int[] helper = new int[arr.length];
for (int i = 0; i <=high; i++){
helper[i] = arr[i];
}
int i = low;
int j = middle+1;
int k = low;
while ( i <= middle && j <= high) {
if (helper[i] <= helper[j]) {
arr[k++] = helper[i++];
} else {
arr[k++] = helper[j++];
}
}
while ( i <= middle){
arr[k++] = helper[i++];
}
while ( j <= high){
arr[k++] = helper[j++];
}
return arr;
}
public static void printArray(int[] B) {
for (int i = 0; i < B.length ; i++) {
System.out.print(B[i] + " ");
}
System.out.println("");
}
public static int[] populateA(int[] B) {
for (int i = 0; i < B.length; i++) {
Random rand = new Random();
B[i] = rand.nextInt(20);
}
return B;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int A[] = new int[10];
A = populateA(A);
System.out.println("Before sorting");
printArray(A);
A = merge_sort(A,0, A.length -1);
System.out.println("Sorted Array");
printArray(A);
}
}

Resources