Polyphase29 Polyphase29 - 1 month ago 11
Java Question

Using a Comparator with sorts

I'm trying to create a small program to take an input 1-3 and sorts through a list of contacts using a different sorting algorithm depending on what the user selects. I've got all my code written, but I'm having an issue when I try to use my sorts. The program runs fine if I use Collections sort, but I need to use those three algorithms.

public class {

public static void main(String[] args) {

Contact[] contacts = {

};


int input;
do{
Scanner in = new Scanner(System.in);
System.out.println("Sort by last name: [0]");
System.out.println("Sort by first name: [1]");
System.out.println("Sort by age: [2]");
System.out.println("Enter an option or 0 to end input: ");
input = in.nextInt();

if(input == 0)
{
System.out.println("Exiting...");
System.exit(input);
}

else if(input == 1)
{
Merge.sort(contacts, new LastNameComparator());

for(Contact contact : contacts)
{
System.out.println(contact);
}
}

else if(input == 2)
{
Quick.sort(contacts, new FirstNameComparator());

for(Contact contact : contacts)
{
System.out.println(contact);
}
}

else if(input == 3)
{
Heap.sort(contacts, new AgeComparator());

for(Contact contact : contacts)
{
System.out.println(contact);
}
}

else if(input > 3 || input < 0)
{
System.out.println("Invalid entry");
}

} while (input != 0);
}


}

public class Contact implements Comparable{
import java.util.Comparator;

String lastName;
String firstName;
String homeState;
Integer age;

Contact(String lastName, String firstName, String homeState, Integer age)
{
this.lastName = lastName;
this.firstName = firstName;
this.homeState = homeState;
this.age = age;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getHomeState() {
return homeState;
}

public void setHomeState(String homeState) {
this.homeState = homeState;
}

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}

@Override
public String toString() {
return String.format("%8s %8s %7s, %7d", this.lastName, this.firstName, this.homeState, this.age);
}

class FirstNameComparator implements Comparator<Contact> {
public int compare(Contact a, Contact b) {
return a.firstName.compareToIgnoreCase(b.firstName);
}

class LastNameComparator implements Comparator<Contact>{
public int compare(Contact a, Contact b) {
return a.lastName.compareToIgnoreCase(b.lastName);
}

class AgeComparator implements Comparator<Contact> {
public int compare(Contact a, Contact b) {
return a.age < b.age ? -1 : a.age == b.age ? 0 : 1;
}

}
}
}


}

Any tips are greatly appreciated. Thank you!

Answer

@Mark, here are the changes that I have made.

  1. Its some ambiguous to use Comparator and Comparable, you can read this post and see the differences: What is the difference between compare() and compareTo()?

  2. Your indexes were wrong, like 0 to 'Sort by last name' and 'exit'

  3. The import is always before the class statement

  4. There were some brackets missing

4.5 There were one main method in Heap and the other options in Assignment1 that I removed just to compile

  1. I would advice you to use Generics to make this class, you can read more here: https://docs.oracle.com/javase/tutorial/java/generics/. In your Head.sort method, you definied it to receive a Comparable and you were passing a Comparable and a Comparator, like I said, its ambiguous. Its better to you pass a generic array (Like anything-> String[], int[], yourOwnClass[]) and provide a second argument: the Comparator! So, lets go back, changed to use generics and provide your Comparator! Now you are calling the method sort and saying to it what is the parameter to compare (Comparator). You can see the final result here:

    import java.util.Scanner; public class Assignment1 {

    public static void main(String[] args) {
    
    Contact[] contacts = {
            new Contact("Collins", "Kelly", "Illinois", 26),
            new Contact("Smith", "Brandon", "Michigan", 32),
            new Contact("Jones", "Mark", "California", 29),
            new Contact("McDowell", "Ryan", "Texas", 30),
            new Contact("Thompson", "April", "New York", 35)
    };
    
    
    int input;
    do {
        Scanner in = new Scanner(System.in);
        System.out.println("Sort by last name:     [1]");
        System.out.println("Sort by first name:    [2]");
        System.out.println("Sort by age:           [3]");
        System.out.println("Enter an option or 0 to end input: ");
        input = in.nextInt();
    
        if (input == 0) {
            System.out.println("Exiting...");
            System.exit(input);
        } else if (input == 3) {
            Heap.sort(contacts, new Contact.AgeComparator());
    
    
            for (Contact contact : contacts) {
                System.out.println(contact);
            }
        } else if (input > 3 || input < 0) {
            System.out.println("Invalid entry");
        }
    
    } while (input != 0);
    

    } }

