数据结构——链表的实现(Java版)

这篇具有很好参考价值的文章主要介绍了数据结构——链表的实现(Java版)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一、链表

二、代码实现

1.创建结点

2.构造函数

3.链表的相关属性

4.添加虚拟节点

5.判断链表是否为空

6.添加方法

(1)在头部添加

(2)在尾部添加

(3)在索引位置添加

(4)对头插法和尾插法代码进行简化(调用任意位置添加的方法)

7.打印链表(遍历,重写toString方法)

8.获取链表元素个数(链表长度)

9.获取链表结点

(1)获取头结点

(2)获取尾结点

(3)获取指定位置结点

10.判断结点是否存在

11.删除结点

(1)删除头结点

(2)删除尾节点

(3)在指定位置删除结点

(4)删除元素

(5)不使用虚拟节点删除


一、链表

链表是真正的动态数据结构,也是最简单的动态数据结构。

动态数据结构还有:二叉树,trie等

优点:不需要处理固定容量的问题,真正的动态

缺点:丧失了随机访问的能力

学习链表有助于更深理解引用和递归

二、代码实现

1.创建结点

使用内部类来创建结点

//使用内部类——创建结点
    class Node<T>{
        T data;//节点本身
        Node next;//指向下个节点

2.构造函数

两个构造函数(传入的参数不同)

public Node(T data){
            this.data=data;
            this.next=null;
        }

        public Node(T data,Node next){
            this.data=data;
            this.next=null;
        }

    }

3.链表的相关属性

头结点和结点个数(链表长度)

private Node head;//头结点
    private int size;//表示链表中有多少个结点

4.添加虚拟节点

public SelfLinkedList(){
        //创建一个虚拟头结点
        Node dummyHead=new Node(Integer.MIN_VALUE);
        this.head=dummyHead;
        this.size=0;

        dummyHead.next=head;
    }

5.判断链表是否为空

public boolean isEmpty(){
        return this.size==0;
    }

6.添加方法

(1)在头部添加

public void addHead(T data){
        //创建一个节点
        Node node= new Node(data);
        //挂接
        node.next=this.head;
        this.head=node;
        //更新size
        this.size++;
    }

(2)在尾部添加

public void addTail(T data){
        Node node=new Node(data);
        //针对空链表做处理
        if(this.head==null){
            this.head=node;
            this.size++;
            return;
        }
        Node curNode=this.head;
        while(curNode.next!=null){
            curNode=curNode.next;
        }
        curNode.next=node;
        this.size++;
    }

(3)在索引位置添加

//在任意位置添加
    public void add(int index,T data){
        //判断index是否有效
        if(index<0||index>this.size){
            throw new IllegalArgumentException("index is invalid");
        }
        //创建一个节点
        Node node= new Node(data);
        //特殊处理1:如果索引为0,
        if(index==0){
            this.head=new Node(data,this.head);
            this.size++;
            return;
        }
        //特殊处理2:链表为空(异常已抛出)
        //找前驱结点,从头开始找,让索引移动index-1次
        Node pre=this.head;
        for(int i=1;i<=index;i++){
            pre=pre.next;
        }
        //开始进行结点的挂接
        node.next=pre.next;
        pre.next=node;
        this.size++;
    }

(4)对头插法和尾插法代码进行简化(调用任意位置添加的方法)

//在头部添加
    public void addHead(T data){
       
        add(0,data);
    }

    //在尾部添加
    public void addTail(T data){
        
        add(this.size,data);
    }

7.打印链表(遍历,重写toString方法)

//打印整个链表
    @Override
    public String toString() {
        //从this。head开始一直向后
        Node curNode=this.head.next;
        StringBuilder sb=new StringBuilder();
        while(curNode!=null){
            sb.append(curNode.data+"-->");
            curNode=curNode.next;
        }
        sb.append("null");
        return sb.toString();
    }

8.获取链表元素个数(链表长度)

 //获取链表中元素的个数
    public int getSize(){
        return this.size;
    }

9.获取链表结点

(1)获取头结点

//获取链表的头结点
    public Optional getFirst(){
        if(this.head.next==null){
            return Optional.empty();
        }
        return Optional.ofNullable(this.head.next.data);
    }

(2)获取尾结点

//获取链表的尾结点
    public Optional getLast(){
        if(this.head.next==null){
            return Optional.empty();
        }
        Node<T> curNode=this.head;
        while(curNode.next!=null){
            curNode=curNode.next;
        }
        return Optional.of(curNode.data);
    }

