简体   繁体   English

C#中的QuickSort算法有什么问题?

[英]What is wrong with this QuickSort algorithm in C#?

Sadly, I've got problems with Quicksort as well. 可悲的是,我也遇到了Quicksort的问题。 I've discussed it with other students and tried the standard troubleshooting methods. 我已经与其他学生讨论过,并尝试了标准的故障排除方法。 But I can't find what I'm doing wrong... 但是我找不到我做错了什么...

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;
        }
    }

The debugger constantly gives me an 'IndexOutOfRangeException' with the j variable. 调试器不断为我提供带有j变量的'IndexOutOfRangeException'。 I've tried adjusting the 我试过调整

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

part. 部分。 But that didn't do anything (well, it resulted in a StackOverflowException once). 但这并没有做任何事情(嗯,它一次导致了StackOverflowException)。

您有j = A.Length ,但实际上应该是j = A.Length - 1 (基于您使用的循环)。

I notice that you are still trying tio use Quicksort even when the segments are 2 or 3 elements long. 我注意到即使段长为2或3个元素,您仍在尝试使用Quicksort。 I think you need to use an alternate sort technique when you have reduced the size of the input arrays to less than 4 elements. 我认为,当您将输入数组的大小减小到少于4个元素时,您需要使用另一种排序技术。 Remember, the quick sort requires that you break up the input array into a "pivot" element, and 2 separate arrays, one with all the elements less than the pivot, and the other with all the elements greater than the pivot. 请记住,快速排序要求您将输入数组分解为“ pivot”元素,并拆分为2个单独的数组,一个数组的所有元素均小于枢轴,而另一个数组的所有元素均大于枢轴。 To do this the input array has to have at least 3 elements. 为此,输入数组必须至少包含3个元素。 This may be the source of your issue. 这可能是您问题的根源。

Here's a generic quicksort that uses this technique... 这是使用此技术的通用快速排序...

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
}

You are always including the first item as one under the pivot without checking the value, then you are including all the other values even if they are above the pivot, just because i < j , as you use the 'or' operator ( || ) between the conditions. 您总是在不检查值的情况下始终将第一项作为一个项包括在内,然后,即使它们在枢轴之上,也要包括所有其他值,这是因为使用i < ji < j时会使用'or'运算符( || )之间的条件。

This: 这个:

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

Should be: 应该:

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

Well, there are too many mistakes, like you are swapping back the elements you have already swapped and so on. 好吧,这里有太多错误,例如您要交换回已经交换过的元素,依此类推。 This is your solution with your way of doing it without mistakes that also includes what has been said in previous answers and comments. 这是您的解决方案,没有任何错误,还包括以前的答案和评论中提到的内容。 Nice coding! 不错的编码!

    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;
        }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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