STL运用的C++技术(6)——函数对象

http://blog.csdn.net/wuzhekai1985/article/details/6658940?_t_t_t=0.20427969420870595

  STL是C++标准库的重要组成部分之一,它不仅是一个可复用的组件库,更是一个包含算法与数据结构的软件框架,同时也是C++泛型编程的很好例子。STL中运用了许多C++的高级技术。本文介绍函数对象,其实是接上一篇的话题,因为函数对象本质上还是重载操作符。主要参考了《C++ Primer》和《STL源码剖析》。

      可以为类类型的对象重载函数调用操作符,定义了调用操作符的类,其对象称之为函数对象(function object),即它们的行为类似函数对象。这是《C++ Primer》中的定义。下面通过一个例子来引出函数对象的使用。在我的解题笔记系列中,有一篇文章 解题笔记(16)——几个数字的问题,其中第四个问题是调整数组顺序使奇数位于偶数前面(数组)。输入一个整数数组,调整数组中数字的顺序,使得所有奇数位于数组的前半部分。所有偶数位于数组的后半部分。要求时间复杂度为O(n)。这个问题不难,其中用到了函数指针。代码如下:

[cpp] view plain copy
  1. bool IsOdd(int x)    
  2. {    
  3.     return (x & 1)? truefalse;    
  4. }    
  5. //函数功能 : 调整数组顺序使奇数位于偶数前面    
  6. //函数参数 : pArray指向数组的指针,nLen为数组长度    
  7. //返回值 :   无    
  8. void PartionArray(int *pArray, int nLen, bool (*func)(int))    
  9. {    
  10.     int i = -1;    
  11.     for(int j = 0; j < nLen; j++)    
  12.     {    
  13.         if(func(pArray[j])) //满足调整条件    
  14.         {    
  15.             i++;    
  16.             int tmp = pArray[j];    
  17.             pArray[j] = pArray[i];    
  18.             pArray[i] = tmp;    
  19.         }    
  20.     }    
  21. }   

      传递一个函数指针的好处是,可以很方便的修改调整的条件,这个问题希望将奇数放在前面,偶数放在后面。如果有另外一个问题,希望将正数放前面,负数放后面,那么只需定义新的调整函数,类似 IsOdd,然后将它作为参数传递给PartionArray函数即可。

      这里其实也可以使用函数对象,代码如下:

[cpp] view plain copy
  1. #include <iostream>  
  2. using namespace std;  
  3.   
  4. //函数对象  
  5. template<class T>  
  6. struct IsOdd  
  7. {  
  8.     bool operator() (T x){  
  9.         return (x & 1)?truefalse;  
  10.     }  
  11. };  
  12. //函数功能 : 调整数组顺序使奇数位于偶数前面    
  13. //函数参数 : pArray指向数组的指针,nLen为数组长度    
  14. //返回值 :   无    
  15. template <class T, class F>  
  16. void PartionArray(T *pArray, int nLen, F func)  
  17. {    
  18.     int i = -1;    
  19.     for(int j = 0; j < nLen; j++)    
  20.     {    
  21.         if(func(pArray[j])) //满足调整条件    
  22.         {    
  23.             i++;    
  24.             T tmp = pArray[j];    
  25.             pArray[j] = pArray[i];    
  26.             pArray[i] = tmp;    
  27.         }    
  28.     }    
  29. }    
  30. //测试用例  
  31. int main()  
  32. {  
  33.     short a[] = {1,2,3,4,5,6};  
  34.     long b[] = {1,2,3,4,5,6};  
  35.     PartionArray(a, 6, IsOdd<short>());   
  36.     PartionArray(b, 6, IsOdd<long>());   
  37.     return 0;  
  38. }  

       相比函数指针,函数对象的优势在于能很好的满足STL的抽象要求,同时更为灵活。上面这个例子算是一个引子,引出STL中函数对象的运用。

       STL中的函数对象并不是孤立的,而是与STL的算法紧密联系在一起。举个简单的例子就明白了,比如我们希望利用STL的算法为一个数组排序,我们可以这样做。

