单链表的原理及实现,你确定会吗?
2020-12-22 09:01
218 查看
前言
数据结构是计算机存储、组织数据的方式。如果不会数据结构,那么就不可能写出好的代码,因此。数据结构是我们学习编程不可或缺的一部分!链表是数据结构中的一种,但是链表又分为单向链表,双向链表,循环链表,本篇文章主要是聊聊链表中的单向链表。
单向链表(single-linked list)概述
一个单链表的节点(Node)分为两部分,第一个部分(data)保存或者显示关于节点的信息,另一个部分储存下一个节点的地址,最后一个节点的储存地址部分指向空值。
单向表只可向一个方向便利,一般查找一个节点的时候需要从第一个节点开始每次访问下一个节点,一直访问到需要的位置。而插入一个节点,对于单向链表,我们只提供在链表头插入,只需要将当前的节点设置为头节点,next指向源头节点即可。删除一个节点,我们将该节点的上一个的next指向下一个节点
算法分析:
链表中元素的增加(需要按照编号的顺序添加):
- 首先找到新添加的节点的位置, 是通过辅助变量(指针), 通过遍历来搞定
- (新的节点)heroNode.next = temp.next
- 将temp.next = heroNode.next(新的节点)
链表中元素的删除(需要按照编号进行删除):
- 我们先找到需要删除的这个节点的前一个节点 temp
- temp.next.no = herNode.next(temp.next.next)
- 被删除的节点,将不会有其它引用指向,会被垃圾回收机制回收
链表中元素的修改(需要按照编号进行删除):
1、按照no找到要修改的编号
2、temp.name=newHeroNode.name;
3、temp.nickName=newHeroNode.nickName;注意事项:
在创建、修改、删除中所创建的辅助变量temp都是必须的,因为head的值是不能变化的,一旦head发生变化,整个链表就会报错。
代码实现:
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.add(hero1); //singleLinkedList.add(hero2); //singleLinkedList.add(hero3); //singleLinkedList.add(hero4); singleLinkedList.addByOrder(hero1); singleLinkedList.addByOrder(hero4); singleLinkedList.addByOrder(hero2); singleLinkedList.addByOrder(hero3); singleLinkedList.addByOrder(hero3); System.out.println("修改前:"); singleLinkedList.list(); HeroNode newHeroNode =new HeroNode(2, "小卢", "小麒麟"); singleLinkedList.update(newHeroNode); System.out.println("修改后:"); singleLinkedList.list(); singleLinkedList.delete(hero3); System.out.println("删除后:"); singleLinkedList.list(); } } class SingleLinkedList{ //先初始化一个头结点,头结点不要动,不存放具体数据 private HeroNode head = new HeroNode(0, "", ""); public void add(HeroNode heroNode) { HeroNode temp = head;//定义一个辅助变量来存放head,因为head是不可变的 //遍历链表,找到最后 while(true) { if(temp.next==null) { break;//找到链表的最后一个之后。break } //如果没有找到,就将temp后移,当退除循环时,temp指向链表的最后 temp = temp.next; } //temp指向新的节点 temp.next = heroNode; } public void addByOrder(HeroNode heroNode) { HeroNode temp = head; //因为时单链表,因此我们要找的temp是位于插入节点前一个位置的否则插入不了 boolean flag = false;//flag标志添加的编号是否存在,默认为false while(true) { if(temp.next==null)//temp已经再链表的最后,break break; if(temp.next.no>heroNode.no)//与添加位置的后一位no进行比较,位置已找到 break; else if(temp.next.no==heroNode.no){//说明希望添加的heroNode的编号已经存在 flag = true; break; } temp = temp.next; } if(flag == true) { System.out.printf("准备插入的这个英雄的编号%d已经存在,不能加入",heroNode.no); System.out.println(); } else { //插入到链表中 heroNode.next=temp.next; temp.next=heroNode; } } //修改节点的信息,no不能更改 public void update(HeroNode newHeroNode) { if(head.next==null) { System.out.println("LinkedList为空"); return; } HeroNode temp = head; boolean flag = false; while(true) { if(temp.next==null)//已经遍历完链表 break; if(temp.no==newHeroNode.no) { flag = true; break; } temp = temp.next; } if(flag == true) { temp.name=newHeroNode.name; temp.nickName=newHeroNode.nickName; } else { System.out.printf("没有找到编号等于%d的节点",newHeroNode.no); } } public void delete(HeroNode heroNode) { if(head.next==null) { System.out.println("该链表为空,无法删除"); return; } HeroNode temp = head; boolean flag = false; while(true) { if(temp.next==null) break; if(temp.next.no==heroNode.no) { flag = true; break; } temp = temp.next; } if(flag == true) { temp.next=heroNode.next; } else { System.out.printf("要删除的no为%d的节点不存在",heroNode.no); } } //显示链表(遍历) public void list() { //先判断链表是否为空 if(head.next==null) { return; } //因为头节点不能动,因此需要一个辅助变量 HeroNode temp = head.next; while(true) { if(temp==null) { break; } System.out.println(temp.toString()); temp = temp.next;//后移 } } } //定义一个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 + "]"; } }
相关文章推荐
- C#中的深度学习(一):使用OpenCV识别硬币
- 测试面试LeetCode系列:按既定顺序创建目标数组
- 突破某度云盘下载限速,提速30倍!想学?我教你啊
- SpringBoot2 整合OAuth2组件,模拟第三方授权访问
- 容器编排系统k8s之Ingress资源
- 传说之下ink模拟器U77
- 我们该如何正确的中断一个线程的执行??
- 5.用户和权限管理
- 4.IO重定向
- .NET 云原生架构师训练营(模块二 基础巩固 HTTP管道与中间件)--学习笔记
- 2020 .NET 开发者峰会顺利在苏州落幕,相关数据很喜人以及线上直播回看汇总
- Vue2+Koa2+Typescript前后端框架教程--00开始分享
- k8s之深入解剖Pod(二)
- Solr:Slor初识(概述、Windows版本的安装、添加IK分词器)
- 如何用Eggjs从零开始开发一个项目(2)
- Django入门
- Django 跨域访问POST请求需预先发送option请求问题处理方案
- 最火的分布式调度系统 XXL-JOB 安装和简单使用
- 彻底理解Hive中的锁
- 源码分析:通过Spring Boot构建一个购物车微服务 | 云原生应用开发系列6