目录
1.前言
2.注意
3.冒泡排序
4.选择排序
5.直接插入排序
6.总结
1.前言
其实实际中需要自己写排序算法的情况比较少,但是掌握常用排序算法的解题思路对于开发中解决某些问题还是很有用的,这里总结一下常用排序算法的泛型写法,项目中有需要的可以直接使用。冒泡、选择、插入、希尔、堆排、归并、快排这7个估计要写两到三篇博客来完善
这篇先讲三个简单的排序算法:冒泡、选择、插入
2.注意
1.既然要支持泛型的排序,那一定会有先决条件。这里所有参与泛型排序的类/struct需要实现如下接口IComparerSort<T>:
// 泛型要实现IComparerSort<T>接口 参见如下:
//public class Data : IComparerSort<Data>
//{
// public int id; // 示例字段,可自定义
//
// public int Compare(Data x, Data y)
// {
// if (x.id > y.id)
// return 1;
// else if (x.id == y.id)
// return 0;
// else
// return -1;
// }
//}
/// <summary>
/// 泛型类需要实现此接口才能排序
/// </summary>
public interface IComparerSort<T>
{
int Compare(T x, T y);
}
2.以下默认都是升序
3.冒泡排序
冒泡的思路是从第一个开始,依次与后一个比较,比后面大则交换,否则继续,第一轮结束后最小的元素在第一位;然后从第二位开始再重复一遍以上流程找出第二小的元素...依次类推
1.默认写法:
/// <summary>
/// 冒泡排序(升序)时间复杂度O(n2)
/// </summary>
public static List<T> SortBubble<T>(List<T> list) where T : IComparerSort<T>
{
T temp;
int n = list.Count;
for (int i = 0; i < n - 1; i++)
{
for (int k = i + 1; k < n; k++)
{
if (list[i].Compare(list[i], list[k]) > 0)
{
temp = list[i];
list[i] = list[k];
list[k] = temp;
}
}
}
return list;
}
2.优化写法:
/// <summary>
/// 冒泡排序优化算法(升序)时间复杂度O(n2)
/// </summary>
public static List<T> SortBubbleEx<T>(List<T> list) where T : IComparerSort<T>
{
T temp;
int n = list.Count;
bool isLoop = true;
for (int i = 0; i < n - 1 && isLoop ; i++)
{
isLoop = false;
for (int k = n - 1 ; k > i ; k--)
{
if (list[k].Compare(list[k], list[k - 1]) < 0)
{
temp = list[k - 1];
list[k - 1] = list[k];
list[k] = temp;
isLoop = true;
}
}
}
return list;
}
优化思路:从后往前依次与前一个做比较,比前一个小则互换,否则继续;某一趟比较后发现没有交换行为说明已排序完毕,就跳出循环避免后面无意义的趟数
4.选择排序
选择的思路和冒泡有点像,但是不同点是:比较后不做互换,只是记录一下标识位,待这一趟全部比较完再互换,省去了一轮中多次互换的时间消耗
/// <summary>
/// 选择排序(升序)时间复杂度O(n2)
/// </summary>
public static List<T> SortSelect<T>(List<T> list) where T : IComparerSort<T>
{
T temp;
int min = 0;
int n = list.Count;
for(int i = 0 ; i < n - 1 ; i++)
{
min = i;
for(int k = i + 1 ; k < n ; k++)
{
if(list[min].Compare(list[min], list[k]) > 0)
{
min = k;
}
}
temp = list[min];
list[min] = list[i];
list[i] = temp;
}
return list;
}
5.直接插入排序
直接插入排序的思路:假定某个标识位之前的元素是有序的,然后从这个标识位的下一位开始依次往前比较,找到第一个小于等于这个的元素,插入它的后面(后面的元素依次往后移一位)。
程序实现:第一个元素一定是有序的,固索引从第二个元素开始比较,参见如下:
/// <summary>
/// 直接插入排序(升序)时间复杂度O(n2),要优于冒泡和选择排序
/// </summary>
public static List<T> SortInsert<T>(List<T> list) where T : IComparerSort<T>
{
T temp;
int n = list.Count;
int k = 0;
for(int i = 1 ; i < n ; i++)
{
if(list[i].Compare(list[i], list[i - 1]) < 0)
{
temp = list[i];
for(k = i - 1 ; k >= 0 && list[k].Compare(list[k], temp) > 0 ; k--)
{
list[k + 1] = list[k];
}
list[k + 1] = temp;
}
}
return list;
}
6.总结
三种简单排序的时间复杂度都是O(n2),但是在一般情况下:选择排序要优于冒泡排序,而直接插入排序又优于选择排序
插入 > 选择 > 冒泡