链表的翻转

本文介绍了如何实现链表的翻转,包括部分翻转和全部翻转,提供了一种通用的时间复杂度为n的链表翻转程序。通过定义预前节点pre、当前节点current和下一个节点next,详细阐述了翻转过程,并给出了相应的操作步骤和代码实现。

链表的翻转

链表的翻转分为部分翻转和全部翻转。本文,实现了一种通用的链表翻转程序,其时间复杂度为n。

链表如下:
这里写图片描述
程序中包含如下类:
1、Node类,即链表的节点,节点中只有一个属性iData

class Node {
    public int iData;
    Node nextNode = null;

    public Node(int iData) {
        this.iData = iData;
    }
}

2、链表类,链表类中仅实现了插入和打印链表的方法,并且链表具有表头节点root具体如下:

class Link {
    public Node root = null;

    public void insert(int iData) {
        Node newNode = new Node(iData);
        if (root == null) {
            root = newNode;
        } else {
            Node current = root;
            Node pre = root;
            while (current != null) {
                pre = current;
                current = current.nextNode;
            }
            pre.nextNode = newNode;
        }
    }

    public void display() {
        Node current = root;
        while (current != null) {
            System.out.print(current.iData + " ");
            current = current.nextNode;
        }
        System.out.println();
    }
}

3、翻转链表的实现
链表从0开始计数,例如要翻转1到4中的元素(包含边界节点),那么输出应该是:

04321567

如果链表要翻转0到7的所有元素输出应该是

76543210

采用头插法,定义三个指针(这里只java的引用,因为类似c语言中的指针,因此这里借用指针之一概念,但是java里面是没有指针概念的),
pre:用来指向要翻转的节点的前一个节点,例如当要翻转1到4节点时,pre指向第0个节点
current:用来指向需要操作的节点
next:用来指向原链表中的下一个要操作的节点
tmp:指向第一个要操作的节点,当全部的节点翻转完后该节点需要链上剩余的节点(没有被要求翻转的节点),例如当要翻转1到4节点时tmp指向的是第一个节点。
翻转n到m节点,翻转的过程,以翻转1到4节点为例(n=1,m=4),
首先链表的pre空转0步(空转就是pre遍历沿着节点向下走,什么也不做,空转是为了将pre指向需要翻转的节点之前的节点这里时节点0)使pre指向0号节点,从该节点的下一个节点开始翻转;然后将current指向pre节点的下一个节点,接下来需要断开current在原链表中所指向的下一个节点,在断开之前需要将next节点指向current的下一个节点即current.nextNode节点,因此next指向current的下一个节点;然后将current节点的从原链表中断掉,使current的下一个节点(current.netNode)指向pre的下一个节点(pre.nextNode);断掉pre的下一个节点pre.nextNode的原指向,使pre.nextNode指向current节点,这样第一次翻转成功(注意当执行第一次翻转的时候会发现pre.nextNode和current是同一个节点,因此第一次会使current的下一个节点指向自身)。然后将current从新指向next节点。重复步骤直到翻转了n-m次;最后将剩下的不需要翻转的节点链上,当循环结束后next保存的就是剩下的第一个不需要翻转的节点,而如前所述tmp保存的是第一个被翻转的节点,因此将tmp.nextNode指向next节点。
如图:
这里写图片描述
将操作步骤罗列如下:
(1)、链表的pre空转0步使pre指向0号节点;
(2)、将current指向pre节点的下一个节点;
(3)、将next节点指向current的下一个节点 ;
(4)、断开current在原链表中所指向的下一个节点;
(5)、将current的下一个节点指向pre节点的下一个节点;
(6)、断掉pre的下一个节点pre.nextNode的原指向,使pre.nextNode指向current节点;
(7)、将current指向next指向的节点;
(8)、重复步骤3到7,指导翻转了n-m次;
(9)、将tmp.nextNode指向next节点。
注意:当从节点0开始翻转时,上面的步骤需要适当的修改,因为当需要从0号节点开始翻转时,pre是 无法指向0节点之前的节点的,因此如果需要从0 号开始翻转,可以在链表的头部加一个节点,然后在进行翻转,在翻转完成后将链表的root节点从新指向pre.nextNode即可。
翻转操作的代码:

public class LinkFlip {
    public static void main(String[] args) {
        Link myLink = new Link();
        myLink.insert(0);
        myLink.insert(1);
        myLink.insert(2);
        myLink.insert(3);
        myLink.insert(4);
        myLink.insert(5);
        myLink.insert(6);
        myLink.insert(7);
        flip(myLink, 0, 7);
        myLink.display();
    }

    public static void flip(Link mylink, int m, int n) {
        Node pre = mylink.root;
        Node current = mylink.root;
        Node next = mylink.root;
        Node tmp = null;
        if (m == 0) {
            pre = new Node(-1);
            pre.nextNode = mylink.root;
        } else {
            for (int i = 0; i < m - 1; i++) {
                pre = pre.nextNode;
            }
        }

        current = pre.nextNode;
        tmp = current;
        pre.nextNode = null;
        for (int i = 0; i <= (n - m); i++) {
            next = current.nextNode;
            current.nextNode = pre.nextNode;
            System.out.println(current.iData);
            pre.nextNode = current;
            current = next;
        }
        if (m == 0) {
            mylink.root = pre.nextNode;
        }
        tmp.nextNode = next;

    }
}

写了个更简单的

  public ListNode ReverseList(ListNode head) {
        ListNode pre = null;
        ListNode current = head;
        ListNode next = null;
        while(current!=null){
            next = current.next;
            current.next = pre;
            pre= current;
            current = next;
        }
        return pre;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值