集合(四)——ArrayList和LinkedList

集合框架

ArrayList与LinkedList

  • 相同点:
    • 都是List集合的常用的实现类。
    • 对集合中的元素操作的方法基本一致。
  • 不同点:
    • ArrayList底层实现是数组, 使用数组这种数据结构进行数据的存储。 LinkedList底层实现是双链表, 使用双链表这种数据结构进行数据的存储。
      ArrayList与LinkedList的使用场景:
  • 如果对集合中的元素, 增删操作不怎么频繁, 查询操作比较频繁。 使用ArrayList。
  • 如果对集合中的元素, 增删操作比较频繁, 查询操作不怎么频繁。 使用LinkedList。

LinkedList与链表

链表

  • 链表,其实是一种比较常见的数据结构。 增删效率比较高, 查询效率比较低。
  • 数据在链表中存储,是以节点为单位进行存储的。 节点之间在内存上是不连续的。 双向链表中的每一个节点, 除了记录了当前节点存储的元素之外, 还记录了上一个节点和下一个节点的地址。

模拟LinkedList中的方法

/**
 * @Author 昊
 * @Create 2020/4/20 18:24
 * @Description
 */
public class One {
    public static void main(String[] args) {
            MyLinkedList<String> myLinkedList=new MyLinkedList<>();
            myLinkedList.add("lily");
            myLinkedList.add("lucy");
            myLinkedList.add("tom");
            myLinkedList.add("jim");
            myLinkedList.add(1,"kelly");
            myLinkedList.remove(1);
            boolean b=myLinkedList.remove("lucy");
            String s=myLinkedList.get(1);
            int nub=myLinkedList.size();
            boolean b2=myLinkedList.contains("lucy");
            int index=myLinkedList.indexOf("lucy");
            myLinkedList.set(3,"kelly");
            System.out.println(myLinkedList);
            myLinkedList.clear();
            System.out.println(index);
            System.out.println(b2);
            System.out.println(nub);
            System.out.println(s);
            System.out.println(b);
            System.out.println(myLinkedList);
    }
}
//模拟LinkedList,并实现其中相关的方法
//主要是练习双向链表,因为LinkedList的底层实现是双向链表
class MyLinkedList<E>{
    //链表中元素以节点的形式存储

    //内部类,表示一个节点
    private  class Node{
        //表示这个节点需要存储的元素
        E element;
        //下一个节点地址
        Node next;
        //上一个节点地址
        Node previous;

        public Node(E element){
            this.element=element;
        }
    }
    //用来描述首节点
    private Node first;
    //用来描述尾节点
    private Node last;
    //用来描述节点数量
    private int count;

    /**
     * 向集合中添加元素
     * @param element 需要添加的元素
     */
    public void add(E element){
        //1、实例化一个节点,用来存储这个元素
        Node node = new Node(element);
        //2、将这个节点链接到链表尾部
        //2.1、若为空则该节点就作为头节点
        //2.2、若不空则链接到尾部
        if(count==0){
            this.first=node;
        }else{
            this.last.next=node;
            node.previous=this.last;
        }
        this.last=node;
        count++;
    }

    /**
     * 在指定索引位置之前添加节点
     * @param index  指定下标
     * @param element  要插入的元素
     */
    public void add(int index,E element){
        //初始化一个节点
        Node node=new Node(element);
            //如果在头部插入
            if(index==0){
                this.first.previous=node;
                node.next=this.first;
                this.first=node;
            }
            //插入尾部
            else if(index==count){
                this.last.next=node;
                node.previous=this.last;
                this.last=node;
            }else {
                Node target=getNode(index);
                node.previous=target.previous;
                target.previous.next=node;
                node.next=target;
                target.previous=node;
            }
            count++;
    }

    /**
     * 通过下标获取指定位置的节点
     * @param index 指定下标
     * @return    下标对应的节点
     */
    public Node getNode(int index){
        //1、判断下标是否合法,不合法抛出异常
        if(index<0||index>=count){
            throw new IndexOutOfBoundsException("size()="+count+",index="+index);
        }
        //向下循环寻找节点
        Node node=this.first;
            for (int i = 0; i < index; i++) {
                node=node.next;
            }
        return node;
    }

