zoukankan      html  css  js  c++  java
  • Java基础之:List——LinkedList

    Java基础之:List——LinkedList

    LinkedList简单介绍

    LinkedList实现了双向链表(数据结构)和双端队列特点。

    实现了List接口,可以添加任意元素(即可以重复和null),线程不安全。

    LinkedList底层实现分析

    1. LinkedList底层维护了一个双向链表

    2. LinkedList中维护了两个属性first和last,分别指向首节点和尾节点

    3. 每个节点(数据结构中将节点都称作Node对象),里面又维护了prev、next、item三个属性。其中prev指向前一个Node,next指向后一个Node,最终实现双向链表。

    4. 所以LinkedList的元素添加与删除不是通过数组完成的,效率较高。

    模拟最简单的双向链表:

    package class_LinkedList;
    ​
    ​
    public class ClassTest01_DoubleLinkedList {
        
        public static void main(String[] args) {
            
            Node first = null;//首先定义一个first节点,作为标记位置存在
            
            //当添加一个节点时,让first节点指向此节点
            Node node1 = new Node(first, null, "小范");
            first = node1;
            
            //添加第二个节点,在构造时,让第二个节点的prev属性指向前一个节点node1
            Node node2 = new Node(node1, null, "小黄");
            node1.next = node2;  //让node1的next指向node2,实现双向连接
            
            //添加第三个节点
            Node node3 = new Node(node2, null, "小雨");
            node2.next = node3;
            
            //结尾 ,使用last节点,让last节点指向node3,因为node3的next为null代表链表结束
            Node last = node3;
            
            //链表遍历,通常都使用一个临时temp节点来用于遍历链表,不要使用first!
            Node temp = first;
            
            //链表从前向后遍历
            System.out.println("==========从前向后============");
            while(true) {
                System.out.println(temp);
                if(temp.next == null) { //last节点的next属性为null
                    break;
                }
                temp = temp.next; //将temp向后移
            }
            
            //链表从后向前遍历
            System.out.println("==========从后向前============");
            temp = last;
            while(true) {
                System.out.println(temp);
                if(temp.prev == null) { //first节点的prev属性为null
                    break;
                }
                temp = temp.prev; //将temp向前移
            }
            
            //添加节点,让需要添加位置的前后节点分别指向要添加的节点即可。
            //创建需要添加的节点,让其prev属性指向要添加位置的前一个节点,next属性指向要添加位置的后一个节点
            Node add = new Node(node1,node2,"add"); //在第一个和第二个节点中间插入一个节点
            //将node1的next指向add,node2的prev指向add,完成连接,此时node1与node2之间的连接自然就断开了
            node1.next = add;
            node2.prev = add;
            
            //再次遍历检查是否添加成功
            System.out.println("==========添加后===========");
            temp = first;
            while(true) {
                System.out.println(temp);
                if(temp.next == null) { //last节点的next属性为null
                    break;
                }
                temp = temp.next; //将temp向后移
            }
        }
    }
    ​
    class Node{
        //说明  这里为了方便演示案例,没有进行封装,实际开发中需要封装
        
        Node prev;  //指向前一个节点
        Node next;  //指向后一个节点
        String name; //每个节点的自有属性
        public Node(Node prev, Node next, String name) {
            this.prev = prev;
            this.next = next;
            this.name = name;
        }
        
        @Override
        public String toString() {
            return "Node [name=" + name + "]";
        }
    }

    程序输出:

    ==========从前向后============

    Node [name=小范]

    Node [name=小黄]

    Node [name=小雨]

    ==========从后向前============

    Node [name=小雨]

    Node [name=小黄]

    Node [name=小范]

    ==========添加后===========

    Node [name=小范]

    Node [name=add]

    Node [name=小黄]

    Node [name=小雨]

     

    LinkedList常用方法

    package class_LinkedList;
    ​
    import java.util.LinkedList;
    ​
    public class ClassTest02_LinkedListMethods {
    ​
        @SuppressWarnings({ "rawtypes", "unchecked" })
        public static void main(String[] args) {
    ​
            LinkedList linkedList = new LinkedList();
            // 添加
            for (int i = 0; i < 2; i++) {
                linkedList.add("AAA" + i);
            }
    ​
            String kk = "yyy";
            linkedList.add(kk);
            linkedList.add(2, kk);
    ​
            // 遍历
            for (Object object : linkedList) {
                System.out.println(object);
            }
    ​
            // 删除
            // linkedList.remove(0);
            // linkedList.remove(kk);
            
            System.out.println("=================");
            //替换
            linkedList.set(0, "川农");
            for (Object object : linkedList) {
                System.out.println(object);
            }
            
            System.out.println("=================");
            
            //查找,也可以使用下标进行访问
            Object object = linkedList.get(0);
            System.out.println("object=" + object);
            
            //LinkedList特有方法,获取首尾节点
            System.out.println(linkedList.getFirst());
            System.out.println(linkedList.getLast());
        }
    }
    

    添加节点源码分析

    默认添加:

    带下标位置的添加:

     

    Node内部类源码

      private static class Node<E> {
            E item;
            Node<E> next;
            Node<E> prev;
    ​
            Node(Node<E> prev, E element, Node<E> next) {
                this.item = element;
                this.next = next;
                this.prev = prev;
            }
        }

    Node内部类维护了next与prev属性。

     

    LinkedList与ArrayList对比

    如何选择ArrayList和LinkedList:

    1. 如果我们改查的操作多,选择ArrayList

    2. 如果我们增删的操作多,选择LinkedList

    3. 一般来说,在程序中,80%-90%都是查询,因此大部分情况下会选择ArrayList

    4. 在一个项目中,根据业务灵活选择,也可能这样,一个模块使用的是ArrayList,另外一个模块是LinkedList.

     

  • 相关阅读:
    小谈HTML中的META标签
    如何安装ASPAJAXExtSetup.msi
    <asp:Content> MasterPage技术
    Asp.Net数据控件引用AspNetPager.dll分页
    2011年的最后一天,怎么地也应该写篇博客
    asp.net利用存储过程和div+css实现分页(类似于博客园首页分页)
    Asp.Net 利用TimeSpan类实现时间差计算 并返回所需字符串(类似于SNS)
    最简单的asp.net ajax post,适用于初学者.
    分享AjaxPro或者Ajax实现机制
    Windows 7操作系统 IIS 7 配置asp.net网站伪静态配置问题
  • 原文地址:https://www.cnblogs.com/SongHai/p/14191718.html
Copyright © 2011-2022 走看看