206.反转链表


主要有两种解法,双指针迭代和递归方法

1.双指针迭代法

public ListNode reverseList(ListNode head) {
             ListNode pre=null;
             ListNode cur=head;//cur一开始赋值为头节点
             ListNode tmp=null;//该变量负责保存cur的下一个节点,起暂存储功能
             while(cur!=null) {
                 tmp=cur.next;
                 cur.next=pre;//cur调转指针方向,转向pre,也就是反转链表方向
                 pre=cur;
                 cur=tmp;//上面这两行代码其实相当于把pre和cur同时前进一步
             }
             //整个循环相当于重复将cur所指方向进行反转,同时cur不断向前行进
             return pre;
             /*注意,cur在上面循环里会一直走到链表的最终节点
             *所以最后cur跳出循环时是等于null,而pre此时为链表的最终节点*/
         }

思路简述

设置两个指针,第一个指针叫 pre,最初是指向 null 的。
第二个指针 cur 指向 head,然后不断遍历 cur。
同时设置一个指针tmp用来保存cur的下一个节点。
每次迭代到 cur,都将 cur 的 next 指向 pre,然后 pre 和 cur 前进一位。
都迭代完了(cur 变成 null 了),pre 就是最后一个节点了。

2.递归方法

理解递归法的关键就是要理解栈是怎样野蛮生长的,函数调用,函数返回在栈里是怎样进行的

public ListNode reverseList1(ListNode head) {
    if(head==null||head.next==null) {
        return head;
    }
    ListNode cur=reverseList1(head.next);
    head.next.next=head;
    head.next=null;
    return cur;
}

思路简述

关键几点,当一个被调用函数a5遇到retrun head,要销毁栈帧的时候,最后会执行pop eip操作,也就是将代码段的eip指针指向调用a5函数的b4函数的下一条指令。
LIstNode cur=reverseList(head.next)其实是两条指令,第一条是调用函数reverseList,第二条是将reverseList返回值赋值给cur。
也就是说,当a5被调用完毕时,下一步操作就是对cur进行赋值。然后依次执行b4里ListNode cur=reverseList1(head.next);的下面几条指令,⚠️,此时b4里的head是4!直到遇到return cur,此时,b4为被调用函数,c3为调用函数,此时c3里的head是3。
重复上面的操作,简称套娃。
可以看出,cur始终保持不变,指向最后一个节点。

函数调用主要步骤

在函数a调用一个函数b的时候,重要的几个步骤:
一、开始时
1.函数b参数从左至右入栈
2.push eip (将下一条指令入栈保存起来,同时esp指针下移
3.push ebp (将函数a的基指针入栈保存)
4.mov ebp esp (将esp的值存入ebp,也就是将ebp指向esp,同时下移esp指针)
5.push ebx 、push esi 、push edi;然后进行中间的
二、返回时
1.pop edi、 pop esi、pop ebx;
2.mov esp ebp; (将ebp的值给esp,也就是将esp指向ebp,销毁b函数的函数栈帧
3.pop ebp;
4.ret (这一条指令相当于pop eip ;也就是说eip将指向原来保存的下一条指令
5.add esp 8;(此时如果传入b函数的参数已经不需要了,那么此时将esp指针上移,抬升栈帧,保持堆栈平衡。)

21.合并两个链表

public ListNode mergetwoLists(ListNode l1,ListNode l2) {
    if(l1==null) {
        return l2;
    }
    else if(l2==null) {
        return l1;
    }
    else if(l1.val<l2.val) {
        l1.next=mergetwoLists(l1.next,l2);
        return l1;
    }
    else  {
        l2.next=mergetwoLists(l2.next,l1);
        return l2;
    }    
}

思路简述

终止条件:当两个链表都为空时,表示我们对链表已合并完成。
如何递归:我们判断 l1 和 l2 头结点哪个更小,然后较小结点的 next 指针指向其余结点的合并结果。(调用递归)


leetcode      链表 递归

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!