Java实现双链表的具体实现加注释

双向循环链表的节点里面包含前指针prev,指向下一个节点的指针next,和节点内容data。因为指向让用户去操作最外边的测试程序,所以用户不用知道有节点的存在,因此把节点设置为内部类。

首先用一个接口区罗列要实现的功能,主要包括增加节点,删除节点,判断该节点是否存在,判断链表的大小,判断链表是否为空,获取链表的内容等

 

interface ILink{//定义接口
    /**
     *  插入节点,
     * @param obj Object可以接收一切对象
     */
    void add(Object obj);
    /**
     *  //删除节点,用布尔值返回是否删除成功,
     * @param obj 要删除的节点
     * @return  1成功,0失败、
     */
    boolean remove(Object obj);

    /**
     * 修改指定位置的内容
     * @param index 指定位置
     * @param newData 新节点的内容
     * @return 返回之前节点的内容
     */
    Object set(int index,Object newData);

    /**
     * 获取指定节点的内容
     * @param index  指定节点
     * @return 节点内容
     */
    Object get(int index);

    /**
     * 判断链表中是否穿在该节点
     * @param data 节点内容
     * @return  返回-表示不存在该节点
     */
    int contains(Object data);

    /**
     * 求链表的大小
     * @return 返回链表的长度
     */
    int size();

    /**
     * 清空链表
     */
    void clear();

    /**
     * 将链表转化为数组
     * @return 返回节点内容数组
     */
    Object[] toArray();

    /**
     * 打印链表
     */
    void print();
}

定义一个类去实现接口里面的具体功能。各个函数的具体实现以及实现原理都在代码后边备注了。

class LinkImpl implements ILink{//定义一个类 ,继承接口,并实现它
    private Node head;
    private Node last;
    private int size;
    private class Node{//定义节点对外部不可见
        private Node prev;
        private Node next;
        private Object data;
        public Node(Node prev,Node next,Object data){
            this.prev=prev;
            this.next=next;
            this.data=data;
        }
    }
    @Override
    public void add(Object obj){
        Node temp=this.last;//让temp指向最后一个节点
        //让新节点的prev指向最后一个节点,让next指针为null,把新增的节点内容obj给data
        Node newNode=new Node(temp,null,obj);
        this.last=newNode;//让最后一个指针指向newNode

        if(this.head==null){//判断头结点是否为空
            this.head=newNode;//为空,头结点节等于新节点
        }else{//不为空,temp的下一个节点等于新节点
            temp.next=newNode;
        }
        this.size++;//链表的大小加一
    }

    @Override
    public boolean remove(Object obj) {
        if(obj==null){//如果输出对象为空
            for(Node temp=head;temp!=null;temp=temp.next){
                if(temp.data==null){//找到内容为空的对象
                    unLink(temp);//删除对象
                    return true;
                }
            }
        }else{//删除内容不为空
            for(Node temp=head;temp!=null;temp=temp.next){
                if(obj.equals(temp.data)){//判断删除内容个和链表内容是否一致
                    unLink(temp);//删除对象
                    return true;//删除成功
                }
            }
        }
        return false;//删除失败
    }

    @Override
    public Object set(int index, Object newData) {
        if(!isLinkIndex(index)){//判断节点是否存在,不存在返回null
            return null;
        }
        Object element=node(index).data;//获取该节点的内容
        node(index).data=newData;//更改 节点的内容
        return element;//返回更改前的节点
    }

    @Override
    public Object get(int index) {
        if(!isLinkIndex(index)){//判断节点是否存在,不存在返回null
            return null;
        }
        return node(index).data;//节点存在返回他的内容
    }

    @Override
    public int contains(Object data) {
        int i=0;
        if(data==null){//当data等于空时,直接遍历一遍看看里面有没有data==null
            for(Node temp=head;temp!=null;temp=temp.next){
                if(temp.data==null){//找到temp.data等于null是返回i
                    return i;
                }
                i++;//继续向后寻找
            }
        }else{//data不等于空时
            for(Node temp=head;temp!=null;temp=temp.next){
                if(data.equals(temp.data)){//用equals方法判断内容是否相等
                    return i;//相等返回i
                }
                i++;
            }
        }
        return -1;//不存在返回-1
    }

    @Override
    public int size() {
        return this.size;//this表示调用当前对象
    }

    @Override
    public void clear() {
        for(Node temp=head;temp!=null;){
            Node flag=temp.next;//提前保存下一个节点
            temp.prev=temp=temp.next=null;//让节点的三个部分都为null
            temp=flag;//让temp等于下一个节点
            this.size--;//清空一个节点链表的大小减一

        }
    }

