list的排序和比较函数作为参数传递

前几天使用list的排序功能,出现了一点问题,来总结一下。

定义一个简单的节点类,包含一个字符串和一个整数,并重载了小于操作,根据整数的大小进行比较。

class Node
{
    public:
        Node(string nm,int i)
        {
            name = nm;
            id = i;
        }
        void Print()
        {
            cout << name << ":" << id << endl;
        }
        friend bool operator < (const Node& n1,const Node& n2)
        {
            cout << "comparing:" << endl;
            return (n1.id<n2.id);
        }
    public:
        int id;
        string name;
};

然后创建了一个测试的结构,
把一些Node节点的地址放入list中,我一般是这样用的,因为有时候在一个地方用创建了这些节点,在另外的一些地方要用这些节点,
如果创建的时候不使用new的话,把他们存入list之后,在其他地方就不能再使用,所以就只能用new创建了,然后把指针放入list。
代码如下,

class NodeList
{
    public:
        NodeList()
        {
            Node* n1 = new Node("abc",3);
            Node* n2 = new Node("efb",5);
            Node* n3 = new Node("ac",1);
            Node* n4 = new Node("a",0);
            Node* n5 = new Node("4",4);
            nodes.push_back(n1);
            nodes.push_back(n2);
            nodes.push_back(n3);
            nodes.push_back(n4);
            nodes.push_back(n5);
        }
        void Print()
        {
            list<Node*>::iterator it = nodes.begin();
            for(;it!=nodes.end();it++)
            {
                (*it)->Print();
            }
        }
        void Test()
        {
            Print();
            nodes.sort();
            cout << "\nafter sort:" << endl;
            Print();
            struct cmp_node cmpnode;
            nodes.sort(cmpnode);
            cout << "\nafter sort(cmp_node):" << endl;
            Print();
        }
    public:
        list<Node*> nodes;

};

在使用list sort的时候,可以使用默认参数,也可以传递一个比较函数,所以又定义了一个Node的比较函数,放在struct里面,

struct cmp_node
{
    public:
        bool operator () (const Node* n1, const Node* n2) const
        {
            return ((n1->id)<(n2->id));
        }
};

最后进行测试,调用nodeList的Test函数就可以了。期望后两次的结果都是排好序的?但结果确实只有最后的一个是排好序的,也就是第一次没有传递比较函数作为参数的sort没有对list排序。这个不知道是什么原因。
来说一下为什么要把新定义的比较函数放在一个结构体里面。
在C/C++里面,函数不是对象,不能作为参数来传递,所以把要传递的函数放在一个对象里面,这里是放在一个struct里面,按理说放在一个class里面作为public函数也是可以的,没有进行测试过,记得使用unordered_map传递hash函数的时候,也是类似的情况,当时使用的后一种方法。
需要注意的是,在结构体里面定义比较函数的时候,不再是重载小于号,而是一对小括号,然后参数应该是放在list里面的数据类型,是节点指针。

总觉得把指针放在list里面好像很别扭的,希望大家能指导下这种情况下的list的用法。

转载于:https://www.cnblogs.com/Frandy/archive/2012/09/06/list_sort.html

