02-java实现单链表
02-手撸链表
本篇是恋上数据结构第一季个人总结
借鉴https://juejin.im/post/6844904001478066183#heading-0
本人git https://github.com/bigeyes-debug/Algorithm
一丶链表定义
链表是一种链式存储的线性表, 所有节点的内存地址不一定是连续的。

二丶链表设计
创建LinkedList类,用来管理链表数据,其中的size属性记录存储数据的数量,first属性引用链表的第0个节点。
创建私有类Node,其中的element属性用于存储节点,next属性用于指向链表中的下一个节点。
public class SIngleLinkedList<E> extends
AbstractList<E>{
private Node<E> first;
private static class Node<E>{
E element;
Node<E> next;
public Node(E element, Node<E> next) {
this.element = element;
this.next = next;
}
}
接口
// 节点的数量
int size();
// 是否为空
boolean isEmpty();
// 是否包含某个节点
boolean contains(E element);
// 添加节点到最后面
void add(E element);
// 返回index位置对应的节点
E get(int index);
// 设置index位置的节点
E set(int index, E element);
// 往index位置添加节点
void add(int index, E element);
// 删除index位置对应的节点
E remove(int index);
// 查看节点的位置
int indexOf(E element);
// 清除所有节点
void clear();
与动态数组的接口类似,我们可以抽取接口,然后实现,后面我们会提到
三丶链表的实现
3.1 构造方法
- 链表的创建与动态数组不同,动态数组在构造时需要传入一个空间属性,来决定这个数组的容量。但链表节点是在添加时才创建的,内存地址不一定是连续的。所以链表不需要在单独设计构造方法,使用默认构造方法即可。
3.2 添加节点

- 添加节点时候只需要到将最后节点的next指针指向新添加的节点
- 当指定位置添加节点的时候,需要插入位置的前驱,
- 然后用前驱的next指针指向新添加的节点,并且该结点next指向原来的结点
- 需要特别注意的地方是当前插入位置是0时,因为他没没有前驱,需要做特殊处理

代码如下
@Override
public void add(int index, E element) {
//检查越界 和动态数组类似
rangeCheck(index);
//特殊处理
if(index ==0) {
first=new Node<>(element, first);
}else {
// 获得前驱
Node <E>prev=node(index-1);
//上图的①②
prev.next=new Node<>(element, prev.next);
}
// TODO Auto-generated method stub
size++;
}
public void add(E element) {
// 节点添加到size位置, 即添加到最后面
add(size, element);
}
3.3 删除节点
- 删除指定位置的节点,需要找到前驱
- 用前驱next指向该位置节点的后继
- 由于头结点没有前驱,所以我们仍需要对头结点的删除做特殊处理,只需要将头结点指向头结点的后继

//这里我们用到了一个node函数,node是根据索引获取该节点的节点
public E remove(int index) {
rangeCheck(index);//检查越界
Node <E> node =first;
// TODO Auto-generated method stub
if(index==0) {
first=first.next;
}else {
//或得前驱
Node <E>prev=node(index -1);
//index位置的节点
node =prev.next;
//前驱的后继是index位置的后继
prev.next=prev.next.next;
}
size--;
return node.element;
}
private Node<E> node(int index){
rangeCheck(index);
Node<E> node=first;
for(int i=0;i<index;i++) {
node=node.next;
}
return node;
}
3.4 修改节点
修改节点首先根据节点的索引找到节点,然后修改节点的元素,最后返回原来节点的元素的值
public E set(int index, E element) {
Node <E> node=node(index);
E old=node.element;
node.element=(E) element;
return old;
// TODO Auto-generated method stub
}
3.5查找节点
3.5.1 根据下标查找
找到对应的节点, 取出元素即可。
public E get(int index) {
// TODO Auto-generated method stub
return node(index).element;
}
3.5.2 根据元素值查找
- 查找指定元素的索引,需要遍历所有节点,找到节点对应的元素与执行元素相等即可。
- 如果需要支持节点element为null,则需要分两种情况处理。
一定要分开处理,,如果传入的element为null,调用equals方法会报错, 至于为什么用equlas方法,而不用==,自行百度Java基础
public int indexOf(E element) {
if(element == null) {
Node <E> node= first;
for(int i=0;i<size;i++) {
if(node.element==null) {
return i;
}
node=node.next;
}
}else {
Node <E> node= first;
for(int i=0;i<size;i++) {
if(element.equals(node.element)) {
return i;
}
node=node.next;
}
}
return ELEMENT_NOT_FOUND;
}
3.6 获取链表元素的个数
public int size() {
return size;
}
3.7 链表是否为空
public boolean isEmpty() {
return size == 0;
}
3.7 元素是否存在
public boolean contains(E element) {
return indexOf(element) != ELEMENT_ON_FOUND;
}
3.8 打印链表中存储的数据
@Override
public String toString() {
StringBuilder string = new StringBuilder();
string.append("size = ").append(size).append(", [");
Node<E> node = first;
for (int i = 0; i < size; i++) {
if (i != 0) {
string.append(",");
}
string.append(node.element);
node = node.next;
}
string.append("]");
return string.toString();
}
四丶链表的复杂度

五丶代码优化
通过编写代码发现,链表和动态数组的接口一样,部分代码共用,他俩都属于线性表
我们可以优化代码,具体如下
实现list接口
package com.bigeyes;
public interface List<E> {
static final int ELEMENT_NOT_FOUND = -1;
/**
* 清除所有元素
*/
void clear();
/**
* 元素的数量
* @return
*/
int size();
/**
* 是否为空
* @return
*/
boolean isEmpty();
/**
* 是否包含某个元素
* @param element
* @return
*/
boolean contains(E element);
/**
* 添加元素到尾部
* @param element
*/
void add(E element);
/**
* 获取index位置的元素
* @param index
* @return
*/
E get(int index);
/**
* 设置index位置的元素
* @param index
* @param element
* @return 原来的元素ֵ
*/
E set(int index, E element);
/**
* 在index位置插入一个元素
* @param index
* @param element
*/
void add(int index, E element);
/**
* 删除index位置的元素
* @param index
* @return
*/
E remove(int index);
/**
* 查看元素的索引
* @param element
* @return
*/
int indexOf(E element);
}
定义AbstractList抽象类,实现list接口,并且共用代码在这实现
package com.bigeyes;
public abstract class AbstractList<E> implements
List<E> {
/**
* 元素的数量
*/
protected int size;
/**
* 元素的数量
* @return
*/
public int size() {
return size;
}
/**
* 是否为空
* @return
*/
public boolean isEmpty() {
return size == 0;
}
/**
* 是否包含某个元素
* @param element
* @return
*/
public boolean contains(E element) {
return indexOf(element) !=
ELEMENT_NOT_FOUND;
}
/**
* 添加元素到尾部
* @param element
*/
public void add(E element) {
add(size, element);
// System.out.println(siArrayList.javaze);
}
protected void outOfBounds(int index) {
throw new
IndexOutOfBoundsException("Index:" + index + ",
Size:" + size);
}
protected void rangeCheck(int index) {
if (index < 0 || index >= size) {
outOfBounds(index);
}
}
protected void rangeCheckForAdd(int index) {
if (index < 0 || index > size) {
outOfBounds(index);
}
}
}
02-java实现单链表的更多相关文章
- JAVA数据结构——单链表
链表:一. 顺序存储结构虽然是一种很有用的存储结构,但是他有如下几点局限性:1. 因为创造线性表的时候已经固定了空间,所以当需要扩充空间时,就需要重新创建一个地址连续的更大的存储空间.并把原有的数据元 ...
- Java实现单链表的各种操作
Java实现单链表的各种操作 主要内容:1.单链表的基本操作 2.删除重复数据 3.找到倒数第k个元素 4.实现链表的反转 5.从尾到头输出链表 6.找到中间节点 7.检测链表是否有环 8.在 ...
- java实现单链表的增删功能
JAVA 实现单链表的增删功能 package linked; class LinkedTable{ } public class LinkedTableTest { public static vo ...
- 使用java实现单链表(转载自:https://www.cnblogs.com/zhongyimeng/p/9945332.html)
使用java实现单链表----(java中的引用就是指针)转载自:https://www.cnblogs.com/zhongyimeng/p/9945332.html ? 1 2 3 4 5 6 7 ...
- 用Java实现单链表的基本操作
笔试题中经常遇到单链表的考题,下面用java总结一下单链表的基本操作,包括添加删除节点,以及链表转置. package mars; //单链表添加,删除节点 public class ListNode ...
- java实现单链表常见操作
一.概述: 本文主要总结单链表常见操作的实现,包括链表结点添加.删除:链表正向遍历和反向遍历.链表排序.判断链表是否有环.是否相交.获取某一结点等. 二.概念: 链表: 一种重要的数据结构,HashM ...
- Java实现单链表的快速排序和归并排序
本文描述了LeetCode 148题 sort-list 的解法. 题目描述如下: Sort a linked list in O(n log n) time using constant space ...
- 数据结构——Java实现单链表
一.分析 单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素.链表中的数据是以结点来表示的,每个结点由元素和指针构成.在Java中,我们可以将单链表定义成一个类,单链表的基 ...
- Java实现单链表翻转
单链表翻转比方有例如以下链表: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZmVuZ3NoaXp0eQ==/font/5a6L5L2T/fontsize ...
- 用java实现单链表
对于一个单链表来说,要求有最基本的数据节点以及一些重要的方法. 方法应该有增删改查.定位.输出.获取链表长度.排序.链表读入.链表输出.下面是我用java写的单链表 public class List ...
随机推荐
- tensorboard学习笔记
TensorBoard 默认是不会记录每个节点的用时.耗费的内存大小等这些信息的,那么如何才能在图上显示这些信息呢?关键就是如下这些代码,主要就是在 sess.run() 中加入 options 和 ...
- [Antd-vue] Warning: You cannot set a form field before rendering a field associated with the value.
在用ant-design-vue的框架中,使用到了这种场景,就是点击编辑按钮,弹出modal模态框,渲染modal模态框中的form表单页面,并给表单赋值,但是在给表单赋值的时候,总是会报错. 错误提 ...
- 【面试题资源共享】一文总结最高频软件测试|sq|语句|思维发散|计算机基础|Linux|测试用例|接口测试|等技术面试题
思维发散 1.一个球, -把尺子长度是球直径的2/3,怎样测出半径?2.四枚硬币,花面朝上,每次翻转三个,几次可以将四枚硬币变为字面朝上?3. U2合唱团在1 7分钟内赶到演唱会现场问题?4.小明一家 ...
- OSCP Learning Notes - Exploit(7)
Pre-Exploit Password Attacks Tools: 1. ncrack Ncrack 0.6 ( http://ncrack.org )Usage: ncrack [Options ...
- webpack源码-打包资源输出到本地
webpack收集完依赖是怎么打包资源的呢? 入口compiler.js: this.applyPluginsParallel("make", compilation, err = ...
- xenomai内核解析之信号signal(二)---xenomai信号处理机制
xenomai信号 上篇文章讲了linux的信号在内核的发送与处理流程,现在加入了cobalt核,Cobalt内核为xenomai线程提供了信号机制.下面一一解析xenomai内核的信号处理机制. 1 ...
- Oracle11.2安装和完全卸载及卸载后重装等问题
官网:https://www.oracle.com/index.html 安装: 1.官网下载2.解压到同一个目录(database)3.运行安装4.如果提示系统版本低可在(database\stag ...
- APP自动化 -- 坐标获取和点击
一.获取元素坐标 二.点击坐标 1.driver的点击(这个可以实现多点同时点击) 1)执行 这个coordinate变量必须是一个list coordinate_list = [(0, 0), (1 ...
- 如何从Python负零基础到精通数据分析
一.为什么学习数据分析 1.运营的尴尬:运营人需要一个硬技能每个初入行的新人都会察觉到,运营是一个似乎并没有自己的核心竞争力和安全感的工作.因为每天的工作好像都被各种琐事所围绕,而只有一个主题是永恒不 ...
- https://blog.csdn.net/yongchaocsdn/article/details/53355296
https://blog.csdn.net/yongchaocsdn/article/details/53355296