    /**
     * 删除指定标的元素并将这个元素返回
     * @param index 指定下标
     * @return     被删除的元素
     */
    public E remove(int index){
        //找到index对应的节点
        Node target=getNode(index);
        //删除这个节点
        removeNode(target);
        return target.element;
    }

    /**
     * 删除指定节点
     * @param node 需要被删除的节点
     */
    private void removeNode(Node node){
        //当链表中只有一个节点时
        if(count==1){
            this.first=null;
            this.last=null;
            count--;
           // return ;
        }
        //判断是否删除的是首节点
        if(node==this.first){
            //设置新的首节点
            this.first=this.first.next;
            //取消首节点与上一个节点的关联
            this.first.previous=null;
            this.first.next.previous=null;
        }
        //如果删除的是尾节点
        else if(node==this.last){
            //设置新的尾节点
            this.last=this.last.previous;
            //取消尾节点与下一个节点的关联
            this.last.previous.next=null;
            this.last.previous.next=null;
        }else{
            node.previous.next=node.next;
            node.next.previous=node.previous;
        }
        count--;
    }

    /**
     * 删除链表中指定的元素,若删除成功则返回true,否则返回false
     * @param element 要删除的元素
     * @return  删除成功返回true,否则返回false
     */
    public boolean remove(E element){
        boolean flag=true;
        Node node=this.first;
        for(int i=0;i<count;i++){
            if(node.element==element){
                flag=false;
                break;
            }else {
                node= node.next;
            }
        }
        return flag;
    }

    /**
     * 清空链表中所有的元素
     */
    public void clear(){
        Node node=this.first;
        for (int i = 0; i <count ; i++) {
               if(node!=null){
                   node=node.next;
                   node.previous.next=null;
                   node.previous=null;
               }
               this.last=this.first=null;
               count=0;
        }
    }

    /**
     * 修改指定位置的元素,并返回被覆盖的元素
     * @param index    知道下标
     * @param element  新元素
     * @return         被修改的元素
     */
    public E set(int index,E element){
        // 1. 判断下标的合法性
        if (index < 0 || index >= count) {
            throw new IndexOutOfBoundsException("size() = " + count + ", index = " + index);
        }
        //获得指定下标的节点
        Node target=getNode(index);
        //获得下标位置节点的元素
        E res= target.element;
        //修改元素
        target.element=element;
        return res;
    }

    /**
     * 获得指定位置的元素
     * @param index  指定位置
     * @return       指定位置的元素
     */
    public E get(int index){
        //获得指定位置的节点
        Node target=getNode(index);
        E res=target.element;
        return res;
    }

    /**
     *
     * @return 返回集合元素个数
     */
    public int size(){
        return count;
    }

    /**
     * 检查集合中是否含有指定元素
     * @param element  指定元素
     * @return  若存在返回true,否则返回false
     */
    public boolean contains(E element){
        boolean flag=false;
        Node node=this.first;
        for (int i = 0; i < count; i++) {
              if(node.element!=element){
                  node=node.next;
            }else {
                  flag=true;
                  break;
              }
        }
        return flag;
    }

    /**
     * 返回指定元素第一次出现的下标
     * @param element  指定元素
     * @return         若存在则返回指定元素第一次出现的下标,若不存在返回-1
     */
    public int indexOf(E element){
        int index=-1;
        Node node=this.first;
        for(int i=0;i<count;i++){
            if(node.element!=element){
                node=node.next;
            }else {
                index=i;
                break;
            }
        }
        return index;
    }

    @Override
    public String toString() {
        if(count==0){
            return "[]";
        }
        StringBuilder stringBuilder=new StringBuilder("[");
        Node node=this.first;
        for(int i=0;i<count;i++){
            stringBuilder.append(node.element);
            stringBuilder.append(",");
            node=node.next;
        }
        stringBuilder.replace(stringBuilder.length()-1,stringBuilder.length(),"]");
        return stringBuilder.toString();
    }
}

猜你喜欢

转载自www.cnblogs.com/dch-21/p/12741096.html