0

悲しいことに、クイックソートにも問題があります。私は他の学生とそれについて話し合い、標準的なトラブルシューティング方法を試しました。しかし、私は自分が間違っていることを見つけることができません...

static int partition(int[] A)
    {
        int pivot, i, j;
        i = 0;
        j = A.Length;
        pivot = A[i];

        do
        {
            do
            {
                i++;
            }
            while (A[i] < pivot || i < j);
            do
            {
                j--;
            }
            while (A[j] > pivot);

            swap(ref A[i], ref A[j]);
        }
        while (i < j);

        if (i <= j)
        {
            swap(ref A[i], ref A[j]);
            swap(ref A[0], ref A[j]);
        }

        return j;
    }

    static void swap(ref int a, ref int b)
    {
        int aCopy = a;
        a = b;
        b = aCopy;
    }

    static int[] QuickSort(int[] A)
    {
        int s;
        int left = 0;
        int right = A.Length;
        int[] B, C;

        if (A.Length == 0 || A.Length == 1)
            return A;
        else
        {
            s = partition(A);
            B = new int[s];
            C = new int[right - s];

            for (int i = left; i < s; i++)
            {
                B[i - left] = A[i];
            }
            for (int i = s; i < right; i++)
            {
                C[i - s] = A[i];
            }

            QuickSort(B);
            QuickSort(C);
            return A;
        }
    }

デバッガーは常にj変数で「IndexOutOfRangeException」を返します。調整してみました

while (A[i] < pivot || i < j);

部。しかし、それは何もしませんでした(まあ、それは一度StackOverflowExceptionを引き起こしました)。

4

4 に答える 4

3

あなたは持っていますがj = A.Length、それは本当にそうあるべきですj = A.Length - 1(あなたが使っているループに基づいて)。

于 2012-10-08T16:42:09.057 に答える
1

セグメントの長さが2または3要素の場合でも、クイックソートを使用しようとしていることに気付きました。入力配列のサイズを4要素未満に減らした場合は、別の並べ替え手法を使用する必要があると思います。クイックソートでは、入力配列を「ピボット」要素と2つの別々の配列に分割する必要があることを忘れないでください。1つはすべての要素がピボットよりも小さく、もう1つはすべての要素がピボットよりも大きいです。これを行うには、入力配列に少なくとも3つの要素が必要です。これが問題の原因である可能性があります。

これは、この手法を使用する一般的なクイックソートです...

public delegate int CompareDlg<T>(T thisOne, T otherOne);

public class QuickSort<T> 
{
    #region private variable to sort inplace
    readonly private IList<T> itms;
    private CompareDlg<T> cmp;
    #endregion private variable to sort inplace

    #region properties
    public CompareDlg<T> Comparer
    {
        set { cmp = value; }
        get { return cmp; }
    }
    #endregion properties

    #region ctor
    private QuickSort() { } //     Hide parameterless constructor
    /// <summary>
    /// Constructor, requires generic List of Ts 
    /// where T must implement CompareTo() method...
    /// </summary>
    /// <param name="list">List of T elements to sort</param>
    public QuickSort(IList<T> list) : this(list, null) { }
    /// <summary>
    /// Constructor, requires generic List of Ts 
    /// where T must implement CompareTo() method,
    /// And Compare method to use when sorting,
    /// (Overrides default CompareTo() implemented by T) ...
    /// </summary>
    /// <param name="list">List of T elements to sort</param>
    /// <param name="compareDelegate">Method to use to compare elements</param>
    public QuickSort(IList<T> list, CompareDlg<T> compareDelegate)
        : this()
    {
        if (list.Count == 0) throw new InvalidOperationException(
            "Empty List passed to QuickSort.");
        var first = default(T);
        if (typeof(T).IsClass)
        {
            foreach (var t in list)
                if (!((first = t).Equals(default(T))))
                    break;

            if (first.Equals(default(T)))
                throw new InvalidOperationException(
                    "List passed to QuickSort contains all nulls.");
        }
        if (compareDelegate == null && !(first is IComparable<T>))
            throw new InvalidOperationException(string.Format(
                "Type {0} does not implement IComparable<{0}>. " +
                "Generic Type T must either implement IComparable " +
                "or a comparison delegate must be provided.", typeof(T)));
        itms = list;
        cmp += compareDelegate ?? CompareDefault;
    }
    #endregion ctor