[cpp] view plain copy
  1. #include <iostream>  
  2. #include <algorithm>  
  3. using namespace std;  
  4. int main()  
  5. {  
  6.     int a[] = {1,3,2,4,5,7};  
  7.     sort(&a[0], &a[6]);  
  8.     for(int i = 0; i < 6; i++)  
  9.         cout<<a[i]<<' ';  
  10.     cout<<endl;  
  11.     return 0;  
  12. }  
       这个排序算法默认是递增排序,那么如果希望是递减排序呢?很方便,在函数实参中加入一个函数对象即可。记住需包含头文件 #include <functional>

[cpp] view plain copy
  1. #include <iostream>  
  2. #include <functional>  
  3. #include <algorithm>  
  4. using namespace std;  
  5. int main()  
  6. {  
  7.     int a[] = {1,3,2,4,5,7};  
  8.     sort(&a[0], &a[6], greater<int>());  
  9.     for(int i = 0; i < 6; i++)  
  10.         cout<<a[i]<<' ';  
  11.     cout<<endl;  
  12.     return 0;  
  13. }  

         可以说在STL中,函数对象扮演着重要的角色,发挥着巨大的作用。下面列出了几个常用的函数对象,摘自HP的STL源码,做了部分修改。STL定义了两个类,作为一元操作和二元操作的基类,这两个基类仅仅是使用了内嵌型别技术,为什么要这样子呢?后面介绍函数适配器时有说明,可以看到它的强大之处。

[cpp] view plain copy
  1. //用来定义一元操作的参数类别和返回值类别  
  2. template <class Arg, class Result>  
  3. struct unary_function {  
  4.     typedef Arg argument_type;  //内嵌型别技术  
  5.     typedef Result result_type;  
  6. };  
  7. //用来定义二元操作的参数类别和返回值类别  
  8. template <class Arg1, class Arg2, class Result>  
  9. struct binary_function {  
  10.     typedef Arg1 first_argument_type;  
  11.     typedef Arg2 second_argument_type;  
  12.     typedef Result result_type;  
  13. };  
  14.   
  15. //一元操作,就两个  
  16. template <class T>  
  17. struct negate : public unary_function<T, T> {  
  18.     T operator()(const T& x) const { return -x; }  
  19. };  
  20. template <class T>  
  21. struct logical_not : public unary_function<T,bool> {  
  22.     bool operator()(const T& x) const { return !x; }  
  23. };  
  24. //加减乘除取模  
  25. template <class T>  
  26. struct plus : public binary_function<T, T, T> {  
  27.     T operator()(const T& x, const T& y) const { return x + y; }  
  28. };  
  29. template <class T>  
  30. struct minus : public binary_function<T, T, T> {  
  31.     T operator()(const T& x, const T& y) const { return x - y; }  
  32. };  
  33. template <class T>  
  34. struct multiplies : public binary_function<T, T , T> {  
  35.     T operator()(const T& x, const T& y) const { return x * y; }  
  36. };  
  37. template <class T>  
  38. struct divides : public binary_function<T ,T, T> {  
  39.     T operator()(const T& x, const T& y) const { return x / y; }  
  40. };  
  41. template <class T>  
  42. struct modulus : public binary_function<T, T, T> {  
  43.     T operator()(const T& x, const T& y) const { return x % y; }  
  44. };  
  45. //关系运算  
  46. template <class T>  
  47. struct equal_to : public binary_function<T, T, bool> {  
  48.     bool operator()(const T& x, const T& y) const { return x == y; }  
  49. };  
  50. template <class T>  
  51. struct not_equal_to : public binary_function<T, T,bool> {  
  52.     bool operator()(const T& x, const T& y) const { return x != y; }  
  53. };  
  54. template <class T>  
  55. struct greater : public binary_function<T, T, bool> {  
  56.     bool operator()(const T& x, const T& y) const { return x > y; }  
  57. };  
  58. template <class T>  
  59. struct less : public binary_function<T, T, bool> {  
  60.     bool operator()(const T& x, const T& y) const { return x < y; }  
  61. };  
  62. template <class T>  
  63. struct greater_equal : public binary_function<T, T, bool> {  
  64.     bool operator()(const T& x, const T& y) const { return x >= y; }  
  65. };  
  66. template <class T>  
  67. struct less_equal : public binary_function<T, T, bool> {  
  68.     bool operator()(const T& x, const T& y) const { return x <= y; }  
  69. };  
  70. //逻辑运算  
  71. template <class T>  
  72. struct logical_and : public binary_function<T, T, bool>{  
  73.     bool operator()(const T& x, const T& y) const { return x && y; }  
  74. };  
  75. template <class T>  
  76. struct logical_or : public binary_function<T, T, bool>  
  77. {  
  78.   bool operator()(const T& x, const T& y) const { return x || y; }  
  79. };  

      上面这些函数对象都比较简单,接下来介绍几个稍微复杂点的,它们被称为函数适配器(function adapter),用于特化和扩展一元和二元函数对象。分为两类,第一是绑定器(binder),它通过将一个操作数绑定到给定值而将二元函数对象转换为一元函数。第二是求反器(negator),它将谓词函数对象的真值求反。这些定义来自《C++ Primer》一书。书上还给了两个例子,这里罗列一下:

