单链表的反转、环校验、删除倒数第n位

一、链表

链表是一种线性数据结构,它不像数组,需要连续的内存空间,链表是由一个个节点组成,每个节点包含数据和指针(引用)两部分,单链表只有后置引用,双链表有前置和后置两个引用。

链表包含:单链表,双链表,循环链表

 

二、链表的几个常见的问题

单链表反转
链表中环的检测
删除链表倒数第 n 个结点
求链表的中间结点

 

1. 创建单链表的节点

单链表的节点是由数据和指针(引用)组成, 指针指向下一个节点

 1 package OOO1.linkedlist;
 2 
 3 public class Node {
 4     String data;
 5     Node next;
 6 
 7     public Node() {
 8     }
 9 
10     public Node(String data) {
11         this.data = data;
12     }
13 
14     public Node(String data, Node next) {
15         this.data = data;
16         this.next = next;
17     }
18 
19     @Override
20     public String toString() {
21         return "Node{" +
22                 "data='" + data + '\'' +
23                 '}';
24     }
25 }

 

2. 链表,加一个哨兵节点,头节点head,和一个记录链表长度的size

public class MySingleLinkedList {
    public Node header;
    public long size;

    public MySingleLinkedList() {
        this.header = null;
        this.size = 0;

    }


 /**
     * to String 方法
     *
     * @return
     */
    public String toString() {
        StringBuffer sb = new StringBuffer();
        Node tmp = header;
        while (tmp != null) {
            sb.append(tmp.data).append(",");
            tmp = tmp.next;
        }
        return sb.toString();
    }

/**
     * 在链表的末尾添加数据
     *
     * @param item
     */
    public void add(String item) {
        Node tmp = header;
        if (tmp == null) {
            header = new Node(item, null);
            size++;
        } else {
            while (tmp.next != null) {
                tmp = tmp.next;
            }
            tmp.next = new Node(item, null);
            size++;
        }
    }
}

 

当然,针对size自己也可实现一个方法

 1 /**
 2      * 链表的长度
 3      * @return
 4      */
 5     public long length(){
 6         long len = 0;
 7         Node tmp = header;
 8         while (tmp!=null){
 9             len++;
10             tmp = tmp.next;
11         }
12         return len;
13     }

 

链表插入数据

 1 /**
 2      * 插入数据
 3      *
 4      * @param index
 5      * @param item
 6      * @throws Exception
 7      */
 8     public void insert(long index, String item) throws Exception {
 9         if (index > size || index < 0) {
10             throw new IllegalArgumentException();
11         }
12 
13         if (index == 0) {
14             header = new Node(item, header);
15             size++;
16         } else {
17             Node tmp = header;
18             long i = 0;
19             while (tmp != null) {
20                 if (i == index) {
21                     break;
22                 }
23                 i++;
24                 tmp = tmp.next;
25             }
26             Node node = new Node(item, tmp.next);
27             tmp.next = node;
28             size++;
29         }
30 
31 
32     }

 

问题1 : 单链表反转

 1 /**
 2      * 链表反转
 3      */
 4     public void reversal() {
 5         Node pre_node = null;
 6         Node curr_node = header;
 7 
 8         while (curr_node != null) {
 9             //用tmp记录,当前节点下一个节点,因为后面要给它进行重置
10             Node tmp = curr_node.next;
11 
12             curr_node.next = pre_node; //当前节点的指针指向前一个节点
13             pre_node = curr_node; //然后将当前节点的赋值给前节点
14             curr_node = tmp; // 当前节点往后移一位
15         }
16         header = pre_node;   //将前节点赋值给头节点
17     }

 

问题二 : 链表中环的检测

 1 /**
 2      * 链表加环
 3      */
 4     public void cycle() {
 5         Node tmp = header;
 6         while (tmp.next != null) {
 7             tmp = tmp.next;
 8         }
 9         tmp.next = header;
10     }
11 
12 
13  /**
14      * 环检测
15      * 快慢指针,慢每次前进1 ,快的每次前进2 ,如果有一个环必定会相遇
16      * 环可能不是完全的一个圆环,可能有尾巴 如 __O
17      *
18      * @return
19      */
20     public boolean cycleCheck() {
21 
22         if (header == null || header.next == null || header.next.next == null) {
23             return false;
24         }
25 
26         Node slow = header;
27         Node faster = header.next.next;
28 
29         while (faster != null && faster.next != null) { //faster.next不为空,因为如果为空,快指针的fater.next.next就变成null.next 这是错误的
30             if (slow == faster) {
31                 return true;
32             }
33             slow = slow.next;
34             faster = faster.next.next;
35         }
36         return false;
37     }

 

问题三 : 删除链表倒数第 n 个结点

 1  /**
 2      * 删除链比倒数第n个节点
 3      * 设置两个指针 一个每次前进1,另一个每次也前进1,但第一次在n的位置,
 4      * 当后一个节点到达终点是,前一个节点刚好是倒数第n的位置。
 5      * 另外,删除某个节点时,需要知道前置节点
 6      *
 7      * @param n
 8      */
 9     public void deleteLastIndex(long n) {
10         if (n < 0 || n > size) {
11             throw new IllegalArgumentException();
12         }
13 
14        if(n==size){ //删除头节点的情况
15            header = header.next;
16            size--;
17        }else {
18            Node pre_step = new Node();
19            pre_step.next = header;
20            Node nex_step = header;
21            for(long i =0;i<n;i++){ //设置nex_step的起始位置为n
22                nex_step = nex_step.next;
23            }
24 
25            while (nex_step!=null){ //当nex_step到终点时,pre_step刚好到倒数第n的位置
26                pre_step = pre_step.next;
27                nex_step = nex_step.next;
28            }
29            pre_step.next = pre_step.next.next;
30            size--;
31        }
32   }

 

问题四 : 求链表的中间结点

 1  /**
 2      * 链表的中间节点,不考虑环
 3      * 快慢指针,快的跑完了,慢的在中间
 4      *
 5      * @throws Exception
 6      */
 7 
 8     public Node middleNode() {
 9         if (header == null || header.next == null || header.next.next == null) {
10             return header;
11         }
12 
13         Node slow = header;
14         Node faster = header.next.next;
15         while (slow != null && faster != null) {
16             if (faster.next != null) {
17                 slow = slow.next;
18                 faster = faster.next.next;
19             } else {
20                 return slow.next;
21             }
22         }
23 
24         return slow;
25 
26     }

 

测试及结果

 1 public static void main(String[] args) throws Exception {
 2         MySingleLinkedList list = new MySingleLinkedList();
 3         list.add("a");
 4         System.out.println("inert : "+list.toString());
 5         list.add("b");
 6         System.out.println("insert : "+list.toString());
 7 
 8         list.insert(0L, "c");
 9         System.out.println("insert index=0 \t"+list.toString());
10 
11         System.out.println("middle : "+list.middleNode().toString());
12 
13         System.out.println("legth : "+list.length());
14 
15         list.insert(2L, "d");
16         System.out.println("insert index=2 \t" +list.toString());
17 
18         System.out.println("middle : "+list.middleNode().toString());
19 
20 
21         list.reversal();
22         System.out.println("reversal : "+list.toString());
23         System.out.println("size : "+list.size);
24 
25         list.deleteLastIndex(4);
26         System.out.println("delete index =4 \t"+list.toString());
27 
28         list.deleteLastIndex(1);
29         System.out.println("delete index =1 \t"+list.toString());
30 
31         list.cycle();
32         //System.out.println(list.toString());
33         boolean b = list.cycleCheck();
34         System.out.println("cycle check : "+ b);
35     }

 

结果

 

posted @ 2021-07-26 15:16  Leoli20  阅读(93)  评论(0)    收藏  举报