每日编程6之单链表反转递归版本

来源:互联网 发布:vue.js设置button隐藏 编辑:程序博客网 时间:2024/06/05 04:12

既然链表逆序输出可以用递归方法实现,单链表反转也可以采用递归思想实现。

不同的地方时,后者需要破坏原有的链表结构


不晓得采用1个指针能不能实现

先考虑用2个指针p,q分别记录原来的链表关系

初始时:p = NULL,q = head;  特殊条件为q==NULL,表示链表中没有元素,这也可以作为递归结束条件(这可以成为一种找递归结束条件的思路)

递归处理操作是:p=q;q=q->next;linkList_reverse_recur(p,q)                            如果这里q==NULL,说明p为最后一个元素,p即为反转后的链表表头

核心处理操作是:q->next = p


不对

如果是递归的话,在核心处理部分开始的时候,原有的链表结构为被打乱,也就不需要用一个额外的指针记录前一个节点指针,

用1个指针p开始递归,p初始为p=head,结束应该是p->next == NULL   考虑到head==NULL的特殊情况,这也应该放到递归结束条件里去

核心处理为:p->next->next = p;                             因为虽然递归的因子是p,但实际上处理的是p->next的后继指针,所以p->next == NULL 为结束条件    当然为了保证逆序,该处理                                                                                                         要放在递归操作之后

递归操作:linkList_reverse_recur(p->next)



关于递归函数的返回值,这个其实没关系,因为我只要保证最后一层的返回结果就行了。但因为递归还要进行出栈,所以这里不能return,因此必须增加一个参数来保存反转后表头的位置


执行程序的时候出现无限循环,原来是第一个元素没有处理,导致第一个元素和第二个元素徐成一个链循环,不停的打印8和9

要对一个元素和最后一个处理的第一个元素进行单独处理,那么如何判断一个元素是那个元素,只能通过指针判断,因此必须加一个参数来说明原来表头指针oldhead,通过判断p==oldhead来进行处理


核心代码:

int linkList_reverse_recur(struct node *oldhead,struct node* &newhead,struct node *p)     //三个参数是必须的,见前面的分析
{
        if(p == NULL)                                           //链表为空的特殊情况处理,仅在第一次递归时判断一次,后续的递归不可能出现这种情况,切记这一点
                return 0;
        if(p->next != NULL)
        {
                linkList_reverse_recur(oldhead,newhead,p->next);
                p->next->next = p;                           //核心处理,此时顺序的链表结构尚未被破坏
        }
        else
        {
                newhead = p;
        }
        if(p == oldhead)                                             //放在最后,单独处理第一个元素
                p->next = NULL;
}



OVER!!!