链表的反转(java实现)

链表的反转(java实现)

本文参考博文: http://blog.csdn.net/feliciafay/article/details/6841115
本文参考博文:http://blog.csdn.net/ns_code/article/details/25737023
对于给定的链表,
 例如,输入: 1 -> 2 ->3 ->4 ->5
    输出: 5 -> 4 ->3 ->2 ->1

class ListNode {
    int val;
    ListNode next;
    ListNode(int x) {
        val = x;
    }
}

笔者在参考了其他博文后给出四种方式

  1. 利用数组完成反转
  2. 使用3指针进行迭代
  3. 从第2个节点到第N个节点,依次逐节点插入到第1个节点(head节点)之后,最后将第一个节点挪到新表的表尾。
  4. 递归

方式一

  形式简单,直接遍历链表,将每一个节点存储到数组中,然后再反向遍历数组构建出新链表,即完成链表的反转,但至少需要多开辟出等链表长度的数组,因此不划算

方式二

  对于 1 -> 2 -> 3 ->4 -> 5的链表,head为头节点
假使在遍历链表的过程中,有这样的情形
思路:在遍历的过程中,要完成反转,则期望第一趟遍历时,2 ->1, 第二趟遍历时 3 -> 2… 这样最后一个结点指向倒数第二个结点,此时,最后一个结点就成为了头结点
遍历前:q = head.next,
第一趟:将链表分为(1,2)(3,4,5),将2对应的结点的next域指向1对应的结点,那么问题来了,示例的链表中1对应的结点为head结点,可是反转后的链表,head.next必定为null,因此在循环前必须执行语句 head.next = null
第二趟:链表被分为(1,2,3)(4,5),其中 2 -> 1; 只需要在此时将3对应的结点指向2对应的结点
依次遍历…. 即完成所有结点的指向
备注:笔者说的链表拆分只是形式的认为,这样在长度为n的链表中,在进行第 j 趟排序时,只需要关注(1~ j+1)的数据位置即可

/**
     * 链表的反转(使用3个指针遍历单链表,逐个链接点进行反转)
     * @param head
     * @author Lancelot
     * @return
     */
    public static ListNode reverse(ListNode head){
        ListNode p = head;
        ListNode q = head.next;
        head.next = null;
        ListNode r;
        while(q != null){
            r = q;
            q = q.next;
            r.next = p;
            p = r;
        }
        return p;
    }
方法三

  从第2个节点到第N个节点,遍历过程中,都将当前结点插入到头结点后面,最后将头结点移到最后
未排序:1 -> 2 -> 3 ->4 -> 5
第一趟:1 -> 3 -> 2 ->4 -> 5
第二趟:1 -> 4 -> 3 ->2 -> 5
第三趟:1 -> 5 -> 4 ->3 -> 2
第四趟:5 -> 4 -> 3 ->2 -> 1

/**
     * 从第2个节点到第N个节点,依次逐节点插入到第1个节点(head节点)之后,最后将第一个节点挪到新表的表尾
     * @author Lancelot
     * @param head
     * @return
     */
    public static ListNode reverse2(ListNode head){
        if(head == null)
            return null;
        if(head.next == null)
            return head;
        ListNode p = null;
        ListNode q = head.next;
        while(q.next != null){
            p = q.next;
            q.next = p.next;
            p.next = head.next;
            head.next = p;
        }
        q.next = head;
        head = q.next.next;
        q.next.next = null;
        return head;
    }
方法四(递归)

  使用递归首要的任务就是构建相似性,对于1 -> 2 -> 3 ->4 -> 5这样的链表,如果把(2,3,4,5)看成整体,则只需要考虑(2,3,4,5)和 1 的指向问题,那么同理,对于(2,3,4,5),则只需要考虑 2 和(3,4,5)的指向问题。这样,相似性就被找到了,就可以很容易写出相应的代码(备注:*此处思路参考博文*)

    static ListNode reverse = null;  //新链表的头结点,即原链表的尾结点
    /**
     * 
     * @author Lancelot
     * @param head
     * @return
     */
    public static ListNode reverse3(ListNode head){
        if(head == null)
            return null;
        if(head.next == null){
            reverse = head;
            return head;
        }
        ListNode newTail = reverse3(head.next);
        newTail.next = head;
        head.next = null;
        return head;
    }
最后,附上三种思路的所有代码
/**
 * 反转链表
 * @author Lancelot
 *
 */
public class ReverseListNode {

    public static void main(String[] args) {
        ListNode head = new ListNode(1);
        ListNode node2 = new ListNode(2); head.next = node2;
        ListNode node3 = new ListNode(3); node2.next = node3;
        ListNode node4 = new ListNode(4); node3.next = node4;
        ListNode node5 = new ListNode(5); node4.next = node5;
        //方法二
//      ListNode reverse2 = reverse(head);
//      print(reverse2);
        //方法三
        ListNode reverse3 = reverse2(head);
        print(reverse3);
        //方法四
    //  reverse3(head);
    //  print(reverse);
    }

    static ListNode reverse = null;  //新链表的头结点,即原链表的尾结点
    /**
     * @author Lancelot
     * @param head
     * @return
     */
    public static ListNode reverse3(ListNode head){
        if(head == null)
            return null;
        if(head.next == null){
            reverse = head;
            return head;
        }
        ListNode newTail = reverse3(head.next);
        newTail.next = head;
        head.next = null;
        return head;
    }

    /**
     * 从第2个节点到第N个节点,依次逐节点插入到第1个节点(head节点)之后,最后将第一个节点挪到新表的表尾
     * @author Lancelot
     * @param head
     * @return
     */
    public static ListNode reverse2(ListNode head){
        if(head == null)
            return null;
        if(head.next == null)
            return head;
        ListNode p = null;
        ListNode q = head.next;
        while(q.next != null){
            p = q.next;
            q.next = p.next;
            p.next = head.next;
            head.next = p;
        }
        q.next = head;
        head = q.next.next;
        q.next.next = null;
        return head;
    }

    /**
     * 链表的反转(使用3个指针遍历单链表,逐个链接点进行反转)
     * @param head
     * @author Lancelot
     * @return
     */
    public static ListNode reverse(ListNode head){
        ListNode p = head;
        ListNode q = head.next;
        head.next = null;
        ListNode r;
        while(q != null){
            r = q;
            q = q.next;
            r.next = p;
            p = r;
        }
        return p;
    }

    /**
     * 计算链表的长度
     * @param li    1, 2, 3, 4, 5,
     * @return
     */
    public static int getLength(ListNode li){
        int x = 0;
        while(li != null){
            x ++;
            li = li.next;
        }
        return x;
    }
    /**
     * 打印链表
     * @param node
     */
    public static void print(ListNode node){
        while(node != null){
            System.out.print(node.val + " ");
            node = node.next;
        }
    }

}
class ListNode {
    int val;
    ListNode next;
    ListNode(int x) {
        val = x;
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值