Java实现单链表翻转

单链表翻转指将一个单链表从中间翻转过来,如 1 2 3 4 5反转后就是 5 4 3 2 1;1 2 3 4 反转后就是 4 3 2 1。

分析:听起来好像有点麻烦,实际上只需要把 1->2->3->4->5改成 5->4->3->2->1 即  1<-2<-3<-4<-5即把头节点的next指向空,从第二个节点开始后一个节点的next指向前一个节点(就是把箭头反过来),这样头节点就变成了尾节点,尾节点就变成了头节点。

需要注意的是:不能简单地将头节点置空,然后将后面的都指向前一个节点,否则,修改了当前节点的next后就找不到下一个节点了。比如:翻转 1->2->3,首先先将头节点的next置空,就变成了 1  2->3,这样2 和3 怎么找到呢。

可以使用递归来实现:在修改当前指针时,先把后续节点的指针给翻转了,层层递进到最后2个节点。

过程如下:

1->2->3->4 这个链表翻转

 先反转其从第二个节点开始的子链表  则为翻转   2->3->4

再翻转子链表的子链表 3->4

此时可以直接翻转了,将头节点(3)的next节点(4)的next指向头(3),就变成了  3->4->3 (这里应该是一个环,3指向4,4指向3,需要画图才能画出来)再将头节点(3)的next置空,此时头节点(3)就变成了尾节点: 4->3->null。

但此时原来的头节点(3)的next置空了!需要把原来的尾节点(4)变成头节点,但是原来的尾节点(4)是找不出来的(单项链表找上一个节点是从头节点开始找的,此时没有头节点了),所以需要一开始这个最后要变成头节点的节点找出来,作为参数传进递归方法,在每一层递归里都手动的将这个节点变成头节点。

单链表的实现见前文。 Java实现单链表

具体代码如下:

 public Node getTail(){
        if(0 == this.getLength()){
            return null;
        }
        Node tail;
        for(tail=this.head;tail.getNext()!=null;tail=tail.getNext()){}
        return tail;
    }

    /**
     * 单链表翻转算法,head参数是最后会变成头节点的
     * @param head
     * @return
     */
    public boolean overturn(Node head){
        if(0 == this.getLength()){
            return false;
        }
        // 开始单链表翻转递归
        // 当前长度大于2时,翻转当前链表从第二个节点开始的子链表
        while (2<this.getLength()){
            // 获取子链表
            MyLinkedList curList = new MyLinkedList(this.findNodeByIndex(1));
            // 子链表翻转,并将最后应该成为头节点的head传进去
            curList.overturn(head);
        }
        // 当前长度已经为2了 是最后2个节点
        // 找出后一个节点,将其next指向前一个节点
        Node tail = this.head.getNext();
        tail.setNext(this.head);
        // 把之前的头,next置空
        this.head.setNext(null);
        // 最后 将头节点变成一开始就决定好的head参数
        this.head = head;
        return true;
    }
public class TestMain {
    public static void main(String[] args) {
        MyLinkedList myLinkedList = new MyLinkedList();
        Node head = new Node(1);
        myLinkedList.addNodeTail(head);
        myLinkedList.addNodeTail(new Node(2));
        myLinkedList.addNodeTail(new Node(3));
        myLinkedList.addNodeTail(new Node(4));
        myLinkedList.addNodeTail(new Node(5)); // 向链表里往尾部插入5个节点 现在链表长度为5
        myLinkedList.printList();
       /* myLinkedList.delNodeTail(); // 删除尾部的一个节点,现在长度为4
        myLinkedList.printList();
        Node curNode = myLinkedList.findNodeByIndex(2);
        Node node999 = new Node(999);
        myLinkedList.addNode(curNode,node999); // 往第二个节点的后面插入一个新节点
        System.out.println(myLinkedList.findLast(node999).getData());
        myLinkedList.printList();
        myLinkedList.delNode(node999); // 删除这个新节点
        myLinkedList.printList();*/
      //  Node aNode = myLinkedList.findNodeByIndex(4);
        // 找出最后一个节点,作为参数传进递归方法,这个节点会变成反转后的头节点
        myLinkedList.overturn(myLinkedList.getTail());
        myLinkedList.printList();
    }

结果:

上面是自己想的,比较麻烦。也有不需要递归,只需要3个临时指针(pre/cur/next)即可实现翻转,代码更简洁。

原理(偷来的图):

图解已在如下代码中增加注释:

/**
     * 借助3个指针实现链表翻转
     * @return
     */
    public boolean overturnBy3Point(){
        if(0 == this.getLength()){
            return false;
        }
        // 定义3个指针
        Node pre = null;
        Node cur = this.head;
        Node next;
        int length = this.getLength();
        // 循环n次,前n个节点翻转
        for(int i=0;i<length;i++){
            // 先将cur的next保存起来
            next = cur.getNext();
            // 将cur的next指向前一个节点,实际上这里就是翻转了
            cur.setNext(pre);
            // 将cur和pre一起后移一位,每循环一次,翻转的链表长度就往后推一位
            pre = cur;
            cur = next;
        }
        // 最后的pre指针就是头节点
        this.head = pre;
        return true;
    }

测试:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java 单链表翻转可以采用以下四种方法: 1. 迭代法: 迭代法是通过遍历链表,将每个节点的指针指向前一个节点来实现翻转。需要用到三个指针,分别是当前节点、当前节点的前一个节点和当前节点的后一个节点。具体步骤如下: - 初始化当前节点为头节点,前一个节点和后一个节点都为 null。 - 进入循环,循环条件是当前节点不为 null。 - 在循环内部,先用一个临时变量保存当前节点的后一个节点。 - 将当前节点的指针指向前一个节点。 - 更新前一个节点为当前节点,当前节点为临时变量保存的后一个节点。 - 重复上述步骤直到当前节点为 null。 - 最后将头节点指向反转后的链表的头节点,并返回头节点。 2. 递归法: 递归法是利用递归的思想实现链表翻转。 - 首先判断链表是否为空或者只有一个节点,如果是,则直接返回该链表。 - 否则,递归调用翻转链表函数,将头节点的下一个节点作为参数传入。 - 在翻转函数内部,先递归翻转后面的链表。 - 接着将头节点的下一个节点的下一个节点指向头节点,同时将头节点的下一个节点指向 null。 - 最后返回翻转后的链表的头节点。 3. 栈法: 栈法是利用栈的先进后出特性实现链表翻转。 - 先将链表的所有节点依次入栈。 - 然后从栈中依次弹出节点,每次弹出的节点都是从末尾开始的,依次指向前一个弹出的节点。 - 最后返回栈顶节点作为新的链表的头节点。 4. 头插法: 头插法是依次将链表的节点插入到一个新的链表中,并将新的链表的头节点指向原链表的尾节点。 - 首先创建一个新的空链表和一个指向原链表的头节点的指针。 - 进入循环,循环条件是原链表的指针不为 null。 - 在循环内部,先保存原链表指针的下一个节点,然后将原链表指针当前指向的节点插入到新链表的头部。 - 更新原链表指针为保存的下一个节点。 - 重复上述步骤直到原链表指针为 null。 - 最后返回新链表的头节点。 以上四种方法都可以实现单链表翻转,具体选择哪种方法取决于个人偏好和场景需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值