单链表
简单介绍:
- 链表是以节点的方式链式存储的
- 每个节点包含data域、next域:指向下一个节点
- 链表的各个节点不一定是连续存储的
- 链表分为带头节点的链表和没有头节点的链表,根据实际需求来确定
实例分析
将水浒传中的英雄作为节点,关于单链表的增删查操作
public class SingleLinkedListDemo { public static void main(String[] args) { //进行测试 HeroNode hero1 = new HeroNode(1, "宋江", "及时雨"); HeroNode hero2 = new HeroNode(2, "卢俊义", "玉麒麟"); HeroNode hero3 = new HeroNode(3, "吴用", "智多星"); HeroNode hero4 = new HeroNode(4, "林冲", "豹子头"); SingleLinkedList singleLinkedList = new SingleLinkedList(); singleLinkedList.addByOrder(hero4); singleLinkedList.addByOrder(hero2); singleLinkedList.addByOrder(hero1); singleLinkedList.addByOrder(hero3); singleLinkedList.list(); System.out.println("删除一个"); singleLinkedList.delete(1); singleLinkedList.list(); } } //定义一个HeroNode,每个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 + '\'' + '}'; } } //定义一个SingleLinkedList 管理我们的英雄 class SingleLinkedList { //先初始化一个头节点,不存放任何数据 private HeroNode head = new HeroNode(0, "", ""); /*添加方法(不考虑编号的顺序) *思路: * 1、找到当前链表的最后节点 * 2、将最后这个节点的next 指向 新的节点 */ public void add(HeroNode heroNode) { //定义一个辅助节点 HeroNode temp = head; //遍历链表 while (true) { //找到了最后一个节点 if (temp.next == null) { break; } temp = temp.next; } temp.next = heroNode; } /** * 添加方法(考虑编号的顺序) * 1、首先找到新节点添加的位置 * 2、新的节点的next等于temp.next * 3、将temp.next等于新的节点 */ public void addByOrder(HeroNode heroNode) { HeroNode temp = head; //标识新添加的编号是否存在 boolean flag = false; while (true) { if (temp.next == null) { //temp已经到链表的最后 break; } if (temp.next.no > heroNode.no) { break; } else if (temp.next.no == heroNode.no) { //说明标号已经存在 flag = true; break; } temp = temp.next; } if (flag) { throw new RuntimeException(heroNode.no + " 编号已经存在!"); } else { heroNode.next = temp.next; temp.next = heroNode; } } /*删除 * 1、找到需要删除的这个节点的前一个节点 * 2、temp.next = temp.next.next; */ public void delete(int no) { HeroNode temp = head; boolean flag = false;//是否找到待删除节点 while (true) { if (temp.next == null) { break; } if (temp.next.no == no) { flag = true; break; } temp = temp.next; } if (flag) { temp.next = temp.next.next; } else { throw new RuntimeException("需要删除的节点不存在"); } } /** * 遍历显示链表 */ public void list() { if (head.next == null) { throw new RuntimeException("链表为空!"); } HeroNode temp = head.next; while (true) { if (temp == null) { break; } System.out.println(temp); temp = temp.next; } } /** * * @param head 链表的头节点 * @return 返回的就是有效节点的个数 */ public static int getLength(HeroNode head){ if (head.next == null){ return 0; } int length = 0; //定义一个辅助的变量 HeroNode cur = head.next; while(cur!=null){ length++; cur = cur.next; } return length; } }
面试题
1、查找单链表中的倒数第k个节点
/** * 查找单链表中的倒数第k个节点 * 思路: * 1、编写一个方法,接收head节点,同时接收一个index * 2、index 表示是倒数第index个节点 * 3、先把链表从头到尾遍历,得到链表的总的长度 * 4、从链表的第一个开始遍历(size-index)个 * 5、如果找到了,则返回该节点,否则返回null */ public static HeroNode findLastIndexNode(HeroNode head,int index){ if (head.next == null){ return null; } int size = getLength(head); if (index<=0||index>size){ throw new RuntimeException("传入参数范围误!"); } HeroNode temp = head.next; for (int i = 0; i < size-index; i++) { temp = temp.next; } return temp; }
2、单链表的反转
/** * 单链表的反转 * 思路: * 1、先定义一个新的节点reverseHead * 2、从头到尾遍历原来的链表,每遍历一个节点,就将其取出来,并放在reverseHead的后面 * 3、然后原来链表的head.next = reverseHead.next; */ public static void reverseList(HeroNode head){ if (head.next == null || head.next.next == null){ return ; } HeroNode cur = head.next; HeroNode next = null;//指向当前节点的下一个节点 HeroNode reverseHead = new HeroNode(0,"",""); //遍历原来的链表 while (cur!=null){ next = cur.next; cur.next = reverseHead.next;//将cur的下一个节点指向新的链表的最前端 reverseHead.next = cur; cur = next; } head.next = reverseHead.next; }
3、逆序打印单链表
/** * 逆序打印单链表 * 思路:使用栈的性质 */ public static void reversePrint(HeroNode head){ if (head.next == null){ return; } HeroNode cur = head.next; Stack<HeroNode> stack = new Stack<HeroNode>(); while (cur!=null){ stack.push(cur); cur = cur.next; } while (stack.size()>0){ System.out.println(stack.pop()); } }