简体   繁体   中英

Have a sort of working Merge Sort, but not quite, could someone tell me what I am doing wrong?

First off, I want to start with my reasoning behind my method. My idea is that I will be either feeding in an array that is even or odd. This array will be broken down in a 2D array the length of the original array with each index having an array of size one. I will then proceed to merge indexes together. This works with lengths of size 2, 4, 8, 16. Now, I had to edit my method a little because 3, 5, 6, 7 weren't working. Now, my issue is even though they work, not all cases work. For example, a length of 25 doesn't return properly. Below is my code:

/**
* A method to perform a merge sort
* @param array The array being fed in
*/
public static int[] mergeSort(int[] array)
{
  if (array.length == 1)
  {
     return array;
  }

  int size = array.length;
  int[][] miniArrayList = new int[size][1];

  for (int index = 0; index < array.length; index++)
  {
     miniArrayList[index][0] = array[index];
  }

  while (miniArrayList.length > 1)
  {
     if (miniArrayList.length % 2 == 0)
     {
        miniArrayList = mergeEven(miniArrayList);
     }
     else
     {
        miniArrayList[0] = mergeOdd(miniArrayList);
     }
  }
  return miniArrayList[0];
}

My idea for the above method is that I feed an array in, it break it down, and then it merges the array little by little until I have a sorted array of size 1. The above method calls the following methods:

private static int[][] mergeEven(int[][] array)
{
  int[][] tempSortList = new int[array.length / 2][];
  int tempIndex = 0;
  for (int index = 0; index < array.length; index += 2)
  {
     tempSortList[tempIndex] = merge(array[index], array[index + 1]);
     if (tempIndex != tempSortList.length)
     {
        tempIndex++;
     }
  }
  array = tempSortList;
  return array;
}

private static int[] mergeOdd(int[][] array)
{
  /**
   * The concept is to call the even merge method on the even part
   * of the list and then once I get to one array, I merge that array
   * with the extra array.
   */
  int[][] localArray = new int[array.length - 1][1];
  int[][] extra = new int[1][1];

  for (int index = 0; index < localArray.length; index++)
  {
     localArray[index][0] = array[index][0];
  }

  extra[0][0] = array[array.length - 1][0];

  int[][] tempSortList = new int[localArray.length / 2][];
  int tempIndex = 0;
  for (int index = 0; index < localArray.length; index += 2)
  {
     tempSortList[tempIndex] = merge(localArray[index], localArray[index + 1]);
     if (tempIndex != tempSortList.length)
     {
        tempIndex++;
     }
  }
  localArray = tempSortList;

  return localArray[0] = merge(localArray[0], extra[0]);
}

It is pretty self explanatory, but just in case. The methods above sort differently because of the array being either odd or even. Finally, these methods call the actual merge method (which works I think):

/**
* A merge method to merge smaller arrays to bigger
* arrays
* @param arrayOne The first array being fed in
* @param arrayTwo The second array being fed in
* @return A new integer array which is the sum of the
* length of the two arrays
*/
private static int[] merge(int[] arrayOne, int[] arrayTwo)
{
  /*
   * To make a proper method that deals with odd array sizes
   * look into seeing if it odd, only merging length of the array -1
   * and then once that is all merged merge that array with the last part of the array
   */
  //Creating the size of the new subarray
  int[] mergedArray;

  if (arrayOne.length % 2 == 0 && arrayTwo.length % 2 == 0)
  {
     int size = arrayOne.length;
     int doubleSize = 2 * size;
     mergedArray = new int[doubleSize];

     //Positions of each array
     int posOne = 0;
     int posTwo = 0;
     int mergeIndex = 0;

     while (posOne < size && posTwo < size)
     {
        if (arrayOne[posOne] < arrayTwo[posTwo])
        {
           mergedArray[mergeIndex] = arrayOne[posOne];
           mergeIndex++;
           posOne++;
        }
        else
        {
           mergedArray[mergeIndex] = arrayTwo[posTwo];
           mergeIndex++;
           posTwo++;
        }
     }

     if (posOne == size)
     {
        for (int rest = posTwo; rest < size; rest++)
        {
           mergedArray[mergeIndex] = arrayTwo[rest];
           mergeIndex++;
        }
     }
     else
     {
        for (int rest = posOne; rest < size; rest++)
        {
           mergedArray[mergeIndex] = arrayOne[rest];
           mergeIndex++;
        }
     }

  }
  else
  {
     int arrayOneSize = arrayOne.length;
     int arrayTwoSize = arrayTwo.length;
     int newArraySize = arrayOneSize + arrayTwoSize;
     mergedArray = new int[newArraySize];

     //Position in each array
     int posOne = 0;
     int posTwo = 0;
     int mergeIndex = 0;

     while (posOne < arrayOneSize && posTwo < arrayTwoSize)
     {
        if (arrayOne[posOne] < arrayTwo[posTwo])
        {
           mergedArray[mergeIndex] = arrayOne[posOne];
           mergeIndex++;
           posOne++;
        }
        else
        {
           mergedArray[mergeIndex] = arrayTwo[posTwo];
           mergeIndex++;
           posTwo++;
        }
     }
     if (posOne == arrayOneSize)
     {
        mergedArray[mergeIndex] = arrayTwo[posTwo];
        mergeIndex++;
     }
     else
     {
        for (int rest = posOne; rest < arrayOneSize; rest++)
        {
           mergedArray[mergeIndex] = arrayOne[rest];
           mergeIndex++;
        }
     }

  }

  return mergedArray;
}

So my issue is, it any array size I feed in properly, it only works on certain sizes. I have done some reading through articles, but my implementation is pretty different than most I have seen which is why I posted here. I don't want to just copy a working one, I want to understand what I am doing wrong so I can fix it. Thanks in advance for the help guys!

Your problem is in the logic of merge . By using the line

int size = arrayOne.length;

you assume that both arrays have the same length. However, in the uneven case, not all arrays have the same length.

Change that into two different sizes and the code should be fine.

Your bigger problem is that your algorithm is way too complicated, not to mention inefficient for really large arrays.

I'm assuming you're doing this as an academic exercise, but whenever you get it working check out java.util.Arrays.mergeSort (private method) for an example.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM