Home  |  FAQ  |  About  |  Contact  |  View Source   
 
SEARCH:
 
BROWSE:
    My Hood
Edit My Info
View Events
Read Tutorials
Training Modules
View Presentations
Download Tools
Scan News
Get Jobs
Message Forums
School Forums
Member Directory
   
CONTRIBUTE:
    Sign me up!
Post an Event
Submit Tutorials
Upload Tools
Link News
Post Jobs
   
   
Home >  Tutorials >  General Coding >  Better Sorting Techniques using Java
Add to MyHood
   Better Sorting Techniques using Java    [ printer friendly ]
Stats
  Rating: 4.8 out of 5 by 64 users
  Submitted: 04/07/02
Larry Mak ()

 
Sorting Effectively in Java

This tutorial is generally about sorting in Java – ways to do it, and how to do it correctly, quickly, and effectively. This tutorial will use one problem, and shows the many approaches to do so.

Here’s the problem:
Suppose you’re to sort a list of books, given by the number of pages, and the initial of the author. The style of input is on one line, a number between 0 – 999 denoting the number of pages, a space, then the author’s initials with 2 uppercase letters.

We are to sort them by the number of pages, and then by the first, then last initials of the author.

The input will be given by one string, with one number denoting the number of books. We’re to implement a “bookOrder” method that returns the sorted string.

Input:
15 AB 219 AE 518 SE 518 AB 17 CE, 5

Output:
15 AB 17 CE 219 AE 518 AB 518 SE


Method 1
Because in competitions, this is timed, so one might write it very inefficently, using bubblesort:

import java.util.*;
public class Book{
    public String bookOrder( String books, int number ){
        
    int[] pages = new int[ number ];
    String[] title = new String[ number ];
    StringTokenizer st = new StringTokenizer( books );

    // Parsing
    for ( int i = 0; i < number; i++ ){
        pages[i] = Integer.parseInt( st.nextToken() );
        title[i] = st.nextToken();
    }

    // Bubblesort
    for ( int i = 0; i < number; i++ ){
        for ( int j = 0; j < number - 1; j++ ){
        // This does the actual comparison
        if ( pages[j] > pages[j+1] || 
            ( pages[j] == pages[j+1] && title[j].compareTo( title[j+1] ) > 0 ) ){
            // Swapping
            pages[j] ^= pages[j+1];
            pages[j+1] ^= pages[j];
            pages[j] ^= pages[j+1];
            String temp = title[j];
            title[j] = title[j+1];
            title[j+1] = temp;
        }
        }
    }

    // Returns it in the format required.    
    String s = "";
    for ( int i = 0; i < number; i++ ){
        s += (int)pages[i] + " " + title[i] + " ";
    }
    // trim() trims the trailing ( and leading spaces ) in a string.
        return s.trim();
    }
}


The above method took about 5 minutes to write, is stable, but isn't very efficient. ( At O( n^2 ) )

This code is also very flexible, as you only need to change this statement to sort it differently:
if ( pages[j] > pages[j+1] || 
( pages[j] == pages[j+1] && title[j].compareTo( title[j+1] ) > 0 ) )


If we wanted to sort by initial first and then page number, we can easily modified this to:
if ( title[j].compareTo( title[j+1] ) > 0 ) || 
( title[j].compareTo( title[j+1] ) == 0 && pages[j] > pages[j+1] ) )


or changed the signs if we wanted to sort descendingly:
if ( pages[j] < pages[j+1] || 
( pages[j] == pages[j+1] && title[j].compareTo( title[j+1] ) > 0 ) )


Method 2
A better and more efficient way is to use the Java API. This is using a relatively underused class java.util.Arrays and the interface Comparable:

import java.util.*;
public class Book{
    private class B implements Comparable {
    // Fields to be sorted
    int pages;
    String title;
    
    // Initializer
    public B ( int p, String t ){
        title = t;
        pages = p;
    }
    
    // The required compareTo method.
    public int compareTo( Object o ){
        B k = (B) o;
        if ( pages != k.pages ){
        return pages - k.pages;
        }
        else 
        return title.compareTo( k.title );
    }
    }

