手写单链表(用Java代码实现)

it2024-11-29  3

面试必备之手撸单链表

链表的基础知识

当我们开始学习Java或者C语音的时候我们刚开始学习的数据结构可能就是数组,队列和链表了,作为计算机科班出身的小编在此深感惭愧,在大学期间真的没有好好的学习链表,导致毕业后还依然懵懵懂懂的,不说了不说了,说多了都是泪,那么就只有在工作之余来进行相关的知识的储备的补习了,不多逼逼了,那么我们就开始进行相关的链表的知识的学习吧。 首先我们知道链表是一个有序的列表,但是在内存中并不是像数组一样连续的存储在内容中,下面我们来先看一下我们的链表在内存中的图。

结合我们的学习我们可以知道链表具有以下特点:

链表是以节点的方式来进行储存的,是典型的链式存储每个节点包含data域和next域,其中next域指向下一个节点对象正如我们所知道的那样,链表在内存上并不一定是连续存在的,只有一个指针对象指向下一个节点对象链表分为带头节点的链表和不带头节点的链表,此时我们要根据实际情况来进行分析

带头节点的逻辑结构的示意图如下所示

结合实例来分析单链表的应用

题目: 使用带head头的单向链表实现 –水浒英雄排行榜管理 完成对英雄人物的增删改查操作, 注: 删除和修改,查找可以考虑学员独立完成,也可带学员完成 1.第一种方法在添加英雄时,直接添加到链表的尾部 2.第二种方式在添加英雄时,根据排名将英雄插入到指定位置(如果有这个排名,则添加失败,并给出提示)

单链表的分析

首先我们要建立一个节点对象,在节点对象里面我们要设置data和对应的next值报证头节点对象是不变的,这样的话可以报证链表的位置是固定的封装一个SingleLinkedList类对象,在这个对象中我们可以进行对这个链表的增删改查的操作对数据进行相关的功能的测试,即对这个单链表的功能的功能的实现

链表具体实现流程分析

1.建立一个节点对象

//定义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 + '\'' + '}'; } }

2.建立一个链表对象,此时我们关于链表的增删改查的操作都应该在链表对象中进行操作

//定义SingleLinkedList来管理我们的英雄 class SingleLinkedList{ //首先是定义一个头节点,这个头节点不用动,不存放具体的数据 private HeroNode head = new HeroNode(0,"",""); //添加节点到单向链表 //思路:不考虑编号顺序的时候 //1.找到当前链表的最后节点 //2.将最后这个节点的next指向新的节点 public void add(HeroNode heroNode){ //因为head节点不能动,因此我们需要一个辅助节点遍历temp HeroNode temp = head; //遍历节点对象,找到最后 while (true){ //如果找到链表的最后 if (temp.next == null){ break; } //显然是这个时候没有找到链表的最后,显然是后移 temp = temp.next; } //当退出这个while循环的时候,显然是查询到了链表的最后一个节点,这实现了数据的后移并赋值 temp.next = heroNode; } //第二种添加英雄时候,根据排名将各路英雄插入到指定的位置,如果有这个排名,则添加失败,并给出提示 public void addByOrder(HeroNode heroNode){ //显然此时头节点的位置不能动,因此我们可以通过一个辅助节点的值来帮助我们找到添加的位置 //因为是辅助节点,所以我们添加的是temp的前一个位置 HeroNode temp = head; boolean flag = false;//说明该temp标记的是添加的编号已经存在,默认是false while (true){ if (temp.next== null){ //说明该temp已经在链表的最后了 break; } if (temp.next.no > heroNode.no){ //位置找到,就在temp后面加入 break; } else if (temp.next.no == heroNode.no){ flag = true; //说明编号存在 break; } temp = temp.next; //后移,遍历当前链表 } //判断flag的值 if (flag){ //不能填加,说明编号存在 System.out.printf("准备插入的英雄的编号 %d 已经存在,不能加入\n",heroNode.no); }else { //插入到链表中,temp的后面 heroNode.next = temp.next; temp.next = heroNode; } } //修改节点的信息,根据no编号来进行修改,即改编号不能够发生改变 //1.根据heroNode的编号进行修改 public void update(HeroNode newHeroNode){ //判断是否为空 if (head.next == null){ System.out.println("该链表是空的"); return; } //根据no编号来查询到我们要查询的节点对象 //添加一个辅助变量来进行我们的相关的节点的对象的信息 HeroNode temp = head.next; boolean flag = false; //标志变量,用来来分析我们是否找到了要查询的节点 while (true){ if (temp == null){ break;//显然说的是我们已经遍历完了我们的链表 } //查询到我们的想要查询的节点 if (temp.no == newHeroNode.no){ flag = true; break; } temp = temp.next; } //根据flag来判断我们是否找到了要修改的节点 if (flag){ temp.name = newHeroNode.name; temp.nickname = newHeroNode.nickname; } else { System.out.printf("显示是没有找到编号为 %d 的节点,不能够修改\n",newHeroNode.no); } } //删除思路 //1.首先head节点是不能够动的,所以我们首先需要选择一个temp的节点来删除当前节点的前一个节点 //2.所以我们需要对比temp.next.no和我们当前选择的no的数据进行对比 public void del(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; //temp后移,进行遍历 } //判断flag的信息 if (flag){ //找到了相关的功能 //可以删除 temp.next = temp.next.next; } else { System.out.printf("要删除的 %d 节点不存在",no); } } //遍历数据 public void list(){ //首先是遍历链表判断其是否为空 if (head.next == null){ System.out.println("改链表是空链表"); return; } //因为头节点不能动,所以我们需要一个辅助变量进行遍历 HeroNode temp = head.next; while (true){ //判断其当前的链表是否是空 if (temp == null){ return; } //输出节点的信息 System.out.println(temp); //将temp对象进行回移 temp = temp.next; } } }``` 2.测试数据 ```java 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.add(hero1); singleLinkedList.add(hero2); singleLinkedList.add(hero3); singleLinkedList.add(hero4); */ //安装编号进行添加 singleLinkedList.addByOrder(hero1); singleLinkedList.addByOrder(hero4); singleLinkedList.addByOrder(hero3); singleLinkedList.addByOrder(hero2); singleLinkedList.addByOrder(hero2); //显示一把 singleLinkedList.list(); //测试修改节点的代码 HeroNode newHeroNode = new HeroNode(2, "小卢", "玉麒麟~~~~"); singleLinkedList.update(newHeroNode); //显示一把 System.out.println("修改后的数据~~~~"); singleLinkedList.list(); //删除其中的一个节点 singleLinkedList.del(1); //显示一把 System.out.println("修改后的数据~~~~"); singleLinkedList.list(); } }

运行结果

经过我们的分析和对其增删改查的实现,我们明确了其中其指针的相关的移动,通过对这个指针的数据的来回的移动,能够实现我们相关的功能,在尾部添加的时候,能够实现自动添加的作用,删除和修改都是完成了相关的功能的判断,对其指针的数据的来回的移动,能够让我我们的系统的功能能够稳定的实现相关的功能

最新回复(0)