这篇主要写关于顺序排序的十二种算法,也是我有关算法的第一帖。主要是写,对每种算法的理解与测试。

速度测试,主要根据一千、一万、五万、百万这 四种。速度纪录还是用Stopwatch 这个类。使用随机数Random生成随机的集合。

其中数量五万左右的小数量排序,使用快速排序,速度最快。大数量百万左右使用鸽巢排序,速度最快。废话不多说,接下来上代码。

第一种:冒泡排序

冒泡排序我相信是每个程序员,都会学到的一种比较排序算法。非常简单,通过多次重复比较每对相邻元素,并按规定的顺序交换他们,最终把数列进行排序。

public static IList<int> BubbleSort(IList<int> list)
{
try
{
//获取集合数量,比较排序,所以取倒数第二个
int n = list.Count - ;
//大方向从前往后,一直到倒数第二个
for (int i = ; i < n; i++)
{
//小方向从后往前,一直到大方向的索引
for (int j = n; j > i; j--)
{
//强转比较类型,从最后往前比较一位
if (((IComparable)list[j - ]).CompareTo(list[j]) > )
{
//利用优先级
list[j - ] = list[j] + (list[j] = list[j - ]) * ;
}
}
}
return list;
}
catch (Exception ex)
{
throw ex;
}
}

可以看到,是两个循环,大方向是从0到最后,小方向是从后往前。从后往前分别比较前后的数字,数字小的往前。

这种方法,是最慢的方法。因为只是一个一个比较,尾部小数问题严重影响速度。下面,上测试结果

一万就5秒了,十万和百万,就不测试了。总而言之,非常慢。

第二种:双向冒泡

双向冒泡是在冒泡排序的基础上由两个方向同时进行。只是解决了尾部小数问题,还是比较排序算法。效率也不高。

public static IList<int> BiDerectionalBubleSort(IList<int> list)
{
try
{
//获取集合数量
int limite = list.Count;
int st = -;
bool swapped = false;
do
{
swapped = false;
st++;
limite--;
//从左开始往右循环
for (int j = st; j < limite; j++)
{
//强转排序类型比较,如果左边比右边大
if (((IComparable)list[j]).CompareTo(list[j + ]) > )
{
list[j] = list[j + ] + (list[j + ] = list[j]) * ;
swapped = true;
}
}
//从右开始往左循环
for (int j = limite - ; j >= st; j--)
{
//强转排序类型比较,如果左边比右边大
if (((IComparable)list[j]).CompareTo(list[j + ]) > )
{
list[j] = list[j + ] + (list[j + ] = list[j]) * ;
swapped = true;
}
}
} while (st < limite && swapped);
return list;
}
catch (Exception ex)
{
throw ex;
}
}

首先是定义集合总数与-1。分别代表两个循环的方向,然后使用do while,进行初步循环。

在do while里面,分别对定义的变量,进行增减操作。一直到相交为止。定义两个方向的循环,然后就行前后比较,交换位置。

因为终究也是比较性排序,所以效率也不是很高。我们看一下

第三种:桶排序

桶排序顾名思义,就是把数列划分成若干个桶的一种算法。属于分布排序算法。在每个桶内各自进行排序,每个桶内各自排序方式不限。

public static IList<int> BucketSort(IList<int> list)
{
int max = list[];
int min = list[];
//找集合中,最小值与最大值
for (int i = ; i < list.Count; i++)
{
if (((IComparable)list[i]).CompareTo(max) > )
{
max = list[i];
} if (((IComparable)list[i]).CompareTo(min) < )
{
min = list[i];
}
}
//定义一个足够大的容器。因为是最大值-最小值。所以肯定是足够装下所有集合。
//注意事项:数组数量溢出
ArrayList[] holder = new ArrayList[max - min + ]; //让数组变成二维数组
for (int i = ; i < holder.Length; i++)
{
holder[i] = new ArrayList();
}
//把集合的数据,付给二维数组
for (int i = ; i < list.Count; i++)
{
holder[list[i] - min].Add(list[i]);
}
int k = ;
//循环容器
for (int i = ; i < holder.Length; i++)
{
//判断是否有值
if (holder[i].Count > )
{
//重新给list进行赋值操作
for (int j = ; j < holder[i].Count; j++)
{
list[k] = (int)holder[i][j];
k++;
}
}
} return list;
}

首先第一步就是创建一个桶,也就是一个交叉数组(数组的数组)。那么我们找集合中,最大与最小,来创建一个能够完全保存进去的集合。

然后循环进行交叉数组初始化操作。

