原理:
选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。
目的:
实现数组元素的有序排列。
具体方法:
假设有数组:int[] arr = { 1, 2, 4, 3, 8, 6, 9, 5, 7 };当我们首先进行第一趟排序,每次比较相邻的两个元素并把较大的元素值的索引记录下来,然后拿最大的元素的值和接下来的所有元素比较,只要;没有后面的值大,就记录下来索引,直到最终找出最大值的索引,第一趟比较完毕,交换取到的的最大的元素,放在索引为0的位置,第二趟比较的时候我们依然是从剩下的元素中找到最大的元素,将它放在索引为1的位置......依次类推,我们每次从剩下的元素中找到最大的元素放在上一次排序后的那个位置,就完成了对素组的排序!这是大的方向,具体怎么排序呢,下面有代码展示。
/// <summary>
/// int类型的选择排序
/// </summary>
/// <param name="arr"></param>
public static void SelectSort(int[] arr)
{
//首先初始化一个变量用来记录索引
int index = 0;
for (int i = 0; i < arr.Length-1; i++)
{
index = i;
for (int j = i+1; j < arr.Length; j++)
{
if (arr[index] < arr[j])
{
//如果找到最大值,就对index重新赋值
index = j;
}
}
int temp = arr[index];
arr[index] = arr[i];
arr[i] = temp;
}
}
我们使用如下代码测试一下:
int[] arr = { 1, 2, 4, 3, 8, 6, 9, 5, 7 };
PrintArr(arr);
SelectSort(arr);
PrintArr(arr);
结果如图所示:
此时如果是字符串数组该如何排序呢?我们可以考虑做一些修改,看能不能实现排序,代码修改后如下:
/// <summary>
/// string类型的数组的选择排序
/// </summary>
/// <param name="arr"></param>
public static void SelectSort(string[] arr)
{
//首先初始化一个变量用来记录索引
int index = 0;
for (int i = 0; i < arr.Length - 1; i++)
{
index = i;
for (int j = i + 1; j < arr.Length; j++)
{
if (arr[index].Length < arr[j].Length)
{
//如果找到最大值,就对index重新赋值
index = j;
}
}
string temp = arr[index];
arr[index] = arr[i];
arr[i] = temp;
}
}
然后我们来测试以下代码:
string[] arr = { "ca", "adff", "iuop", "zcvvcvn", "hafsdakjsfalsdf" };
PrintArr(arr);
SelectSort(arr);
PrintArr(arr);
运算结果如图所示:
那么我们是否考虑到用一个通用的选择排序方法呢?通过观察这两个选择排序我们可以看出,二者只有比较的条件不同,其他的代码几乎是一样的,那么我们考虑把这个不同的条件给提取出来!不难想象我们可以使用委托的办法来传这个比较的条件,我们可以在命名空间下声明一个泛型的委托用来传递不同的条件,代码如下:
public delegate int DelCompare<T>(T t1,T t2);
然后我们来修改选择排序的方法,如下所示:
public static void SelectSort<T>(T[] arr,DelCompare<T> del)
{
//首先初始化一个变量用来记录索引
int index = 0;
for (int i = 0; i < arr.Length-1; i++)
{
index = i;
for (int j = i + 1; j < arr.Length; j++)
{
if (del(arr[index], arr[j]) < 0)
{
index = j;
}
}
T temp = arr[index];
arr[index] = arr[i];
arr[i] = temp;
}
}
再写一个打印的方法:
/// <summary>
/// 打印数组的所有元素
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="arr"></param>
public static void PrintArr<T>(T[] arr)
{
for (int i = 0; i < arr.Length; i++)
{
Console.Write(arr[i]+" ");
}
Console.WriteLine();
}
然后我们再次测试一下:
string[] arr = { "ca", "adff", "iuop", "zcvvcvn", "hafsdakjsfalsdf" };
PrintArr<string>(arr);
SelectSort<string>(arr, (string t1, string t2) =>
{
return t1.Length - t2.Length;
});
PrintArr<string>(arr);
运算结果依然是:
我们再次测试一个稍微复杂一点的,写一个Person类:
public class Person
{
//一些属性
public string Name { get; set; }
public int Age { get; set; }
public int MathScore { get; set; }
public int ChineseScore { get; set; }
public int EnglishScore { get; set; }
public Person()
{
}
public Person(string name, int age, int mathScore, int chineseScore, int englishScore)
{
this.Name = name;
this.Age = age;
this.MathScore = mathScore;
this.ChineseScore = chineseScore;
this.EnglishScore = englishScore;
}
public override string ToString()
{
return string.Format("{0} {1} {2} {3} {4} {5}", this.Name, this.Age, this.ChineseScore, this.MathScore, this.EnglishScore, (this.ChineseScore + this.MathScore + this.EnglishScore));
}
}
然后初始化一个Person数组,再进行选择排序,代码如下:
Person[] pArr = new Person[10];
Random range = new Random();
for (int i = 0; i < pArr.Length; i++)
{
int rAge = range.Next(10, 15);
int rChineseScore = range.Next(0, 101);
int rMathScore = range.Next(0, 101);
int rEnglishScore = range.Next(0, 101);
pArr[i] = new Person("张三_" + i, rAge, rMathScore, rChineseScore, rEnglishScore);
}
为了方便显示,修改下打印方法:
public static void PrintArr<T>(T[] arr)
{
for (int i = 0; i < arr.Length; i++)
{
Console.WriteLine(arr[i]);
}
Console.WriteLine();
}
万事俱备,我们再次来测试
PrintArr<Person>(pArr);
SelectSort<Person>(pArr, (Person p1, Person p2) =>
{
return p1.ChineseScore + p1.MathScore + p1.EnglishScore - p2.ChineseScore - p2.MathScore - p2.EnglishScore;
});
PrintArr<Person>(pArr);
结果如我们所预示,如图: