2.3.26 #
解答 #
在切换为插入排序之前先记录一下当前子数组的大小。
在排序类内添加一个大小为 M+1 的数组,用于记录每种数组大小出现的次数。
结果如下(N=100000): M=10
M=20
M=50
代码 #
using System;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using Quick;
namespace _2._3._26
{
public partial class Form2 : Form
{
private int M;
private int N;
public Form2(int m, int n)
{
InitializeComponent();
this.M = m;
this.N = n;
}
/// <summary>
/// 启动页面时启动后台测试。
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Form2_Shown(object sender, EventArgs e)
{
this.Text = "正在绘图";
this.backgroundWorker1.RunWorkerAsync();
}
/// <summary>
/// 后台测试方法。
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
QuickSortInsertion quickSortInsertion = new QuickSortInsertion
{
M = this.M
};
int[] data = SortCompare.GetRandomArrayInt(this.N);
worker.ReportProgress(50);
quickSortInsertion.Sort(data);
e.Result = quickSortInsertion.Counts;
}
/// <summary>
/// 更新后台进度方法。
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.Text = "正在绘图,已完成 " + e.ProgressPercentage + " %";
}
/// <summary>
/// 测试完毕,进行绘图的方法。
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
MessageBox.Show(e.Error.Message);
}
//新建画布
Graphics graphics = this.CreateGraphics();
//翻转默认坐标系
graphics.TranslateTransform(0, this.Height);
graphics.ScaleTransform(1, -1);
int[] countsOrigin = e.Result as int[];
int[] counts = new int[countsOrigin.Length - 1];
for (int i = 0; i < counts.Length; i++)
{
counts[i] = countsOrigin[i + 1];
}
//获取最大值
double max = counts.Max();
//计算间距
double unit = this.Width / (3.0 * counts.Length + 1);
double marginTop = 100;
//计算直方图的矩形
Rectangle[] rects = new Rectangle[counts.Length];
rects[0].X = (int)unit;
rects[0].Y = 0;
rects[0].Width = (int)(2 * unit);
rects[0].Height = (int)((counts[0] / max) * (this.Height - marginTop));
for (int i = 1; i < counts.Length; ++i)
{
rects[i].X = (int)(rects[i - 1].X + 3 * unit);
rects[i].Y = 0;
rects[i].Width = (int)(2 * unit);
rects[i].Height = (int)((counts[i] / (max + 1)) * (this.Height - marginTop));
}
//绘图
graphics.FillRectangles(Brushes.Black, rects);
//释放资源
graphics.Dispose();
this.Text = "绘图结果,最高次数:" + counts.Max() + " 最低次数:" + counts.Min();
}
}
}
快速排序类
public class QuickSortInsertion : BaseSort
{
/// <summary>
/// 切换到插入排序的阈值。
/// </summary>
public int M { get; set; }
public int[] Counts;
/// <summary>
/// 默认构造函数。
/// </summary>
public QuickSortInsertion()
{
M = 8;
}
/// <summary>
/// 用快速排序对数组 a 进行升序排序。
/// </summary>
/// <typeparam name="T">需要排序的类型。</typeparam>
/// <param name="a">需要排序的数组。</param>
public override void Sort<T>(T[] a)
{
Counts = new int[M + 1];
for (var i = 0; i < M + 1; i++)
{
Counts[i] = 0;
}
Shuffle(a);
Sort(a, 0, a.Length - 1);
Debug.Assert(IsSorted(a));
}
/// <summary>
/// 用快速排序对数组 a 的 lo ~ hi 范围排序。
/// </summary>
/// <typeparam name="T">需要排序的数组类型。</typeparam>
/// <param name="a">需要排序的数组。</param>
/// <param name="lo">排序范围的起始下标。</param>
/// <param name="hi">排序范围的结束下标。</param>
protected void Sort<T>(T[] a, int lo, int hi) where T: IComparable<T>
{
if (hi <= lo) // 别越界
return;
if (hi - lo <= M)
{
Counts[hi - lo]++;
// 调用插入排序
for (var i = lo; i <= hi; i++)
for (var k = i; k > lo && Less(a[k], a[k - 1]); k--)
Exch(a, k, k - 1);
return;
}
var j = Partition(a, lo, hi);
Sort(a, lo, j - 1);
Sort(a, j + 1, hi);
}
/// <summary>
/// 对数组进行切分,返回枢轴位置。
/// </summary>
/// <typeparam name="T">需要切分的数组类型。</typeparam>
/// <param name="a">需要切分的数组。</param>
/// <param name="lo">切分的起始点。</param>
/// <param name="hi">切分的末尾点。</param>
/// <returns>枢轴下标。</returns>
private int Partition<T>(T[] a, int lo, int hi) where T : IComparable<T>
{
int i = lo, j = hi + 1;
var v = a[lo];
while (true)
{
while (Less(a[++i], v))
if (i == hi)
break;
while (Less(v, a[--j]))
if (j == lo)
break;
if (i >= j)
break;
Exch(a, i, j);
}
Exch(a, lo, j);
return j;
}
/// <summary>
/// 打乱数组。
/// </summary>
/// <typeparam name="T">需要打乱的数组类型。</typeparam>
/// <param name="a">需要打乱的数组。</param>
private void Shuffle<T>(T[] a)
{
var random = new Random();
for (var i = 0; i < a.Length; i++)
{
var r = i + random.Next(a.Length - i);
var temp = a[i];
a[i] = a[r];
a[r] = temp;
}
}
}