第44课 递归的思想与应用(中)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第44课 递归的思想与应用(中)相关的知识,希望对你有一定的参考价值。

1. 单向链表的转置

技术分享 

【编程实验】单向链表的转置(Node* reverse(Node* list)

2. 单向排序链表的合并

技术分享 

【编程实验】单向排序链表的合并(Node* merge(Node* list1, Node* list2)

3. 汉诺塔问题

(1)游戏规则

技术分享 

  ①将木块借助B柱由A柱移动C柱

  ②每次只能移动一个土块

  ③只能出现小土块在大木块之上

(2)递归求解的问题分解

技术分享 

  ①将n-1个木块借助C柱由A移动到B柱。

  ②将最底层的唯一木块直接移动到C柱

  ③将n-1个木块借助A柱由B柱移动到C柱

【编程实验】汉诺塔问题求解(void HanoiTower(int n, char a, char b, char c)

4. 全排列问题

技术分享 

【编程实验】全排列的递归解法(void permutation(char* s)

 //main.cpp

#include <iostream>
#include <cstring>

using namespace std;

struct Node
{
    int value;
    Node* next;
};

//创建无表头结点的单链表(己填充数据):v结点的值,len链表长度
Node* create_list(int v, int len)
{
    Node* ret = NULL;
    Node* slider = NULL;

    for(int i=0; i<len; i++){
        Node* node = new Node();

        node->value = v++;
        node->next = NULL;

        //每创建好一个节点,slider指向这个节点
        if( slider == NULL ){
            slider = node;
            ret = node;
        }else{
            slider->next = node;
            slider = node;
        }
    }

    return ret;
}

void destroy_list(Node* list)
{
    while(list){
        Node* del = list;
        list = list->next;

        delete del;
    }
}

//打印链表的内容
void print_list(Node* list)
{
    while(list){
        cout << list->value << "->";
        list = list->next;
    }

    cout << "NULL" << endl;
}

//单链表转置(递归法)
Node* reverse(Node* list)
{
    //递归出口
    if((list == NULL) || (list->next == NULL)){
        return list;
    }else{
        Node* guard = list->next;  //指向反转前的子链表第1个结点
        Node* ret = reverse(list->next); //转置子链表
        guard->next = list; //反转后,guard变成子链表的最后一个结点
        list->next = NULL;

        return ret;
    }
}

//单向排序链表的合并
Node* merge(Node* list1, Node* list2)
{
    //递归出口
    if(list1 == NULL)
        return list2;

    if(list2 == NULL)
        return list2;

    //取出子链表的第1个结点并比较
    if(list1->value < list2->value){
        //由于当前list1结点的值较小,取出当前结点,其next
        //指向由该结点后继的子链表和list2合并的新链表
        list1->next = merge(list1->next, list2);
        return list1;
    }else{
        //list2当前结点的值较小
        list2->next = merge(list1, list2->next);
        return list2;
    }
}

//汉诺塔
void HanoiTower(int n, char a, char b, char c)
{
    if(n == 1){
        cout << a  << "-->" << c << endl;
    }else{
        HanoiTower(n-1, a, c, b); //将n-1块,从a柱借c柱移动到b柱
        HanoiTower(1, a, b, c);   //将a柱剩下的最后一块移到c柱上
        HanoiTower(n-1, b, a, c); //将b柱中的n-1块借助a柱移到c柱。
    }
}

//全排列
void permutation(char* s, char* e)
{
    if(*s == \\0)
    {
        cout << e << endl;//打印出全排列好的字符串
    }else{
        int len = strlen(s);

        //如将abc
        //1.第1轮:将abc变成以a开头,然后全排列bc
        //2.第2轮:将abc变成以b开头,然后全排列ac
        //3.第3轮:将abc变成以c开头,然后全排列ba
        for(int i=0; i<len; i++){
            if((i == 0) || (s[0] != s[i])){ //去重复,如aba就不交换两个a
                swap(s[0], s[i]);  //以s[0]开头(每轮会变化),全排列其后的子串。
                permutation(s+1, e); //全排列子串
                swap(s[0], s[i]); //恢复为原来的串,如abc,以便下一轮全排列。
            }
        }
    }
}

int main()
{
    //测试:单链表转置
    Node* list = create_list(1, 10);
    print_list(list);


    list = reverse(list);
    print_list(list);

    destroy_list(list);

    //测试:单向排序链表的合并
    Node* list1 = create_list(1,5);
    Node* list2 = create_list(3,7);

    print_list(list1);
    print_list(list2);

    Node* ret = merge(list1, list2);
    print_list(ret);

    destroy_list(ret);

    //测试:汉诺塔
    HanoiTower(3, a, b, c);

    //测试:全排列
    char s[]="aabc";
    permutation(s, s);

    return 0;
}
/*测试结果:
1->2->3->4->5->6->7->8->9->10->NULL
10->9->8->7->6->5->4->3->2->1->NULL
1->2->3->4->5->NULL
3->4->5->6->7->8->9->NULL
1->2->3->3->4->4->5->5->6->7->8->9->NULL
a-->c
a-->b
c-->b
a-->c
b-->a
b-->c
a-->c
aabc
aacb
abac
abca
acba
acab
baac
baca
bcaa
caba
caab
cbaa
*/

以上是关于第44课 递归的思想与应用(中)的主要内容,如果未能解决你的问题,请参考以下文章

数据--第20课-递归的应用实战二

数据-第19课-递归的应用实战一

C语言-第36课 - 函数递归与函数设计技巧

20165231 第四周测试课下补做

第47课 递归函数分析

《英雄编程体验课》第 12 课 | 递归