Java数据结构详解(四)-LinkedList
来源:互联网 发布:人工智能bob和alice 编辑:程序博客网 时间:2024/06/05 23:46
LinkedList源码详解
一, LinkedList字段
//返回链表的逻辑大小 transient int size = 0; //头部节点 transient Node<E> first; //尾部节点 transient Node<E> last;
二,LinkedList构造方法
一,无参构造器
public LinkedList() {}
二,有参数的构造器
public LinkedList(Collection<? extends E> c) { this();//调用无参构造器 addAll(c);//调用 addAll() }
addAll(Collection
public boolean addAll(Collection<? extends E> c) { return addAll(size, c);//调用addAll(size ,c) }
addAll(int index, Collection
public boolean addAll(int index, Collection<? extends E> c) { //检查index是不是超出范围了,size > index >= 0 checkPositionIndex(index); //将c转换为数组。 Object[] a = c.toArray(); //得当新增的数组的长度 int numNew = a.length; //检查是不是空数组 if (numNew == 0) return false; 定义两个节点(没有new) 上一个节点:pred ,下一个节点:succ Node<E> pred, succ; //如果index == size 那么说明是在双向链表尾部插入。 if (index == size) { //将节点succ指向null; succ = null; //将节点pred指向原链表中的最后一个节点 pred = last; } else { //如果index !=size 那么插入位置应该在头部或者中间部位 //将节点succ指向index位置的节点 succ = node(index); //将节点pred 指向index位置的节点的上一个节点。 pred = succ.prev; } //foreach循环 for (Object o : a) { @SuppressWarnings("unchecked") E e = (E) o; //new 一个新节点,节点的上一个节点是pred,数据是e,下一个节点是null; Node<E> newNode = new Node<>(pred, e, null); //如果上一个节点为null,说明是在头部插入的数据,只需要将插入数据的第一个数据设置为头部节点。 if (pred == null) first = newNode; else //上一个节点不为空,则把上一个节点的下一个节点的指向新建节点。这样 双向链表的指向就完成了。 pred.next = newNode; //将节点重新指向pred pred = newNode; } //在链表尾部插入数据,succ == null if (succ == null) { //将循环完成之后的最后一个pred指向last; last = pred; } else { //将succ指向循环完成之后的最后一个pred的下一个节点 pred.next = succ; //将指向循环完成之后的最后一个pred指向succ 的上一个节点,双向链表 完成。 succ.prev = pred; } //size = size + numNew ; size += numNew; modCount++; return true; }
Node node(int index)
Node<E> node(int index) { // assert isElementIndex(index); //如果index<siez/2 if (index < (size >> 1)) { Node<E> x = first; for (int i = 0; i < index; i++) x = x.next; return x; } else { Node<E> x = last; for (int i = size - 1; i > index; i--) x = x.prev; return x; } }
构造方法结束
LinkedList的增删改查
增
向链表中插入数据 分为三种情况 :
一,在链表头部插入数据:
public void addFirst(E e)
public void addFirst(E e) { linkFirst(e); } private void linkFirst(E e) { //将第一个节点first赋值给f。 final Node<E> f = first; //new一个新的 Node节点,新节点的上一个节点指向null,数据为e,下一个节点为f。 final Node<E> newNode = new Node<>(null, e, f); //更新first节点 first = newNode; 如果f==null 说明是一个空链表。则first和last都指向新建的节点。 if (f == null) last = newNode; else //将f的上一个节点指向新建节点。 f.prev = newNode; size++; modCount++; }
二,在链表的尾部插入数据:
public void addLast(E e)
public boolean add(E e) { linkLast(e); return true; } public void addLast(E e) { linkLast(e); } void linkLast(E e) { final Node<E> l = last; final Node<E> newNode = new Node<>(l, e, null); last = newNode; if (l == null) first = newNode; else l.next = newNode; size++; modCount++; }
三,在链表的中部插入数据:
public void add(int index, E element)
public void add(int index, E element) { //检查index有没有超过范围 checkPositionIndex(index); //如果index == size ,就相当于在链表尾部增加数据,则调用linkLast(); if (index == size) linkLast(element); else //否则调用linkBefore() linkBefore(element, node(index)); } void linkBefore(E e, Node<E> succ) { // assert succ != null; //拿到succ的上一个节点(succ 为index指向的节点) final Node<E> pred = succ.prev; //新建一个节点,其上一个节点为 succ的上一个节点,数据为 e,下一个节点为 succ。这样一个单向链表就完成了。 final Node<E> newNode = new Node<>(pred, e, succ); //succ的上一个节点指向新建节点。 succ.prev = newNode; //pred 为null则表示新增节点为头部节点。 if (pred == null) first = newNode; else //succ的上一个节点的下一个节点的引用指向新建节点。 pred.next = newNode; size++; modCount++; }
删
public E remove(int index) {}
public E remove(int index) { //检查index是不是超出范围了 checkElementIndex(index); //返回调用unlink方法,参数为 node(index) return unlink(node(index)); }
E unlink(Node x) {}
E unlink(Node<E> x) { // assert x != null; final E element = x.item; final Node<E> next = x.next; final Node<E> prev = x.prev; if (prev == null) { first = next; } else { prev.next = next; x.prev = null; } if (next == null) { last = prev; } else { next.prev = prev; x.next = null; } x.item = null; size--; modCount++; return element; }
改
public E set(int index, E element) {}
public E set(int index, E element) { //检查index checkElementIndex(index); //找到index的节点 Node<E> x = node(index); E oldVal = x.item; 修改数据 x.item = element; 返回数据修改之前的值 return oldVal; }
查
public E get(int index) {}
public E get(int index) { checkElementIndex(index); return node(index).item; }
链表的 get 和 set 都调用了方法 node(index)
而node方法内部是 循环遍历数组. 所以get和set方法比较耗时.
而remove和add 方法只是修改了 对象的引用.时间短效率高.
ArrayList 和 LinkedList 相比
ArrayList查询和修改 的复杂度为O(1); 增加和删除的时间复杂度为O(N)
LinkedList查询和修改的时间复杂度为O(N/2),增加和删除的时间复杂度为O(1);
阅读全文
0 0
- Java数据结构详解(四)-LinkedList
- Java数据结构-LinkedList(四)
- 用java源代码学数据结构<四>: LinkedList 详解
- 共同学习Java源代码--数据结构--LinkedList类(四)
- java中的数据结构--LinkedList
- Java数据结构-LinkedList
- java集合类(四)LinkedList应用
- Java中集合(四)LinkedList
- 集合框架四:LinkedList基本应用(用LinkedList模拟堆栈或队列的数据结构)
- Redis内部数据结构详解之双向链表(linkedlist)
- Java之LinkedList详解
- 【JAVA】LinkedList使用详解
- java的LinkedList详解
- java linkedlist操作详解
- 【JAVA集合详解】LinkedList
- 数据结构(LinkedList的java实现)
- 数据结构--LinkedList的java实现
- 数据结构-Java实现-ArrayList&LinkedList
- Boosting and AdaBoost
- iOSalertviewcontroller的action回调对横竖屏切换有影响
- MATLAB基本操作
- 通过键盘输入多位学生成绩,并计算这些成绩的总和
- 51nod 1548欧姆诺姆和糖果(枚举优化)
- Java数据结构详解(四)-LinkedList
- 哎哎哎哎哎
- JAVA基础--字节流,字符流,对象序列化
- Linux系统优化基础和系统监控
- 9-26 DAIRY
- 第四周项目3—单链表应用(1)
- 拦截导弹
- 中国剩余定理 【CRT 两种模型的讲解】
- 单例模式Singleton