2.1.35

2.1.35 #

解答 #

难点是如何生成符合这些分布的随机数。

Java 的话官方给的 stdRandom 里面都有相应的实现。

结果:

代码 #

几种随机数的实现:

public static class SortUtil
{
    /// <summary>
    /// 随机数发生器,所有对象共享同一个随机数发生器。
    /// </summary>
    public static Random UniformGenerator = new();

    /// <summary>
    /// 产生符合正态分布的随机数。
    /// </summary>
    /// <param name="average">正态分布的期望值 μ。</param>
    /// <param name="standardDeviation">正态分布的标准差 σ。</param>
    /// <returns>符合正态分布的随机数。</returns>
    public static double Normal(double average, double standardDeviation)
    {
        var u1 = UniformGenerator.NextDouble();
        var u2 = UniformGenerator.NextDouble();

        var z0 = Math.Sqrt(-2.0 * Math.Log(u1)) * Math.Cos(Math.PI * 2 * u2);
            
        return z0 * standardDeviation + average;
    }

    /// <summary>
    /// 生成符合泊松分布的随机数。
    /// </summary>
    /// <param name="average">泊松分布的期望值 λ。</param>
    /// <returns>一个符合泊松分布的随机数。</returns>
    public static double Poission(double average)
    {
        double x = 0;
        var p = Math.Pow(Math.E, -average);
        var s = p;
        var u = UniformGenerator.NextDouble();
        do
        {
            x++;
            p *= average / x;
            s += p;
        } while (u > s);
        return x;
    }

    /// <summary>
    /// 生成符合几何分布的随机数。
    /// </summary>
    /// <param name="p">几何分布的概率 p,这应该是一个小于 1 的非负数。</param>
    /// <exception cref="ArgumentOutOfRangeException">概率不能大于 1.</exception>
    /// <returns>符合几何分布的随机数。</returns>
    public static double Geometry(double p)
    {
        if (p > 1)
        {
            throw new ArgumentOutOfRangeException("p", "概率不能大于 1");
        }

        double result;
        result = Math.Ceiling(Math.Log(1 - UniformGenerator.NextDouble()) / Math.Log(1 - p));

        return result;
    }

    /// <summary>
    /// 根据指定的几率数组产生符合离散分布的随机数。
    /// </summary>
    /// <param name="probabilities">各取值的可能性。</param>
    /// <exception cref="ArgumentNullException"><paramref name="probabilities"/> 为 <c>null</c> 时抛出。</exception>
    /// <exception cref="ArgumentException"><paramref name="probabilities"/> 中存在大于 1 或 小于 0 的数,或者总和不为 1 时抛出。</exception>
    /// <returns>符合随机分布的随机整数。</returns>
    public static double Discrete(double[] probabilities)
    {
        if (probabilities == null)
        {
            throw new ArgumentNullException(nameof(probabilities), "Argument array is null");
        }

        var epsion = 1E-14;
        double sum = 0;
        for (var i = 0; i < probabilities.Length; i++)
        {
            if (probabilities[i] <= 0)
            {
                throw new ArgumentException("array entry " + i + " must be nonnegative:" + probabilities[i]);
            }

            sum += probabilities[i];
        }

        if (sum > 1.0 + epsion || sum < 1.0 - epsion)
        {
            throw new ArgumentException("sum of array entries does not equal 1.0:" + sum);
        }

        while (true)
        {
            var r = UniformGenerator.NextDouble();
            sum = 0.0;
            for (var i = 0; i < probabilities.Length; i++)
            {
                sum += probabilities[i];
                if (sum > r)
                {
                    return i;
                }
            }
        }
    }
}

Main 方法:

var insertionSort = new InsertionSort();
var selectionSort = new SelectionSort();
var shellSort = new ShellSort();
var n = 10000;

// 高斯分布(正态分布)
var arrayInsertion = SortCompare.GetNormalDistributionArray(n);
var arraySelection = new double[n];
var arrayShell = new double[n];
arrayInsertion.CopyTo(arraySelection, 0);
arrayInsertion.CopyTo(arrayShell, 0);
Console.WriteLine("Normal Distribution:");
Console.WriteLine("Insertion: " + SortCompare.Time(insertionSort, arrayInsertion));
Console.WriteLine("Selection: " + SortCompare.Time(selectionSort, arraySelection));
Console.WriteLine("Shell: " + SortCompare.Time(shellSort, arrayShell));

// 泊松分布
arrayInsertion = SortCompare.GetPossionDistributionArray(n);
arrayInsertion.CopyTo(arraySelection, 0);
arrayInsertion.CopyTo(arrayShell, 0);
Console.WriteLine("Poission Distribution:");
Console.WriteLine("Insertion: " + SortCompare.Time(insertionSort, arrayInsertion));
Console.WriteLine("Selection: " + SortCompare.Time(selectionSort, arraySelection));
Console.WriteLine("Shell: " + SortCompare.Time(shellSort, arrayShell));

// 几何分布
arrayInsertion = SortCompare.GetGeometricDistributionArray(n, 0.3);
arrayInsertion.CopyTo(arraySelection, 0);
arrayInsertion.CopyTo(arrayShell, 0);
Console.WriteLine("Geometric Distribution:");
Console.WriteLine("Insertion: " + SortCompare.Time(insertionSort, arrayInsertion));
Console.WriteLine("Selection: " + SortCompare.Time(selectionSort, arraySelection));
Console.WriteLine("Shell: " + SortCompare.Time(shellSort, arrayShell));

// 离散分布
arrayInsertion = SortCompare.GetDiscreteDistributionArray(n, new[] { 0.1, 0.2, 0.3, 0.1, 0.1, 0.1, 0.1 });
arrayInsertion.CopyTo(arraySelection, 0);
arrayInsertion.CopyTo(arrayShell, 0);
Console.WriteLine("Discret Distribution:");
Console.WriteLine("Insertion: " + SortCompare.Time(insertionSort, arrayInsertion));
Console.WriteLine("Selection: " + SortCompare.Time(selectionSort, arraySelection));
Console.WriteLine("Shell: " + SortCompare.Time(shellSort, arrayShell));

另请参阅 #

Sort 库