<think>好的,用户现在问的是“函数能否作为参数传递”。之前他问过关于C#中传递类成员函数的问题,现在可能是在更广泛的语言范围内提问。需要先确定用户是否仍然关注C#,还是想了解其他语言的情况。 首先,用户可能是想扩展知识,了解不同编程语言中函数作为参数传递的情况。之前的对话集中在C#的实现细节,比如委托闭包,但现在的问题更通用。需要先明确回答“可以”,然后分情况讨论。 用户可能的实际需求是,在编程中需要回调、事件处理或者高阶函数的使用,比如在算法中传递比较函数,或者异步编程中的回调函数。需要举例说明常见应用场景,帮助他理解为什么需要这样做。 考虑到用户之前的问题涉及类内参数生命周期,可能在传递函数时遇到问题,比如闭包捕获变量或对象实例的管理。在回答时应该涵盖这些注意事项,但这次需要更通用,而不仅限于C#。 需要比较不同语言的实现方式,比如C#用委托,JavaScript用函数对象,PythonJava的不同机制。这样用户能了解不同语言之间的差异,满足他可能的跨语言学习需求。 还要注意用户可能的误区,比如函数作为参数时的作用域问题,或者在某些静态语言中的类型限制。需要解释清楚,传递函数时的类型安全语法要求。 最后,总结应用场景,强调函数作为参数带来的灵活性,比如策略模式、回调机制等,帮助用户理解其实际价值。同时提醒注意事项,如生命周期管理、类型匹配性能考量,避免常见错误。</think>在大多数现代编程语言中,**函数可以作为参数传递**,这是函数式编程现代面向对象编程的重要特性。具体实现方式因语言而异,以下是主要实现形式技术要点: --- ### 一、实现方式对比(主流语言示例) | 语言 | 实现方式 | 典型语法示例 | |------------|--------------------------|---------------------------------------| | **C#** | 委托(Delegate) | `Action<int>`, `Func<string, bool>` | | **Java** | 函数式接口/λ表达式 | `Consumer<T>`, `Function<T,R>` | | **Python** | 函数对象 | 直接传递函数名 | | **JS/TS** | 函数对象/Callback | `(param) => { ... }` | | **C++** | 函数指针/λ表达式 | `std::function<void(int)>` | --- ### 二、核心技术原理 1. **第一类公民(First-class Function)** - 函数与其他数据类型(如int, string)具有同等地位 - 可赋值给变量、作为参数传递、作为返回值 2. **闭包(Closure)机制** ```javascript // JavaScript示例 function createMultiplier(factor) { return function(x) { return x * factor; // 捕获外部factor变量 }; } ``` - 自动捕获上下文环境变量 - 维持变量的生命周期 3. **类型安全约束** ```csharp // C#委托类型匹配 public void ProcessData(Func<int, string> converter) { // 参数必须匹配int入参、string返回值 } ``` --- ### 三、实际应用场景 1. **回调机制(Callback)** ```python # 异步下载完成回调 def download_complete(result): print(f"Downloaded {len(result)} bytes") start_download("http://example.com", callback=download_complete) ``` 2. **策略模式** ```java // 排序策略选择 list.sort((a, b) -> a.age - b.age); // 按年龄排序 list.sort((a, b) -> a.name.compareTo(b.name)); // 按姓名排序 ``` 3. **高阶函数** ```javascript // 数组过滤 const numbers = [1, 2, 3, 4]; const even = numbers.filter(n => n % 2 === 0); ``` --- ### 四、注意事项 1. **生命周期问题** - 当传递闭包时,注意捕获变量的有效期 - 避免循环引用导致内存泄漏(尤其在JS中) 2. **性能考量** - 虚函数调用比普通函数调用稍慢(C++/C#) - 大量闭包可能增加内存压力 3. **语言特性差异** - Python/JS允许动态参数类型 - Java需要严格匹配函数式接口 - C#需预定义委托类型或使用`Action`/`Func` --- ### 五、特殊案例解析 **C语言中的函数指针:** ```c // 计算器功能实现 void calculate(int a, int b, int (*op)(int, int)) { printf("Result: %d\n", op(a, b)); } int add(int x, int y) { return x + y; } calculate(5, 3, add); // 输出 8 ``` **Rust的所有权机制:** ```rust // 需要明确指定闭包所有权 let data = vec![1,2,3]; let closure = move || { println!("Data: {:?}", data); // data所有权被转移 }; ``` --- 通过函数参数化,可以实现:<br> ✓ 代码解耦 ✓ 逻辑复用 ✓ 动态行为控制<br> 但需要根据具体语言特性合理使用,避免滥用导致的代码可读性下降。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值