引言
在对链表进行递归逆置的学习中,了解到了递归逆置的进阶操作,即对链表的部分节点进行逆置。思路因为基于整表逆置,故顺便进行了一番学习和了解,在此感谢大佬的labuladong的
如何纯递归反转链表的一部分对我的学习和帮助,推荐大家详细阅读原文,本文只是方便自己日后复习的笔记和记录,主要以详解代码为主。
正文
整表递归逆置
void *reslink8(linklist *link)
{
//如果链表本身为空或者到达最后一个节点,则返回此节点本身
if (!link || !link->next)
{
return link;
}
//开始递归
//一直到达最后一个节点处,并将此节点返回给temp,即temp是最后一项的指针
linklist *temp = reslink8(link->next);
//不要思路绕进递归里,从最外面来看,这个递归的结果就是返回一个逆置好的队列的头指针
所以每次的图应该为
// link(link->next ...temp)
//括号代表指向关系相反
link->next->next = link;//后一个节点接到自己,即图为
//(link link->next .... temp)
link->next = NULL;//自己指向空
//temp 因为是最后一项,所以返回temp作为原链表的头节点
return temp;
}
对于这种非尾递归的递归来说,尽量不要把自己绕进去,要明确递归的作用和返回,在最外层对递归的后续进行处理,这样可以有效学习掌握
前n个节点逆置
其实对整表逆置的判断条件和后续处理更改一下就能简单实现
linklist *xia = NULL;
void *renserve(linklist * link, int n)
{
if (n == 1)
{
xia = link->next;
return link;
}
linklist *temp = renserve(link->next, n - 1);
link->next->next = link;
link->next = xia;
return temp;
}
原来是判断是否到达最后一个节点
if (!link || !link->next)
{
return link;
}
现在每次递归的时候n-1;
当n==1的时候意味着到达了需要逆置的最后一个节点
if (n == 1)
{
xia = link->next; //存下一个节点的位置
return link;
}
//link还是整个链表的第一个节点,但是每次递归给link->next后面继续添加->next 所以递归中存入xia指针的link->next 实际上在最外层来看是temp后面的节点
此时需要将下一个不需要逆置的节点存进一个递归不改变值的链表指针中,以便后续处理节点之间的关系
在此应在函数外定义一个链表指针。
//和之前一样进行递归,每次n-1
//返回排序好的队列队首
linklist *temp = renserve(link->next, n - 1);
//递归后的图为
// link(link->next...temp)xia ...
link->next->next = link;
//图
//(link........temp)xia
link->next = xia;//link与xia建立联系
//temp仍是反转后链表的头节点
return temp;
反转链表指定区间
因为begin(b)肯定小于end(e)
所以每次递归对b-1,e-1,先到达1的肯定是b,此时e相当于需要反转的项数,
所以函数功能就相当于再次对e项的逆置,与上种方法相同
但特殊的是从b到b=1一直在递归中
处理完b=1之后要对原b项到b=1的中间的项仍然进行逆置,本函数在每次递归语句执行完成后对前一项进行处理,直到所有递归退出。
//表 ...... ....... link(...temp)xia
//下标 0 ... 原b b=1
而每次递归语句执行完成后的前一项为link,即对link与后面的链表进行关联(有点绕,,尽量理解)
//表 ...... ....... link(...temp)xia
//下标 0 ... 原b b=2
一直到
//表 ...... link....(...temp)xia
//下标 0 ... 原b
递归自然结束
void *rennserve(linklist *link, int b, int e)
{
if (b == 1) //开始逆序
{
return renserve(link, e);
}
linklist *temp = rennserve(link->next, b - 1, e - 1);
//以下仍是递归的一部分
//此时链表指针如图
// ..... link (... temp) xia...
//因为逆序前n项函数已经对需要逆转链表与之后的普通链表进行了关联,所以此函数只需要处理temp头与link的关系
link->next = temp;
//...(link ...temp)xia ..
return link;
//外层递归来说 link为新link
// 。。。新link(原link 。。。temp)xia
//每次对逆置链表的最左边一项与逆置链表之前的正常链表最后一项建立联系,返回后边的排好的链表,以便外层递归继续处理,最后link一次一次退回到头节点处,完成
}