1、链表介绍:
2、单链表:
我们以梁山英雄排行榜举例说明:
代码演示:
package com.linkedlist; public class LinkedListDemo { public static void main(String[] args) { HeroNode node1 = new HeroNode(1,"宋江","及时雨"); HeroNode node3 = new HeroNode(3,"卢俊义","玉麒麟"); HeroNode node5 = new HeroNode(5,"林冲","豹子头"); HeroNode node4 = new HeroNode(4,"吴用","智多星"); HeroNode node2 = new HeroNode(2,"晁盖","天王"); LinkedList linkedList = new LinkedList(); linkedList.addByOrder(node1); linkedList.addByOrder(node3); linkedList.addByOrder(node5); linkedList.addByOrder(node4); linkedList.addByOrder(node2); linkedList.showLinkedList(); System.out.printf("节点个数为%d个",linkedList.getLength()); System.out.println(); System.out.println("删除编号为3的卢俊义后:"); linkedList.deleteByNo(3); linkedList.showLinkedList(); System.out.println(); System.out.println("修改编号为5林冲后:"); HeroNode node6 = new HeroNode(5,"林冲的仇人高俅","靠足球上位的高太尉"); linkedList.update(node6); linkedList.showLinkedList(); } } //定义HeroNode类,表示每一个节点 class HeroNode { public int no; public String name; public String nickName; public HeroNode next; public HeroNode(int no, String name, String nickName) { this.no = no; this.name = name; this.nickName = nickName; } @Override public String toString() { return "HeroNode{" + "no=" + no + ", name='" + name + '\'' + ", nickName='" + nickName + '\'' + '}'; } } //定义LinkedList类,表示链表,管理HereNode类 class LinkedList { //定义一个空的头节点,不存放数据 private HeroNode head = new HeroNode(0, "", ""); //获取该单链表的节点个数 public int getLength(){ if(head.next == null){ return 0; } int length = 0; HeroNode temp = head.next; while(true){ if(temp == null){ break; } length ++; temp = temp.next; } return length; } //添加节点到链表,不考虑顺序,直接加到当前链表的最后 public void add(HeroNode node) { if (node == null) { return; } //定义一个辅助节点temp,帮助找到链表的最后 HeroNode temp = head; while (true) { //找到链表的最后了 if (temp.next == null) { break; } //没有找到,后移temp temp = temp.next; } temp.next = node; } //添加节点到链表,按照编号no插入 public void addByOrder(HeroNode node) { if (node == null) { return; } //定义一个辅助节点temp,帮助找到链表的最后 HeroNode temp = head; boolean flag = false; while (true) { if (temp.next == null) { break; } if (temp.next.no > node.no) {//从小到大的顺序插入 break;//找到位置了,结束循环 } else if (temp.next.no == node.no) { flag = true;//已经存在有这个编号的heroNode了 break; } temp = temp.next; } if (flag == true) { System.out.printf("已经存在编号为%d的了,不能插入", node.no); } else { node.next = temp.next;//将插入的节点与后一个节点连接 temp.next = node;//将插入的节点与前一个节点连接 } } //根据HeroNode的no来修改 节点信息 public void update(HeroNode node) { if (node == null) { return; } //定义一个辅助节点temp,帮助找到链表的最后 HeroNode temp = head.next; boolean flag = false; if (temp == null) { System.out.println("链表为空"); return; } while (true) { if (temp == null) { break; } if (temp.no == node.no) {//找到要修改的节点 flag = true; break; } temp = temp.next; } if (flag == true) { temp.name = node.name; temp.nickName = node.nickName; } else { System.out.printf("没有编号为%d的节点,不能修改", node.no); } } //根据编号no删除节点 public void deleteByNo(int no) { //定义一个辅助节点temp,帮助找到链表的最后 HeroNode temp = head; boolean flag = false; if (temp.next == null) { System.out.println("链表为空"); return; } while (true) { if (temp.next == null) { break; } if (temp.next.no == no) {//找到要删除的节点 flag = true; break; } temp = temp.next; } if (flag == true) { temp.next = temp.next.next;//把要删除的节点的后一个节点指向被删除的节点的前一个节点,没有了指针指向,相当于删了 } else { System.out.printf("没有编号为%d的节点,不能删除", no); } } //遍历链表 public void showLinkedList() { HeroNode temp = head.next; if (head.next == null) { System.out.println("链表为空"); return; } while (true) { if (temp == null) { break; } System.out.println(temp); temp = temp.next; } } } 结果输出: HeroNode{no=1, name='宋江', nickName='及时雨'} HeroNode{no=2, name='晁盖', nickName='天王'} HeroNode{no=3, name='卢俊义', nickName='玉麒麟'} HeroNode{no=4, name='吴用', nickName='智多星'} HeroNode{no=5, name='林冲', nickName='豹子头'} 节点个数为5个 删除编号为3的卢俊义后: HeroNode{no=1, name='宋江', nickName='及时雨'} HeroNode{no=2, name='晁盖', nickName='天王'} HeroNode{no=4, name='吴用', nickName='智多星'} HeroNode{no=5, name='林冲', nickName='豹子头'} 修改编号为5林冲后: HeroNode{no=1, name='宋江', nickName='及时雨'} HeroNode{no=2, name='晁盖', nickName='天王'} HeroNode{no=4, name='吴用', nickName='智多星'} HeroNode{no=5, name='林冲的仇人高俅', nickName='靠足球上位的高太尉'}
关于辅助指针的问题:
A、如果是增加,删除操作,牵涉到指针next的改变的,初始temp = head,使得操作的是temp的下一个节点
B、如果是遍历,修改操作,不涉及到指针next的改变的,初始temp = head.next,直接把辅助指针定位到要操作的节点上
3、单链表相关的面试题
3.1查找单链表中倒数第k个节点
class LinkedList { //定义一个空的头节点,不存放数据 private HeroNode head = new HeroNode(0, "", ""); //查找单链表的倒数第k个节点 public HeroNode findNode(int k){ int length = getLength();//总的节点个数 int index = length-k;//要找的第几个节点数 HeroNode temp = head.next; for(int i=0;i<index;i++){ temp = temp.next; } return temp; } }
3.2单链表的反转
//单链表反转 public void reverseList(){ if(head.next == null && head.next.next == null){ return; } HeroNode temp = head.next;//辅助指针,帮助遍历原来的链表 HeroNode next = null;//指向当前节点的下一个节点 HeroNode reverseHead = new HeroNode(0,"",""); while(temp != null){ next = temp.next; temp.next = reverseHead.next; reverseHead.next = temp; temp = next; } head.next = reverseHead.next; }
3.3单链表的逆序打印
//单链表的逆序打印,根据栈的特点,使用栈 public void reversePrint(){ if(head.next == null ){ return; } Stack<HeroNode> stack = new Stack<>(); HeroNode temp = head.next;//辅助指针,遍历使用 while (temp!= null){ stack.push(temp); temp = temp.next; } while(stack.size()>0){ System.out.println(stack.pop().toString()); } }