当前位置: 首页 > news >正文

链表原理与实现:从单链表到LinkedList

1.链表的概念及结构

链表是一种物理存储结构上非连续存储结构,数据元素的逻辑顺序是通过链表中的引用链接次序实现的 。 可以形象的理解,在逻辑上来看,链表就像是一节节火车车厢。

链表的分类:链表的结构有很多种,单向或双向、带头或不带头、循环或不循环。这篇文章就从最简单的链表结构讲起———不带头单向非循环链表(单链表)。

2.单链表模拟实现

为了更好的学习对于单链表的操作。我们自己模拟实现一些基本的功能。

1.准备工作

接口

package List;public interface IList {//头插法void addFirst(int data);//尾插法public void addLast(int data);//任意位置插入,第一个数据节点为0号下标public void addIndex(int index,int data);//查找是否包含关键字key是否在单链表当中public boolean contains(int key);//删除第一次出现关键字为key的节点public void remove(int key);//删除所有值为key的节点public void removeAllKey(int key);//得到单链表的长度public int size();//清空public void clear() ;//打印public void display() ;
}

通过实现接口中的抽象方法实现单链表增删查改的实现。

单链表的定义

单链表(SinglyLinkedList)的定义需要定义单个节点ListNode。单个节点有data存储数据,next存储下一个节点的引用。同时单链表还需要一个成员变量head存储单链表的头位置。基于以上的需要可以把ListNode定义为单链表的内部类。

public class SinglyLinkedList {public class ListNode{public int data;public ListNode next;public ListNode(int data) {this.data = data;}}public ListNode head;
}

2.具体接口实现

添加