Contact class:

import java.util.Comparator;

public class Contact {

String lastName;
String firstName;
String homeState;
Integer age;

Contact(String lastName, String firstName, String homeState, Integer age) {
    this.lastName = lastName;
    this.firstName = firstName;
    this.homeState = homeState;
    this.age = age;
}

public String getLastName() {
    return lastName;
}

public void setLastName(String lastName) {
    this.lastName = lastName;
}

public String getFirstName() {
    return firstName;
}

public void setFirstName(String firstName) {
    this.firstName = firstName;
}

public String getHomeState() {
    return homeState;
}

public void setHomeState(String homeState) {
    this.homeState = homeState;
}

public Integer getAge() {
    return age;
}

public void setAge(Integer age) {
    this.age = age;
}

@Override
public String toString() {
    return String.format("%8s %8s %7s, %7d", this.lastName, this.firstName, this.homeState, this.age);
}

static class FirstNameComparator implements Comparator<Contact> {
    public int compare(Contact a, Contact b) {
        return a.firstName.compareToIgnoreCase(b.firstName);
    }
}

static class LastNameComparator implements Comparator<Contact> {
    public int compare(Contact a, Contact b) {
        return a.lastName.compareToIgnoreCase(b.lastName);
    }
}

static  class AgeComparator implements Comparator<Contact> {
    public int compare(Contact a, Contact b) {
        return a.age < b.age ? -1 : a.age == b.age ? 0 : 1;
    }

}
}

Heap class

import java.util.Comparator;

public class Heap {

// This class should not be instantiated.
private Heap() { }

/**
 * Rearranges the array in ascending order, using the natural order.
 * @param pq the array to be sorted
 */
public static <T> void sort(T[] pq, Comparator<T> comparator) {
    int n = pq.length;
    for (int k = n/2; k >= 1; k--)
        sink(pq, k, n, comparator);
    while (n > 1) {
        exch(pq, 1, n--);
        sink(pq, 1, n, comparator);
    }
}

private static <T> void sink(T[] pq, int k, int n, Comparator<T> comparator) {
    while (2*k <= n) {
        int j = 2*k;
        if (j < n && less(pq, j, j+1, comparator)) j++;
        if (!less(pq, k, j, comparator)) break;
        exch(pq, k, j);
        k = j;
    }
}


private static <T> boolean less(T[] pq, int i, int j, Comparator<T> comparator) {
    return comparator.compare(pq[i-1],pq[j-1]) < 0;
}

private static void exch(Object[] pq, int i, int j) {
    Object swap = pq[i-1];
    pq[i-1] = pq[j-1];
    pq[j-1] = swap;
}

}

Merge

    import java.util.Comparator;

public class Merge {

    // This class should not be instantiated.
    private Merge() {
    }

    // stably merge a[lo .. mid] with a[mid+1 ..hi] using aux[lo .. hi]
    private static <T> void merge(T[] a, T[] aux, int lo, int mid, int hi, Comparator<T> comparator) {
        // precondition: a[lo .. mid] and a[mid+1 .. hi] are sorted subarrays
        assert isSorted(a, lo, mid, comparator);
        assert isSorted(a, mid + 1, hi, comparator);

        // copy to aux[]
        for (int k = lo; k <= hi; k++) {
            aux[k] = a[k];
        }

        // merge back to a[]
        int i = lo, j = mid + 1;
        for (int k = lo; k <= hi; k++) {
            if (i > mid) a[k] = aux[j++];
            else if (j > hi) a[k] = aux[i++];
            else if (less(aux[j], aux[i], comparator)) a[k] = aux[j++];
            else a[k] = aux[i++];
        }

        // postcondition: a[lo .. hi] is sorted
        assert isSorted(a, lo, hi, comparator);
    }

    // mergesort a[lo..hi] using auxiliary array aux[lo..hi]
    private static <T> void sort(T[] a, T[] aux, int lo, int hi, Comparator<T> comparator) {
        if (hi <= lo) return;
        int mid = lo + (hi - lo) / 2;
        sort(a, aux, lo, mid, comparator);
        sort(a, aux, mid + 1, hi, comparator);
        merge(a, aux, lo, mid, hi, comparator);
    }

