单链表的反转、环校验、删除倒数第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 }
结果

码无止境

浙公网安备 33010602011771号