JAVA中自己写双链表LinkedList

目录

双链表结构图

定义成员变量

设计内部类Node

无参构造方法

定义个简易的索引异常判断

查找、定义索引节点方法

一些功能性成员方法

1.addFirst

2.addLast

3.add

4.读值方法get

5.设值方法

6.头部删除removeFirst

7.尾部删除removeLast

 8.指定位置删除remove

完整源码(含注释解读)


双链表结构图

定义成员变量

//定义成员变量
    int size = 0;       //存放元素数
    Node<K> first;      //头节点
    Node<K> last;       //尾节点

设计内部类Node<K>

K为泛型

 //定义内部类Node<K>
    private static class Node<K>{
        //成员变量
        K item;         //定义K类型item 用来存储
        Node<K> left;   //定义左节点
        Node<K> right;  //定义右节点

        //成员方法
        Node(Node<K> left,K data,Node<K> right){
            this.item = data;
            this.left = left;
            this.right = right;
        }
    }

无参构造方法

//无参构造方法
    public MyLinkedList() {
    }

定义个简易的索引异常判断

//索引异常报错
    private void indexWrong(int index){
        if(!isIndexOk(index)){
            throw new RuntimeException("错误啦");
        }else
            return ;
    }

    //定义个boolean类型方法  判断索引是否合法
    private boolean isIndexOk(int index){
        return index >= 0 && index < size;  //索引大于0 并且索引永远比size小只有在空的时候相等都为0,判断了索引是否合法
    }

查找、定义索引节点方法

//查找、定义索引节点
    Node<K> node(int index){
        if(index < (size >> 1)){
            Node<K> x = first;
            for (int i = 0; i < index; i++) {
                x = x.right;
            }
            return x;
        }else {
            Node<K> x = last;
            for (int i = size-1; i > index; i--) {
                x = x.left;
            }
            return x;
        }
    }

一些功能性成员方法

1.addFirst

功能:在头部添加

2.addLast

功能:在尾部添加

3.add

功能:指定位置添加

官方原码解读:

自己的实现:

    //add方法   指定位置添加
    public void myAdd(int index,K k){
        indexWrong(index);      //判断索引合法性
        if(index == size){      //判断是否为空链表
            myAddFirst(k);
        }else {
            add(k,node(index));
        }
    }

    //myAdd添加实现的主要部分
    void add(K k,Node<K> after){
        final Node<K> before = after.left;      //before当作插入位置的前一个元素
        final Node<K> newNode = new Node<>(before,k,after);     //after当作插入位置的后一个元素
        after.left = newNode;
        if(before == null ){
            first = newNode;
        }else {
            before.right = newNode;     //前面有元素,则和插入的元素连接起来
        }
        size++;
    }

4.读值方法get

5.设值方法

6.头部删除removeFirst

7.尾部删除removeLast

 8.指定位置删除remove

测试:

完整源码(含注释解读)

public class MyLinkedList<K> {
    //定义成员变量
    int size = 0;       //存放元素数
    Node<K> first;      //头节点
    Node<K> last;       //尾节点

    //定义内部类Node<K>
    private static class Node<K>{
        K item;         //定义K类型item 用来存储
        Node<K> left;   //定义左节点
        Node<K> right;  //定义右节点

        //构造方法
        Node(Node<K> left,K data,Node<K> right){
            this.item = data;
            this.left = left;
            this.right = right;
        }
    }

    //无参构造方法
    public MyLinkedList() {
    }

    //查找、定义索引节点方法
    Node<K> node(int index){
        if(index < (size >> 1)){
            Node<K> x = first;
            for (int i = 0; i < index; i++) {
                x = x.right;
            }
            return x;
        }else {
            Node<K> x = last;
            for (int i = size-1; i > index; i--) {
                x = x.left;
            }
            return x;
        }
    }

    //索引异常报错
    private void indexWrong(int index){
        if(!isIndexOk(index)){
            throw new RuntimeException("错误啦");
        }else
            return ;
    }

    //定义个boolean类型方法  判断索引是否合法
    private boolean isIndexOk(int index){
        return index >= 0 && index < size;  //索引大于0 并且索引永远比size小只有在空的时候相等都为0,判断了索引是否合法
    }

    //addFirst方法  在头部添加
    public void myAddFirst(K k){
        final Node<K> f = first;        //存原来的头指针
        final Node<K> newNode = new Node<>(null,k,f);       //定义一个新节点(即要插入的节点)
        first = newNode;        //将新节点作为头指针
        if(f == null){      //f为null就是空链表,此时插入一个又是头又是尾
            last = newNode;
        }else {
            f.left = newNode;     //新节点插在了原来的头节点前面,f.left就是原来头节点向左指向插入的新节点
        }
        size++;
    }



