📜  C++ 中的递归 lambda 表达式

📅  最后修改于: 2022-05-13 01:55:48.996000             🧑  作者: Mango

C++ 中的递归 lambda 表达式

递归 lambda 表达式是函数直接或间接调用自身的过程称为递归,相应的函数称为递归函数。使用递归算法,可以很容易地解决某些问题。此类问题的示例有河内塔 (TOH)、中序/前序/后序树遍历、图的 DFS 等。

递归函数只是一种循环结构。不同之处在于它自己维护一个内存堆栈。显然,它必须有像 for 和 while 循环这样的中断条件。因此,递归函数具有以下结构-

function name(arguments)
{
    a base case (a breaking condition)   
    recursive code (the actual logic)
}
int fact(int n)
{
    // Base Case
    if (n < = 1)
        return 1;
    else    
        return n * fact(n - 1);    
}

C++ 11 引入了 lambda 表达式,使我们能够编写一个内联函数,该函数可用于不会重用且不值得命名的短代码片段。最简单的 lambda 表达式可以定义如下:

[ capture clause ] (parameters) -> return-type  
{   
   definition of method   
} 

方案一:

下面是 C++ 中 sort() 方法中 lambda 表达式的程序:



C++14
// C++ program to implement
// the above approach
#include 
using namespace std;
 
// Driver code
int main()
{
    int arr[] = { 5, 2, 1, 4, 3 };
    sort(arr, arr + 5, [](int& a,
                          int& b) {
        // Instant lambda function
        return a > b;
    });
 
    for (int i = 0; i < 5; i++)
        cout << arr[i] << " ";
    return 0;
}


C++14
// C++ program to implement
// the above approach
#include 
using namespace std;
 
// Stored lambda expression
auto cmp = [](int& a, int& b) {
    return a > b;
};
 
// Driver code
int main()
{
    int arr[] = { 5, 2, 3, 1, 4 };
    sort(arr, arr + 5, cmp);
 
    for (int i = 0; i < 5; i++)
        cout << arr[i] << " ";
 
    return 0;
}


C++14
// C++ program to implement
// the above approach
#include 
using namespace std;
 
// Recursive function to print
// the digits of a number
void printReverse(int n)
{
    if (n == 0)
        return;
    cout << n % 10 << " ";
    printReverse(n / 10);
}
 
// Driver code
int main()
{
    int n = 12345;
    printReverse(n);
    return 0;
}


C++14
// C++ program to implement
// the above approach
#include 
using namespace std;
 
// Driver code
int main()
{
    int n = 12345;
 
    // Recursive lambda function to
    // print the digits of a number
    auto printReverse = [&]() {
        if (n == 0)
            return;
        cout << n % 10;
        n = n / 10;
        printReverse();
 
        // As it is a part of main body,
        // semicolon is must
    };
 
    printReverse();
    return 0;
}


C++14
// C++ program to implement
// the above approach
#include 
using namespace std;
 
// Driver code
int main()
{
    int n = 12345;
 
    // Function itself as a parameter
    auto printReverse = [&](auto&& printReverse) {
        if (n == 0)
            return;
        cout << n % 10 << " ";
        n = n / 10;
        printReverse(printReverse);
    };
 
    // Function as an argument
    printReverse(printReverse);
    return 0;
}


C++
// C++ program to implement
// the above approach
#include 
using namespace std;
 
// Declaring of a function
void declaringFunction(string s);
 
// Driver code
int main()
{
    declaringFunction("Hello I am learning how to declare a function");
    return 0;
}
 
// Body of a function
void declaringFunction(string s)
{
    cout << s;
}


C++14
// C++ program to implement
// the above approach
#include 
#include 
using namespace std;
 
// Driver code
int main()
{
    int n = 12345;
 
    // Function < return type (parameter
    // types) > functionName
 
    // Don't forget to include functional
    // header
 
    // Declaration
    function printReverse;
 
    printReverse = [&]() {
        if (n == 0)
            return;
 
        // Defination
        cout << n % 10 << " ";
        n /= 10;
        printReverse();
    };
 
    printReverse();
}


C++14
// C++ program to implement
// the above approach
#include 
#include 
using namespace std;
 
// Driver code
int main()
{
    int n = 12345;
 
    // Function < return type (parameter
    // types) > functionName
    function printReverse = [&]() {
        if (n == 0)
            return;
 
        // Declaration + Body
        cout << n % 10 << " ";
        n /= 10;
        printReverse();
    };
 
    printReverse();
}