[cpp] view plain copy
  1. #include <iostream>  
  2. #include <functional>  
  3. #include <vector>  
  4. #include <algorithm>  
  5. using namespace std;  
  6. int main()  
  7. {  
  8.     vector<int> vec(10, 1);  
  9.     int count1 = count_if(vec.begin(), vec.end(), bind2nd(less_equal<int>(), 10));       //求容器中小于等于10的元素个数  
  10.     int count2 = count_if(vec.begin(), vec.end(), not1(bind2nd(less_equal<int>(), 10))); //求容器中不小于等于10的元素个数,正好是上面结果的取反  
  11.     cout<<count1<<' '<<count2<<endl;  //10 0  
  12.     return 0;  
  13. }  
        下面分析一下STL是如何实现函数适配器的,先给出STL的源码。已经整理过了。

[cpp] view plain copy
  1. //绑定第一个参数  
  2. template <class Operation>   
  3. class binder1st: public unary_function<typename Operation::second_argument_type, typename Operation::result_type> {  
  4. public:  
  5.     binder1st(const Operation& x, const typename Operation::first_argument_type& y) : op(x), value(y) {} //构造函数  
  6.     typename Operation::result_type operator()(const typename Operation::second_argument_type& x) const {  
  7.         return op(value, x);  //固定第一个参数  
  8.     }  
  9. protected:  
  10.     Operation op;  
  11.     typename Operation::first_argument_type value;  
  12. };  
  13. //绑定第二个参数  
  14. template <class Operation>   
  15. class binder2nd: public unary_function<typename Operation::first_argument_type,typename Operation::result_type> {  
  16. public:  
  17.     binder2nd(const Operation& x, const typename Operation::second_argument_type& y) : op(x), value(y) {}  
  18.     typename Operation::result_type operator()(const typename Operation::first_argument_type& x) const {  
  19.         return op(x, value);  //固定第二个参数  
  20.     }  
  21. protected:  
  22.     Operation op;  
  23.     typename Operation::second_argument_type value;  
  24. };  
  25. //外部接口  
  26. template <class Operation, class T>  
  27. inline binder1st<Operation> bind1st(const Operation& fn, const T& x) {  
  28.     typedef typename Operation::first_argument_type Arg1_type;  
  29.     return binder1st<Operation>(fn,Arg1_type(x));  
  30. }  
  31. //外部接口  
  32. template <class Operation, class T>  
  33. inline binder2nd<Operation> bind2nd(const Operation& fn, const T& x) {  
  34.     typedef typename Operation::second_argument_type Arg2_type;  
  35.     return binder2nd<Operation>(fn, Arg2_type(x));  
  36. }  
