【数据结构】单链表的递归算法

本文探讨了如何使用递归算法设计单链表的遍历方法,重点在于理解递归模型的构造,包括递归体和递归出口。通过举例展示了链表正向和反向遍历的递归实现,强调了递归函数位置对遍历顺序的影响,揭示了递归从外向内或从内向外的遍历特性。

设计递归算法的方法

主要是求递归模型,递归模型的求解类似于(其实就是)数学中的归纳法。递归模型中应该包含递归体递归出口两部分。

代码如下:

#include <stdio.h>

#define NUM 8
int A[NUM] = { 102,102,32,44,202,32,61,56 };

int min(int a,int b)
{
    if (a < b)return a;
    else return b;
}

int F(int A[], int i)//使用递归求数组A[]中A[0]~A[i]的最小值
{
    if (i == 0)return A[0];
    else
    {
        return min(F(A, i - 1), A[i]);
    }
}

int main()
{
    printf("F: %d\n", F(A, NUM - 1));
    return 0;
}

递归的魅力-不带头结点的单链表的递归算法

#include <stdio.h>
#include <stdlib.h>

typedef struct Node {
    int data;
    struct Node* next;
}Node, * LkList;

void CreatLkList(LkList& L, int n);
void Tranvers_Twd(LkList L);//递归正向遍历
void Tranvers_Bk(LkList L);//递归反向遍历
void DestoryList(LkList& L);

int main()
{
    LkList L;
    CreatLkList(L, 5);
    printf("正向遍历:\n");
    Tranvers_Twd(L);
    printf("反向遍历:\n");
    Tranvers_Bk(L);
    printf("销毁链表:\n");
    DestoryList(L);
	return 0;
}


void CreatLkList(LkList& L,int n)//递归创建不带头结点的单链表
{
    if (n == 0)//终止条件
    {
        L = NULL;
    }
    else
    {
        L = (LkList)malloc(sizeof(Node));
        if (!L)exit(0);

        scanf_s("%d",&(L->data));
        CreatLkList(L->next, n - 1);
    }
}

void Tranvers_Twd(LkList L)//递归正向遍历
{
    if (L == NULL)return;
    printf("%d\n",L->data);
    Tranvers_Twd(L->next);
}
void Tranvers_Bk(LkList L)//递归反向遍历
{
    if (L == NULL)return;
    Tranvers_Bk(L->next);
    printf("%d\n", L->data);
}

void DestoryList(LkList& L)
{
    if (L)
    {
        DestoryList(L->next);
        printf("free:%d\n", L->data);//显示释放过程
        free(L);
        L = NULL;
    }
}

递归函数的位置很重要,它决定了该递归从哪里展开,也就会有不同的效果。

void Tranvers_Twd(LkList L)//递归正向遍历
{
    if (L == NULL)return;
    printf("%d\n",L->data);
    Tranvers_Twd(L->next);
}
void Tranvers_Bk(LkList L)//递归反向遍历
{
    if (L == NULL)return;
    Tranvers_Bk(L->next);
    printf("%d\n", L->data);
}

比如上文的链表的正向遍历和反向遍历,他们的差别只是递归函数的位置不同!我们知道代码是从前往后执行的,如果递归函数是在最后调用(尾递归),我们递归展开一次就会是这样:

void Tranvers_Twd(LkList L)//递归正向遍历
{
    if (L == NULL)return;
    printf("%d\n", L->data);
        if (L->next == NULL)return;
        printf("%d\n", L->next->data);
        Tranvers_Twd(L->next->next);
}

再展开一次就是这样:

void Tranvers_Twd(LkList L)//递归正向遍历
{
    if (L == NULL)return;
    printf("%d\n", L->data);
        if (L->next == NULL)return;
        printf("%d\n", L->next->data);
            if (L->next->next == NULL)return;
            printf("%d\n", L->next->next->data);
            Tranvers_Twd(L->next->next->next);
}

 ...展开下去就是从L开始一直打印两边中的节点的数据,直到L->next....->next=NULL就会终止。

同样的道理,我们对反向遍历函数Tranvers_Bk展开两次:

void Tranvers_Bk(LkList L)//递归反向遍历
{
    if (L == NULL)return;
        if (L->next == NULL)return;
            if (L->next->next == NULL)return;
            Tranvers_Bk(L->next->next->next);
            printf("%d\n", L->next->next->data);
        printf("%d\n", L->next->data);
    printf("%d\n", L->data);
}

 可以看到,是从内往外打印的!这就是递归反向遍历链表的道理!

总的来说,递归函数前的是有外入内,递归函数后的是有内出外。

void f()
{
	//由外到内
	f();//递归体
	//由内到外
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值