为什么我在quicksort的helper函数中遇到stackoverflow异常?

时间:2018-04-18 21:27:27

标签: c# algorithm

我想使用Quicksort解决以下问题。

我在一个数组中有 n 字符串,其中每个字符串都保证为正正数,没有前导零和1到10 ^ 6之间的数字。我使用带有BigInteger结构的常规快速排序来做到这一点,但是我有很多超时情况导致我认为我需要优化我的比较方式并从string[]中删除解析到BigInteger[]并返回string[],所以我决定按原样排序。这是我的代码:

static void swap(string[] array, int first, int second)
{
    var temp = array[first];
    array[first] = array[second];
    array[second] = temp;
}

static void quickSort(string[] array, int left, int right)
{
    if (left >= right) return;
    var pivot = array[(left + right) / 2];
    var index = partition(array, left, right, pivot);
    quickSort(array, left, index - 1);
    quickSort(array, index, right);
}

static int partition(string[] array, int left, int right, string pivot)
{
    while(left <= right)
    {
        while (left < array.Length && !array[left].IsBigger(pivot)) left++;
        while (right < array.Length && array[right].IsBigger(pivot)) right--;
        if (left <= right)
        {
            swap(array, left, right);
            left++;
            right--;
        }
    }

    return left;
}

static bool IsBigger(this string a, string b)
{
    if (a.Length < b.Length) return false;
    else if(a.Length > b.Length) return true;

    for (int i = 0; i < a.Length; i++)
    {
        if (a[i] > b[i]) return true;
        else return false;
    }

    return false;
}

但是,当IsBigger函数的输入非常小[ "31415926535897932384626433832795", "1", "3", "10", "3", "5" ]时,我会在quickSort(unsorted, 0, unsorted.Length - 1);函数中出现异常,而我似乎无法尝试原因。

没有任何有趣的时刻叫做quicksort - 我就是这样做的RuntimeHelpers.EnsureSufficientExecutionStack();

到目前为止我尝试了什么

  • 听起来很疯狂,但是我试图强制.NET确保这个方法需要更多的堆栈大小,因为在IsBigger中调用Function MySQL-nonQuery($server, $user, $pass, $database, $sql){ try{ #set up My SQL connection [void][System.Reflection.Assembly]::LoadWithPartialName("MySql.Data") $connectionString = "server=" + $server + ";port=3306;uid=" + $user + ";pwd=" + $pass + ";database="+$database + ";AllowUserVariables=True" $connection = New-Object MySql.Data.MySqlClient.MySqlConnection $connection.ConnectionString = $ConnectionString $connection.Open() } catch{ $Error[0] } #set up command $updateCOD = New-Object MySql.Data.MySqlClient.MySqlCommand($sql, $connection) $updateCOD.CommandText $updateCOD.ExecuteNonQuery() $connection.Close() } 但是没有工作,一切看起来都不错也

4 个答案:

答案 0 :(得分:2)

IsBigger似乎存在问题

“1234” .IsBigger( “1235”) 和 “1235”.IsBigger(“1234”)

都返回false。

应该删除循环中的else子句。

答案 1 :(得分:1)

问题是我很傻到相信 x&gt; y ==!(x&lt; y)当它真的应该是 x&gt; y == x&lt; = y 。注意离散数学家的类别。

这让我介绍另一种辅助方法

static bool IsLessThan(this string a, string b)
    => a.Equals(b) ? false : !a.IsBigger(b);

最终将分区方法更改为

static int partition(string[] array, int left, int right, string pivot)
{
    while (left <= right)
    {
        while (array[left].IsLessThan(pivot)) left++;
        while (array[right].IsBigger(pivot)) right--;
        if (left <= right)
        {
            swap(array, left, right);
            left++;
            right--;
        }
    }
    return left;
}

答案 2 :(得分:0)

出于某种原因,这种情况永远不会发生

if (left >= right) return;

你永远不会回来。因此,你永远地递归并溢出你的筹码。使用您的调试器找出您正确的原因&gt;左

答案 3 :(得分:0)

可以尝试这样的方法,并将“IsBigger”扩展方法调整为您想要的内容:

using System;

namespace ConsoleApp1
{
    class Program
    {
        static void swap(string[] array, int first, int second)
        {
            var temp = array[first];
            array[first] = array[second];
            array[second] = temp;
        }

        static void quickSort(string[] array, int left, int right)
        {
            int i = left, j = right;
            var pivot = array[(left + right) / 2];

            while (i <= j)
            {
                while (array[i].IsBigger(pivot))
                {
                    i++;
                }

                while (array[j].IsBigger(pivot))
                {
                    j--;
                }

                if (i <= j)
                {
                    // Swap                    
                    swap(array, i, j);

                    i++;
                    j--;
                }
            }

            // Recursive calls
            if (left < j)
            {
                quickSort(array, left, j);
            }

            if (i < right)
            {
                quickSort(array, i, right);
            }
        }

        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");

            var array = new[] { "31415926535897932384626433832795", "1", "3", "10", "3", "5" };

            // Print the unsorted array
            for (int i = 0; i < array.Length; i++)
            {
                Console.Write(array[i] + " ");
            }

            Console.WriteLine();

            quickSort(array, 0, array.Length - 1);

            // Print the sorted array
            for (int i = 0; i < array.Length; i++)
            {
                Console.Write(array[i] + " ");
            }

            Console.WriteLine();
            Console.WriteLine("Done!");

            Console.ReadLine();
        }
    }

    public static class StringExtension
    {
        public static bool IsBigger(this string a, string b)
        {
            if (a.Length < b.Length) return false;
            else if (a.Length > b.Length) return true;

            for (int i = 0; i < a.Length; i++)
            {
                if (a[i] > b[i]) return true;

                return false;
            }

            return false;
        }
    }
}