    #region public sort method
    public static void Sort(IList<T> itms) { (new QuickSort<T>(itms)).Sort(); }
    public void Sort(bool asc) { Sort(0, itms.Count - 1, asc); }
    public static void Sort(IList<T> itms, CompareDlg<T> compareDelegate)
    { (new QuickSort<T>(itms, compareDelegate)).Sort(); }
    public void Sort() { Sort(0, itms.Count - 1, true); }
    /// <summary>
    /// Executes QuickSort algorithm
    /// </summary>
    /// <param name="L">Index of left-hand boundary of partition to sort</param>
    /// <param name="R">Index of right-hand boundary of partition to sort</param>
    /// <param name="asc"></param>
    private void Sort(int L, int R, bool asc)
    {
        // Call iSort (insertion-sort) 
        if (R - L < 4) iSort(L, R);
        //for partitions smaller than 4 elements
        else
        {
            int i = (L + R) / 2, j = R - 1;
            // Next three lines to set upper and lower bounds
            if (Comparer(itms[L], itms[i]) > 0 == asc) Swap(L, i);
            if (Comparer(itms[L], itms[R]) > 0 == asc) Swap(L, R);
            if (Comparer(itms[i], itms[R]) > 0 == asc) Swap(i, R);
            Swap(i, j);
            // --------------------------------------------
            var p = itms[j]; // p = itms[j] is pivot element
            i = L;
            while (true)
            {
                while (Comparer(itms[++i], p) < 0 == asc) { }
                while (Comparer(itms[--j], p) > 0 == asc) { }
                if (j < i) break;
                Swap(i, j);
            }
            Swap(i, R - 1);
            Sort(L, i, asc);     // Sort  Left partition
            Sort(i + 1, R, asc); // Sort Right partition
        }
    }
    private static int CompareDefault(T thisOne, T otherOne)
    {
        if(!(thisOne is IComparable<T>)) 
            throw new InvalidCastException(
                "Type must implement IComparable<T>");
        return (thisOne as IComparable<T>).CompareTo(otherOne);
    }
    #endregion public sort method

    #region private Helper methods
    private void Swap(int L, int R)
    {
        var t = itms[L];
        itms[L] = itms[R];
        itms[R] = t;
    }
    private void iSort(int L, int R)
    {
        for (var i = L; i <= R; i++)
        {
            var t = itms[i];
            var j = i;
            while ((j > L) && Comparer(itms[j - 1], t) > 0)
            {
                itms[j] = itms[j - 1];
                j--;
            }
            itms[j] = t;
        }
    }
    #endregion private Helper methods
}
于 2012-10-08T16:54:28.750 に答える
1

値をチェックせずに常に最初の項目をピボットの下に含めます。その後、条件の間にi < j「または」演算子()を使用するため、ピボットの上にある場合でも、他のすべての値を含めます。||

これ:

do
{
  i++;
}
while (A[i] < pivot || i < j);

する必要があります:

while (i < j && A[i] < pivot);
{
  i++;
}
于 2012-10-08T16:54:52.417 に答える
1

さて、あなたがすでに交換した要素を交換しているなど、あまりにも多くの間違いがあります。これは、以前の回答やコメントで述べられたことも含めて、間違いなくそれを行うためのあなたの解決策です。素晴らしいコーディング!

    static int partition(int[] A)
    {
        int pivot, i, j;
        i = 0;
        j = A.Length-1;
        pivot = A[0];

        while (i < j)
        {
            while (A[i] < pivot && i < j)
            {
                i++;
            }

            while (A[j] > pivot && j > i)
            {
                j--;
            }
            swap(ref A[i], ref A[j]);
        }

        return j;
    }

    static void swap(ref int a, ref int b)
    {
        int aCopy = a;
        a = b;
        b = aCopy;
    }

    static int[] QuickSort(int[] A)
    {
        int s;
        int left = 0;
        int right = A.Length;
        int[] B, C;

        if (A.Length == 0 || A.Length == 1)
            return A;
        else
        {
            s = partition(A);
            B = new int[s];
            C = new int[right - s - 1];

            for (int i = left; i < s; i++)
            {
                B[i - left] = A[i];
            }
            for (int i = s + 1; i < right; i++)
            {
                C[i - s - 1] = A[i];
            }

            B = QuickSort(B);
            C = QuickSort(C);
            for(int i = 0; i < s;i++)
                A[i] = B[i - left];
            for (int i = s + 1; i < right; i++)
            {
                A[i] = C[i - s - 1];
            }
            return A;
        }
    }
于 2012-10-08T17:53:33.177 に答える