Quicksort ArrayList <myobject>具有多个相同的值(myObject.getId())并不是完全排序</myobject>

时间:2014-07-29 14:58:12

标签: java sorting arraylist quicksort

我有一个快速排序算法来对ArrayLists进行排序。由于我使用的是ArrayLists而不是Arrays,因此与the traditional way相比,我不得不修改/添加部分代码。

除了一件小事之外,一切都按预期工作:当我有多个具有相同排序值的对象时,ArrayList未正确排序。

所以,首先,这是我的代码:

public class Sort
{
    ... // Other sorting classes that always have an unique sorting-value anyway, so are working fine

    // The following sorting class can have double sorting-values, and here the sorting goes wrong
    public static class OPI{
        public static ArrayList<OrderedProductItem> opisByProductId;
        public static void sortOrderedProductItems(ArrayList<OrderedProductItem> orderedProductItems){
            opisByProductId = new ArrayList<OrderedProductItem>();

            if(orderedProductItems != null && orderedProductItems.size() > 0){
                // Since Java automatically creates a pointer behind the scenes,
                // we need to make a new ArrayList and fill them with the values
                for(OrderedProductItem opi : orderedProductItems)
                    opisByProductId.add(opi);

                quicksortOpisByProductId(0, opisByProductId.size() - 1);
            }
        }
        private static void quicksortOpisByProductId(int low, int high){
            int i = low, j = high;
            // Get the middle element from the middle of the list
            int middle = opisByProductId.get(low + (high - low) / 2).getProductId();

            // Divide into two lists
            while(i <= j){
                // If the current value from the left list is smaller than the middle
                // element, then get the next element from the left list
                while(opisByProductId.get(i).getProductId() < middle){
                    i++;
                    if(i > j){
                        i = j;
                        break;
                    }
                }

                // If the current value from the right list is larger than the middle
                // element, then get the next element from the right list
                while(opisByProductId.get(j).getProductId() > middle){
                    j--;
                    if(j < i){
                        j = i;
                        break;
                    }
                }

                // If we have found a value in the left list which is larger than
                // the middle element and if we have found a value in the right list
                // which is smaller than the middle element, then we exchange the values
                // PS: It might happen that the same values swap places
                if(i < j){
                    OrderedProductItem temp = opisByProductId.get(i);
                    opisByProductId.set(i, opisByProductId.get(j));
                    opisByProductId.set(j, temp);
                }

                if(i <= j){
                    i++;
                    j--;
                }
            }
            // Recursion
            if(low < j)
                quicksortOpisByProductId(low, j);
            if(i < high)
                quicksortOpisByProductId(i, high);
        }
    }
}

示例列表:

在排序算法之前:

position        ProductId
0               12
1               12
2               54
3               54
4               12
5               4
6               4
7               4

排序算法后:

position        ProductId
0               4
1               4
2               12
3               12
4               12
5               4
6               54
7               54

2 个答案:

答案 0 :(得分:0)

好的我调试了你的程序,在这里发现了我的

你的高位继续下降从未回升过。

if(low < j)
    quicksortOpisByProductId(low, j);
if(i < high)
    quicksortOpisByProductId(i, high);

我将此更改为

if(low < j)
    quicksortOpisByProductId(low, j);
if(i < high)
    quicksortOpisByProductId(i, opisByProductId.size() - 1);

它有效

未完成您的程序更改了阵列7次

添加此项后,它会再循环3次,最多需要10次。

Sorting Visualization

答案 1 :(得分:0)

好的,我弄清楚了我的错误。在我有的while循环中

// If the current value from the left list is smaller than the middle
// element, then get the next element from the left list
while(opisByProductId.get(i).getProductId() < middle){
    i++;
    if(i > j){
        i = j;
        break;
    }
}

// If the current value from the right list is larger than the middle
// element, then get the next element from the right list
while(opisByProductId.get(j).getProductId() > middle){
    j--;
    if(j < i){
        j = i;
        break;
    }
}

我在if语句中使用j和i。相反,我现在使用以下内容修复我的问题:

// If the current value from the left list is smaller than the middle
// element, then get the next element from the left list
while(opisByProductId.get(i).getProductId() < middle){
    i++;
    if(i > high){ // <- high instead of j
        i = high; // <- high instead of j
        break;
    }
}

// If the current value from the right list is larger than the middle
// element, then get the next element from the right list
while(opisByProductId.get(j).getProductId() > middle){
    j--;
    if(j < low){ // <- low instead of i
        j = low; // <- low instead of i
        break;
    }
}

编辑:

使用@ DaveP的测试数据创建了一个UnitTest,并且成功了:

package business;

import java.util.ArrayList;

import junit.framework.Assert;

import org.junit.Test;

import viewmodels.OrderedProductItem;

public class SUnitTest
{
    ... // Other UnitTests

    @Test
    public void testDoubleSorting(){
        // Arrange
        // Could be with any of them, but we do it with the OrderedProductItems,
        // since they can contain doubles
        ArrayList<OrderedProductItem> opis = new ArrayList<OrderedProductItem>();
        int[] unsortedIds = new int[]{
            12, 12, 54, 54, 12, 4, 4, 4, 7, 76, 45, 44, 1, 2, 34, 5, 4
        };
        // Sorted array of the exact same ID's for comparison
        int[] sortedIds = new int[]{
            1, 2, 4, 4, 4, 4, 5, 7, 12, 12, 12, 34, 44, 45, 54, 54, 76
        };
        for(int i = 0; i < unsortedIds.length; i++)
            // OrderedProductItem uses setProductId in its Constructor
            opis.add(new OrderedProductItem(unsortedIds[i]));

        // Invoke
        Sort.OPI.sortOrderedProductItems(opis);
        ArrayList<OrderedProductItem> resultOpis = Sort.OPI.opisByProductId;

        // Assert
        Assert.assertNotNull("resultOpis should not be null", resultOpis);
        Assert.assertEquals("resultOpis' size should equal the unsortedIds' size", unsortedIds.length, resultOpis.size());
        for(int i = 0; i < sortedIds.length; i++){
            Assert.assertNotNull("The OrderedProductItem at " + String.valueOf(i) + " should not be null", resultOpis.get(i));
            Assert.assertEquals("The OrderedProductItem's ProductId at " + String.valueOf(i) + " should be " + String.valueOf(sortedIds[i]), sortedIds[i], resultOpis.get(i).getProductId());
        }
    }
}