接着遍历一遍集合,holder[list[i] - min].Add(list[i]); 这句话是关键,把集合的值,当作数组的索引,进行Add添加。因为是二维数组,所以相同的数据,再多也没事。

最后一步就简单了,循环遍历然后给list,进行复制操作。因为已经把list的值,放到桶里面了,所以操作数据,不会受到影响。

其实这也算是,插入排序算法。只不过声明这种非常大的容器是很消耗内存的。并不是很推荐这种方法。我们看一下性能

第四种:梳排序

梳排序中,是保持间距并不断减少的过程。开始的时候间距设定为列表长度,然后每一次都会除以损耗因子(一般为1.3)。间距可以四舍五入,不断重复,直到间距变为1。最后在进行一次冒泡排序。

 public static IList<int> CombSort(IList<int> list)
{
//获取集合数量
int gap = list.Count;
int swaps = ; do
{
//计算递减率,必须大于1
gap = (int)(gap / 1.3);
if (gap < )
{
gap = ;
}
int i = ;
swaps = ;
do
{
//每次循环1与另一个数进行调换,直到循环尾部为止
if (((IComparable)list[i]).CompareTo(list[i + gap]) > )
{
list[i] = list[i + gap] + (list[i + gap] = list[i]) * ;
swaps = ;
}
i++;
} while (!(i + gap >= list.Count));
} while (!(gap == && swaps == ));
return list;
}

首先计算递减率,集合总数除以损耗因子,递减率必须大于1。

从0开始 与 间隔值继续比较,调换位置。一直到间隔位置大于集合总数。

并且每次进行间隔递减,每次间隔都除以1.3。

其实重点也是比较排序,只不过是进行间隔排序基础上。性能也是比较好的。

第五种:圈排序

圈排序是一种不稳定的排序算法,是一种理论上最优的比较算法。他的思想是要把数列分解为圈,可以分别旋转得到排序结果。

与其他排序不同的是,元素不会被放入数组的任何位置,如果这个值在正确位置,则不动。否则只会写一次即可。

public static IList<int> CycleSort(IList<int> list)
{
//循环每一个数组
for (int cycleStart = ; cycleStart < list.Count; cycleStart++)
{
int item = list[cycleStart];
int pos = cycleStart;
do
{
int to = ;
//循环整个数组,找到其相应的位置
for (int i = ; i < list.Count; i++)
{
if (i != cycleStart && ((IComparable)list[i]).CompareTo(item) < )
{
to++;
}
}
if (pos != to)
{
while (pos != to && ((IComparable)item).CompareTo(list[to]) == )
{
to++;
}
int temp = list[to];
list[to] = item;
item = temp;
pos = to;
}
} while (cycleStart != pos);
}
return list;
}

首先进行从前往后的循环。获取不同位置的数据,当获取到数据以后,会循环整个数组找到其相应的位置。然后进行位置插入。

看一下,具体的性能。对于非常杂乱无章的序列来讲,真的好慢。

第六种:堆排序

堆排序是从数据集构建一个数据堆,然后提取最大元素,放到有序数列末尾。然后重新构造新的数据堆,一直到没有数据为止。属于插入排序。

public static IList<int> HeapSort(IList<int> list)
{
//循环因为每次都能取出最大和最小,所以循环次数折中
for (int i = (list.Count - ) / ; i >= ; i--)
{
Adjust(list, i, list.Count - );
}
for (int i = list.Count - ; i >= ; i--)
{
list[i] = list[] + (list[] = list[i]) * ;
Adjust(list, , i - );
}
return list;
} public static void Adjust(IList<int> list, int i, int m)
{
int temp = list[i];//获取该标识值
int j = i * + ;//获取对应尾部标识
while (j <= m) //循环直到标识 <= 总数
{
if (j < m) //尾部标识 小于 总数
{
//如果左边小于右边,右边标识加一位
if (((IComparable)list[j]).CompareTo(list[j + ]) < )
{
j = j + ;
}
}
if (((IComparable)temp).CompareTo(list[j]) < )
{
//交换位置
list[i] = list[j];
i = j;
j = * i + ;
}
else
{
//结束循环
j = m + ;
}
}
list[i] = temp;
}

看一下性能

第七种:插入排序

插入排序的原理是构造一个有序数列,对未排序的数据,从后向前扫描,找到相应的位置并插入。需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。

public static IList<int> InsertionSort(IList<int> list)
{
for (int i = ; i < list.Count; i++)
{
int val = list[i];
int j = i - ;
bool done = false;
do
{
if (((IComparable)list[j]).CompareTo(val) > )
{
list[j + ] = list[j];
j--;
if (j < )
{
done = true;
}
}
else
{
done = true;
}
} while (!done);
list[j + ] = val;
}
return list;
}

