Using Shellsort to sort a list of countries by population (Java)

1.1k views Asked by At

In my program, I have a class Sorting, that inputs a file called CountryUnsortedFormat that contains a random list of countries and their populations. The class is supposed to use shellsort to sort the countries by population and display them on the screen.

Here is my code:

package assignment3;
import java.io.PrintWriter;
import java.io.File;
import java.util.Arrays;
import java.util.Random;
import java.util.Scanner;

public class Assignment3 {

public static void main(String[] args) throws Exception{
    //Array for handling list of countries
    String[] line = new String[238];
    //read list of countries into array
    readInArray(line);
    //unsort the array
    unSort(line);


}

 static void readInArray(String[] line) throws Exception{
     Scanner stdIn = new Scanner(new File("C:/Users/Vicki/Desktop/CountrySortedFormat.txt"));

     //Read in countries from sorted file into an array
    int k=0;
    while (stdIn.hasNextLine()){    
        line[k]=stdIn.nextLine();   
        k++;
    }
 }

 static void unSort(String[] line) throws Exception{
    PrintWriter out = new PrintWriter("C:/Users/Vicki/Desktop/CountryUnsortedFormat.txt");
    //Pick a random int from 1 to 238 called where
    //Write where into Unsorted Country Format file
    //Make where null
    //Repeat until all 238 countries are written in random order
    int j = line.length-1;
    Random r = new Random();
    while (j > 0){
        int where = r.nextInt(j)+1;
        out.println(line[where]);
        line = pop(where, line);
        j--;
    }
    out.close();

 }

 static String[] pop(int index, String[] line){
     String[] newLine = new String[line.length-1];
     int offset = 0;
     for (int i = 0; i<line.length; i++){
         if(i == index){
             offset = 1;
             continue;
         }
         newLine[i - offset] = line[i];
     }
     return newLine;
 }

}

class Sorting {

public static void main(String[] args) throws Exception{

    //Array for handling list of countries
    String[] line = new String[238];

    readInArray(line);
    shellsort(line);

    System.out.println(Arrays.toString(line));

}

static void readInArray(String[] line) throws Exception{
    Scanner stdIn = new Scanner(new File("C:/Users/Vicki/Desktop/CountryUnsortedFormat.txt"));

    //Read in countries from unsorted file into an array
    int k=0;
    while (stdIn.hasNextLine()){    
        line[k]=stdIn.nextLine();   
        k++;
    }
}

static void shellsort(String[] line){
    int j;
    for(int gap = line.length-1/2; gap > 0; gap /= 2){
        for(int i = gap; i < line.length-1; i++){
            String tmp = line[i];
            for (j = i; j >= gap && getPopulation(line, j-gap) > getPopulation(line, i); j -= gap){
                line[j] = line[j -gap];
            }
            line[j] = tmp;
        }
    }
}

static int getPopulation(String[] line, int index){
    String populationString = line[index].substring(50,65).trim().replaceAll(",","");
    int population = Integer.parseInt(populationString);
    return population;
}


}

My classes work separately but when put together my program doesn't print to the screen. All it shows is "BUILD SUCCESSFUL (total time: 0 seconds)"

What am I doing wrong?

1

There are 1 answers

2
Dylan Madisetti On

This is pretty obviously a homework assignment, and it'd be wrong to help you further. I would first organize your code into a more readable format. Eg:

public class Country{
    private int population;
    public Country(String line){
       // parse and set population
    }
    public int getPopulation(){
       return population;
    }
}

then implement the sort

# Sort an array countires[0...n-1].
# Start with the largest gap and work down to a gap of 1 
int j;
for(int gap = countries.length/2; gap > 0; gap /= 2){
    # Do a gapped insertion sort for this gap size.
    # The first gap elements countries[0..gap-1] are already in gapped order
    # keep adding one more element until the entire array is gap sorted 
    for(int i = gap; i < line.length; i++){
        # add countries[i] to the elements that have been gap sorted
        # save countries[i] in temp and make a hole at position i
        int temp = countries[i].getPopulation();
        # shift earlier gap-sorted elements up until the correct location for countries[i] is found
        for (j = i; j >= gap && a[j - gap].getPopulation() > temp; j -= gap){
            countries[j] = countries[j - gap]
        }
        # put temp (the original countries[i]) in its correct location
        countries[j] = temp
    }
}