C++14
// C++ program to implement
// the above approach
#include 
using namespace std;
 
// Driver code
int main()
{
    int n = 6;
 
    // Recursive Lambda function to
    // find the factorial of a number
    auto factorial = [&](auto&& factorial) {
        if (n == 1)
            return n;
        return n-- * factorial(factorial);
    };
 
    auto factorial2 = [](int n, auto&& factorial2) {
        if (n == 1)
            return n;
        return n * factorial2(n - 1, factorial2);
    };
 
    // Given n = 6
    cout << factorial(factorial) << endl;
 
    // Given n = 5
    cout << factorial2(5, factorial2);
}


C++14
// C++ program to implement
// the above approach
#include 
using namespace std;
 
// Driver code
int main()
{
    // Sorted array
    int arr[] = { 1, 2, 5, 7, 10, 12, 15 };
    int size = 7;
 
    // Item to be searched
    int key = 10;
 
    auto binarySearch = [&](int startIndex,
                            int endIndex,
                            auto&& binarySearch) {
        if (startIndex > endIndex)
            return -1;
        int midIndex = (startIndex + endIndex) / 2;
        if (arr[midIndex] == key)
            return midIndex;
        if (arr[midIndex] > key)
            return binarySearch(startIndex,
                                midIndex - 1,
                                binarySearch);
        if (arr[midIndex] < key)
            return binarySearch(midIndex + 1,
                                endIndex,
                                binarySearch);
        // Not found
        return -1;
    };
 
    int index = binarySearch(0, size - 1,
                             binarySearch);
    if (index == -1)
        cout << "Not found";
    else
        cout << "Found on index " << index;
 
    return 0;
}


输出
5 4 3 2 1 

说明:这里使用的是 Instant lambda函数,不能在其他排序方法中使用,即需要重新编写相同的代码。此 lambda 表达式仅在执行 sort() 方法期间存在。但是也可以将 lambda 表达式存储在变量中(最好将其称为函数),如下所示。通过存储它,它可以进一步使用,当然也可以进行递归。

方案二:

C++14

// C++ program to implement
// the above approach
#include 
using namespace std;
 
// Stored lambda expression
auto cmp = [](int& a, int& b) {
    return a > b;
};
 
// Driver code
int main()
{
    int arr[] = { 5, 2, 3, 1, 4 };
    sort(arr, arr + 5, cmp);
 
    for (int i = 0; i < 5; i++)
        cout << arr[i] << " ";
 
    return 0;
}
输出
5 4 3 2 1 

说明:这里的 auto cmp 是 lambda 存储函数,可用于多种排序方法。

使用 Lambda 进行递归:让我们通过考虑下面的递归函数一起讨论递归和 lambda 表达式的概念:

方案三:

C++14

// C++ program to implement
// the above approach
#include 
using namespace std;
 
// Recursive function to print
// the digits of a number
void printReverse(int n)
{
    if (n == 0)
        return;
    cout << n % 10 << " ";
    printReverse(n / 10);
}
 
// Driver code
int main()
{
    int n = 12345;
    printReverse(n);
    return 0;
}
输出

5 4 3 2 1 

说明:以上是使用递归以相反顺序打印数字的数字的函数。使用 lambda 表达式也可以做到这一点。

程序4:

下面是使用 lambda 表达式实现上述代码的 C++ 程序:

C++14

// C++ program to implement
// the above approach
#include 
using namespace std;
 
// Driver code
int main()
{
    int n = 12345;
 
    // Recursive lambda function to
    // print the digits of a number
    auto printReverse = [&]() {
        if (n == 0)
            return;
        cout << n % 10;
        n = n / 10;
        printReverse();
 
        // As it is a part of main body,
        // semicolon is must
    };
 
    printReverse();
    return 0;
}

输出:

错误

哎呀,这个函数用auto返回类型定义的,必须先扣除(编译器必须能够判断返回类型auto是否可以转换为void或int或其他)

解释:这里,函数将如何识别变量 n,即使它没有作为参数传递。带有空捕获子句 [ ] 的 lambda 只能访问其本地变量。这里使用了捕获close[&],它允许函数访问变量n(变量n的实际值正在改变)。有两种方法可以解决上述错误:

1. 通过将函数本身传递给函数参数:

下面是实现上述概念的 C++ 程序:

计划5:

C++14

// C++ program to implement
// the above approach
#include 
using namespace std;
 