    //addLast方法  在尾部添加
    public void myAddLast(K k){
        final Node<K> l = last;     //存原来的尾指针
        final Node<K> newNode = new Node<>(l,k,null);       //定义一个新节点(即要插入的节点)
        last = newNode;     //将新节点作为尾指针
        if(l == null){      //l为null就是空链表,此时插入一个又是头又是尾
            first = newNode;
        }else {
            l.right = newNode;  //新节点插在了原来的尾节点后面,l.right就是原来尾节点向右指向插入的新节点
        }
        size++;
    }

    //add方法   指定位置添加
    public void myAdd(int index,K k){
        indexWrong(index);      //判断索引合法性
        if(index == size){      //判断是否为空链表
            myAddFirst(k);
        }else {
            add(k,node(index));
        }
    }

    //myAdd添加实现的主要部分
    void add(K k,Node<K> after){
        final Node<K> before = after.left;      //before当作插入位置的前一个元素
        final Node<K> newNode = new Node<>(before,k,after);     //after当作插入位置的后一个元素
        after.left = newNode;
        if(before == null ){
            first = newNode;
        }else {
            before.right = newNode;     //前面有元素,则和插入的元素连接起来
        }
        size++;
    }





    //读值方法
    public K myGet(int index){
           indexWrong(index);
            return node(index).item;
        }


    //设值方法
    public K mySet(int index,K k){
        indexWrong(index);
        Node<K> x = node(index);
        K oldK = x.item;
        x.item = k;
        return oldK;
    }



    //删除头部
    public K myRemoveFirt(){
        final Node<K> f = first;    //f就是要删除的头节点
        if(f == null){      //判断是否有头节点,没有头节点那么就是空链表
            throw new RuntimeException("链表为空,无法删除!");
        }
        return removeFirst(f);
    }

    //删除头部的主要部分
    private K removeFirst(Node<K> f){
        final K data = f.item;      //存储删除的数据
        final Node<K> after = f.right;  //删除的头节点指向的后一个元素after
        f.item = null;      //将数据删除
        f.right = null;     //将删除的头节点与后面元素的连接断开,此时已删除,方便GC回收这个删除的节点
        first = after;      //后一个元素成为新的头节点
        if(after == null){
            last = null;    //如果删除了头节点后,后面没有元素了,那么尾节点就为空,即链表中现在没有元素
        }else {     //删除后,后面还有元素
            after.left = null;      //将后面元素的前端指向null,即成为了新的头节点
        }
        size-- ;
        return data;    //返回删除的数据
    }



    //删除尾部
    public K myRemoveLast(){
        final Node<K> l = last;     //l就是要删除的尾节点
        if(l == null){
            throw new RuntimeException("链表为空,无法删除!");
        }
        return removeLast(l);
    }
    //尾部删除的主要部分
    private K removeLast(Node<K> l){
        final K data = l.item;      //存储删除的数据
        final Node<K> before = l.left;  //删除的尾节点前面的一个元素 before
        l.item = null;      //将数据删除
        l.left = null;      //将删除的尾节点与前面元素的连接断开,此时已删除,方便GC回收这个删除的节点
        last = before;      //前一个元素称为新的尾节点
        if(before == null){
            first = null;   //如果删除了尾节点后,前面没有元素了,那么头节点就为空,即链表中现在没有元素
        }else {     //删除后,前面还有元素
            before.right = null;  //将前面元素的后端指向null,即成为了新的尾节点
        }
        size--;
        return data;
    }

    //指定位置删除
    public K myRemove(int index){
        indexWrong(index);      //判断索引是否合法
        return remove(node(index));
    }

    //指定位置删除的主要部分
    private K remove(Node<K> index){
        final K data = index.item;      //存储要删除位置的数据
        final Node<K> before = index.left;  //before为插入位置前一个元素
        final Node<K> after = index.right;  //after为插入位置后一个元素

        if(before == null){
            first = after;      //如果前一个元素为null,即前面没有元素,那么删除的就是头节点,那么头节点删除后后面那个元素after就成为新的头节点
        }else {
            before.right = after;   //删除的元素的前后两个元素连接
            index.left = null;  //删除一个节点要把和前后两个元素的连接都断掉,这一步是断掉和前面元素的连接
        }

        if(after == null){
            last = before;      //如果后一个元素为null,即后面没有元素,那么删除的就是尾节点,那么尾节点删除后前面那个元素before就成为新的尾节点
        }else {
            after.left = before;     //删除的元素的前后两个元素连接
            index.right = null;      //删除一个节点要把和前后两个元素的连接都断掉,这一步是断掉和后面元素的连接
        }
        index.item = null;      //删除数据
        size--;
        //此时已完全删除
        return data;        //返回删除的数据
    }
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值