文章目录

引言

实现思路

添加元素

插入元素

删除元素

查找元素

更新元素

显示链表

实现代码(完整)

总结

留言


引言

链表是一种重要的数据结构。它的存储空间是不连续的,单向链表是最简单的一种链表。本文主要介绍单向链表,及其“增删改查”等功能的实现。我们希望设计出来的链表不仅仅只能存储一种类型的数据。而是可以像ArrayList集合那样,存储任意类型的数据,因此设计的时候要结合泛型。

实现思路

链表是由一个个的节点链接起来的,这里介绍的是单向链表,每个节点都要有一个数据域“value”用来存储数据,和指向下一个节点的引用“next”,它就像是一根链子,把每一个节点链接起来。除了最后一个节点之外,其余的每个节点的“next”都指向它的下一个节点,这样就形成了一个链表。

为了方便之后进行“增删改查”操作,链表要有一个头结点“head”,尾结点“tail”及链表的长度“size”。

首先要有一个私有的静态内部类,这个类是“节点类”,它是为整个链表服务的,我们要存入链表中的数据就要被封装成一个个节点,然后链接在链表中。显然,每个节点都是根据这个节点类创建出来的。

   private static class ListNode<T> {// 定义私有节点内部类T value;// 用来存储数据(数据域)ListNode<T> next;// 用来存储下一节点的引用(地址域)public ListNode(T val) {// 构造方法,this.value = val;}

添加元素

添加元素时,我们只需要把要添加的元素封装成一个节点,然后链接在链表的尾部即可。如果链表为空,那么链表的头结点和尾结点都是这个节点。否则就把这个节点直接链接到“尾结点”后面。同时它就是新的“尾结点”

    public void append(T val) {// 添加元素,直接添加在链表的末尾ListNode<T> newNode = new ListNode<T>(val);// 如果尾结点为空,那么这个链表一个节点都没有,即第一次添加节点if (tail == null) {head = tail = newNode;} else {// 否则直接把节点链接在链表尾部tail.next = newNode;tail = newNode;}size++;}

插入元素

插入元素时,如果是在链表头部插入新节点newNode,那么直接让newNode的next指向头结点,然后newNode就是新的头结点。如果是在链表尾部插入,则直接添加元素方法append()即可。如果是在中间某个位置插入新节点newNode,那么通过for循环,从头结点开始,找到要插入位置的前一个节点prev,和prev的下一个节点after;然后让prev的next指向newNode,newNode的next指向after,链表长度加1即可。如图:

public boolean insert(int position, T val) {// 插入节点,可以在链表的任意位置插入节点if (position > size || position < 0) {//如果插入的位置不合法,做出提示System.out.println("请输入正确的下标:0-" + (size - 1));return false;}ListNode<T> newNode = new ListNode<T>(val);if (position == 0) {// 在链表头结点中插入节点newNode.next = head;head = newNode;if (tail == null) {tail = newNode;// 如果第一次添加元素,此时尾结点也是此节点}size++;return true;} else if (position == size) {// 在链表尾结点中插入节点this.append(val);return true;} else {ListNode<T> prev = head;//找到要插入位置的前一个节点for (int i = 0; i < position - 1; i++) {prev = prev.next;}//此时prev的下一个节点就就是要插入位置的后一个节点ListNode<T> after = prev.next;//更改指向,即完成了添加元素prev.next = newNode;newNode.next = after;size++;return true;}}

删除元素

删除元素时,如果删除的节点是“头结点”,那么新的“头结点”就是原头结点的下一个节点,然后再判断链表的长度是否为0,如果为0,那么尾结点为null,删除的节点是其他的节点的话,就要从“头结点”开始遍历链表,找到要删除的节点“cur”和它前一个节点“prev”。然后让“prev”的next指向 “cur”的“next”即可。

   public boolean delete(T val) {if (head != null && head.value.equals(val)) {head = head.next;size--;// 删除后如果长度为0,头结点和尾结点都为空if (size == 0) {tail = null;}return true;} else {ListNode<T> prev = head;//标记要删除的节点的前一个节点ListNode<T> cur = head;//标记要删除的节点//从头结点开始遍历链表,找到了要删除的节点while (prev != null && cur != null) {if (cur.value.equals(val)) {//此条件如果成立,则找到了要删除的节点if (cur == tail) {//如果它是尾结点,那么新的尾结点就是前一个节点tail = prev;}prev.next = cur.next;//让前一个节点指向要删除节点的下一个节点size--;return true;}prev = cur;cur = cur.next;}}return false;}

查找元素

查找元素,通过使用for循环,从头结点开始查找。找到目标节点后,将index返回。如果没有找到 ,就返回-1。

    public int search(T val) {// 查找元素,返回该元素在链表中的下标,如果没有则返回-1ListNode<T> cur = head;//从头结点遍历链表,寻找目标节点for (int index = 0; cur != null; index++) {//如果某个节点的value内容和val一样,即找到了目标节点if (cur.value.equals(val)) {return index;}cur = cur.next;}//遍历链表没找到目标节点,返回-1return -1;}

更新元素

更新元素时,通过while循环查找要更新的节点。找到目标节点之后,把它的“value”修改成要修改的数据“newVal”即可。

    public boolean update(T oldVal, T newVal) {// 更新链表中的某个节点中的值ListNode<T> cur = head;// 从头结点开始遍历链表,寻找要更新的节点while (cur != null) {//找到目标节点后,更新它的值if (cur.value.equals(oldVal)) {cur.value = newVal;return true;}cur = cur.next;}return false;}

显示链表

显示链表可以先创建一个ArrayList集合对象“NodeList”。通过while循环,把链表的每个节点都添加进去,然后把“”NodeList打印输出即可。也可以创建一个StringJoiner对象,通过循环把每个节点的value 添加进去,然后打印输出。

public void display() {// 用于显示链表ArrayList<ListNode<T>> NodeList = new ArrayList<LinkedList.ListNode<T>>();StringJoiner sj = new StringJoiner(",", "[", "]");ListNode<T> cur = head;// 通过while循环遍历链表所有节点while (cur != null) {// 把链表节点添加到ArrayList集合中NodeList.add(cur);cur = cur.next;}System.out.println(NodeList);// 打印//     while (cur != null) {
//          sj.add(cur.value.toString());
//          cur = cur.next;
//      }
//      System.out.println(sj.toString());}

实现代码(完整)

LinkedList.java


import java.util.ArrayList;
import java.util.StringJoiner;public class LinkedList<T> {ListNode<T> head;// 链表的头结点ListNode<T> tail;// 链表的尾结点int size;// 链表的长度private static class ListNode<T> {// 定义私有节点内部类T value;// 用来存储数据(数据域)ListNode<T> next;// 用来存储下一节点的引用(地址域)public ListNode(T val) {// 构造方法,this.value = val;}@Override// 重写toString()方法,便于查看链表内容,如果链表中放入自己定义的类的对象,那么在该类中一定要重写toString()方法public String toString() {// TODO Auto-generated method stubreturn this.value.toString();}}public LinkedList() {// 链表的构造方法,head = null;tail = null;size = 0;}public void append(T val) {// 添加元素,直接添加在链表的末尾ListNode<T> newNode = new ListNode<T>(val);// 如果尾结点为空,那么这个链表一个节点都没有,即第一次添加节点if (tail == null) {head = tail = newNode;} else {// 否则直接把节点链接在链表尾部tail.next = newNode;tail = newNode;}size++;}public boolean insert(int position, T val) {// 插入节点,可以在链表的任意位置插入节点if (position > size || position < 0) {System.out.println("请输入正确的下标:0-" + (size - 1));return false;}ListNode<T> newNode = new ListNode<T>(val);if (position == 0) {// 在链表头结点中插入节点newNode.next = head;head = newNode;if (tail == null) {tail = newNode;// 如果第一次添加元素,此时尾结点也是此节点}size++;return true;} else if (position == size) {// 在链表尾结点中插入节点this.append(val);return true;} else {ListNode<T> prev = head;// 找到要插入位置的前一个节点for (int i = 0; i < position - 1; i++) {prev = prev.next;}// 此时prev的下一个节点就就是要插入位置的后一个节点ListNode<T> after = prev.next;// 更改指向,即完成了添加元素prev.next = newNode;newNode.next = after;size++;return true;}}public void display() {// 用于显示链表ArrayList<ListNode<T>> NodeList = new ArrayList<LinkedList.ListNode<T>>();StringJoiner sj = new StringJoiner(",", "[", "]");ListNode<T> cur = head;// 通过while循环遍历链表所有节点while (cur != null) {// 把链表节点添加到ArrayList集合中NodeList.add(cur);cur = cur.next;}System.out.println(NodeList);// 打印//        while (cur != null) {
//          sj.add(cur.value.toString());
//          cur = cur.next;
//      }
//      System.out.println(sj.toString());}// 用于删除链表的元素public boolean delete(T val) {if (head != null && head.value.equals(val)) {head = head.next;size--;// 删除后如果长度为0,头结点和尾结点都为空if (size == 0) {tail = null;}return true;} else {ListNode<T> prev = head;// 标记要删除的节点的前一个节点ListNode<T> cur = head;// 标记要删除的节点// 从头结点开始遍历链表,找到了要删除的节点while (prev != null && cur != null) {if (cur.value.equals(val)) {// 此条件如果成立,则找到了要删除的节点if (cur == tail) {// 如果它是尾结点,那么新的尾结点就是前一个节点tail = prev;}prev.next = cur.next;// 让前一个节点指向要删除节点的下一个节点size--;return true;}prev = cur;cur = cur.next;}}return false;}public int search(T val) {// 查找元素,返回该元素在链表中的下标,如果没有则返回-1ListNode<T> cur = head;// 从头结点遍历链表,寻找目标节点for (int index = 0; cur != null; index++) {// 如果某个节点的value内容和val一样,即找到了目标节点if (cur.value.equals(val)) {return index;}cur = cur.next;}// 遍历链表没找到目标节点,返回-1return -1;}public boolean update(T oldVal, T newVal) {// 更新链表中的某个节点中的值ListNode<T> cur = head;// 从头结点开始遍历链表,寻找要更新的节点while (cur != null) {//找到目标节点后,更新它的值if (cur.value.equals(oldVal)) {cur.value = newVal;return true;}cur = cur.next;}return false;}
}

Main.java 

public class Main {public static void main(String[] args) {LinkedList<String> list = new LinkedList<String>();list.append("关羽");list.append("张飞");list.append("赵云");list.append("马超");list.append("黄忠");list.display();System.out.println("---------------------------------");int index1 = list.search("赵云");System.out.println("赵云的位置:"+index1);int index2 = list.search("刘备");System.out.println("刘备的位置:"+index2);System.out.println("---------------------------------");list.insert(2, "刘备");list.delete("马超");list.update("张飞", "孙权");list.display();}
}

测试结果 :

总结

单向链表只有指向下一个节点的引用“next”,因此,遍历只能从头结点开始从前往后遍历,直到尾结点。

要实现链表的“插入”,“删除”,“更新”等操作,关键是要通过对链表的遍历找到“目标节点”,然后更改其引用“next”的指向即可。

留言

由于水平有限,一些细节可能没有考虑到位,还请理解!本文仅供参考使用,如有帮助,不甚荣幸!

Java实现单向链表——精简相关推荐

  1. java实现单向链表

    一.单向链表的结构. (1).首先节点的结构,其中包含本节点内容,以及需要指向下一个节点. Java代码 private static class Entry<E>{ E e; Entry ...

  2. Java实现单向链表基本功能

    一.前言 最近在回顾数据结构与算法,有部分的算法题用到了栈的思想,说起栈又不得不说链表了.数组和链表都是线性存储结构的基础,栈和队列都是线性存储结构的应用- 本文主要讲解单链表的基础知识点,做一个简单 ...

  3. java集合单向链表_Java实现单向链表数据结构

    本文章同步到本人的博客站点 燕归来 链表是一种数据结构,和数组同级.比如,Java中我们使用的ArrayList,其实现原理是数组.而LinkedList的实现原理就是链表了.链表在进行循环遍历时效率 ...

  4. java实现单向链表的增、删、改、查

    单向链表 作者:vashon package com.ywx.link; /*** 单向链表* @author vashon**/ public class LinkTest {public stat ...

  5. java简单单向链表_用java简单的实现单链表的基本操作

    packagecom.tyxh.link;//节点类 public classNode {protected Node next; //指针域 protected int data;//数据域 pub ...

  6. java简单单向链表_【新手自白书】简单单项链表的实现(JAVA)

    复习一下简单单项链表的实现. 在动手写链表之前,需要思考链表是如何组成的,一般来说,一个简单的单项链表主要是由节点构成,由于链表的特性,头节点是一个十分重要的成员,所以,链表必须的成员是节点Node, ...

  7. 用Java实现单向链表

    [说明] 封装节点类,既用于存储数据data和下一个节点的首地址next,又封装了基本的增删改查的功能. 方便以后调用,而不用要用户手工去处理各个节点的关系. //class Link{ privat ...

  8. 【java】Java实现单向链表反转

    1.概述 转载:https://www.jb51.net/article/136185.htm 遇到了这个问题,记录一下 2.案例1 2.1 实现思路 递归:从尾部开始处理 非递归:从头部开始处理 2 ...

  9. 反转单向链表java_Java实现单向链表反转

    本文实例为大家分享了Java实现单向链表反转的具体代码,供大家参考,具体内容如下 1.实现代码 public class LinkedListTest { public static void mai ...

最新文章

  1. @bean注解和@component注解的区别_阿里面试题一:spring里面使用xml配置和注解配置区别...
  2. Mac安装 ohmyzsh发生443错误
  3. 【MIPS汇编】ADDI,ADDIU,ADD,ADDU的区别、有符号无符号的谬误
  4. dotnet-httpie 0.2.0 Released
  5. java线程切换速度_为什么说线程太多,cpu切换线程会浪费很多时间?
  6. 使用go的ssh包快速打造一个本地命令行ssh客户端
  7. 设置eclipse代码自动补全功能
  8. mysql的索引和触发器_MYSQL数据库学习----索引和触发器
  9. Java对证书的操作
  10. 微信小程序--音乐播放器
  11. linux tuxedo查看服务进程数,tuxedo常用命令
  12. sql 2008 R2 备份和还原
  13. JAVA班车项目_JavaBooks/班车服务.md at master · Aim-Tric/JavaBooks · GitHub
  14. Scanner的close()方法的使用以及Scanner应该如何关闭
  15. Strong-Convexity
  16. 【Qt开发】QThread中的互斥、读写锁、信号量、条件变量
  17. 瑜伽断食法——From《瑜伽祖本》(手敲版)
  18. 基于机智云平台的智能花盆
  19. 电脑右键新建,少了office的几个图标,如:excel,word
  20. 地质体剖面从构建到Web三维展示

热门文章

  1. 重启随机游走算法(RWR)
  2. 在跨境电商领域,国际短信的优势你了解多少?
  3. 大小端(网络字节序)等概念
  4. 《实况赶海》技术支持网址
  5. 活动调度/活动安排(超详细)
  6. Ledger of Harms
  7. 上海全栈开发学院8月《专业二》第一周周考技能
  8. 解决xshell 中文乱码
  9. missing values in newdata
  10. mysql ifnull 无效_MySQL IFNULL判空问题解决方案