C#实现所有经典排序算法
C#
实现所有经典排序算法
1
、选择排序
选择排序
原理:
选择排序是从冒泡排序演化而来的,每一轮比较得出最小的那个值,然后依次和每轮比较的第一个值进行交换。
目的:按从小到大排序。
方法:假设存在数组:72, 54, 59, 30, 31, 78, 2, 77, 82, 72
第一轮依次比较相邻两个元素,将最小的一个元素的索引和值记录下来,然后和第一个元素进行交换。
如上面的数组中,首先比较的是72,54,记录比较小的索引是54的索引1。接着比较54和59,比较小的索引还是1。直到最后得到最小的索引是2的索引6,然后索引6和0互相交换。
第二轮比较的时候是最小的一个元素和索引1进行交换。第三轮、第四轮以此类推。
class SelectionSorter
{
private int min;
public void Sort(int[] arr)
{
for (int i = 0; i < arr.Length - 1; ++i)
{
min = i;
for (int j = i + 1; j < arr.Length; ++j)
{
if (arr[j] < arr[min])
min = j;
}
int t = arr[min];
arr[min] = arr[i];
arr[i] = t;
}
}
}
2
、冒泡排序
冒泡排序
原理:以此比较相邻的两个元素,每次比较完毕最大的一个字跑到本轮的末尾。
目的:按从小到大排序。
方法:
假设存在数组:72, 54, 59, 30, 31, 78, 2, 77, 82, 72
第一轮比较相邻两个元素,如果左边元素大于右边元素,则交换。
72和54比较的结果就是,54在前,72在后;
然后72和59比较的结果,59在前,72在后;
以此类推,第一轮比较之后的结果是:54, 59, 30, 31, 72, 2, 77, 78, 72, 82
经过第一轮比较,最大的元素跑到了最后一个,所以第二轮比较,最后一个元素不需要进行比较了。
第二轮还是从索引0和1开始比较,只是不许要比较最后一个了,算法还是一样的。第三轮、第四轮以此类推。
排序之后的结果:2, 30, 31, 54, 59, 72, 72, 77, 78, 82
class EbullitionSorter
{
public void Sort(int[] arr)
{
int i, j, temp;
bool done = false;
j = 1;
while ((j < arr.Length) && (!done))//
判断长度
{
done = true;
for (i = 0; i < arr.Length - j; i++)
{
if (arr[i] > arr[i + 1])
{
done = false;
temp = arr[i];
arr[i] = arr[i + 1];//
交换数据
arr[i + 1] = temp;
}
}
j++;
}
}
}
3
、快速排序
快速排序
原理:
通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,
然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
class QuickSorter
{
private void swap(ref int l, ref int r)
{
int temp;
temp = l;
l = r;
r = temp;
}
public void Sort(int[] list, int low, int high)
{
int pivot;//
存储分支点
int l, r;
int mid;
if (high <= low)
return;
else if (high == low + 1)
{
if (list[low] > list[high])
swap(ref list[low], ref list[high]);
return;
}
mid = (low + high) >> 1;
pivot = list[mid];
swap(ref list[low], ref list[mid]);
l = low + 1;
r = high;
do
{
while (l <= r && list[l] < pivot)
l++;
while (list[r] >= pivot)
r--;
if (l < r)
swap(ref list[l], ref list[r]);
} while (l < r);
list[low] = list[r];
list[r] = pivot;
if (low + 1 < r)
Sort(list, low, r - 1);
if (r + 1 < high)
Sort(list, r + 1, high);
}
}
4
、插入排序
插入排序
原理:
插入排序分为直接插入排序和希尔排序
每次将一个待排序的记录,按其关键字大小插入到前面已经排好序的子列表当中的适当位置,直到全部记录插入完成为止。
对直接插入排序我的理解就是:先将第一个记录视为一个有序序列,然后依次将后面的记录插入到这个有序序列中来。每次要插入的记录时,须从后往前依次比较有序序列中的记录,直到找到在有序序列中的位置,记录下该位置,该位置开始的每个记录都后移一位,然后将插入记录插入该位置。这样每插入一个记录进去,有序序列长度加1,剩余记录减1,直到所有记录都插入到有序序列中,排序完成。
public class InsertionSorter
{
public void Sort(int[] arr)
{
for (int i = 1; i < arr.Length; i++)
{
int t = arr[i];
int j = i;
while ((j > 0) && (arr[j - 1] > t))
{
arr[j] = arr[j - 1];//
交换顺序
--j;
}
arr[j] = t;
}
}
}
5
、希尔排序
希尔排序:也称缩小增量排序。将记录序列分成若干子序列,每个子序列分别进行插入排序。关键是这种子序列不是由相邻记录构成的,而是按一定间隔从序列取出来组成的。在直接插入排序算法中,每次插入一个数,使有序序列只增加1个节点, 并且对插入下一个数没有提供任何帮助。如果比较相隔较远距离(称为增量)的数,使得数移动时能跨过多个元素,则进行一次比较就可能消除多个元素交换。D.L.shell于1959年在以他名字命名的排序算法中实现了这一思想。算法先将要排序的一组数按某个增量d分成若干组,每组中记录的下标相差d.对每组中全部元素进行排序,然后再用一个较小的增量对它进行,在每组中再进行排序。当增量减到1时,整个要排序的数被分成一组,排序完成。
希尔排序
public class ShellSorter
{
public void Sort(int[] arr)
{
int inc;
for (inc = 1; inc <= arr.Length / 9; inc = 3 * inc + 1)
for (; inc > 0; inc /= 3)
{
for (int i = inc + 1; i <= arr.Length; i += inc)
{
int t = arr[i - 1];
int j = i;
while ((j > inc) && (arr[j - inc - 1] > t))
{
arr[j - 1] = arr[j - inc - 1];//
交换数据
j -= inc;
}
arr[j - 1] = t;
}
}
}
}
6
、归并排序
归并排序
原理:归并排序是一种能将一串数据依照特定排序方式进行排列的一种算法。最常用到的排序方式是数值顺序以及字典顺序。有效的排序算法在一些算法(例如搜索算法与合并算法)中是重要的,如此这些算法才能得到正确解答。排序算法也用在处理文字数据以及产生人类可读的输出结果。
/// <summary>
///
归并排序之归:归并排序入口
/// </summary>
/// <param name="data">
无序的数组
</param>
/// <returns>
有序数组
</returns>
/// <author>Lihua(
www.zivsoft.com)</author
>
int[] Sort(int[] data)
{
//
取数组中间下标
int middle = data.Length / 2;
//
初始化临时数组
let,right
,并定义
result
作为最终有序数组
int[]
left
=
new
int[middle],
right
=
new
int[middle],
result
= new int[data.Length];
if (data.Length % 2 != 0)//
若数组元素奇数个,重新初始化右
临时数组
{
right = new int[middle + 1];
}
if (data.Length <= 1)//
只剩下
1 or 0
个元数,返回,不排序
{
return data;
}
int i = 0, j = 0;
foreach (int x in data)//
开始排序
{
if (i < middle)//
填充左数组
{
left[i] = x;
i++;
}
else//
填充右数组
{
right[j] = x;
j++;
}
}
left = Sort(left);//
递归左数组
right = Sort(right);//
递归右数组
result = Merge(left, right);//
开始排序
//this.Write(result);//
输出排序
,
测试用
(lihua debug)
return result;
}
/// <summary>
///
归并排序之并
:
排序在这一步
/// </summary>
/// <param name="a">
左数组
</param>
/// <param name="b">
右数组
</param>
/// <returns>
合并左右数组排序后返回
</returns>
int[] Merge(int[] a, int[] b)
{
//
定义结果数组,用来存储最终结果
int[] result = new int[a.Length + b.Length];
int i = 0, j = 0, k = 0;
while (i < a.Length && j < b.Length)
{
if (a[i] < b[j])//
左数组中元素小于右数组中元素
{
result[k++] = a[i++];//
将小的那个放到结果数组
}
else//
左数组中元素大于右数组中元素
{
result[k++] = b[j++];//
将小的那个放到结果数组
}
}
while (i < a.Length)//
这里其实是还有左元素,但没有右元素
{
result[k++] = a[i++];
}
while (j < b.Length)//
右右元素,无左元素
{
result[k++] = b[j++];
}