    public String bookOrder( String books, int number ){
    B[] book = new B[ number ];
    StringTokenizer st = new StringTokenizer( books );

    // Parsing
    for ( int i = 0; i < number; i++ ){
        book[i] = new B(Integer.parseInt( st.nextToken() ), st.nextToken() ); 
    }
    
    // Using Arrays.sort
    Arrays.sort( book );
    
    // Return it in the format required.
    String s = "";
    for ( int i = 0; i < number; i++ ){
        s += (int)book[i].pages + " " + book[i].title + " ";
    }
    return s.trim();
    }
}


This ensures that it runs in O( n * log n ) time, using a tuned quicksort. The best thing about writing
the code this way is that it's cleaner, and it's also less error-prone, if you let the API do the work.

Let's go over it in detail:
private class B implements Comparable 

This is a private helper class. It implements Comparable so that we can sort it later.

public int compareTo( Object o ){
    B k = (B) o;
    if ( pages != k.pages ){
    return pages - k.pages;
    }
    else 
    return title.compareTo( k.title );
}


This method is the method that does the comparing. Naturally, it returns a negative integer if this object is smaller, a zero if they're the same, and a positive interger if the specified Object is smaller.

Arrays.sort( Object[] ) 

This lets us sort anything, but it requires that all elements in the array be implementing the Comparable interface. That means if you're sorting just ints, or doubles, or Strings, this is very handy and let you get the work done quicker. Why reinvent the wheel, after all?

The above way is not that hard to implement, and it doesn't take too long, but generally requires me to remember too much syntax.

However, it is the preferable way to sort things in Java. Learning it helps a lot in sorting in general.

To modify what to sort, we simply modify the compareTo method:
public int compareTo( Object o ){
    B k = (B) o;
    if ( pages != k.pages ){
    return pages - k.pages;
    }
    else 
    return title.compareTo( k.title );
}


as with method 1, if we wanted to sort descendingly:
public int compareTo( Object o ){
    B k = (B) o;
    if ( pages != k.pages ){
    return k.pages - pages;
    }
    else 
    return title.compareTo( k.title );
}