    /**
     * Rearranges the array in ascending order, using the natural order.
     *
     * @param a the array to be sorted
     */
    public static <T> void sort(T[] a, Comparator<T> comparator) {
        T[] aux = (T[])new Object[a.length];
        sort(a, aux, 0, a.length - 1, comparator);
        assert isSorted(a, comparator);
    }

    // is v < w ?
    private static <T> boolean less(T v, T w, Comparator<T> comparator) {
        return comparator.compare(v,w) < 0;
    }


    private static <T> boolean isSorted(T[] a, Comparator<T> comparator) {
        return isSorted(a, 0, a.length - 1, comparator);
    }

    private static <T> boolean isSorted(T[] a, int lo, int hi, Comparator<T> comparator) {
        for (int i = lo + 1; i <= hi; i++)
            if (less(a[i], a[i - 1], comparator)) return false;
        return true;
    }
}

Quick

    import java.util.Comparator;

public class Quick {
    // This class should not be instantiated.
    private Quick() {
    }

    /**
     * Rearranges the array in ascending order, using the natural order.
     *
     * @param a the array to be sorted
     */
    public static <T> void sort(T[] a, Comparator<T> comparator) {
        sort(a, 0, a.length - 1, comparator);
        assert isSorted(a, comparator);
    }

    // quicksort the subarray from a[lo] to a[hi]
    private static <T> void sort(T[] a, int lo, int hi, Comparator<T> comparator) {
        if (hi <= lo) return;
        int j = partition(a, lo, hi, comparator);
        sort(a, lo, j - 1, comparator);
        sort(a, j + 1, hi, comparator);
        assert isSorted(a, lo, hi, comparator);
    }

    // partition the subarray a[lo..hi] so that a[lo..j-1] <= a[j] <= a[j+1..hi]
// and return the index j.
    private static <T> int partition(T[] a, int lo, int hi, Comparator<T> comparator) {
        int i = lo;
        int j = hi + 1;
        T v = a[lo];
        while (true) {

            // find item on lo to swap
            while (less(a[++i], v, comparator))
                if (i == hi) break;

            // find item on hi to swap
            while (less(v, a[--j], comparator))
                if (j == lo) break;      // redundant since a[lo] acts as sentinel

            // check if pointers cross
            if (i >= j) break;

            exch(a, i, j);
        }

        // put partitioning item v at a[j]
        exch(a, lo, j);

        // now, a[lo .. j-1] <= a[j] <= a[j+1 .. hi]
        return j;
    }

    /**
     * Rearranges the array so that {@code a[k]} contains the kth smallest key;
     * {@code a[0]} through {@code a[k-1]} are less than (or equal to) {@code a[k]}; and
     * {@code a[k+1]} through {@code a[n-1]} are greater than (or equal to) {@code a[k]}.
     *
     * @param a the array
     * @param k the rank of the key
     * @return the key of rank {@code k}
     */
    public static <T> T select(T[] a, int k, Comparator<T> comparator) {
        if (k < 0 || k >= a.length) {
            throw new IndexOutOfBoundsException("Selected element out of bounds");
        }
        int lo = 0, hi = a.length - 1;
        while (hi > lo) {
            int i = partition(a, lo, hi, comparator);
            if (i > k) hi = i - 1;
            else if (i < k) lo = i + 1;
            else return a[i];
        }
        return a[lo];
    }


    // is v < w ?
    private static <T> boolean less(T v, T w, Comparator<T> comparator) {
        return comparator.compare(v, w) < 0;
    }

    // exchange a[i] and a[j]
    private static  void exch(Object[] a, int i, int j) {
        Object swap = a[i];
        a[i] = a[j];
        a[j] = swap;
    }


    private static <T>  boolean isSorted(T[] a, Comparator<T> comparator) {
        return isSorted(a, 0, a.length - 1, comparator);
    }

    private static <T> boolean isSorted(T[] a, int lo, int hi, Comparator<T> comparator) {
        for (int i = lo + 1; i <= hi; i++)
            if (less(a[i], a[i - 1], comparator)) return false;
        return true;
    }
}
Comments