    @Override
    public Object[] toArray() {
        Object[] result=new Object[size];//定义一个对象数组
        int i=0;
        for(Node temp=head;temp!=null;temp=temp.next){
            //定义一个temp等于头节点,区便利链表
            result[i++]=temp.data;//把temp的值给对象数组
        }
        return result;//返回对象数组
    }

    @Override
    public void print() {
        Object[] data =this.toArray();
        for(Object temp:data){//foreach循环输出内容
            System.out.println(temp);
        }
    }
    private boolean isLinkIndex(int index){
        //判断这个节点是否在这个链表里
        return index>=0&&index<size;
    }
    private Node node(int index){//在链表中找这个节点,并返回该节点
        if(index<(size>>1)){//判断这个节点是否在前半部分
            Node temp=head;
            for(int i=0;i<index;i++){
                temp=temp.next;//向后循环直到等于index
            }
            return temp;
        }
        Node temp=this.last;//节点在后半部分
        for(int i=size-1;i>index;i--){//节点从最后一个向前数,到index时停止
            temp=temp.prev;//向前循环直到等于index
        }
        return temp;
    }
private void unLink(Node node){//删除节点
        Node prev =node.prev;
        Node next=node.next;
        if(prev==null){//删除头结点
            this.head=next;//让head等于next
        }else{
            prev.next=next;//让前一个指针的next指向下一个节点
            node.prev=null;//让前节点的prev=null
        }
        if(next==null){//删除尾节点
            this.last=prev;//让他的尾节点等于他前一个节点
        }else{
            next.prev=prev;//next的前指针prev等于前一个节点
            node.next=null;//让node 的下一个节点为空
        }
        node.data=null;//把节点的内容置空
        this.size--;//链表的大小减一
}
}

测试函数

public class Link {
    public static void main(String[] agrs){

        ILink link = new LinkImpl();
        link.add("火车头");
        link.add("车厢1");
        link.add("车厢2");
        link.add(null);
        link.add("车厢尾");
        link.print();
        System.out.println();
        link.remove("火车头");
        link.print();
        System.out.println();

        link.remove("车厢尾");
        link.print();
        System.out.println();

        link.remove(null);
        link.remove("哈哈哈");
        link.print();
    }
}

 

 

 

 

 

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是Java链表的实现代码,包含详细的中文注释: ```java // 定义一个链表节点类 public class ListNode { int val; // 当前节点的值 ListNode next; // 指向下一个节点的指针 // 构造函数 public ListNode(int val) { this.val = val; this.next = null; } } // 定义一个链表类 public class LinkedList { ListNode head; // 链表头节点 // 构造函数 public LinkedList() { this.head = null; } // 在链表末尾添一个节点 public void addAtTail(int val) { ListNode newNode = new ListNode(val); if (head == null) { head = newNode; // 如果链表为空,则新节点为头节点 } else { ListNode cur = head; while (cur.next != null) { cur = cur.next; // 找到链表的最后一个节点 } cur.next = newNode; // 在最后一个节点的后面添新节点 } } // 在链表头部添一个节点 public void addAtHead(int val) { ListNode newNode = new ListNode(val); newNode.next = head; // 将新节点的 next 指针指向原头节点 head = newNode; // 将新节点设为头节点 } // 在指定位置添一个节点 public void addAtIndex(int index, int val) { if (index <= 0) { addAtHead(val); // 如果插入位置为 0 或负数,则在头部插入 return; } ListNode newNode = new ListNode(val); ListNode cur = head; int i = 0; while (cur != null && i < index - 1) { cur = cur.next; i++; } if (cur == null) { return; // 如果插入位置超出链表长度,则不插入 } newNode.next = cur.next; cur.next = newNode; } // 删除指定位置的节点 public void deleteAtIndex(int index) { if (index < 0) { return; // 如果删除位置为负数,则不删除 } if (index == 0) { head = head.next; // 如果要删除的是头节点,则将头节点指向下一个节点 return; } ListNode cur = head; int i = 0; while (cur != null && i < index - 1) { cur = cur.next; i++; } if (cur == null || cur.next == null) { return; // 如果删除位置超出链表长度,则不删除 } cur.next = cur.next.next; } // 获取指定位置的节点值 public int get(int index) { if (index < 0) { return -1; // 如果获取位置为负数,则返回 -1 } ListNode cur = head; int i = 0; while (cur != null && i < index) { cur = cur.next; i++; } if (cur == null) { return -1; // 如果获取位置超出链表长度,则返回 -1 } return cur.val; } } ``` 以上代码实现了链表的基本操作,包括在末尾、头部、指定位置添节点,删除指定位置的节点以及获取指定位置的节点值。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值