首先是从前往后进行循环,将数据与前一个比较并交换位置。

看一下性能:

第八种:奇偶排序

通过比较相邻的奇偶数进行排序,对存在错误的顺序进行交换。并一直重复这个过程,直到列表有序。

public static IList<int> OddEventSort(IList<int> list)
{
bool sorted = false;
while (!sorted)
{
sorted = true;
for (int i = ; i < list.Count - ; i += )
{
if (((IComparable)list[i]).CompareTo(list[i + ]) > )
{
list[i] = list[i + ] + (list[i + ] = list[i]) * ;
sorted = false;
}
}
for (int i = ; i < list.Count - ; i += )
{
if (((IComparable)list[i]).CompareTo(list[i + ]) > )
{
list[i] = list[i + ] + (list[i + ] = list[i]) * ;
sorted = false;
}
}
}
return list;
}

看一下性能

第九种:鸽巢排序(大数据量中最快的排序方法)

鸽巢排序假设有个待排序的数组,给它建立一个空的辅助数组(俗称鸽巢)。把原始数组的每个值作为格子(鸽巢的索引),遍历原始数据,根据每个值放入辅助数组对应的格子中。

顺序遍历鸽巢数组,把非空的鸽巢中的元素放回原始数组。这种排序方式适合在差值很小的范围内使用。

public static IList<int> PigeonHoleSort(IList<int> list)
{
int min = list[], max = list[];
foreach (int x in list)
{
if (((IComparable)min).CompareTo(x) > )
{
min = x;
}
if (((IComparable)max).CompareTo(x) < )
{
max = x;
}
}
int size = max - min + ;
int[] holes = new int[size];
foreach (int x in list)
{
holes[x - min]++;
}
int i = ;
for (int count = ; count < size; count++)
{
while (holes[count]-- > )
{
list[i] = count + (int)min;
i++;
}
}
return list;
}

看一下性能

第十种:快速排序(小数据量中最快方法)

快速排序会把集合分为两个集合,并选择一个元素作为基准。把小于基准的数据排到基准前面,大于放到后面。

public static IList<int> QuickSort(IList<int> list, int left, int right)
{
right = right == ? list.Count - : right;
int i = left, j = right;
double privotValue = (left + right) / ;
int x = list[(int)privotValue];
while (i <= j)
{
while (((IComparable)list[i]).CompareTo(x) < )
{
i++;
}
while (((IComparable)x).CompareTo(list[j]) < )
{
j--;
}
if (i <= j)
{
list[i] = list[j] + (list[j] = list[i]) * ;
i++;
j--;
}
}
if (left < j)
{
QuickSort(list, left, j);
}
if (i < right)
{
QuickSort(list, i, right);
}
return list;
}

看一下性能

第十一种:选择排序

在未排序的列表中找到最小或最大的元素,存放到排序序列的起始位置,然后,再从剩余的排序元素中继续找寻最小(大)元素,放到末尾。

public static IList<int> SelectionSort(IList<int> list)
{
int min;
for (int i = ; i < list.Count; i++)
{
min = i;
for (int j = i + ; j < list.Count; j++)
{
if (((IComparable)list[j]).CompareTo(list[min]) < )
{
min = j;
}
}
list[i] = list[min] + (list[min] = list[i]) * ;
}
return list;
}

看一下性能

第十二种:希尔排序

通过将比较的全部元素分为几个区域来提升插入排序的性能。这样可以让一个元素一次性地朝最终位置前进一大步。然后步伐越来越小,最后就是普通的插入排序。

 int length = list.Length;
for (int h = length / ; h > ; h = h / )
{
for (int i = h; i < length; i++)
{
int temp = list[i];
if (temp.CompareTo(list[i - h]) < )
{
for (int j = ; j < i; j += h)
{
if (temp.CompareTo(list[j]) < )
{
temp = list[j];
list[j] = list[i];
list[i] = temp;
}
}
}
}
}
return list;

看一下性能

