2.4.16 #
解答 #
最好情况比较简单,只需要一个所有键值完全相同的数组即可。
最坏情况的构造方法参考了一篇论文(见「另请参阅」部分),结果如下:
最好输入:
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
最坏输入:
1 4 7 12 10 16 14 19 17 20 5 27 8 28 2 24 9 18 6 23 11 22 21 31 13 26 25 30 15 29 3 32
代码 #
用于构造堆排序最坏情况的类。
public class MaxPqWorstCase
{
/// <summary>
/// 保存元素的数组。
/// </summary>
/// <value>保存元素的数组。</value>
private readonly int[] _pq;
/// <summary>
/// 堆中的元素数量。
/// </summary>
/// <value>堆中的元素数量。</value>
private int _n;
/// <summary>
/// 建立指定容量的最大堆。
/// </summary>
/// <param name="capacity">最大堆的容量。</param>
public MaxPqWorstCase(int capacity)
{
_pq = new int[capacity + 1];
_n = 0;
}
/// <summary>
/// 制造堆排序的最坏情况。
/// </summary>
/// <param name="n">需要构造的数组大小。</param>
/// <returns>最坏情况的输入数组。</returns>
public int[] MakeWorst(int n)
{
var strategy = Win(n);
for (var i = 0; i < strategy.Length; i++)
{
UnRemoveMax(strategy[i]);
}
for (var i = 1; i <= _n / 2; i++)
UnFixHeap(i);
var worstCase = new int[n];
for (var i = 1; i <= n; i++)
worstCase[i - 1] = _pq[i];
return worstCase;
}
private bool Less(int i, int j) => _pq[i].CompareTo(_pq[j]) < 0;
private int PullDown(int i, int j)
{
var toReturn = _pq[j];
for (var m = j; m / 2 >= i; m /= 2)
{
_pq[m] = _pq[m / 2];
}
return toReturn;
}
private void UnFixHeap(int i)
{
var j = (int)(i * Math.Pow(2, Math.Floor(Math.Log10(_n / i) / Math.Log10(2))));
_pq[i] = PullDown(i, j);
}
private void UnRemoveMax(int i)
{
var p = (_n + 1) / 2;
if (Less(p, i))
return;
_n++;
_pq[_n] = PullDown(1, i);
_pq[1] = _n;
}
private int[] Par(int l)
{
var n = (int)Math.Pow(2, l) - 1;
int[] s7 = { 0, 1, 2, 3, 4, 4, 5 };
var strategy = new int[n];
for (var i = 0; i < Math.Min(n, 7); i++)
{
strategy[i] = s7[i];
}
if (n <= 7)
return strategy;
for (var lev = 3; lev < l; lev++)
{
var i = (int)Math.Pow(2, lev) - 1;
strategy[i] = i;
strategy[i + 1] = i - 1;
strategy[i + 2] = i + 1;
strategy[i + 3] = i + 2;
strategy[i + 4] = i + 4;
strategy[i + 5] = i + 3;
for (var k = i + 6; k <= 2 * i; k++)
{
strategy[k] = k - 1;
}
}
return strategy;
}
private int[] Win(int n)
{
var strategy = new int[n];
var s = Par((int)Math.Floor(Math.Log10(n) / Math.Log10(2)) + 1);
for (var i = 1; i <= n - 1; i++)
{
strategy[i] = s[i];
}
var I = (int)Math.Pow(2, Math.Floor(Math.Log10(n + 1) / Math.Log10(2))) - 1;
if ((n == I) || (n <= 7))
return strategy;
strategy[I] = I;
if (n == I + 1)
return strategy;
strategy[I + 1] = (I + 1) / 2;
if (n == I + 2)
return strategy;
for (var i = I + 2; i <= n - 1; i++)
{
if (i == 2 * I - 2)
strategy[i] = i;
else
strategy[i] = i - 1;
}
return strategy;
}
}
另请参阅 #
给出堆排序最坏情况构造方法的论文 Suchenek M A. A Complete Worst-Case Analysis of Heapsort with Experimental Verification of Its Results, A manuscript (MS)[J]. arXiv preprint arXiv:1504.01459, 2015. 本题用到的库文件 PriorityQueue 库