链表反转之头插法
花了半天才终于搞懂这个头插法的原理,最后还是在Visio下面画图弄明白的。。。直接上代码
1 //单链表反转 2 public static void reverseNode(PersonNode head){ 3 //若链表为空,则直接返回 4 if (head.next == null || head.next.next == null) { 5 return; 6 } 7 //定义一个辅助的指针,辅助遍历原链表 8 PersonNode temp = head.next; 9 PersonNode next = null; //指向当前节点(temp)的下一个节点 10 PersonNode reverseHead = new PersonNode(0, "", ""); 11 //遍历原来的链表,每遍历一个节点,就将其取出,并放在新的链表reverseHead的最前端 12 while (temp != null) { 13 next = temp.next; //保存当前节点的下一个节点 14 temp.next = reverseHead.next; //将temp的下一个节点指向新的链表的最前端 15 reverseHead.next = temp; //将temp连接到新的链表上 16 temp = next; //让temp后移 17 } 18 //将head.next指向reverseHead.next,实现单链表的反转 19 head.next = reverseHead.next; 20 }
先说明头插法需要两个头节点,在这里定义为初始链表的头节点head和一个空节点reverseHead,reverseHead的下一个位置为null,记住这一点。
这里需要说明两个指针,一个是temp指针,它用于原始链表的遍历,初始位置就是在head.next上,可以直接从这个位置进行操作;第二个指针是next,它的位置在temp指针之后的节点,可能会有疑问是为什么不直接用temp.next来表示,其实原因在于头插法在每一次的循环中都需要将temp.next指向reverseHead链表里上一次循环的头部节点处,即temp.next,每一次循环都会使temp不在与原始的head链表相连,所以就需要额外定义一个next指针来记录之前未到达的节点位置。
下图是初始状态
当执行 temp.next = reverseHead.next;时,Node1与Node2之间的连接断开,Node1.next指向Reverse链中的NULL
执行reverseHead.next = temp; 时,Reverse.next指向Node1, 同时Head与Node1之间的连接也断开;
执行temp = next; 并且进入第二次循环,temp与next都向后移一个单位
重复上面的步骤,将之前已经舍弃的连接线省略
可以看到,链表正在按照从后往前的顺序依次连接。