(3)获取指定位置结点

 //从链表中获取任意位置的结点
    public T get(int index) {
        if (index < 0 || index >= this.size) {
            throw new IllegalArgumentException("index is invalid");
        }
        Node<T> curNode = this.head.next;
        int i = 0;
        while (i < index) {
            curNode = curNode.next;
            i++;
        }
        return curNode.data;
    }

10.判断结点是否存在

 //从链表中查找指定位置元素是否存在
    public boolean contains(T data) {
        Node curNode = this.head.next;
        while (curNode != null) {
            if (curNode.data.equals(data)) {
                return true;
            }
        }
        return false;
    }

11.删除结点

(1)删除头结点

 //从链表的头部删除元素
    public T removeHead() {
        if (this.isEmpty()) {
            return null;
        }
        Node<T> delNode = this.head.next;
        this.head.next = delNode.next;
        delNode.next = null;
        //更新size;
        this.size--;
        return delNode.data;
    }

(2)删除尾节点

//链表的尾部删除元素
    public T removeTail() {
        if (this.isEmpty()) {
            return null;
        }
        Node<T> pre = this.head;
        while (pre.next.next != null) {
            pre = pre.next;
        }
        Node<T> delNode = pre.next;
        pre.next = delNode.next;
        delNode.next = null;
        //更新size;
        this.size--;
        return delNode.data;
    }

(3)在指定位置删除结点

//删除任意位置的结点
    public T remove(int index){
        if(index<0||index>=this.size){
            throw new IllegalArgumentException("index is invalid");
        }
        //找删除结点的前驱
        Node<T>pre=this.head;
        int i=0;
        while(i<index){
            pre=pre.next;
            i++;
        }
        Node<T>delNode=pre.next;
        pre.next=delNode.next;
        delNode.next=null;
        this.size--;
        return delNode.data;
    }

(4)删除元素

//根据值从链表中删除元素
    public int removeByValue(T value){
        int count=0;
        //定义前驱结点
        Node<T>pre=this.head;
        while(pre.next!=null){
            Node curNode=pre.next;
            if(curNode.data.equals(value)){
                pre.next=pre.next.next;
                curNode.next=null;
                this.size--;
                count++;
            }else{
                pre=pre.next;
            }
        }
        return count;
    }

(5)不使用虚拟节点删除

//不使用虚拟头结点
    public int removeByValue2(T val){
        int count = 0;
        Node<T> realHead = this .head.next;

        while(realHead!=null&&realHead.data.equals(val)){
            realHead=realHead.next;
            this.size--;
            count++;
        }

        //判断链表是否为空
        if(realHead==null){
            return count;
        }

        //头结点不是删除的点
        Node pre = realHead;
        while(pre.next!=null){
            Node<T> delNode = pre.next;
            if(delNode.equals(val)){
                pre.next = delNode .next;
                delNode.next = null;
                this.size--;
                count++;
            }else{
                pre = pre .next;
            }
        }
        return count;
    }

三、完整代码文章来源地址https://www.toymoban.com/news/detail-817690.html

package com.algo.lesson.lesson03;

import java.util.Optional;
import java.util.Random;

public class SelfLinkedList<T> {
    //使用内部类——创建结点
    class Node<T> {
        T data;//节点本身
        Node next;//指向下个节点

        public Node(T data) {
            this.data = data;
            this.next = null;
        }

        public Node(T data, Node next) {
            this.data = data;
            this.next = null;
        }

    }

    //链表相关的属性和方法
    private Node head;//头结点
    private int size;//表示链表中有多少个结点

    public SelfLinkedList() {
        //创建一个虚拟头结点
        Node dummyHead = new Node(Integer.MIN_VALUE);
        this.head = dummyHead;
        this.size = 0;

        dummyHead.next = head;
    }

    //判断链表是否为空
    public boolean isEmpty() {
        return this.size == 0;
    }

    //向链表中添加结点
    //在头部添加
    public void addHead(T data) {
        /*//创建一个节点
        Node node= new Node(data);
        //挂接
        node.next=this.head;
        this.head=node;
        //更新size
        this.size++;*/
        add(0, data);
    }

    //在尾部添加
    public void addTail(T data) {
        /*Node node=new Node(data);
        //针对空链表做处理
        if(this.head==null){
            this.head=node;
            this.size++;
            return;
        }
        Node curNode=this.head;
        while(curNode.next!=null){
            curNode=curNode.next;
        }
        curNode.next=node;
        this.size++;*/
        add(this.size, data);
    }

    //在任意位置添加
    public void add(int index, T data) {
        //判断index是否有效
        if (index < 0 || index > this.size) {
            throw new IllegalArgumentException("index is invalid");
        }
        //创建一个节点
        Node node = new Node(data);
        //特殊处理1:如果索引为0,
        if (index == 0) {
            this.head = new Node(data, this.head);
            this.size++;
            return;
        }
        //特殊处理2:链表为空(异常已抛出)
        //找前驱结点,从头开始找,让索引移动index-1次
        Node pre = this.head;
        for (int i = 1; i <= index; i++) {
            pre = pre.next;
        }
        //开始进行结点的挂接
        node.next = pre.next;
        pre.next = node;
        this.size++;
    }

    //打印整个链表
    @Override
    public String toString() {
        //从this。head开始一直向后
        Node curNode = this.head.next;
        StringBuilder sb = new StringBuilder();
        while (curNode != null) {
            sb.append(curNode.data + "-->");
            curNode = curNode.next;
        }
        sb.append("null");
        return sb.toString();
    }

    //从链表中查找指定位置元素是否存在
    public boolean contains(T data) {
        Node curNode = this.head.next;
        while (curNode != null) {
            if (curNode.data.equals(data)) {
                return true;
            }
        }
        return false;
    }

    //获取链表中元素的个数
    public int getSize() {
        return this.size;
    }

    //获取链表的头结点
    public Optional getFirst() {
        if (this.head.next == null) {
            return Optional.empty();
        }
        return Optional.ofNullable(this.head.next.data);
    }

    //获取链表的尾结点
    public Optional getLast() {
        if (this.head.next == null) {
            return Optional.empty();
        }
        Node<T> curNode = this.head;
        while (curNode.next != null) {
            curNode = curNode.next;
        }
        return Optional.of(curNode.data);
    }

    //从链表中获取任意位置的结点
    public T get(int index) {
        if (index < 0 || index >= this.size) {
            throw new IllegalArgumentException("index is invalid");
        }
        Node<T> curNode = this.head.next;
        int i = 0;
        while (i < index) {
            curNode = curNode.next;
            i++;
        }
        return curNode.data;
    }

    //从链表的头部删除元素
    public T removeHead() {
        if (this.isEmpty()) {
            return null;
        }
        Node<T> delNode = this.head.next;
        this.head.next = delNode.next;
        delNode.next = null;
        //更新size;
        this.size--;
        return delNode.data;
    }

    //链表的尾部删除元素
    public T removeTail() {
        if (this.isEmpty()) {
            return null;
        }
        Node<T> pre = this.head;
        while (pre.next.next != null) {
            pre = pre.next;
        }
        Node<T> delNode = pre.next;
        pre.next = delNode.next;
        delNode.next = null;
        //更新size;
        this.size--;
        return delNode.data;
    }

    //删除任意位置的结点
    public T remove(int index){
        if(index<0||index>=this.size){
            throw new IllegalArgumentException("index is invalid");
        }
        //找删除结点的前驱
        Node<T>pre=this.head;
        int i=0;
        while(i<index){
            pre=pre.next;
            i++;
        }
        Node<T>delNode=pre.next;
        pre.next=delNode.next;
        delNode.next=null;
        this.size--;
        return delNode.data;
    }

    //根据值从链表中删除元素
    public int removeByValue(T value){
        int count=0;
        //定义前驱结点
        Node<T>pre=this.head;
        while(pre.next!=null){
            Node curNode=pre.next;
            if(curNode.data.equals(value)){
                pre.next=pre.next.next;
                curNode.next=null;
                this.size--;
                count++;
            }else{
                pre=pre.next;
            }
        }
        return count;
    }

    //不使用虚拟头结点
    public int removeByValue2(T val){
        int count = 0;
        Node<T> realHead = this .head.next;

        while(realHead!=null&&realHead.data.equals(val)){
            realHead=realHead.next;
            this.size--;
            count++;
        }

        //判断链表是否为空
        if(realHead==null){
            return count;
        }

        //头结点不是删除的点
        Node pre = realHead;
        while(pre.next!=null){
            Node<T> delNode = pre.next;
            if(delNode.equals(val)){
                pre.next = delNode .next;
                delNode.next = null;
                this.size--;
                count++;
            }else{
                pre = pre .next;
            }
        }
        return count;
    }

到了这里,关于数据结构——链表的实现(Java版)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【(数据结构)— 双向链表的实现】

    注意: 这里的 “带头” 跟前面我们说的 “头节点” 是两个概念,实际前面的在单链表阶段称呼不严 谨,但是为了同学们更好的理解就直接称为单链表的头节点。 带头链表里的头节点,实际为 “哨兵位” ,哨兵位节点不存储任何有效元素,只是站在这里“放哨 的” “哨

    2024年02月06日
    浏览(46)
  • 数据结构----链表介绍、模拟实现链表、链表的使用

    ArrayList底层使用连续的空间,任意位置插入或删除元素时,需要将该位置后序元素整体往前或者往后搬移,故时间复杂度为O(N) 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。 增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后

    2024年02月21日
    浏览(51)
  • Java 数据结构篇-实现双链表的核心API

    🔥博客主页:  小扳_-CSDN博客 ❤感谢大家点赞👍收藏⭐评论✍       文章目录         1.0 双链表的说明         1.1 双链表 - 创建         1.2 双链表 - 根据索引查找节点         1.3 双链表 - 根据索引插入节点         1.4 双链表 - 头插节点         1.5 双链表 - 尾插

    2024年02月04日
    浏览(59)
  • 数据结构:双向链表的实现(C实现)

    个人主页 : 个人主页 个人专栏 : 《数据结构》 《C语言》 本篇博客,将要实现的是 带头双向循环链表 ,该结构实现尾插,尾删只需要O(1)的时间复杂度。 其结构如下所示: 既然要实现的链表是双向循环的,那么对于指针域,我们就需要 指向节点上一个的指针 和 指向节点

    2024年02月14日
    浏览(52)
  • 数据结构中链表的实现以及排序

    本期和大家主要分享的是关于数据结构中双向链表的实现过程,那么话不多说,来具体看看吧! 来分析一下,这里呢定义了一个int的数据类型,表明整个链表存放的是整形的数据;其次定义了链表节点的数据类型,其中包括了此节点存放的数据以及链接向下一个节点的地址;

    2024年02月02日
    浏览(45)
  • Java 数据结构篇-用链表、数组实现栈

    🔥博客主页: 【 小扳_-CSDN博客】 ❤感谢大家点赞👍收藏⭐评论✍    文章目录         1.0 栈的说明         2.0 用链表来实现栈         2.1 实现栈 - 入栈方法(push)         2.2 实现栈 - 出栈(pop)         2.3 实现栈 - 查看栈顶元素(peek)         2.4 实

    2024年02月05日
    浏览(58)
  • 数据结构(Java实现)LinkedList与链表(上)

    链表 逻辑结构 无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如哈希桶、图的邻接表等等。 无头双向链表:在Java的集合框架库中LinkedList底层实现就是无头双向循环链表。 链表的实现 创建一个链表 遍历单链表 、 得到

    2024年02月11日
    浏览(53)
  • 数据结构(Java实现)LinkedList与链表(下)

    ** ** 结论 让一个指针从链表起始位置开始遍历链表,同时让一个指针从判环时相遇点的位置开始绕环运行,两个指针都是每次均走一步,最终肯定会在入口点的位置相遇。 LinkedList的模拟实现 单个节点的实现 尾插 运行结果如下: 也可以暴力使用 全部代码 MyLinkedList IndexOut

    2024年02月11日
    浏览(46)
  • 【数据结构】 链表简介与单链表的实现

    在【数据结构】 ArrayList简介与实战中我们已经熟悉了ArrayList的使用,并且进行了简单模拟实现。通过源码知道,ArrayList底层使用数组来存储元素 由于其底层是一段连续空间, 当在ArrayList任意位置插入或者删除元素时,就需要将后序元素整体往前或者往后搬移,时间复杂度为

    2024年02月12日
    浏览(202)
  • Java 数据结构篇-用链表、数组实现队列(数组实现:循环队列)

    🔥博客主页: 【 小扳_-CSDN博客】 ❤感谢大家点赞👍收藏⭐评论✍   文章目录         1.0 队列的说明         1.1 队列的几种常用操作         2.0 使用链表实现队列说明         2.1 链表实现队列         2.2 链表实现队列 - 入栈操作         2.3 链表实现队

    2024年02月05日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包