[cpp] view plain copy
  1. //一元操作求反  
  2. template <class Predicate>  
  3. class unary_negate: public unary_function<typename Predicate::argument_type, bool> {  
  4. protected:  
  5.     Predicate pred;  
  6. public:  
  7.     explicit unary_negate(const Predicate& x) : pred(x) {}  
  8.     bool operator()(const typename Predicate::argument_type& x) const {  
  9.     return !pred(x);  
  10.   }  
  11. };  
  12. //二元操作求反  
  13. template <class Predicate>   
  14. class binary_negate : public binary_function<typename Predicate::first_argument_type, typename Predicate::second_argument_type,bool> {  
  15. protected:  
  16.     Predicate pred;  
  17. public:  
  18.     explicit binary_negate(const Predicate& x) : pred(x) {}  
  19.     bool operator()(const typename Predicate::first_argument_type& x, const typename Predicate::second_argument_type& y) const {  
  20.         return !pred(x, y);   
  21.     }  
  22. };  
  23. //外部接口  
  24. template <class Predicate>  
  25. inline unary_negate<Predicate> not1(const Predicate& pred)  
  26. {  
  27.     return unary_negate<Predicate>(pred);  
  28. }  
  29. //外部接口  
  30. template <class Predicate>  
  31. inline binary_negate<Predicate> not2(const Predicate& pred)  
  32. {  
  33.     return binary_negate<Predicate>(pred);  
  34. }  
          到这里,我们可以回答之前的一个问题,就是STL为什么要定义两个基类,里面仅仅是内嵌型别。通过上面代码,不难发现,原来是用来萃取函数对象所操作的数据类型。比如 binder1st 这个类,它的模板中只有一个形参,它继承自unary_function,而unary_function的模板有两个形参。如何实现这种继承关系呢?内嵌型别技术,因为binder1st 的模板实参是个函数对象,继承自unary_function或binary_function,通过内嵌型别技术很容易萃取出数据类型。

         再进一步,函数适配器是如何工作的呢?

[cpp] view plain copy
  1. include <iostream>  
  2. #include <functional>  
  3. #include <vector>  
  4. #include <algorithm>  
  5. using namespace std;  
  6. int main()  
  7. {  
  8.     vector<int> vec(10, 1);  
  9.     int count1 = count_if(vec.begin(), vec.end(), bind2nd(less_equal<int>(), 10));       //求容器中小于等于10的元素个数  
  10.     int count2 = count_if(vec.begin(), vec.end(), not1(bind2nd(less_equal<int>(), 10))); //求容器中不小于等于10的元素个数,正好是上面函数的取反  
  11.     cout<<count1<<' '<<count2<<endl;  //10 0  
  12.     return 0;  
  13. }  
        还是以这个程序为例,介绍一下count_if(vec.begin(), vec.end(), bind2nd(less_equal<int>(), 10))具体执行。首先执行bind2nd(less_equal<int>(), 10)这个函数,这个函数会返回一个binder2nd的函数对象,注意构造这个函数对象的时候,binder2nd(const Operation& x, const typename Operation::second_argument_type& y) : op(x), value(y) {} 。第二个参数value的值设置为10,而第一个参数op设置成less_equal<int>()这个函数对象。

       接着count_if 执行时,下面是它的源码。执行时,pred(*first)其实就是binder2nd中的运算,而这个运算的第二个参数是固定的,也就是10,所以pred只传递了一个实参进去就可以了。

