【Java心得总结六】Java容器中——Collection在前面自己总结的一篇博文中对Collection的框架结构做了整理,这里深究一下Java中list的实现方式

1.动态数组

In computer science, a dynamic arraygrowable arrayresizable arraydynamic tablemutable array, or array list is a random access, variable-size list data structure that allows elements to be added or removed. It is supplied with standard libraries in many modern mainstream programming languages.

A dynamic array is not the same thing as a dynamically allocated array, which is a fixed-size arraywhose size is fixed when the array is allocated, although a dynamic array may use such a fixed-size array as a back end.

——维基百科

我们可以看出动态数组在动态分配数组(固定大小数组)的基础上实现的可随机存取大小可变的一种数据结构

2.Java中ArrayList实现

我截取了部分ArrayList的Java实现:

代码段1

 public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
private transient Object[] elementData; private int size; public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
} public ArrayList() {
this(10);
} public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
size = elementData.length;
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
} private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
} /* 增加元素 */
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
} public void add(int index, E element) {
rangeCheckForAdd(index); ensureCapacityInternal(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
} private void rangeCheckForAdd(int index) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
} /* 删除元素 */
public E remove(int index) {
rangeCheck(index); modCount++;
E oldValue = elementData(index); int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // Let gc do its work return oldValue;
} public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
} private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // Let gc do its work
} /* 查找元素 */
public E get(int index) {
rangeCheck(index); return elementData(index);
} public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
} public boolean contains(Object o) {
return indexOf(o) >= 0;
} private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
} /* 修改元素 */
public E set(int index, E element) {
rangeCheck(index); E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
}

代码段2

 public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
T[] copy = ((Object)newType == (Object)Object[].class)
? (T[]) new Object[newLength]
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
  • 代码4行,可以看出Java利用了一个Object数组来支持动态数组ArrayList的存取,Object[]的初始大小可以利用构造函数来进行设置
  • 在代码28行,可以看出当Object数组不够用的时候,Java会利用grow函数对原有数组进行扩展。查看Java Arrays类会找到copyOf静态方法,会发现Java会新开辟一段更大的存储空间(newLength),然后再将原有数组的数据全部复制到新的数组中,并返回新的引用。之后grow会将elementData指向新的数组。
  • 而接下来我按照增删查改的顺序对Java中的函数进行了列举,基本就是普通的动态数组操作,就不一一说明。

3.Java中LinkedList实现

Java中LinkedList就是用双向链表来实现的,我截取了部分代码:

代码段1:

 public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
transient int size = 0; transient Node<E> first; transient Node<E> last; public LinkedList() {
} public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
/* 链表基本操作 */
private void linkFirst(E e) {
final Node<E> f = first;
final Node<E> newNode = new Node<>(null, e, f);
first = newNode;
if (f == null)
last = newNode;
else
f.prev = newNode;
size++;
modCount++;
} 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++;
} void linkBefore(E e, Node<E> succ) {
// assert succ != null;
final Node<E> pred = succ.prev;
final Node<E> newNode = new Node<>(pred, e, succ);
succ.prev = newNode;
if (pred == null)
first = newNode;
else
pred.next = newNode;
size++;
modCount++;
} private E unlinkFirst(Node<E> f) {
// assert f == first && f != null;
final E element = f.item;
final Node<E> next = f.next;
f.item = null;
f.next = null; // help GC
first = next;
if (next == null)
last = null;
else
next.prev = null;
size--;
modCount++;
return element;
} private E unlinkLast(Node<E> l) {
// assert l == last && l != null;
final E element = l.item;
final Node<E> prev = l.prev;
l.item = null;
l.prev = null; // help GC
last = prev;
if (prev == null)
first = null;
else
prev.next = null;
size--;
modCount++;
return element;
} 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 int indexOf(Object o) {
int index = 0;
if (o == null) {
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null)
return index;
index++;
}
} else {
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item))
return index;
index++;
}
}
return -1;
} public int lastIndexOf(Object o) {
int index = size;
if (o == null) {
for (Node<E> x = last; x != null; x = x.prev) {
index--;
if (x.item == null)
return index;
}
} else {
for (Node<E> x = last; x != null; x = x.prev) {
index--;
if (o.equals(x.item))
return index;
}
}
return -1;
} /*添加操作*/
public boolean addAll(int index, Collection<? extends E> c) {
checkPositionIndex(index); Object[] a = c.toArray();
int numNew = a.length;
if (numNew == 0)
return false; Node<E> pred, succ;
if (index == size) {
succ = null;
pred = last;
} else {
succ = node(index);
pred = succ.prev;
} for (Object o : a) {
@SuppressWarnings("unchecked") E e = (E) o;
Node<E> newNode = new Node<>(pred, e, null);
if (pred == null)
first = newNode;
else
pred.next = newNode;
pred = newNode;
} if (succ == null) {
last = pred;
} else {
pred.next = succ;
succ.prev = pred;
} size += numNew;
modCount++;
return true;
} public boolean add(E e) {
linkLast(e);
return true;
} /* 删除操作 */
public E removeFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return unlinkFirst(f);
} public E removeLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return unlinkLast(l);
} /* 修改操作 */
public E set(int index, E element) {
checkElementIndex(index);
Node<E> x = node(index);
E oldVal = x.item;
x.item = element;
return oldVal;
}
}

代码段2:

 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;
}
}
  • 代码段1的7行和9行,我们可以看到Java中LinkedList的实现就是我们所熟知的双向链表数据结构,并且声明了头指针和尾指针分别指向链表的头和尾
  • 每个节点的结构见代码段2,发现是基本的双向链表节点结构
  • 而从代码18行开始就是常规的链表操作,包括插入结点和删除结点的操作
  • 而之后的增删查改操作大都是利用基本的链表操作实现的
  • 另外,值得注意的是LinkedList在Java中还有一个特殊功效就是通过向上转型当做队列Queue来使用

  如下面这段代码

