美文网首页
【Java基础】自己实现一个LinkedList容器

【Java基础】自己实现一个LinkedList容器

作者: 灰色孤星 | 来源:发表于2018-10-07 13:44 被阅读0次

源代码:https://gitee.com/AgentXiao/Collection

一、LinkedList底层实现

LinkedList的底层是双向链表。该链表由多个节点组成。

package pri.xiaowd.demo02;

/**
 * @ClassName Node
 * @Description 节点
 * @Author xwd
 * @Date 2018/10/7 11:07
 */
public class Node {
    private Node previous;//上一个节点
    private Object obj;//存储的对象
    private Node next;//下一个节点

    public Node() {

    }

    public Node(Node previous, Object obj, Node next) {
        this.previous = previous;
        this.obj = obj;
        this.next = next;
    }

    public Node getPrevious() {
        return previous;
    }

    public void setPrevious(Node previous) {
        this.previous = previous;
    }

    public Object getObj() {
        return obj;
    }

    public void setObj(Object obj) {
        this.obj = obj;
    }

    public Node getNext() {
        return next;
    }

    public void setNext(Node next) {
        this.next = next;
    }
}

2、自己实现一个LinkedList
(1)在链表中,比较重要的是第一个节点和最后一个节点。

    private Node first;//第一个节点
    private Node last;//最后一个节点

(2)add(Object obj)方法

add(Object obj)
    /**
     * @MethodName add
     * @Descrition 添加一个节点
     * @Param [object]
     * @return void
     */
    public void add(Object object){
        Node node = new Node();
        //如果第一个链表都是空的,说明添加的是第一个节点
        if(first == null){
            node.setPrevious(null);  //第一个节点的上一个节点是null
            node.setObj(object);  //第一个节点的内容
            node.setNext(null);  //第一个节点的下一个节点也暂时是空的

            first = node;  //添加了第一个节点之后第一个和最后一个都是新添加的
            last = node;
        }else{  //直接在最后一个节点的后面添加
            node.setPrevious(last);   //新添加的节点的上一个节点是之前的最后一个
            node.setObj(object);  //新添对象
            node.setNext(null);  //新添加的节点的下一个节点是null

            last.setNext(node);  //形成链表,原先的最后一个的下一个节点设置为新增的节点
            last = node;  //将最后一个节点设置为新增的节点
        }
        size++;  //长度+1
    }

(3)我们来测试一下

public static void main(String[] args) {
        MyLinkedList mll = new MyLinkedList();
        mll.add("aaa");
        mll.add("bbb");
        System.out.println(mll.size);
    }

得到如果示意图:

debug示意图

(4)get(int index):因为链表是没有下标的,所以只能从头开始一个一个遍历。
首先需要进行索引值越界判断

    /**
     * @MethodName rangeCheck
     * @Descrition 索引检测
     * @Param [index]
     * @return void
     */
    private void rangeCheck(int index){
        if(index < 0 || index >= size){
            throw new RuntimeException("你输入的索引值不在范围之内!");
        }
    }

获取一个对象,特别需要注意循环遍历的时候什么时候就能得到想要的对象

    /**
     * @MethodName getNode
     * @Descrition 找到指定位置的节点
     * @Param [index]
     * @return pri.xiaowd.demo02.Node
     */
    public Node getNode(int index){
        Node temp = null;
        if(first != null){
            temp = first;
            for(int i=0;i<index;i++){
                temp = temp.getNext();
            }
        }
        return temp;
    }
    /**
     * @MethodName get
     * @Descrition 获取指定位置节点的内容
     * @Param [index]
     * @return java.lang.Object
     */
    public Object get(int index){
        rangeCheck(index);
        Node temp = getNode(index);
        return temp.getObj();
    }

(5)移除指定位置的节点remove(int index)

remove.png
    /**
     * @MethodName remove
     * @Descrition 移除指定索引位置的节点
     * @Param [index]
     * @return void
     */
    public void remove(int index){
        rangeCheck(index);
        //找到索引位置的节点
        Node temp = getNode(index);
        if(temp != null){
            Node upNode = temp.getPrevious();
            Node downNode = temp.getNext();
            upNode.setNext(downNode);
            downNode.setPrevious(upNode);
            size -- ;
        }
    }