Which is more or less ripped directly from Wikipedia, and what you have....

This looks like a case of needing better debugging. Drop some breakpoints or some printlns in populating line. There's a chance Netbeans isn't printing anything, because there is nothing to print out. Or you could simply be messing up your parsing. You have hard-coded values in there for your substrings and chances are that's where it's breaking. Using a regex or scanner could solve this problem, simply by not being an an unholy cluster of functions. I don't know what your input looks like so I couldn't tell you. However, I know your sort works because I copy and pasted with some random values and ran it myself:

class Sorting {

    public static void main(String[] args) throws Exception{

        int[] line = new int[]{97,95,66,91,33,91,73,63,67,84,40,34,85,43,73,8,45,14,86,23,74,22,50,33,4,75,12,28,44,43,20,69,95,28,8,44,5,21,50,53,83,53,93,4,62,45,24,57,41,30,32,21,44,76,42,85,35,36,20,96,95,35,5,49,21,43,29,97,69,15,40,15,82,73,24,30,53,50,73,2,86,25,35,50,83,15,66,80,36,22,46,34,89,18,15,59,99,85,12,65};

        int j;
        for(int gap = line.length/2; gap > 0; gap /= 2){
            for(int i = gap; i < line.length; i++){
                int population = line[i];
                for (j = i; j >= gap && line[j - gap] > population; j -= gap){
                    line[j] = line[j -gap];
                }
                line[j] = population;
            }
        }
        for (int l : line) {
            System.out.println(l);
        }
    }
}

The lack of error log sounds like an environmental issue, or might comes down to what you unsorted file looks like, which is most likely wrong since I attempted to answer your previous question which you have since deleted

Traversing Through Array Using A Random Int and Unsorting a File

So the difficulty with your code as is that you will not end up with a shuffled array. Instead you will have probably duplicates. Let's run through this with an array of 4 lines = ["Argentina","Barbados","Canada","Dominica"]

Iteration 1. j = 4, let's have where = 2 and therefore out = "Canada"

Iteration 2. j = 3, there's nothing to stop where = 2 again as such, out = "Canada, Canada"

To properly scramble your array, I would recommend popping the chosen value To prevent duplicates. Given you are using a plain old array and not an ArrayList you should have a function pop (although I would suggest using an ArrayList):

// pop(2,["Argentina","Barbados","Canada","Dominica"]) == ["Argentina","Barbados","Dominica"]
function String[] pop(int index, String[] list){
     newList = new String[list.length - 1]
     int offset = 0;
     for(int i; i < list.length; i++){
         if(i == index){
             offset = 1; // Start skipping 
             continue;
         }
         newList[i - offset] = list[i];
     }
     return newList;
}

Your new unSort should like:

public static void unSort(String[] line) throws Exception{
    Scanner stdIn = new Scanner(new File("C:/Users/Vicki/Desktop/CountryUnsortedFormat.txt"));
    PrintWriter out = new PrintWriter("C:/Users/Vicki/Desktop/CountryUnsortedFormat.txt");

    int j = line.length; // Opposed to hardcoding 238
    Random r = new Random(); // Let's put random out so we don't have to continuously initialize
    while (j > 0){
        int where = r.nextInt(j);
        out.println(line[where]);
        line = pop(where, line); // get rid of what we just printed
        j--;
    }
    out.close();
}

Of course there are other shuffles, for instance: you could perform a Fisher-Yates on line and then print it out after. I don't fully understand what you're directly asking for, but I imagine it's something like this:

public static void unSort(String[] line) throws Exception{
    Scanner stdIn = new Scanner(new File("C:/Users/Vicki/Desktop/CountryUnsortedFormat.txt"));
    PrintWriter out = new PrintWriter("C:/Users/Vicki/Desktop/CountryUnsortedFormat.txt");

    int j = line.length; // Opposed to hardcoding 238
    Random r = new Random(); // Let's put random out so we don't have to continuously initialize
    while (j > 0){
        int where = r.nextInt(line.length);
        if(line[where] != null){
            out.println(line[where]);
            j--;
            line[where] = null;
        }
    }
    out.close();
}

Where this guarantees no duplicates. However this has a best case run time of O(n) and a worst case of being an infinite loop.