C#12种顺序排序的更多相关文章

  1. php四种基础排序算法的运行时间比较

    /** * php四种基础排序算法的运行时间比较 * @authors Jesse (jesse152@163.com) * @date 2016-08-11 07:12:14 */ //冒泡排序法 ...

  2. php四种基础排序算法的运行时间比较!

    /** * php四种基础排序算法的运行时间比较 * @authors Jesse (jesse152@163.com) * @date 2016-08-11 07:12:14 */ //冒泡排序法 ...

  3. 深入理解DOM节点类型第一篇——12种DOM节点类型概述

    × 目录 [1]元素 [2]特性 [3]文本[4]CDATA[5]实体引用[6]实体名称[7]处理指令[8]注释[9]文档[10]文档类型[11]文档片段[12]DTD 前面的话 DOM是javasc ...

  4. 基于python的七种经典排序算法

    参考书目:<大话数据结构> 一.排序的基本概念和分类 所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作.排序算法,就是如何使得记录按照要求排列的方法. ...

  5. ORACLE自定义顺序排序-转

    ORACLE可以借助DECODE函数,自定义顺序排序: select * from ( select 'Nick' as item from dual union all select 'Viki' ...

  6. 【转载】Python编程中常用的12种基础知识总结

    Python编程中常用的12种基础知识总结:正则表达式替换,遍历目录方法,列表按列排序.去重,字典排序,字典.列表.字符串互转,时间对象操作,命令行参数解析(getopt),print 格式化输出,进 ...

  7. Python编程中常用的12种基础知识总结

    原地址:http://blog.jobbole.com/48541/ Python编程中常用的12种基础知识总结:正则表达式替换,遍历目录方法,列表按列排序.去重,字典排序,字典.列表.字符串互转,时 ...

  8. 七种经典排序算法及Java实现

    排序算法稳定性表示两个值相同的元素在排序前后是否有位置变化.如果前后位置变化,则排序算法是不稳定的,否则是稳定的.稳定性的定义符合常理,两个值相同的元素无需再次交换位置,交换位置是做了一次无用功. 下 ...

  9. (网页)12种不宜使用的Javascript语法(转)

    转自阮一峰: 最近写的一些小东西,总是出各种各样的问题,用了angular.js反应居然比我的jQuery还慢,客户吐槽了,我又把一个小操作,改成了jQuery.浏览一下大神的的博客.转载一点东西: ...

随机推荐

  1. canvas drag 实现拖拽拼图小游戏

    博主一直心心念念想做一个小游戏-  前端时间终于做了一个小游戏,直到现在才来总结,哈哈- 以后要勤奋点更新博客! 实现原理 1.如何切图? 用之前的方法就是使用photoshop将图片切成相应大小的图 ...

  2. Qt 学习笔记 TreeWidget 增删改

    在窗体上放一个TreeWidget控件和四个PushButton加一个Horizontal Spacer 布局如图 给树添加元素节点的方法和实现 .h文件 QTreeWidgetItem * AddT ...

  3. 如何在 Apache 中为你的网站设置404页面

    一个好的网站,拥有一个好的 404页面 是标配. 为何要有 404页面?如何设置一个 404页面? why 404 pages? 在本地,比如我打开 localhost/fuck.htm(该文件不存在 ...

  4. ul、li实现横向导航按钮

    好久没写博客了,主要是懒得呼气都不想呼,上周分给我一个新的任务,就是自己新建一个系统,快速极限开发,虽然之前自己也做过小的系统,但毕竟是自己做,随着自己的心意做,没有做其他的限制等,现在呢是给公司做, ...

  5. weinre 简记

    在入职不久接触了移动端WEB开发,刚开始遇到的问题就是调试的问题.在PC端的时候,我常常纠结在IE与IE之间,主要的兼容问题还是IE一家子和他们的亲戚(啥多核浏览器,也是各种坑不断)之间.IE虽然问题 ...

  6. nios II--实验3——led 100M软件部分

    软件开发 参照实验二(led),该实验与实验二(led)的不同之处在于系统的时钟由50M提成为100M.运行结果,在调试窗口输出Hello from Nios II!,并且板上的四个LED灯流动显示, ...

  7. 《ImageNet Classification with Deep Convolutional Neural Networks》 剖析

    <ImageNet Classification with Deep Convolutional Neural Networks> 剖析 CNN 领域的经典之作, 作者训练了一个面向数量为 ...

  8. MAC OS上Nginx安装

    admin@admindeMac:local]$ brew install nginx ==> Installing dependencies for nginx: pcre, openssl ...

  9. linux基础-第十五单元 软件包的管理

    使用RPM安装及移除软件 什么是RPM rpm的文件名 rpm软件安装与移除工作中经常使用的选项 查看RPM软件包中的信息 查询已安装的软件包信息 RPM包的属性依赖性问题 什么是RPM包的属性依赖性 ...

  10. PHP与MySQL

    这周学习了PHP与MySQL的搭接下面来给大家分享一下: 1.账号注册,论坛发帖... 思路:通过form表单提交到PHP页面,PHP页面往MySQL中插入数据: 2.账号登陆 思路:form提交数据 ...