|
这几天无聊,就去研究排序算法,话不多说,用事实说话。
|
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Diagnostics;
namespace 排序算法大PK
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("规则:取20000随机数,比较各自耗时");
for (int i = 0; i < 5; i++)
{
List<int> list = new List<int>();
//取20000个随机数到集合中
for (int j = 0; j < 20000; j++)
{
Thread.Sleep(1);
list.Add(new Random((int)DateTime.Now.Ticks).Next(0, 1000000));
}
Console.WriteLine("\n第" + i + "轮PK:");
Stopwatch watch = new Stopwatch(); //Stopwatch类可用于准确地测量运行时间
watch.Start(); //开始或继续测量某个时间间隔的运行时间
var result = list.OrderBy(single => single).ToList();
watch.Stop();
Console.WriteLine("快速排序耗费时间:" + watch.ElapsedMilliseconds + "毫秒");
Console.WriteLine("输出前十个数:" + string.Join(",", result.Take(10).ToList()));
watch.Reset();
watch.Start();
result = DirectSequence(list);
watch.Stop();
Console.WriteLine("选择排序耗费时间:" + watch.ElapsedMilliseconds + "毫秒");
Console.WriteLine("输出前十个数:" + string.Join(",", result.Take(10).ToList()));
watch.Reset();
watch.Start();
result = BubbleSort(list);
watch.Stop();
Console.WriteLine("冒泡排序耗费时间:" + watch.ElapsedMilliseconds + "毫秒");
Console.WriteLine("输出前十个数:" + string.Join(",", result.Take(10).ToList()));
watch.Reset();
watch.Start();
result = HeapSort(list);
watch.Stop();
Console.WriteLine("堆排序耗费时间:" + watch.ElapsedMilliseconds + "毫秒");
Console.WriteLine("输出前十个数:" + string.Join(",", result.Take(10).ToList()));
watch.Reset();
watch.Start();
result = InsertionSort(list);
watch.Stop();
Console.WriteLine("插入排序耗费时间:" + watch.ElapsedMilliseconds + "毫秒");
Console.WriteLine("输出前十个数:" + string.Join(",", result.Take(10).ToList()));
watch.Reset();
watch.Start();
result = HillSort(list);
watch.Stop();
Console.WriteLine("希尔排序耗费时间:" + watch.ElapsedMilliseconds + "毫秒");
Console.WriteLine("输出前十个数:" + string.Join(",", result.Take(10).ToList()));
watch.Reset();
watch.Start(); //开始或继续测量某个时间间隔的运行时间
result = list.OrderByDescending(single => single).Take(10).ToList();
watch.Stop();
Console.WriteLine("快速排序取最大的前十个耗费时间:" + watch.ElapsedMilliseconds + "毫秒");
Console.WriteLine("输出前十个数:" + string.Join(",", result.Take(10).ToList()));
watch.Reset();
watch.Start();
result = NewHeapSort(list, 10);
watch.Stop();
Console.WriteLine("堆排序取最大的前十个耗费时间:" + watch.ElapsedMilliseconds + "毫秒");
Console.WriteLine("输出前十个数:" + string.Join(",", result.Take(10).ToList()));
}
Console.Read();
}
#region 冒泡排序
private static List<int> BubbleSort(List<int> list)
{
int temp = 0;
for (int i = 0; i < list.Count - 1; i++)
{
for (int j = list.Count - 1; j > i; j--)
{
if (list[j] < list[j - 1])
{
temp = list[j - 1];
list[j - 1] = list[j];
list[j] = temp;
}
}
}
return list;
}
#endregion
#region 选择排序
static List<int> DirectSequence(List<int> list)
{
for (int i = 0; i < list.Count - 1; i++)
{
int min = i; //假设min的下标的值最小
for (int j = i + 1; j < list.Count; j++)
{
//如果min下标的值大于j下标的值,则记录较小值下标j
if (list[min] > list[j])
{
min = j;
}
}
//最后将假想最小值跟真的最小值进行交换
var temp = list[min];
list[min] = list[i];
list[i] = temp;
}
return list;
}
#endregion
#region 堆排序
//构建堆
static void HeapAdjust(List<int> list, int parent, int length)
{
//temp保存当前父节点
int temp = list[parent];
//得到左孩子(这可是二叉树的定义,大家看图也可知道)
int child = 2 * parent + 1;
while (child < length)
{
//如果parent有右孩子,则要判断左孩子是否小于右孩子
if (child + 1 < length && list[child] < list[child + 1])
child++;
//父亲节点大于子节点,就不用做交换
if (temp >= list[child])
break;
//将较大子节点的值赋给父亲节点
list[parent] = list[child];
//然后将子节点做为父亲节点,已防止是否破坏根堆时重新构造
parent = child;
//找到该父亲节点较小的左孩子节点
child = 2 * parent + 1;
}
//最后将temp值赋给较大的子节点,以形成两值交换
list[parent] = temp;
}
///<summary>
/// 堆排序
///</summary>
///<param name="list"></param>
static List<int> HeapSort(List<int> list)
{
//list.Count/2-1:就是堆中父节点的个数
for (int i = list.Count / 2 - 1; i >= 0; i--)
{
HeapAdjust(list, i, list.Count);
}
//最后输出堆元素
for (int i = list.Count - 1; i > 0; i--)
{
//堆顶与当前堆的第i个元素进行值对调
int temp = list[0];
list[0] = list[i];
list[i] = temp;
//因为两值交换,可能破坏根堆,所以必须重新构造
HeapAdjust(list, 0, i);
}
return list;
}
#endregion
#region 堆排序(取前N大的数)
///<summary>
/// 构建堆
///</summary>
///<param name="list">待排序的集合</param>
///<param name="parent">父节点</param>
///<param name="length">输出根堆时剔除最大值使用</param>
static void NewHeapAdjust(List<int> list, int parent, int length)
{
//temp保存当前父节点
int temp = list[parent];
//得到左孩子(这可是二叉树的定义哇)
int child = 2 * parent + 1;
while (child < length)
{
//如果parent有右孩子,则要判断左孩子是否小于右孩子
if (child + 1 < length && list[child] < list[child + 1])
child++;
//父节点大于子节点,不用做交换
if (temp >= list[child])
break;
//将较大子节点的值赋给父亲节点
list[parent] = list[child];
//然后将子节点做为父亲节点,已防止是否破坏根堆时重新构造
parent = child;
//找到该父节点左孩子节点
child = 2 * parent + 1;
}
//最后将temp值赋给较大的子节点,以形成两值交换
list[parent] = temp;
}
///<summary>
/// 堆排序
///</summary>
///<param name="list">待排序的集合</param>
///<param name="top">前K大</param>
///<returns></returns>
public static List<int> NewHeapSort(List<int> list, int top)
{
List<int> topNode = new List<int>();
//list.Count/2-1:就是堆中非叶子节点的个数
for (int i = list.Count / 2 - 1; i >= 0; i--)
{
NewHeapAdjust(list, i, list.Count);
}
//最后输出堆元素(求前K大)
for (int i = list.Count - 1; i >= list.Count - top; i--)
{
//堆顶与当前堆的第i个元素进行值对调
int temp = list[0];
list[0] = list[i];
list[i] = temp;
//最大值加入集合
topNode.Add(temp);
//因为顺序被打乱,必须重新构造堆
NewHeapAdjust(list, 0, i);
}
return topNode;
}
#endregion
#region 插入排序
static List<int> InsertionSort(List<int> list)
{
for (int i = 1; i < list.Count; i++)
{
var temp = list[i];
int j;
for (j = i - 1; j >= 0 && temp < list[j]; j--)
{
list[j + 1] = list[j];
}
list[j + 1] = temp;
}
return list;
}
#endregion
#region 希尔排序(“插入排序”的改进版)
static List<int> HillSort(List<int> list)
{
int num = list.Count / 2; //取增量
while (num >= 1)
{
for (int i = num; i < list.Count; i++) //无须序列
{
var temp = list[i];
int j;
for (j = i - num; j >= 0 && temp < list[j]; j = j - num) //有序序列
{
list[j + num] = list[j];
}
list[j + num] = temp;
}
num = num / 2;
}
return list;
}
#endregion
}
}
本文通过实验对比了多种排序算法(包括快速排序、选择排序、冒泡排序等)在相同数据集上的性能表现,并记录了每种算法所需的时间。实验采用20000个随机整数作为输入数据,重复进行了五轮测试。
427

被折叠的 条评论
为什么被折叠?



