Java Merge Sorting Algorithm Error - Not Sorting

痴心易碎 提交于 2019-12-25 04:22:27

问题


I can't figure out why my algorithm for a Merge Sort program using ArrayLists won't work... If guys and gals could help me figure it out that would be amazing!! The format required for printing needs to be tabbed every number and place on a new line every 20 numbers. My program has also been limited to the standard Java packages. Sample input and output can be found here. Here's my code:

import java.io.*;
import java.util.*;

public class MergeSort {
public static void main(String[] args) throws IOException{
    Scanner in  = new Scanner(System.in);
    Random r = new Random();
    int size, largestInt, holder;

    System.out.println("How many integers would you like me to create?");
    size = in.nextInt();
    ArrayList<Integer>list = new ArrayList<Integer>(size);
    System.out.println("What would the largest integer be?");
    largestInt = in.nextInt();

    for(int i = 0; i < size; i++){
        holder = r.nextInt(largestInt + 1);
        list.add(holder);
    }
    mergeSort(list);

    for (int j = 0; j < list.size(); j++) {
        if(j == 19 || j == 39 || j == 59 || j == 79 || j == 99 || j == 119 || j == 139 || j == 159 || j == 179 || j == 199){
            System.out.print(list.get(j));
            System.out.println();
        }
        else{
            System.out.print(list.get(j) + "\t");
        }
    }
}

static void mergeSort(ArrayList<Integer> list) {
    if (list.size() > 1) {
        int q = list.size()/2;
        ArrayList<Integer> leftList = new ArrayList<Integer>();
        for(int i = 0; i >0 && i <= q; i++){
            leftList.add(list.get(i));
        }
        ArrayList<Integer> rightList = new ArrayList<Integer>();
        for(int j = 0; j > q && j < list.size(); j++){
            rightList.add(list.get(j));
        }

        mergeSort(leftList);
        mergeSort(rightList);
        merge(list,leftList,rightList);
    }
}

static void merge(ArrayList<Integer> a, ArrayList<Integer> l, ArrayList<Integer> r) {
    int totElem = l.size() + r.size();
    int i,li,ri;
    i = li = ri = 0;
    while ( i < totElem) {
        if ((li < l.size()) && (ri<r.size())) {
            if (l.get(li) < r.get(ri)) {
                a.set(i, l.get(li));
                i++;
                li++;
            }
            else {
                a.set(i, r.get(ri));
                i++;
                ri++;
            }
        }
        else {
            if (li >= l.size()) {
                while (ri < r.size()) {
                    a.set(i, r.get(ri));
                    i++;
                    ri++;
                }
            }
            if (ri >= r.size()) {
                while (li < l.size()) {
                    a.set(i, l.get(li));
                    li++;
                    i++;
                }
            }
        }
    }
}

Thanks in advance!


回答1:


Your question is unclear, but since you need to implement a merge sort algorithm I assume this is the part that is broken for you. Format printing should be rather easy through trial and error once you have a properly sorted list.

I think you are greatly overcomplicating the problem in your solution. MergeSort is one of the simplest sorting algorithms out there, yet your code is far from simple.

Think about how Merge Sort works - it is recursive by nature because it is a divide and conquer method. It solves a large complex problem by splitting it into small easy problems, and basically just merges the result from all of these problems - your MergeSort algorithm just needs to encompass this.

If we write it up you need to do these steps:

(1) Check if the list contains only one element - then it is already sorted

(2) Split the input into equally sized lists and sorted these before proceeding (recursive step)

(3) Merge the two sorted lists, and return a single sorted list.

I see that you have a complex method for the merge part and use basic iteration for the splitting part. Java List (superclass of e.g. ArrayList) offers a .subList(fromIndex, toIndex) to split lists into smaller lists. You should use this. For the merging part:

Based on this animation from wikipedia

it should be rather simple how you should think about merging the two lists:

First maintain both lists as lists that are easy to remove objects from. Since at this point we know that the lists are gonna be sorted, we are ever only interested in the first object in each list (the smallest element).

Second, we only ever need to compare the first element of each list, remove the smallest of the two from its respective list and add it to our sorted list. We keep doing this until both lists are empty - at this point we have merged our lists.

In Java this indicates that we should use a datastructure for the merge part that allows us to look at the first element of each lists, and quickly remove the one we are interested in. In Java this data structure is LinkedList - ArrayList both performs terribly at this task and does not offer proper methods for doing this. LinkedList behaves as a queue and offers methods for easily checking and removing objects at the end of the list e.g. the first element.

So you should reconsider your implementation strategy and simplify your code based on how you should attack the MergeSort algorithm. If it seems comfusing here is a sample implementation of MergeSort in Java using only the standard API (no build in sorting method).

Hope it helps.

import java.util.LinkedList;
import java.util.Random;
import java.util.List;

public class Main {

    public static void main(String[] args){

        Random random = new Random();
        LinkedList<Integer> unsorted = new LinkedList<Integer>();
        for(int i = 0; i<100; i++){
            unsorted.add(random.nextInt(100));
        }

        System.out.println("unsorted: " + unsorted.toString());

        List<Integer> sorted = mergeSort(unsorted);

        System.out.println("sorted: " + sorted.toString());
    }

    //Recursive function for sorting a LinkedList
    private static LinkedList<Integer> mergeSort(LinkedList<Integer> unsorted){

        //If the list only contains 1 object it is sorted
        if(unsorted.size() == 1){
            return unsorted;
        }

        //Split the list in two parts and create a new list to store our sorted list
        LinkedList<Integer> left = mergeSort(new LinkedList<Integer>(unsorted.subList(0, unsorted.size()/2)));
        LinkedList<Integer> right = mergeSort(new LinkedList<Integer>(unsorted.subList(unsorted.size()/2, unsorted.size())));
        LinkedList<Integer> sorted = new LinkedList<Integer>();

        //Actual loop for merging the two sublists. Using LinkedLists, this is efficient. (Compared to ArrayList)
        while(!left.isEmpty() || !right.isEmpty()){
            Integer leftInt = left.peekFirst();
            Integer rightInt = right.peekFirst();

            if(!(leftInt == null) && !(rightInt == null)){
                if(leftInt < rightInt){
                    sorted.add(left.pollFirst());
                }
                else{
                    sorted.add(right.pollFirst());
                }
            }
            else if(leftInt == null){
                sorted.add(right.pollFirst());
            }
            else{
                sorted.add(left.pollFirst());
            }
        }

        return sorted;
    }
}


来源:https://stackoverflow.com/questions/21771119/java-merge-sorting-algorithm-error-not-sorting

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!