(6)add(int index,Object obj)

add(int index,Object obj) index=1的情况
    /**
     * @MethodName add
     * @Descrition 在指定位置插入对象
     * @Param [index, obj]
     * @return void
     */
    public void add(int index,Object obj){
        rangeCheck(index);
        Node temp = getNode(index);//得到索引位置的节点

        Node newNode = new Node();//创建新的节点
        newNode.setObj(obj);

        if(index == 0){ //如果想在第一个位置插入,不考虑索引位置的节点是否为空
            newNode.setPrevious(null);
            newNode.setNext(temp);
            temp.setPrevious(newNode);
            first = newNode;
        }else{
            if(temp != null) {  //实际上经过了索引检测之后,temp不会为空
                Node upNode = temp.getPrevious();//得到上一个节点
                upNode.setNext(newNode);
                newNode.setPrevious(upNode);
                newNode.setNext(temp);
                temp.setPrevious(newNode);
            }
        }
        size++;
    }

(7)set(int index,Object obj)

set(int index,Object obj)
    /**
     * @MethodName set
     * @Descrition 在指定的索引位置替换对象
     * @Param [index, obj]
     * @return void
     */
    public void set(int index,Object obj){
        rangeCheck(index);
        Node temp = getNode(index);//得到索引位置的节点

        Node newNode = new Node();//创建新的节点
        newNode.setObj(obj);

        if(index == 0){
            newNode.setPrevious(null);
            newNode.setNext(temp.getNext());
            temp.getNext().setPrevious(newNode);
            first = newNode;
        }else if(index == size-1){
            newNode.setNext(null);
            newNode.setPrevious(temp.getPrevious());
            temp.getPrevious().setNext(newNode);
            last = newNode;
        }else{
            Node upNode = temp.getPrevious();
            Node downNode = temp.getNext();
            upNode.setNext(newNode);
            newNode.setPrevious(upNode);
            newNode.setNext(downNode);
            downNode.setPrevious(newNode);
        }
    }

(8)remove(Object obj)

remove(Object obj)
    /**
     * @MethodName getNode
     * @Descrition 根据obj查找对应的节点
     * @Param [obj]
     * @return pri.xiaowd.demo02.Node
     */
    public Node getNode(Object obj){
        Node temp = first;
        if(first != null){
            for(int i=0;i<size;i++){
                if(temp.getObj().equals(obj)){
                    return temp;
                }
                temp = temp.getNext();
            }
        }
        return temp;
    }
/**
     * @MethodName remove
     * @Descrition 移除指定的节点
     * @Param [obj]
     * @return void
     */
    public void remove(Object obj){
        Node node = getNode(obj);
        Node downNode = node.getNext();
        Node upNode = node.getPrevious();
        if(node.getPrevious() == null){  //如果是第一个节点
            downNode = node.getNext();
            downNode.setPrevious(null);
            first = downNode;
        }else if(node.getNext() == null){  //如果是最后一个节点
            upNode = node.getPrevious();
            upNode.setNext(null);
            last = upNode;
        }else{  //如果是中间的节点
            upNode.setNext(downNode);
            downNode.setPrevious(upNode);
        }
        size--;
    }

三、总结

最为重要的,是能够画出链表的图示,对着图示进行代码的编写。

【补充】细节完善
对于get(int index)方法,如果始终从0开始遍历话,当index较大时,效率太低。因此可以使用二分法进行拆分,提高效率。

    /**
     * @MethodName getNode
     * @Descrition 找到指定位置的节点
     * @Param [index]
     * @return pri.xiaowd.demo02.Node
     */
    public Node getNode(int index){
        Node temp = null;
        if(first != null){
            if(index < (size >> 1)){
                temp = first;
                for(int i=0;i<index;i++){
                    temp = temp.getNext();
                }
            }else{
                temp = last;
                for(int i=size-1;i>index;i--){
                    temp = temp.getPrevious();
                }
            }
        }
        return temp;
    }

相关文章

网友评论

      本文标题:【Java基础】自己实现一个LinkedList容器

      本文链接:https://www.haomeiwen.com/subject/ngflaftx.html