链表的翻转

来源:互联网 发布:anaconda for mac 编辑:程序博客网 时间:2024/06/01 08:12

链表的翻转

链表的翻转分为部分翻转和全部翻转。本文,实现了一种通用的链表翻转程序,其时间复杂度为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中的元素(包含边界节点),那么输出应该是:

0 4 3 2 1 5 6 7

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

7 6 5 4 3 2 1 0

采用头插法,定义三个指针(这里只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;    }
0 0
原创粉丝点击