一道笔试题的解法和联想

(注:这里只是想通过排序算法来描述一下抽象的过程,所以大家不要太关注于数组的排序)

作者:方明

原题是这样的,请用C#编写一个可以对任意类型进行冒泡排序算法,我们先看一个整型的冒泡排序来了解一下冒泡排序:

 

整型冒泡排序

 

这个题其实考的重点并不在冒泡排序(当然不懂冒泡排序肯定不行),而是考一种抽象能力,对于冒泡排序来说,任意类型排序他们共同的东西就是冒泡排序的思想,而不同的部分在比较上,所以我们就要想一种方法将变化的部分和不变的部分隔离开,我们首先想到的方法是使用接口,下边是一种解法:

 

接口实现1

 

这个解法可以应对更多的类型排序,只要这些需要排序的类型都实现IArray接口就可以了,但是问题是如果这样,这个排序算法又不支持整型了,我们总不能为了这个排序算法重新封装一下整型吧。我们得继续寻找办法,于是我们想到了系统的一个接口IComparable,这个接口定义通用的比较方法,由值类型或类实现以创建类型特定的比较方法。系统自定义类型几乎都实现了这个接口,所以只要自定义类也实现这个接口就可以利用到这里了,代码如下:

 

接口实现2

 

现在基本符合题意了,但看起来好像还不是好的解决方案,因为每个类型都要实现IComparable仍然是个限制,那如何打破这个限制呢,仔细想想,我们想出另外一个解决方案,就是想办法把比较方式封装起来,然后调用排序函数时传进来不就成了么。

 

接口实现3

 

大家可能觉得这个和上一个方案很象阿,不都要实现一个接口么,其实后一个方案中的最大优点在于你自定义类不用继承任何接口了,我们想一下,为了让某个类型支持这个冒泡排序而去实现一个接口是很牵强的。.net对数组,集合等的排序就是使用这个方法来做的,大家可以研究一下Array类中的静态方法public static void Sort(Array array, IComparer comparer);。那这个是不是最好的解决方案呢,我们本着不撞南墙不回头的原则继续前进,这个接口好像用委托也可以实现吧,那写个版本先:

 

委托实现

 

似乎也没有什么改进,还要写多写一个方法,但是这个委托版本已经基本接近我们的答案了,下面我们使用Lambda表达式来实现我认为的最优的答案(这个答案中需要大家了解Lambda表达式,范型以及Func委托):

 

Lambda表达式实现

 

ps:有网友问,不同类型排序怎么办,我觉得一样是需要把比较的方式和排序算法本身分离开来,我写了个简单例子供参考

 

任意类型排序
posted @ 2008-08-23 23:18 Lance.Liang 阅读(2259) 评论(15)  编辑 收藏 网摘 所属分类: C#

  回复  引用  查看    
#1楼 2008-08-23 23:23 | Gray Zhang      
其实,有个叫Comparison的委托就是了……
所以可以这样
void Sort(IComparable array);

void Sort(IEnumerable array, IComparer comparer);

void Sort(IEnumerable array, Comparison comparison);
  回复  引用  查看    
#2楼 2008-08-23 23:31 | 江南白衣      
楼上正解
  回复  引用  查看    
#3楼 2008-08-23 23:33 | Clingingboy      
委托和Lambda最佳,不过这都需要编程语言的支持.
  回复  引用  查看    
#4楼 [楼主]2008-08-23 23:34 | Lance.Liang      
@Gray Zhang
这里并不是单纯为了解决排序问题,而是想通过这个排序来记录一下隔离变化的过程
  回复  引用  查看    
#5楼 2008-08-23 23:34 | Gray Zhang      
楼主其实不知不觉中说明了“依赖倒置”的概念呢
  回复  引用  查看    
#6楼 2008-08-24 00:35 | Steven Chen      
俄 不管是否框架已经带了这个东西,循序渐进的说明总能给人带来新的思考。

喜欢这篇文章。
  回复  引用  查看    
#7楼 2008-08-24 00:38 | Angel Lucifer      
C++ 中使用仿函数进行排序的点子也不错,而且因为内联,比委托的性能高不少。
  回复  引用  查看    
#8楼 2008-08-24 00:40 | guojing      
能不能不同类型彼此排序呢?
  回复  引用  查看    
#9楼 2008-08-24 00:48 | Angel Lucifer      
同意楼主的观点。
不过另举一例,嘿嘿。
在接口实现时,可以这样实现:

static void BubbleSort<T>(T[] array) where T : IComparable<T>
{
for (int i = 0; i < array.Length - 1; i++)
{
for (int j = array.Length - 1; j > i; j--)
{
if (array[j].CompareTo(array[j - 1]) < 0)
{
T temp = array[j];
array[j] = array[j - 1];
array[j - 1] = temp;
}
}
}
}
  回复  引用  查看    
#10楼 2008-08-24 10:58 | 水言木      
学习..
  回复  引用  查看    
#11楼 [楼主]2008-08-24 11:52 | Lance.Liang      
@Steven Chen

呵,可能这个例子举的不够恰当,如果举个框架中不支持的更实用的例子就好了

@guojing

不同类型的排序的前提也是要提供比较算法,我觉得使用委托是可以解决的

@Angel Lucifer

恩,不错,用范型是更好些
  回复  引用  查看    
#12楼 2008-08-24 12:25 | Cat Chen      
你的comparator(也就是Compare())设计其实是不对的,返回bool只能表示两种情况,但实际上偏序关系也必须至少要有3种情况来表示(在数值大小的全序关系中这叫做“大于”、“等于”、“小于”)。

你可以看看楼上提到的IComparable,它的comparator(也就是CompareTo())才是正确的,通过返回一个int来区分这三种状态。当然,继承自IComparable比较麻烦,所以还是写lamda最快,但lamda应该返回int。
  回复  引用  查看    
#13楼 2008-08-24 12:31 | Cat Chen      
@Lance.Liang
用泛型确实比较好,只要你多用一点,你就习惯泛型的思维了。我觉得最简单的做法就是多用Linq,你很快就会对泛型和lamda运用自如。
  回复  引用  查看    
#14楼 2008-08-25 11:04 | 雅阁布      
不错!!
  回复  引用  查看    
#15楼 2008-09-12 19:47 | robi      
@Cat Chen
@Cat Chen
" 你的comparator(也就是Compare())设计其实是不对的,返回bool只能表示两种情况,但实际上偏序关系也必须至少要有3种情况来表示(在数值大小的全序关系中这叫做“大于”、“等于”、“小于”)。"

public bool Compare(IArray IA)
{
return this.Age>((Employee)IA).Age;
}

返回bool并不是表示您说的偏序关系,而是判断this.Age>((Employee)IA).Age是否是正确的。


标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2008-09-16 00:14 编辑过
Google站内搜索
[推荐职位]上海盛大网络招聘架构师



China-pub 计算机图书网上专卖店!6.5万品种 2-8折!
近千种 9-95 新二手计算图书火热销售中!
开发者征途系统新作:《设计模式——基于C#的工程化实现及扩展》

相关文章:

相关链接: