java 实现一个不带头节点的单链表 实现其增删查改功能

学一学单链表

描述

一组任意储存单元(可连续、可不连续)组成的线性表

特点

因为不是连续存储结构,所以需要再存储单元的元素中存储对应的逻辑关系(即存储它后续单元的地址)

结构图

在这里插入图片描述

循环截至条件

节点的指针指向是否等于NULL

JAVA代码实现

package com.example.demo.data;

import java.util.Objects;

/**
 * @author tm
 * @date 2021-06-21 15:42
 * @description java 实现一个不带头节点的单链表 (下标从0开始) 并实现其增删查改功能
 * |操作             |最好时间复杂度|最坏时间复杂度
 * |新增             |O(1)        |  O(n)
 * |删除第index个元素 |O(1)        |  O(n)
 * |根据数据删除      |O(1)        |  O(n)
 * |根据index查询    |O(1)        |  O(n)
 * |根据数据查询     |O(1)        |  O(n)
 * |替换第n个元素    |O(1)        |  O(n)
 * |替换旧的元素     |O(1)        |  O(n)
 * <p>
 * 理解:
 * 插入删除比较频繁 只有第一次查找数据的时候O(n) 后面插入删除的操作都是O(1)
 */
public class SingleLinkList<T> {

    public static void main(String[] args) {

        SingleLinkList<Object> listNode = new SingleLinkList<>();
        System.out.println("======新增=====");
        System.out.println("增加前元素情况:" + listNode.toString());
        //增 处理空链表的情况 在找最后一个向后引用为空的节点赋值
        System.out.println("增加前长度:" + listNode.count);
        for (int i = 0; i < 10; i++) {
            listNode.add(i);
        }
        System.out.println("增加前长度:" + listNode.count);
        System.out.println("增加后元素情况:" + listNode.toString());
        System.out.println("======删除=====");
        //删除 考虑0坐标的删除  然后前置节点的向后引用-->当前删除节点的向后引用
        Object removeByIndex = listNode.remove(9);
        System.out.println("通过下标删除的元素为:" + removeByIndex.toString());
        System.out.println("通过下标删除之后元素情况:" + listNode.toString());
        System.out.println("通过下标删除之后长度:" + listNode.count);
        //通过数据删除
        listNode.remove(new Integer("8"));
        System.out.println("通过数据删除之后元素情况:" + listNode.toString());
        System.out.println("通过数据删除之后长度:" + listNode.count);
        System.out.println("======查询=====");
        //通过下标查询
        System.out.println("通过下标查询" + listNode.get(7).data);
        //存的int 就必须用integer取
        System.out.println("通过数据查询" + listNode.get(1).data);
        System.out.println("======通过下标修改=====");
        System.out.println("通过下标替换数据替换前0标数据" + listNode.get(0).data);
        System.out.println("通过下标替换数据替换0标数据为100:" + listNode.replace(0, new Integer(100)));
        System.out.println("通过下标替换数据替换后0标数据" + listNode.get(0).data);
        System.out.println("======通过数据项修改=====");
        System.out.println("先查询是否包含数据1000是否存在:" + listNode.get(new Integer("1000")));
        System.out.println("通过数据项替换数据替将100替换为1000:" + listNode.replace(new Integer(100), new Integer(1000)));
        System.out.println("替换后查询数据1000是否存在:" + listNode.get(new Integer("1000")).data);
    }


    //链表长度
    private int count;
    //第一个节点
    private Node<T> root;

    public SingleLinkList() {
    }

    //检查下表范围
    private void checkPositionIndex(int index) {
        if (!isPositionIndex(index))
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

    private boolean isPositionIndex(int index) {
        return index >= 0 && index <= count - 1;
    }

    private String outOfBoundsMsg(int index) {
        return "Index: " + index + ", Count: " + (count - 1);
    }

    //节点元素内部类
    private static class Node<T> {
        //节点数据
        private T data;
        //下一个节点引用
        private Node<T> next;

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

        //---------增--------- 循环方式 || 递归方式
        //==========尾插法==========
        public void add(T data) {
            //循环方式
            Node<T> node = this;
            while (node.next != null) {
                node = node.next;
            }
            node.next = new Node<T>(data);
            //递归方式
//            if (this.next == null) {
//                this.next = new Node<T>(data);
//            }else {
//                this.next.add(data);
//            }

            //==========尾插法==========
        }

        //---------查---------
        public Node<T> get(int index) {
            Node<T> node = this;
            for (int i = 0; i < index; i++) {
//根本无需判断是否为空 因为限制了index的范围 不会导致node.index报NPE
//                if (node == null) {
//                    return null;
//                }
                node = node.next;
            }
            return node;
        }

        public T remove(int index) {
            Node<T> pre = this;
            //循环找到前置节点 前置节点不可能为空 因为目标节点不为空
            for (int i = 0; i < index - 1; i++)
                pre = pre.next;
            //获取目标节点 目标节点不可能为空 因为前面做了index < count 范围排查
            Node<T> current = pre.next;
            T data = current.data;
            pre.next = current.next;
            //help Gc
            current.next = null;
            current.data = null;
            return data;
        }

        public boolean remove(T data) {
            //定义2个变量 前置节点以及当前节点
            Node<T> pre = this;
            Node<T> current = pre.next;
            while (current != null) {
                if (Objects.equals(data, current.data)) {
                    //修改指向
                    pre.next = current.next;
                    //help GC
                    current.next = null;
                    current.data = null;
                    return true;
                }
                pre = pre.next;
                current = pre.next;
            }
            return false;
        }

        public Node<T> get(T data) {
            for (Node<T> node = this; node != null; node = node.next) {
                if (Objects.equals(data, node.data)) {
                    return node;
                }
            }
            return null;
        }
    }

    //新增
    void add(T data) {
        if (isEmpty()) {
            this.root = new Node<>(data);
        } else {
            //尾插法
            this.root.add(data);
            //头插法
//            Node<T> tNode = new Node<>(data);
//            tNode.next = this.root;
//            this.root = tNode;
        }
        //线性表长度加一
        this.count++;
    }

    //通过下标删除
    public T remove(int index) {
        //检查index 范围避免出现NPE
        checkPositionIndex(index);
        //判断链表是否为空
        if (isEmpty()) {
            return null;
        }
        T result;
        //移除元素
        if (index == 0) {
            Node<T> temp = this.root;
            result = this.root.data;
            this.root = root.next;
            //help GC
            temp.next = null;
            temp.data = null;
        } else {
            result = this.root.remove(index);
        }
        count--;
        return result;

    }

    //通过数据删除  找到第一个匹配元素 删除
    public void remove(T data) {
        //判断链表是否为空
        if (isEmpty()) {
            return;
        }
        //考虑首位的情况
        if (Objects.equals(data, this.root.data)) {
            Node<T> temp = root;
            root = root.next;
            //help GC
            temp.next = null;
            temp.data = null;
            this.count--;
        } else {
            boolean remove = this.root.remove(data);
            if (remove) {
                this.count--;
            }
        }

    }

    //查询 获取第n个元素 从0 开始
    public Node<T> get(int index) {
        //检查下标范围
        checkPositionIndex(index);
        //判断链表是否为空
        if (this.isEmpty()) {
            return null;
        }
        return this.root.get(index);
    }

    //查询 通过数据查找
    public Node<T> get(T data) {
        //判断链表是否为空
        if (this.isEmpty()) {
            return null;
        }
        return this.root.get(data);
    }

    //通过下标修改替换数据
    public boolean replace(int index, T data) {
        Node<T> tNode = this.get(index);
        if (null != tNode) {
            tNode.data = data;
            return true;
        }
        return false;
    }

    //新数据替换老数据
    public boolean replace(T oldData, T newData) {
        Node<T> tNode = this.get(oldData);
        if (null != tNode) {
            tNode.data = newData;
            return true;
        }
        return false;
    }

    @Override
    public String toString() {
        StringBuffer result = new StringBuffer();

        for (Node<T> node = this.root; node != null; node = node.next) {
            result.append(node.data);
            result.append(" ");
        }
        return result.toString();
    }

    //链表是否为空
    boolean isEmpty() {
        return count == 0 || this.root == null;
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值