(注:这里只是想通过排序算法来描述一下抽象的过程,所以大家不要太关注于数组的排序)
原题是这样的,请用C#编写一个可以对任意类型进行冒泡排序算法,我们先看一个整型的冒泡排序来了解一下冒泡排序:
static void Main(string[] args)
{
int[] array = { 9,8,2,6,5,4,3,7,1};
BubleSort(array);
for (int i = 0; i < array.Length; i++)
{
Console.WriteLine(array[i]);
}
}
static void BubleSort(int[] array)
{
for (int i = 0; i < array.Length; i++)
{
for (int j = 0; j < array.Length-i-1; j++)
{
if (array[j] > array[j + 1])
{
int temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
}
}
这个题其实考的重点并不在冒泡排序(当然不懂冒泡排序肯定不行),而是考一种抽象能力,对于冒泡排序来说,任意类型排序他们共同的东西就是冒泡排序的思想,而不同的部分在比较上,所以我们就要想一种方法将变化的部分和不变的部分隔离开,我们首先想到的方法是使用接口,下边是一种解法:
public interface IArray
{
bool Compare(IArray IA);
}
public class Employee:IArray
{
public Employee(int age)
{
this.Age = age;
}
public int Age { get; set; }
public bool Compare(IArray IA)
{
return this.Age>((Employee)IA).Age;
}
}
class Program
{
static void Main(string[] args)
{
Employee[] array = { new Employee(23),new Employee(20),new Employee(19),new Employee(30)};
BubleSort(array);
for (int i = 0; i < array.Length; i++)
{
Console.WriteLine(array[i].Age);
}
}
static void BubleSort(IArray[] array)
{
for (int i = 0; i < array.Length; i++)
{
for (int j = 0; j < array.Length-i-1; j++)
{
if (array[j].Compare(array[j + 1]))
{
IArray temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
}
}
}
这个解法可以应对更多的类型排序,只要这些需要排序的类型都实现IArray接口就可以了,但是问题是如果这样,这个排序算法又不支持整型了,我们总不能为了这个排序算法重新封装一下整型吧。我们得继续寻找办法,于是我们想到了系统的一个接口IComparable,这个接口定义通用的比较方法,由值类型或类实现以创建类型特定的比较方法。系统自定义类型几乎都实现了这个接口,所以只要自定义类也实现这个接口就可以利用到这里了,代码如下:
class Program
{
static void Main(string[] args)
{
//Employee[] array = { new Employee(23),new Employee(20),new Employee(19),new Employee(30)};
IComparable[] array = { 9, 8, 2, 6, 5, 4, 3, 7, 1 };
BubleSort(array);
for (int i = 0; i < array.Length; i++)
{
Console.WriteLine(array[i]);
}
}
static void BubleSort(IComparable[] array)
{
for (int i = 0; i < array.Length; i++)
{
for (int j = 0; j < array.Length-i-1; j++)
{
if (array[j].CompareTo(array[j + 1])>0)
{
IComparable temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
}
}
}
现在基本符合题意了,但看起来好像还不是好的解决方案,因为每个类型都要实现IComparable仍然是个限制,那如何打破这个限制呢,仔细想想,我们想出另外一个解决方案,就是想办法把比较方式封装起来,然后调用排序函数时传进来不就成了么。
class IntCompare:IComparer<int>
{
public int Compare(int x, int y)
{
return x.CompareTo(y);
}
}
class Program
{
static void Main(string[] args)
{
//Employee[] array = { new Employee(23),new Employee(20),new Employee(19),new Employee(30)};
int[] array = { 9, 8, 2, 6, 5, 4, 3, 7, 1 };
BubleSort<int>(array,new IntCompare());
for (int i = 0; i < array.Length; i++)
{
Console.WriteLine(array[i]);
}
}
static void BubleSort<T>(T[] array,IComparer<T> compare)
{
for (int i = 0; i < array.Length; i++)
{
for (int j = 0; j < array.Length-i-1; j++)
{
if (compare.Compare(array[j], array[j + 1]) > 0)
{
T temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
}
}
}
大家可能觉得这个和上一个方案很象阿,不都要实现一个接口么,其实后一个方案中的最大优点在于你自定义类不用继承任何接口了,我们想一下,为了让某个类型支持这个冒泡排序而去实现一个接口是很牵强的。.net对数组,集合等的排序就是使用这个方法来做的,大家可以研究一下Array类中的静态方法public static void Sort(Array array, IComparer comparer);。那这个是不是最好的解决方案呢,我们本着不撞南墙不回头的原则继续前进,这个接口好像用委托也可以实现吧,那写个版本先:
class Program
{
static void Main(string[] args)
{
//Employee[] array = { new Employee(23),new Employee(20),new Employee(19),new Employee(30)};
int[] array = { 9, 8, 2, 6, 5, 4, 3, 7, 1 };
BubleSort<int>(array, CompareMethod);
for (int i = 0; i < array.Length; i++)
{
Console.WriteLine(array[i]);
}
}
static bool CompareMethod(int t1, int t2)
{
return t1 > t2;
}
delegate bool Compare<T>(T t1, T t2);
static void BubleSort<T>(T[] array, Compare<T> compare)
{
for (int i = 0; i < array.Length; i++)
{
for (int j = 0; j < array.Length-i-1; j++)
{
if (compare(array[j], array[j + 1]))
{
T temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
}
}
}
似乎也没有什么改进,还要写多写一个方法,但是这个委托版本已经基本接近我们的答案了,下面我们使用Lambda表达式来实现我认为的最优的答案(这个答案中需要大家了解Lambda表达式,范型以及Func委托):
class Program
{
static void Main(string[] args)
{
//Employee[] array = { new Employee(23),new Employee(20),new Employee(19),new Employee(30)};
int[] array = { 9, 8, 2, 6, 5, 4, 3, 7, 1 };
BubleSort<int>(array, (a,b)=>a>b);
for (int i = 0; i < array.Length; i++)
{
Console.WriteLine(array[i]);
}
}
static void BubleSort<T>(T[] array, Func<T,T,bool> compare)
{
for (int i = 0; i < array.Length; i++)
{
for (int j = 0; j < array.Length-i-1; j++)
{
if (compare(array[j], array[j + 1]))
{
T temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
}
}
}
ps:有网友问,不同类型排序怎么办,我觉得一样是需要把比较的方式和排序算法本身分离开来,我写了个简单例子供参考
class ObjectComparer
{
Dictionary<Type, int> priorities = new Dictionary<Type, int>();
public void Add(Type o, int value)
{
if (!priorities.ContainsKey(o))
{
priorities.Add(o, value);
}
}
public bool Compare(object o1, object o2)
{
if (o1.GetType() == typeof(string) && o2.GetType() == typeof(string))
{
return (string.Compare((string)o1, (string)o2) > 0);
}
else if (o1.GetType() == typeof(int) && o2.GetType() == typeof(int))
{
return (int)o1 > (int)o2;
}
else
{
return priorities[o1.GetType()] > priorities[o2.GetType()];
}
}
}
class Program
{
static void Main(string[] args)
{
string str1 = "hello";
string str2 = "a";
int intValue1 = 10;
int intValue2 = 3;
ObjectComparer objectCompare = new ObjectComparer();
objectCompare.Add(typeof(string), 1);
objectCompare.Add(typeof(int), 2);
object[] array = { intValue1, str1 ,intValue2,str2};
BubleSort(array, objectCompare.Compare);
for (int i = 0; i < array.Length; i++)
{
Console.WriteLine(array[i]);
}
}
static void BubleSort(object[] array, Func<object, object, bool> compare)
{
for (int i = 0; i < array.Length; i++)
{
for (int j = 0; j < array.Length - i - 1; j++)
{
if (compare(array[j], array[j + 1]))
{
object temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
}
}
}