[cpp] view plain copy
  1. template <class InputIter, class Predicate, class Size>  
  2. void count_if(InputIter first, InputIter last, Predicate pred, Size& n) {  
  3.     for ( ; first != last; ++first)  
  4.         if (pred(*first))  
  5.             ++n;  
  6. }  
  7. template <class InputIter, class Predicate>  
  8. typename iterator_traits<InputIter>::difference_type count_if(InputIter first, InputIter last, Predicate pred) {  
  9.     typename iterator_traits<InputIter>::difference_type n = 0;  
  10.     for ( ; first != last; ++first)  
  11.         if (pred(*first))  
  12.             ++n;  
  13.     return n;  
  14. }  
        下面把上述综合起来,通过修改STL,写个完整的测试程序。如下所示,注意这里用的都是自定义的代码,没有包含STL的函数对象和函数。

[cpp] view plain copy
  1. #include <iostream>  
  2. #include <vector>  
  3. using namespace std;  
  4.   
  5. //count_if函数  
  6. template <class InputIter, class Predicate, class Size>  
  7. void count_if(InputIter first, InputIter last, Predicate pred, Size& n) {  
  8.     for ( ; first != last; ++first)  
  9.         if (pred(*first))  
  10.             ++n;  
  11. }  
  12. //用来定义一元操作的参数类别和返回值类别  
  13. template <class Arg, class Result>  
  14. struct unary_function {  
  15.     typedef Arg argument_type;  
  16.     typedef Result result_type;  
  17. };  
  18. //用来定义二元操作的参数类别和返回值类别  
  19. template <class Arg1, class Arg2, class Result>  
  20. struct binary_function {  
  21.     typedef Arg1 first_argument_type;  
  22.     typedef Arg2 second_argument_type;  
  23.     typedef Result result_type;  
  24. };  
  25. //本测试之用到关系函数对象  
  26. template <class T>  
  27. struct less_equal : public binary_function<T, T, bool> {  
  28.     bool operator()(const T& x, const T& y) const { return x <= y; }  
  29. };  
  30. //绑定第二个参数  
  31. template <class Operation>   
  32. class binder2nd: public unary_function<typename Operation::first_argument_type,typename Operation::result_type> {  
  33. public:  
  34.     binder2nd(const Operation& x, const typename Operation::second_argument_type& y) : op(x), value(y) { cout<<"binder2nd Constructor"<<endl; }  
  35.     typename Operation::result_type operator()(const typename Operation::first_argument_type& x) const {  
  36.         cout<<"binder2nd's operator()"<<endl;  
  37.         return op(x, value);  //固定第二个参数  
  38.     }  
  39. protected:  
  40.     Operation op;  
  41.     typename Operation::second_argument_type value;  
  42. };  
  43. //外部接口  
  44. template <class Operation, class T>  
  45. inline binder2nd<Operation> bind2nd(const Operation& fn, const T& x) {  
  46.     typedef typename Operation::second_argument_type Arg2_type;  
  47.     return binder2nd<Operation>(fn, Arg2_type(x));  
  48. }  
  49. //一元操作求反  
  50. template <class Predicate>  
  51. class unary_negate: public unary_function<typename Predicate::argument_type, bool> {  
  52. protected:  
  53.     Predicate pred;  
  54. public:  
  55.     explicit unary_negate(const Predicate& x) : pred(x) { cout<<"unary_negate Constructor"<<endl; }  
  56.     bool operator()(const typename Predicate::argument_type& x) const {  
  57.     cout<<"unary_negate's operator()"<<endl;  
  58.     return !pred(x);  
  59.   }  
  60. };  
  61. //外部接口  
  62. template <class Predicate>  
  63. inline unary_negate<Predicate> not1(const Predicate& pred)  
  64. {  
  65.     return unary_negate<Predicate>(pred);  
  66. }  
  67. //测试程序  
  68. int main()  
  69. {  
  70.     vector<int> vec(10, 1);  
  71.     int count1 = 0, count2 = 0;  
  72.     count_if(vec.begin(), vec.end(), bind2nd(less_equal<int>(), 10),count1);       //求容器中小于等于10的元素个数  
  73.     count_if(vec.begin(), vec.end(), not1(bind2nd(less_equal<int>(), 10)),count2); //求容器中不小于等于10的元素个数,正好是上面函数的取反  
  74.     cout<<count1<<' '<<count2<<endl;  //10 0  
  75.     return 0;  
  76. }  
        本人享有博客文章的版权,转载请标明出处 http://blog.csdn.net/wuzhekai1985

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/384210.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