Queue<Integer> queue = new LinkedList<Integer>();

  这里向上转型无非是将LinkedList限制为头尾读取。

Java中的动态数组实现,比较简单,复习回顾下,做下记录^v^

常用数据结构-线性表及Java 动态数组 深究的更多相关文章

  1. 数据结构(1) 第一天 算法时间复杂度、线性表介绍、动态数组搭建(仿Vector)、单向链表搭建、企业链表思路

    01 数据结构基本概念_大O表示法 无论n是多少都执行三个具体步骤 执行了12步 O(12)=>O(1) O(n) log 2 N = log c N / log c N (相当于两个对数进行了 ...

  2. 数据结构与算法系列2 线性表 使用java实现动态数组+ArrayList源码详解

    数据结构与算法系列2 线性表 使用java实现动态数组+ArrayList源码详解 对数组有不了解的可以先看看我的另一篇文章,那篇文章对数组有很多详细的解析,而本篇文章则着重讲动态数组,另一篇文章链接 ...

  3. [数据结构-线性表1.2] 链表与 LinkedList<T>(.NET 源码学习)

    [数据结构-线性表1.2] 链表与 LinkedList<T> [注:本篇文章源码内容较少,分析度较浅,请酌情选择阅读] 关键词:链表(数据结构)    C#中的链表(源码)    可空类 ...

  4. 数据结构----线性表顺序和链式结构的使用(c)

    PS:在学习数据结构之前,我相信很多博友也都学习过一些语言,比如说java,c语言,c++,web等,我们之前用的一些方法大都是封装好的,就java而言,里面使用了大量的封装好的方法,一些算法也大都写 ...

  5. C#实现数据结构——线性表(上)

    什么是线性表 数据结构中最常用也最简单的应该就是线性表,它是一种线性结构(废话,不是线性结构怎么会叫线性表?当然不是废话,古人公孙龙就说白马非马,现代生物学家也说鲸鱼不是鱼). 那什么是线性结构? 按 ...

  6. [从今天开始修炼数据结构]线性表及其实现以及实现有Itertor的ArrayList和LinkedList

    一.线性表 1,什么是线性表 线性表就是零个或多个数据元素的有限序列.线性表中的每个元素只能有零个或一个前驱元素,零个或一个后继元素.在较复杂的线性表中,一个数据元素可以由若干个数据项组成.比如牵手排 ...

  7. Java动态数组

    其中java动态数组: Java动态数组是一种可以任意伸缩数组长度的对象,在Java中比较常用的是ArrayList,ArrayList是javaAPI中自带的java.util.ArrayList. ...

  8. C++语言------顺序表实现,用动态数组的方法

    C++ 中常用的一些东西,通过使用动态数组来实现顺序表, 掌握了一下知识点: 1.预处理有三中方法 宏定义,文件包含,条件编译 2.使用同名的变量时,可以在外层使用命名空间 类解决变量名重定义的错误 ...

  9. 三 基于Java动态数组手写队列

    手写队列: package dataStucture2.stackandqueue; import com.lt.datastructure.MaxHeap.Queue; import dataStu ...

随机推荐

  1. Unity3d学习 预设体(prefab)的一些理解

    之前一直在想如果要在Unity3d上创建很多个具有相同结构的对象,是如何做的,后来查了相关资料发现预设体可以解决这个问题! 预设体的概念: 组件的集合体 , 预制物体可以实例化成游戏对象. 创建预设体 ...

  2. Logstash实践: 分布式系统的日志监控

    文/赵杰 2015.11.04 1. 前言 服务端日志你有多重视? 我们没有日志 有日志,但基本不去控制需要输出的内容 经常微调日志,只输出我们想看和有用的 经常监控日志,一方面帮助日志微调,一方面及 ...

  3. JQuery(2)

    JQuery下拉框操作: 取值赋值操作 body代码: <select id="sel"> <option value="北京">北京& ...

  4. PAT练习题目录

    点题号就能查看题解了,另外代码也放在了开源中国码云上: 甲级:代码集合:https://git.oschina.net/firstmiki/PAT-Advanced-Level-Practise 10 ...

  5. springmvc的拦截器

    什么是拦截器                                                         java里的拦截器是动态拦截action调用的对象.它提供了一种机制可以使 ...

  6. java观察者模式

      像activeMQ等消息队列中,我们经常会使用发布订阅模式,但是你有没有想过,客户端时如何及时得到订阅的主题的信息?其实就里就用到了观察者模式.在软件系统中,当一个对象的行为依赖于另一个对象的状态 ...

  7. javascript 笔记!

    1.通过javascript向文档中输出文本 document是javascript的内置对象,代表浏览器的文档部分 document.write("Hello Javascript&quo ...

  8. JAVA环境变量和TomCat服务器配置

    Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选.对于一个初学者来说,可以这样 ...

  9. Struts2.5需要的最少jar文件

    以Struts2.5.2为例 从官网上下载“struts-2.5.2-min-lib.zip”,里面有7个jar文件: commons-fileupload-1.3.2.jarcommons-io-2 ...

  10. 杂项之python描述符协议

    杂项之python描述符协议 本节内容 由来 描述符协议概念 类的静态方法及类方法实现原理 类作为装饰器使用 1. 由来 闲来无事去看了看django中的内置分页方法,发现里面用到了类作为装饰器来使用 ...