头插
@Overridepublic void addFirst(int data) {ListNode newnode = new ListNode(data);newnode.next = head;head = newnode;}
尾插
@Overridepublic void addLast(int data) {ListNode newnode = new ListNode(data);//链表为空if(head == null){head = newnode;return;}//链表不为空,找尾尾插ListNode cur = head;while (cur.next != null){cur = cur.next;}cur.next = newnode;}
在index位置插入
private void CheckIndex(int index){int len = this.size();if(index < 0 || index > len){throw new IllegalIndexException("index不合法");}}@Overridepublic void addIndex(int index, int data) {try {CheckIndex(index);ListNode newnode = new ListNode(data);if(index == 0){addFirst(data);}if(index == size()){addLast(data);}ListNode cur = head;while(index - 1 != 0){cur = cur.next;index--;}newnode.next = cur.next;cur.next = newnode;}catch (IllegalIndexException e){e.printStackTrace();}}

 删除

删除找到第一个key值
@Overridepublic void remove(int key) {if(head == null){return;}//解决头节点问题if(head.data == key){head = head.next;return;}ListNode cur = head;while(cur.next.data != key){cur = cur.next;}ListNode del = cur.next;cur.next = del.next;}
删除所有等于key的值
@Overridepublic void removeAllKey(int key) {if(head == null){return;}ListNode prev = head;ListNode cur = head.next;while (cur != null){if(cur.data == key){prev.next = cur.next;}else {prev = cur;}cur = cur.next;}//解决头节点data等于key的情况if(head.data == key){head = head.next;}}

查找

@Overridepublic boolean contains(int key) {ListNode cur = head;while (cur != null){if(cur.data == key){return true;}cur = cur.next;}return false;}

得到size

@Overridepublic int size() {int count = 0;ListNode cur = head;while(cur != null){count++;cur = cur.next;}return count ;}

清空

@Overridepublic void clear() {ListNode cur = head;while(cur != null){ListNode ret = cur;cur.next = null;cur = ret.next;}head = null;}

打印

@Overridepublic void display() {ListNode cur = this.head;while(cur != null){System.out.print(cur.data + " ");cur = cur.next;}System.out.println();}

2.链表oj

看这篇文章:单链表oj练习(C语言版)

虽然是C语言完成的,但是做题的思想是一样的。

3.LinkedList的模拟实现

LinkedList是java标准库提供的双向链表的实现。还是一样为了更好的理解并运用,先自己模拟实现一个。

1.准备工作

接口

接口和上面的单链表接口一样。

MyLinkedList的定义

和上面的单链表不同的是ListNode里多一个prev用于存储上一个节点的引用MyLinkedList多一个成员last存储双向链表的尾

2.具体接口实现

添加

@Overridepublic void addFirst(int data) {ListNode newnode = new ListNode(data);if(head == null){head = last = newnode;}else {newnode.next = head;head.prev = newnode;head = newnode;}}@Overridepublic void addLast(int data) {ListNode newnode = new ListNode(data);if(head == null){head = last = newnode;}else {last.next = newnode;newnode.prev = last;last = newnode;}}private void CheckIndex(int index){if(index < 0 || index > size()){throw new IllegalIndexException("index位置不合法");}}private ListNode FindIndexnode(int index){ListNode cur = head;while(index-1 > 0){cur = cur.next;index--;}return cur;}@Overridepublic void addIndex(int index, int data) {try {CheckIndex(index);if(index == 0){addFirst(data);}if(index == size()){addLast(data);}ListNode newnode = new ListNode(data);ListNode cur = FindIndexnode(index);newnode.next = cur;cur.prev.next = newnode;newnode.prev = cur.prev;newnode.next = cur;}catch(IllegalIndexException e){e.printStackTrace();}}

删除

@Overridepublic void remove(int key) {ListNode cur = head;while(cur != null){if(cur.data == key){if(cur == head){head = head.next;if(head != null){head.prev = null;}}else {cur.prev.next = cur.next;if (cur.next == null) {last = last.prev;} else {cur.next.prev = cur.prev;}}return;}cur = cur.next;}}@Overridepublic void removeAllKey(int key) {ListNode cur = head;while(cur != null){if(cur.data == key){if(cur == head){head = head.next;if(head != null){head.prev = null;}}else {cur.prev.next = cur.next;if (cur.next == null) {last = last.prev;} else {cur.next.prev = cur.prev;}}}cur = cur.next;}}

查找 打印 得到size

和单链表一样,本质都是遍历链表

清空

@Overridepublic void clear() {ListNode cur = head;while(cur != null){ListNode Curn = cur.next;cur.prev = null;cur.next = null;cur = Curn;}head = last = head;}

4.LinkedList的使用 

1.构造

public static void main(String[] args) {// 构造一个空的LinkedListList<Integer> list1 = new LinkedList<>();List<String> list2 = new java.util.ArrayList<>();list2.add("JavaSE");list2.add("JavaWeb");list2.add("JavaEE");// 使用ArrayList构造LinkedListList<String> list3 = new LinkedList<>(list2);
}

2.其他方法 

 

 

相关文章:

  • Gin--Blog项目-flags文件解析
  • OpenCV 人脸识别:从基础到实践全解析
  • HarmonyOS5云服务技术分享--云缓存快速上手指南
  • vue2+webpack环境变量配置
  • 开源一个记账软件,支持docker一键部署
  • 详解ip地址、子网掩码、网关、广播地址
  • ArcObjects学习教程
  • CouchDB 可观测最佳实践
  • Centos上搭建 OpenResty
  • 什么是 AI 人工智能?什么是机器学习?什么是深度学习?三者啥关系
  • 企业级 Go 多版本环境部署指南-Ubuntu CentOS Rocky全兼容实践20250520
  • 利用朴素贝叶斯对UCI 的 mushroom 数据集进行分类
  • CentOS 7上部署BIND9 DNS服务器指南
  • RustDesk CentOS自建中继节点
  • CentOS 7上搭建高可用BIND9集群指南
  • 将 /dev/vdb1 的空间全部合并到 /dev/mapper/centos-root(即扩展 CentOS 的根分区)
  • MyBatis 动态 SQL 标签详解教程:_set_、_trim_、_sql_、_choose_、_when_
  • 数据库外键
  • 测试W5500的第3步_使用ioLibrary库创建TCPServer
  • Flink并行数据源:ClickSource实现详解
  • 昆明市委:今年起连续三年,每年在全市集中开展警示教育
  • 中国需加强自主创新和国际合作,提升产业链供应链韧性
  • 习近平:坚定信心推动高质量发展高效能治理,奋力谱写中原大地推进中国式现代化新篇章
  • 在越剧之乡嵊州,浙江音乐学院越剧学院成立
  • “大国重器”、新型反隐身雷达……世界雷达展全面展示尖端装备
  • 菲律宾中期选举结果揭晓,马科斯与杜特尔特家族重回“权力的游戏”