2.1.37

2.1.37 #

解答 #

主要说一下第二个的实现,把一个数组按 10 位进行打乱即可。

代码 #

// 选择排序的性能只与数组大小有关,以上三种情况耗时都是近似的。
// 插入排序的性能与逆序对数量有关,部分有序的情况下耗时会小于完全随机。
// 希尔排序与插入排序类似。
var insertionSort = new InsertionSort();
var selectionSort = new SelectionSort();
var shellSort = new ShellSort();
var n = 100000;
var insertionArray = new int[n];
var shellArray = new int[n];

// 完全随机的对照
Console.WriteLine("totally random");
Console.WriteLine("Selection Sort:" + SortCompare.TimeRandomInput(selectionSort, n, 1));
Console.WriteLine("Insertion Sort:" + SortCompare.TimeRandomInput(insertionSort, n, 1));
Console.WriteLine("Shell Sort:" + SortCompare.TimeRandomInput(shellSort, n, 1));

// 95% 有序,其余部分为随机值。
var selectionArray = Sorted95Random5(n);
selectionArray.CopyTo(insertionArray, 0);
selectionArray.CopyTo(shellArray, 0);
Console.WriteLine("95% sorted + 5% random");
Console.WriteLine("Selection Sort:" + SortCompare.Time(selectionSort, selectionArray));
Console.WriteLine("Insertion Sort:" + SortCompare.Time(insertionSort, insertionArray));
Console.WriteLine("Shell Sort:" + SortCompare.Time(shellSort, shellArray));

// 所有元素和它们的正确位置的距离都不超过 10。
selectionArray = RandomIn10(n);
selectionArray.CopyTo(insertionArray, 0);
selectionArray.CopyTo(shellArray, 0);
Console.WriteLine("all elements placed randomly in range of 10");
Console.WriteLine("Selection Sort:" + SortCompare.Time(selectionSort, selectionArray));
Console.WriteLine("Insertion Sort:" + SortCompare.Time(insertionSort, insertionArray));
Console.WriteLine("Shell Sort:" + SortCompare.Time(shellSort, shellArray));

// 5% 的元素随机分布在整个数组中,剩下的数据都是有序的。
selectionArray = Shuffle5Percent(n);
selectionArray.CopyTo(insertionArray, 0);
selectionArray.CopyTo(shellArray, 0);
Console.WriteLine("95% elements is sorted while 5% elements are placed randomly");
Console.WriteLine("Selection Sort:" + SortCompare.Time(selectionSort, selectionArray));
Console.WriteLine("Insertion Sort:" + SortCompare.Time(insertionSort, insertionArray));
Console.WriteLine("Shell Sort:" + SortCompare.Time(shellSort, shellArray));

// 生成 95% 有序,最后 5% 随机的 <see cref="int"/> 数组。
static int[] Sorted95Random5(int n)
{
    var array = new int[n];
    var randomStart = (int)(n * 0.05);
    var random = new Random();

    for (var i = 0; i < n - randomStart; i++)
    {
        array[i] = i;
    }

    for (var i = n - randomStart; i < n; i++)
    {
        array[i] = random.Next();
    }

    return array;
}

// 返回一个 <see cref="int"/> 数组,其中的每个元素和它的正确位置的距离都不超过 10。
static int[] RandomIn10(int n)
{
    var array = new int[n];

    for (var i = 0; i < n; i++)
    {
        array[i] = i;
    }

    for (var i = 0; i < n; i += 10)
    {
        var max = Math.Min(n, i + 10);
        ShuffleRange(array, i, max);
    }
    
    return array;
}

// 生成 5% 元素随机分布,剩余有序的 int 数组。
static int[] Shuffle5Percent(int n)
{
    var random = new Random();
    var percent5 = (int)(n * 0.05);

    var randomIndex = new int[percent5];
    for (var i = 0; i < percent5; i++)
    {
        randomIndex[i] = random.Next(percent5);
    }

    var randomValue = new int[percent5];
    for (var i = 0; i < percent5; i++)
    {
        randomValue[i] = randomIndex[i];
    }

    Shuffle(randomValue);

    var array = new int[n];
    for (var i = 0; i < n; i++)
    {
        array[i] = i;
    }

    for (var i = 0; i < percent5; i++)
    {
        array[randomIndex[i]] = randomValue[i];
    }

    return array;
}

static void ShuffleRange(int[] a, int lo, int hi)
{
    var random = new Random();
    for (var i = lo; i < hi; i++)
    {
        var r = i + random.Next(hi - i); // 等于StdRandom.uniform(N-i)
        var temp = a[i];
        a[i] = a[r];
        a[r] = temp;
    } 
}

// 打乱数组。
static void Shuffle(int[] a)
{
    ShuffleRange(a, 0, a.Length);
}

另请参阅 #

Sort 库