列表与递归

头部和尾部 [head | tail ] [1] #head 1 tail [] [head | tail ] [1, 2, 3] #head 1 tail [2, 3] [head | tail ] [] #报错 创建映射函数 我们可以使用一个函数来处理列表中的各个元素&#xff0c;如此可以接受更加复杂的处理&#xff0c;也可以…

优先队列小结

不像栈和队列&#xff0c;虽然STL有较好实现但是我们自己也可以很方便的实现&#xff0c;优先队列自己实现起来就比较复杂&#xff0c;比较浪费时间&#xff08;而且自己目前也不会233&#xff09;而优先队列因为其较好的特性经常被使用&#xff0c;因此对它的熟练掌握是做题的…

字典:散列表、散列字典、关键字列表、集合与结构体

字典 散列表和散列字典都实现了Dict的行为。Keyword模块也基本实现了&#xff0c;不同之处在于它支持重复键。 Eunm.into可以将一种类型的收集映射转化成另一种。 defmodule Sum dodef values(dict) dodict |> Dict.values |> Enum.sumend endhd [ one: 1, two: 2, thre…

C++11 学习笔记 lambda表达式

http://blog.csdn.net/fjzpdkf/article/details/50249287 lambda表达式是C11最重要也最常用的一个特性之一。lambda来源于函数式编程的概念&#xff0c;也是现代编程语言的一个特点。 一.函数式编程简介 定义&#xff1a;简单说&#xff0c;“函数式编程”是一种“编程范式”。…

Cutting Codeforces Round #493 (Div. 2)

Cutting There are a lot of things which could be cut — trees, paper, “the rope”. In this problem you are going to cut a sequence of integers. There is a sequence of integers, which contains the equal number of even and odd numbers. Given a limited bud…

Enum、Stream

Enum 其常见用法见&#xff1a;https://cloud.tencent.com/developer/section/1116852 在sort时&#xff0c;如果要获得稳定的排序结果&#xff0c;要使用< 而不是 <。 Stream Stream是延迟处理的&#xff0c;而Enum是贪婪的&#xff0c;则意味着传给它一个收集&#xff…

linux网络编程之posix 线程(三):posix 匿名信号量与互斥锁 示例生产者--消费者问题

http://blog.csdn.net/jnu_simba/article/details/9123603 一、posix 信号量 信号量的概念参见这里。前面也讲过system v 信号量&#xff0c;现在来说说posix 信号量。 system v 信号量只能用于进程间同步&#xff0c;而posix 信号量除了可以进程间同步&#xff0c;还可以线程间…

洛谷P1080-国王游戏-贪心+高精度

P1080-国王游戏 啊啊啊&#xff0c;刚才已经写了一次了&#xff0c;但是Edge浏览器不知道为什么卡住了&#xff0c;难受。 好吧&#xff0c;其实是一道可做题&#xff0c;分析得到的贪心策略就是就是将a * b小的放在前面&#xff08;其他的懒得说了&#xff09;&#xff0c;主要…

字符串与二进制

单引号字符串会被表示成整数值列表。 &#xff1f;c返回字符 c 的整数编码。下面这个例子用于解析字符列表表示法&#xff0c;该表示法用于表示一个任意的有符号的十进制数据。 defmodule Parse dodef number([ ?- | tail ]) do_number_digits(tail, 0) * -1enddef number([ ?…

P1092虫食算-深度优先搜索+玄学剪枝