// Driver code
int main()
{
    int n = 12345;
 
    // Function itself as a parameter
    auto printReverse = [&](auto&& printReverse) {
        if (n == 0)
            return;
        cout << n % 10 << " ";
        n = n / 10;
        printReverse(printReverse);
    };
 
    // Function as an argument
    printReverse(printReverse);
    return 0;
}
输出

5 4 3 2 1 

2. 首先声明函数:

声明一个函数意味着声明其名称和参数类型,以通知编译器有一个名为 xyz 的函数,该函数稍后将编写其主体。

计划6:

下面是实现上述概念的 C++ 程序:

C++

// C++ program to implement
// the above approach
#include 
using namespace std;
 
// Declaring of a function
void declaringFunction(string s);
 
// Driver code
int main()
{
    declaringFunction("Hello I am learning how to declare a function");
    return 0;
}
 
// Body of a function
void declaringFunction(string s)
{
    cout << s;
}
输出
Hello I am learning how to declare a function

程序 7:

由于它是一个 lambda函数,因此必须有某种独特的方法来声明该函数。下面是相同的 C++ 程序:

C++14

// C++ program to implement
// the above approach
#include 
#include 
using namespace std;
 
// Driver code
int main()
{
    int n = 12345;
 
    // Function < return type (parameter
    // types) > functionName
 
    // Don't forget to include functional
    // header
 
    // Declaration
    function printReverse;
 
    printReverse = [&]() {
        if (n == 0)
            return;
 
        // Defination
        cout << n % 10 << " ";
        n /= 10;
        printReverse();
    };
 
    printReverse();
}
输出
5 4 3 2 1 

说明:在上面的代码中,首先声明了函数printReverse,然后我们定义了它的主体。取而代之的是,我们可以直接声明函数及其主体,这称为定义函数。下面是实现上述方法的 C++ 程序:

程序8:



C++14

// C++ program to implement
// the above approach
#include 
#include 
using namespace std;
 
// Driver code
int main()
{
    int n = 12345;
 
    // Function < return type (parameter
    // types) > functionName
    function printReverse = [&]() {
        if (n == 0)
            return;
 
        // Declaration + Body
        cout << n % 10 << " ";
        n /= 10;
        printReverse();
    };
 
    printReverse();
}
输出
5 4 3 2 1 

示例:以下是使用 lambda 表达式的递归函数的一些示例。

程序 9:

C++14

// C++ program to implement
// the above approach
#include 
using namespace std;
 
// Driver code
int main()
{
    int n = 6;
 
    // Recursive Lambda function to
    // find the factorial of a number
    auto factorial = [&](auto&& factorial) {
        if (n == 1)
            return n;
        return n-- * factorial(factorial);
    };
 
    auto factorial2 = [](int n, auto&& factorial2) {
        if (n == 1)
            return n;
        return n * factorial2(n - 1, factorial2);
    };
 
    // Given n = 6
    cout << factorial(factorial) << endl;
 
    // Given n = 5
    cout << factorial2(5, factorial2);
}
输出
720
120

说明:在阶乘函数,使用 [&] 捕获子句直接访问 n。在 factorial2函数, n 作为参数传递。因此,不需要 [&] 子句。

计划10:

C++14

// C++ program to implement
// the above approach
#include 
using namespace std;
 
// Driver code
int main()
{
    // Sorted array
    int arr[] = { 1, 2, 5, 7, 10, 12, 15 };
    int size = 7;
 
    // Item to be searched
    int key = 10;
 
    auto binarySearch = [&](int startIndex,
                            int endIndex,
                            auto&& binarySearch) {
        if (startIndex > endIndex)
            return -1;
        int midIndex = (startIndex + endIndex) / 2;
        if (arr[midIndex] == key)
            return midIndex;
        if (arr[midIndex] > key)
            return binarySearch(startIndex,
                                midIndex - 1,
                                binarySearch);
        if (arr[midIndex] < key)
            return binarySearch(midIndex + 1,
                                endIndex,
                                binarySearch);
        // Not found
        return -1;
    };
 
    int index = binarySearch(0, size - 1,
                             binarySearch);
    if (index == -1)
        cout << "Not found";
    else
        cout << "Found on index " << index;
 
    return 0;
}
输出
Found on index 4
想要从精选的视频和练习题中学习,请查看C++ 基础课程,从基础到高级 C++ 和C++ STL 课程,了解基础加 STL。要完成从学习语言到 DS Algo 等的准备工作,请参阅完整的面试准备课程