单链表
单链表介绍
- 链表是以节点的方式存储的。
- 每个节点包含data域和next域
- 链表的各个节点之间并不是连续的
- 链表分为带头节点的链表和不带头节点的链表
单链表的基本操作
- 链表节点的数据结构
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; this.next = null; } @Override public String toString() { return "HeroNode {" + "no=" + no + ", name='" + name + '\'' + ", nickname='" + nickname + '\'' + '}'; } }
- 带头节点的链表的初始化
class SingleLinkedList { private HeroNode head; public SingleLinkedList() { head = new HeroNode(0, "", ""); } }
- 向链表的尾部添加元素
public void addNode(HeroNode heroNode) { HeroNode temp = head; // 循环找到最后一个节点 while (temp.next != null) { temp = temp.next; } temp.next = heroNode; }
- 按照编号的顺序,将元素加入链表
// 添加英雄时,按照编号顺序 public void addNodeByNoOrder(HeroNode heroNode) { HeroNode temp = head; boolean find = false; while (temp.next != null) { if (temp.next.no > heroNode.no) { break; } else if (temp.next.no == heroNode.no) { find = true; break; } temp = temp.next; } if (find) { System.out.printf("准备插入的英雄编号%d已经存在,不能加入\n", heroNode.no); } else if (temp.next == null) { temp.next = heroNode; } else { heroNode.next = temp.next; temp.next = heroNode; } }
- 根据编号删除链表中指定的节点
// 删除指定的节点 public void deleteHeroNode(int no) { HeroNode temp = head; boolean find = false; while (temp.next != null) { if (temp.next.no == no) { find = true; break; } temp = temp.next; } if (find) { temp.next = temp.next.next; } else { System.out.printf("要删除的节点%d不存在", no); } }
- 根据标号修改链表元素
// 修改链表 public void updateHero(HeroNode newHero) { HeroNode temp = head.next; if (temp == null) { System.out.println("链表为空,没有要修改的元素"); return ; } boolean find = false; while (temp != null) { if (temp.no == newHero.no) { find = true; break; } temp = temp.next; } if (find) { temp.name = newHero.name; temp.nickname = newHero.nickname; } else { System.out.printf("没有找到编号为%d的英雄\n", newHero.no); } }
- 遍历链表
public void showList() { HeroNode temp = head.next; while (temp != null) { System.out.println(temp); temp = temp.next; } }
- 测试表的增删改查
public class SingleLinkedListDemo { public static void main(String[] args) { SingleLinkedList singleLinkedList = new SingleLinkedList(); HeroNode heroNode1 = new HeroNode(1, "宋江", "呼保义"); HeroNode heroNode2 = new HeroNode(2, "卢俊义", "玉麒麟"); HeroNode heroNode3 = new HeroNode(3, "吴用", "智多星"); HeroNode heroNode4 = new HeroNode(4, "公孙胜", "入云龙"); HeroNode heroNode5 = new HeroNode(5, "大刀", "关胜"); HeroNode heroNode6 = new HeroNode(6, "林冲", "豹子头"); // singleLinkedList.addNode(heroNode4); // singleLinkedList.addNode(heroNode1); // singleLinkedList.addNode(heroNode6); // singleLinkedList.addNode(heroNode5); // singleLinkedList.addNode(heroNode3); // singleLinkedList.addNode(heroNode2); singleLinkedList.addNodeByNoOrder(heroNode4); singleLinkedList.addNodeByNoOrder(heroNode1); singleLinkedList.addNodeByNoOrder(heroNode6); singleLinkedList.addNodeByNoOrder(heroNode5); singleLinkedList.addNodeByNoOrder(heroNode3); singleLinkedList.addNodeByNoOrder(heroNode2); singleLinkedList.showList(); HeroNode newHeroNode = new HeroNode(8, "小卢", "玉麒麟~~~"); singleLinkedList.updateHero(newHeroNode); System.out.println("修改后的链表情况~~~~~~~~"); singleLinkedList.showList(); singleLinkedList.deleteHeroNode(1); singleLinkedList.deleteHeroNode(6); System.out.println("删除后的链表情况~~~~~~~~"); singleLinkedList.showList(); } }
单链表面试题
-
求单链表中有效节点的个数。
// 获取链表的长度 public int getLength() { if (head.next == null) { return 0; } int length = 0; HeroNode currNode = head.next; while (currNode != null) { length ++; currNode = currNode.next; } return length; }
-
查找单链表中的倒数第k个节点。
// 获取链表找那个的倒数第k个元素 public HeroNode getReverseKElement(SingleLinkedList singleLinkedList, int k) { // 获取链表的长度 int length = singleLinkedList.getLength(); if (length < k || k < 0) { System.out.println("要获取的第k个元素不存在"); return null; } // 要获取逆序第k个相当有获取正序列的第length - k + 1个元素。 // 如有10 个元素,获取逆序的第5个相当有获取正序的第6个元素 int m = length - k + 1; int cn = 0; HeroNode heroNode = singleLinkedList.getHead(); while (heroNode.next != null) { cn ++; if (cn == m) { return heroNode.next; } heroNode = heroNode.next; } return null; }
-
单链表的反转
// 方法1,定义一个空的链表,遍历原来的链表 public SingleLinkedList getReverseList(SingleLinkedList singleLinkedList) { // 获取老链表的头节点 HeroNode headOld = singleLinkedList.getHead(); // 获取到一个新的空链表 SingleLinkedList newSingleList = new SingleLinkedList(); // 遍历老链表 while (headOld.next != null) { HeroNode heroNode = headOld.next; headOld.next = heroNode.next; heroNode.next = null; HeroNode newListHead = newSingleList.getHead(); // 新链表的头节点 HeroNode temp = newListHead.next; newListHead.next = heroNode; heroNode.next = temp; } return newSingleList; } // 方法2,定义新的头节点 public void getReverseList2(SingleLinkedList singleLinkedList) { // 定义一个新的头节点 HeroNode newHead = new HeroNode(0, "", ""); // 获取老链表的头节点 HeroNode headOld = singleLinkedList.getHead(); // 遍历老链表 while (headOld.next != null) { HeroNode heroNode = headOld.next; headOld.next = heroNode.next; HeroNode temp = newHead.next; newHead.next = heroNode; heroNode.next = temp; } singleLinkedList.setHead(newHead); }
-
从尾到头打印单链表【方式1,反向遍历;方式2,Stack栈】
/** * 借助 stack,逆序打印单链表 * 1. 首先遍历链表,将每个元素入栈 * 2. 遍历栈,打印每一个元素 */ public void printReverseLinkedList(SingleLinkedList singleLinkedList) { HeroNode head = singleLinkedList.getHead(); Stack<HeroNode> stack = new Stack<>(); HeroNode temp = head.next; while (temp != null) { stack.push(temp); temp = temp.next; } while (!stack.isEmpty()) { HeroNode pop = stack.pop(); System.out.println(pop); } }
-
合并两个有序的单链表,合并之后的链表依然有序。
/** * 合并两个链表,将两个有序链表,合并到第三个链表中。而保持合并后的链表依然有序。 */ public SingleLinkedList mergeTwoList(SingleLinkedList singleLinkedList1, SingleLinkedList singleLinkedList2) { HeroNode head1 = singleLinkedList1.getHead(); HeroNode head2 = singleLinkedList2.getHead(); SingleLinkedList singleLinkedList = new SingleLinkedList(); HeroNode head = singleLinkedList.getHead(); HeroNode temp = head; HeroNode temp1 = head1.next; HeroNode temp2 = head2.next; while (temp1 != null && temp2 != null) { if (temp1.no > temp2.no) { temp.next = temp2; temp2 = temp2.next; } else { temp.next = temp1; temp1 = temp1.next; } temp = temp.next; } if (temp1 == null) { temp.next = temp2; } if (temp2 == null) { temp.next = temp1; } return singleLinkedList; }