• C#中的委托(Delegates in C#) part two 野峰


    前文讨论了什么是C#中的委托,那么,C#为什么要引入委托呢?

     

    让我们把话题扯远一点,先来看一个著名的排序算法。

     

    ACM图灵奖获得者、微软剑桥研究院的首席科学家 C. A. R. Hoare1960年作为前苏联莫斯科国立大学的访问学生,在从事一个机器翻译的项目时,为了对要翻译的词进行排序,开发了一个高效排序算法,这就是大名鼎鼎的快速排序算法——QuickSort。快速排序的平均时间复杂度是O(nlogn),最坏时间复杂度是O(n2),实际上QuickSort比其他的O(nlogn)算法往往要快一些。

     

    算法原理

     

    QuickSort是一个典型的“分而治之”的算法,在要排序的表(list or array)中选取一个值作为分界点(pivot),将这个表划分为两个子表(list1 list2),其中list1 中的值都小于等于分界点的值,而 list2 中的值都大于分界点的值,然后对 list1 list2 递归重复这种划分法,直到最后的子表中的元素为0或只有一个元素为止。

     

    算法伪码

     

    function quicksort('array')

    if length('array') <= 1 then return 'array'

    select and remove a pivot value 'pivot' from 'array'

    create empty lists 'less' and 'greater'

    for each 'x' in 'array'

    if 'x' <= 'pivot' then append 'x' to 'less'

    else append 'x' to 'greater'

    return concatenate(quicksort('less'), 'pivot', quicksort('greater'))

     

    从以上算法原理的描述及伪码实现中可以看出,QuickSort是一个基于比较的算法,list1(伪码中的less)和list2(伪码中的greater)中的元素是通过与分界点(伪码中的pivot)进行比较而得来的。

     

    既然是基于比较的算法,这就要求QuickSort要能够对其进行排序的元素进行比较!然而,并非所有数据类型都具有“天然的(或自然的)”比较操作,尤其是用户自定义类型,当然我们可以通过C++C#中的操作符重载来定义比较操作,但对于像C这类没有操作符重载功能的语言,如何实现对用户自定义类型的比较操作呢?

     

    人们找到了一个有效的途径——把比较操作“委托”给用户(client)去实现!

     

    void qsort(void *base, size_t num, size_t width, int (__cdecl *compare)(const void*, const void *));

     

    这是 Microsoft CRT QuickSort 的函数原型(prototype),其中:

     

    base

    要排序的表(数组)

    num

    表中的元素个数

    width

    每个元素所占的字节数(元素大小)

    compare

    (用户提供的)比较函数,其中第一个参数是分界点,第二个参数是要与分界点进行比较的元素

     

    这样一来,qsort算法就一般化了,只要表中的元素具有同样的大小,而且提供了对元素进行比较操作的函数,就可以用qsort对表进行排序,而对于qsort而言,并不需要关心要比较的元素是什么数据类型。

     

    一个C语言的qsort示例如下:

     

    #include <stdlib.h>

    #include <string.h>

    #include <stdio.h>

     

    Int compare(const void *arg1, const char* arg2)

    {

    return _stricmp(*(char **)arg1, *(char **)arg2);

    }

     

    int main(int argc, char **argv)

    {

    /* sort command-line args using QuickSort algorithm */

    qsort((void *)argv, (size_t)argc, sizeof(char *), compare);

     

    int i;

    for (i = 0; i < argc; ++i)

    {

    printf("%s", argv[i]);

    }

    }

     

    在这个例子中,利用compare函数实现了字符串的比较操作,从而可以用qsort对命令行参数进行排序。

     

    compare 这样的函数,也称为回调函数(callback)。回调函数机制在现代软件开发中大量应用,尤其是GUI的事件处理。

     

    上面这种将函数作为参数传递,其实现机制是指针,即实际传递的是函数的指针。

     

    那,qsort C#中是如何实现的呢?

     

    下面是qsortC#版本:

     

    public static void Sort<T>(T[] Array, Comparison<T> comparison);

     

    对比CqosrtC#Sort,基本形式是一样的,只不过void *basesize_t numsize_twidth三个参数由T[] Array一个参数表示了。这里同样有一个比较函数,这个比较函数的类型 Comparison<T> 实际上就是一个委托类型:

     

    public delegate int Comparison<T>(T x, T y);

     

    对比compare的声明:

     

    int (*compare) (const void *arg1, const void *arg2);

     

    可以看出,C版的compare是一个函数指针,而C#版的comparison是一个委托类型,而这个委托类型实际上就是比较函数comparison的一个包装(wrapper),这一点,前文已经讨论过了。

     

    由于指针是一种非安全数据类型,C#不提倡使用。而在必须使用函数指针的场合,C#提供了委托类型,将函数指针作为类包装起来,这样编译器可以做静态检查,提高了程序的类型安全,所以说C#是一种类型安全的语言(type-safe programming language)。

     

  • 相关阅读:
    【解决】client does not support authentication
    DesktopLayer.exe专杀
    SVN客户端操作(clean up|commit|update)系统找不到指定的文件
    怎样判断一个exe可执行程序(dll文件)是32位的还是64位的
    Windows 调用OpenProcess失败
    win10 请求操作需要提升解决方案
    LINUX下C++编程如何获得某进程的ID
    GitHub
    Git分支管理
    Gi命令行操作
  • 原文地址:https://www.cnblogs.com/prowyh/p/2399482.html
Copyright © 2020-2023  润新知