or title first:
public int compareTo( Object o ){
    B k = (B) o;
    if ( title.compareTo( k.title ) != 0 )
    return title.compareTo( k.title );
    else
    return pages - k.pages;


or title descendingly:
public int compareTo( Object o ){
    B k = (B) o;
    if ( title.compareTo( k.title ) != 0 )
    return -1 * title.compareTo( k.title );
    else
    return pages - k.pages;


Method 3
So is there another alternative?

This requires us to think about the boundry conditions. Since Arrays.sort also sort Strings, we can format the entire thing as an Array of Strings, and then sort them:

import java.util.*;
public class Book{
    public String bookOrder( String books, int number ){
    StringTokenizer st = new StringTokenizer( books );
    String[] book = new String[ number ];

    // Parsing
    for ( int i = 0; i < number; i++ ){
        int pages = Integer.parseInt( st.nextToken() );
        String title = st.nextToken();

        /** Format is as following:

         * DDDTTNNNNN
         * Where DDD is the number of pages
         * TT is the initials
         * and NNNNN is the original string
         **/

        book[i] = format( pages ) + title + pages + " " + title;
    }
    
    // Using Arrays.sort
    Arrays.sort( book );
    
    String s = "";
    for ( int i = 0; i < number; i++ ){
    // Why 5?  the first 5 characters are throw away letters to be sorted
        s += book[i].substring(5) + " ";
    }
    return s.trim();
    }

    // This pads the number of pages with zeros.
    String format ( int pages ){
    String temp = "0000000" + pages;
    // Why 3?  Since it only goes up to 999, we only need the last 3 digits.
    return temp.substring( temp.length() - 3 );
    }
}


The above works, is very short to write, and is pretty intuitive. In general, I recommend the second method, but usually I have to look up the syntax on an API, and the above saves me some time, and time is a very important constraint sometimes.

To modify what to sort, we simply modify the parsing line:
   book[i] = format( pages ) + title + pages + " " + title;


to descending pages:
   book[i] = format( 999 - pages ) + title + pages + " " + title;


to initials:
   book[i] = title + format( 999 - pages ) + pages + " " + title;


to descending initials:
   book[i] = (char) ('Z' - ( title.charAt(0) - 'A' )) + (char) ('Z' - ( title.charAt(1) - 'A' ) + 
      format( 999 - pages ) + pages + " " + title;


To test the above methods, we just need to add the main method:
    public static void main( String[] args )
    {
    Book a = new Book();
    System.out.println( a.bookOrder( "15 AB 219 AE 518 SE 518 AB 17 CE", 5 ) );
    }


This was meant to be a quick tutorial to coders that already knows how to program, and to provide them alternative way of solving a problem quicker.

Return to Browsing Tutorials

Email this Tutorial to a Friend

Rate this Content:  
low quality  1 2 3 4 5  high quality

Reader's Comments Post a Comment
 
This is my first tutorial, so any output will be greatly appreciated..
-- Larry Mak, April 09, 2002
 
I think there is a solid effort in this tutorial, and since it seems that you are comfortable with this language, there are many more tutorials you can write. I think one of the problems many have is with linked lists, you can write a merging source with linked lists which would help a lot.
-- can comertoglu, April 09, 2002
 
Nice tutorial, I didn't even realize about the API sort. There is almost everything available in the API so we don't have to reinvent the wheel. I gotta remember that.
-- Malik Keshwani, April 09, 2002
 
***** Nicely written tutorial with good explanations.
-- Kelly Marshall, April 09, 2002
 
Larry,

Great tutorial. Well written and organized. (I see you're putting CSE 114 & CSE 214 to good use). Rating: 5 Stars *****
-- Michael Steinberg, April 09, 2002
 
Nice work on your first tutorial. You have a lot of good content which is the most important thing. You might want to try using some different colors, font, bolding, etc to more easily differentiate heading sections. But that's just a personal preference.
-- Ben Martens, April 10, 2002
 
very good tutorial, and when i have the time to learn java, i will definetly be looking over this tutorial a little more closely so i can learn better some of the things you have gone over... 5*s
-- Justin Jones, April 10, 2002
 
Good tutorial.
-- Brian Simoneau, April 10, 2002
 
Nice tutorial! Just had my Data Structures & Algorithms Analysis final. Hope to see more from you! 5/5
-- Eric Lee, April 11, 2002
 
Good tutorial. Didn't know about the Comparable interface. It'll help speed up writing sorting code in the future. Thanks!
-- Bassam Islam, April 11, 2002
 
Nice tutorial =)

I know our professors are trying to teach language independence, but does anyone else wonder why the API sort wasn't covered in class? I mean we did sorting in 114 AND 214... they could have thrown it in somewhere. Ah well, I'm not the employer who'll be getting the underprepared students :-D

Ooh, and this'll be useful for TopCoder! Thanks Larry =)
-- Juan Walker, April 11, 2002
 
You offer some clever ways to get the fastest sort from the utils. Much preferable to doing it all myself.
-- Simon Parsons, April 11, 2002
 
Excellant Tutorial. Well written.
-- A Vallur, April 12, 2002
 
Good use of code examples. It's nice to be shown the differences in code, which really gets the point across. Well done. 5/5
-- Frank DeRosa, April 12, 2002
 
very good and useful tutorial .
-- justin adrien, April 13, 2002
 
Very well written.
-- Thomas Coogan, April 15, 2002
 
Thanks for the effort -- easy to read and well organized.
-- Kurt Forrester, April 17, 2002
 
Well done tutorial.
-- Trent Taufer, April 18, 2002
 
Very good tutorial! Helpful to review some sorting algorithms...
-- Jorge Balderas, April 20, 2002
 
This is a nice explanation an a simpler approach to sort. I like it. It is straight forward.
-- Jose Malpica, April 22, 2002
 
awesome, i'm not the only one posting tutorials in java :) Clear and useful, 5 *'s
-- Lee Bankewitz, May 04, 2002
 
Good tutorial, Larry!
-- David Chao, September 04, 2002
 
I'll rewrite this in C# one of these days..
-- Larry Mak, September 11, 2002
 
The coded example is available as a tool here
-- Larry Mak, September 12, 2002
 
The C# version of this tutorial is here.
-- Larry Mak, September 20, 2002
 
I hate java but I like sorting stuff. It's uber sex0rz.
Great tut.
-- Brian Li, October 10, 2002
 
nice tutorial
-- Kyoungjin Park, November 05, 2002
 
good job
-- Siyan Li, November 30, 2002
 
Copyright © 2001 DevHood® All Rights Reserved