P1092虫食算 这道题的思想并不复杂&#xff0c;可是难点在于各种玄学剪枝。在仔细研究了题解大佬的剪枝原理后终于氵了过去。 先上代码&#xff1a; #include<cstdio> #include<cstring> #include<algorithm> using namespace std;const int MAXN100; int n…

多进程

使用spawn创建一个新进程&#xff0c;其第一个参数是模块名、第二个参数是函数名、第三个参数是参数列表。spawn会返回一个进程标识符&#xff0c;通常叫做PID。 defmodule Spawn1 dodef greet doreceive do{sender, msg} ->send sender, { :ok, "Hello #{msg}" }…

Linux socket编程(二) 服务器与客户端的通信

http://www.cnblogs.com/-Lei/archive/2012/09/04/2670964.html上一篇写了对套接字操作的封装&#xff0c;这一节使用已封装好的Socket类实现服务器与客户端的通信&#xff08;Socket的定义见上篇Socket.h) 服务器端&#xff1a; ServerSocket.h #ifndef SERVERSOCKET_H #defin…

OTP服务器

defmodule Sequence.Server douse GenServerdef handle_call( :next_number, _from, current_number) do{ :reply, current_number, current_number 1}  #reply告诉OTP将第二个元素返回给客户端end end use的效果将OTP GenServer的行为添加到当前模块。这样它就可以处理所有…

洛谷P1040-加分二叉树-dp+二叉树

P1040-加分二叉树 这道题放在深度优先搜索的训练题中&#xff0c;可是我实在没有看出来应该怎么搜索。看了题解以后才看出来是一个很简单的dp(我果然还是太菜了) 看出dp并且算出来最大的分数不是很复杂&#xff0c;关键是输出给定中序遍历序列的二叉树的先序遍历&#xff0c;要…

UNIX网络编程:I/O复用技术(select、poll、epoll)

http://blog.csdn.net/dandelion_gong/article/details/51673085 Unix下可用的I/O模型一共有五种&#xff1a;阻塞I/O 、非阻塞I/O 、I/O复用 、信号驱动I/O 、异步I/O。此处我们主要介绍第三种I/O符复用。 I/O复用的功能&#xff1a;如果一个或多个I/O条件满足&#xff08;输…

解决iex -S mix报错

执行iex -S mix命令的时候会遇到如下错误&#xff1a; 执行 mix deps.get 然后就可以运行 iex -S mix了 其中&#xff0c;有可能会出现 按照其网站下载相应文件&#xff0c;复制到项目根目录下&#xff0c;然后执行命令&#xff08;mix local.rebar rebar ./rebar&#xff09;即…

贪心算法——选择不相交区间问题

题目描述&#xff1a;设有n个活动的集合&#xff0c;其中每个活动都要求使用同一个资源&#xff0c;而在同一时间内只有一个活动能够使用这一资源&#xff0c;每个活动i都有一个要求使用该资源的起始时间si和一个结束时间fi(si<fi)&#xff0c;如果选择了活动i&#xff0c;则…

Anker—工作学习笔记

http://www.cnblogs.com/Anker/archive/2013/08/17/3263780.html 1、基本知识 epoll是在2.6内核中提出的&#xff0c;是之前的select和poll的增强版本。相对于select和poll来说&#xff0c;epoll更加灵活&#xff0c;没有描述符限制。epoll使用一个文件描述符管理多个描述符&am…

Supervisor监控

可参考&#xff1a;https://www.cnblogs.com/wang_yb/archive/2016/06/08/5564459.html &#xff1a;https://segmentfault.com/a/1190000007379204 转载于:https://www.cnblogs.com/lr1402585172/p/11551488.html

深度搜索剪枝——数的划分

【题目描述】将整数n分成k份&#xff0c;且每份不能为空&#xff0c;问有多少种分法&#xff1f; 【输入格式】两个整数n,m(6<n<200,2<m<6) 【输出格式】输出不同的分法数 【样例输入】7 3 【样例输出】4 对于这种搜索题&#xff0c;关键就在于剪枝&#xff1a;确定…