01.Java数据结构与算法之ArrayList
ArrayList底层原理细节
ArrayList底层结构是一个长度可以动态增长的数组(顺序表)
public Object []elementData;
特点:
在内存中分配连续的空间,只存储数据,不存储地址信息。位置就隐含着地址。
优点:
1.节省存储空间,因为分配给数据的存储单元全用存放结点的数据(不考虑c/c++语言中数组需指定大小的情况), 结点之间的逻辑关系没有占用额外的存储空间。
2. 索引查找效率高,即每一个结点对应一个序号,由该序号可以直接计算出来结点的存储地址。 假设线性表的每个数据元素需占用K个存储单元,并以元素所占的第一个存储单元的地址作为数据元素的存储地址。 则线性表中序号为i的数据元素的存储地址LOC(a i )与序号为i+1 的数据元素的存储地址LOC(a i+1 )之间的关系为
LOC(a i+1 ) = LOC(a i ) + K
通常来说,线性表的i号元素a i 的存储地址为
LOC(a i ) = LOC(a 0 ) + i×K
其中LOC(a 0 )为 0 号元素a 0 的存储地址,通常称为线性表的起始地址。
缺点:
1.插入和删除操作需要移动元素,效率较低。
2.必须提前分配固定数量的空间,如果存储元素少,可能导致空闲浪费。
3.按照内容查询效率低,因为需要逐个比较判断
无参构造(一开始如果用户没设置集合大小,初始值就为10)
public ArrayList(){
this(10); //数组大小初始为10
}
有参构造(给用户设置大小)
public ArrayList(int len){
elementData = new Object[len];
}
集合容量不足时,每次扩容增加50%
void grow(){
//创建新的数组
Object []newArr = new Object[elementData.length + (elementData.length >> 1)];//扩容1.5倍
for(int i = 0; i < size; i++){
//将原来数组的内容存到新数组里
newArr[i] = elementData[i];
}
elementData = newArr;
}
定义List接口
public interface List <T>{
// ------- 添加 -------
void add(Object object);
// ------- 根据坐标删除 -------
void remove(int index);
// ------- 根据内容删除 -------
void removeobj(Object object);
// ------- 取出数据 -------
Object get(int index);
// ------- 求集合的长度 -------
int size();
// ------- 判断集合是否为空 -------
boolean isEmpty();
// ------- 根据内容找到元素坐标 -------
int IndexOf(Object object);
// ------- 判断元素是否存在 -------
boolean contions(Object object);
// ------- 根据坐标位置插入元素 -------
void add(int index, Object object);
// ------- 修改元素 -------
void replase(int index, Object object);
// ------- toString -------
String toString();
// ------- arraylist迭代器 -------
ArrayList.Ite iterator();
}
定义Iterator接口
public interface Iterator <T>{
boolean hasNext();
T next();
}
ArrayList实现类
public class ArrayList <T>implements List {
public Object []elementData; //数组的引用
private int size; //集合的大小,并非elementData.length
//如果用户没设置大小就初始为10
public ArrayList(){
this(10); //数组大小初始为10
}
//集合的大小等于用户设置的大小
public ArrayList(int len){
elementData = new Object[len];
}
// 数组的扩容
void grow(){
//创建新的数组
Object []newArr = new Object[elementData.length + (elementData.length >> 1)];//扩容1.5倍
for(int i = 0; i < size; i++){
//将原来数组的内容存到新数组里
newArr[i] = elementData[i];
}
elementData = newArr;
}
//在集合的尾部添加元素
public void add(Object object) {
//如果数组长度不够就调用扩容
if(elementData.length <= size){
grow();
}
elementData[size] = object;
//大小增加一位
size++;
}
//根据坐标删除元素
public void remove(int index) {
//判断用户是否输入错误
if(index<0|| index >size-1){
throw new IndexOutOfBoundsException("索引越界"+index);
}
Object element=elementData[index];
// 向前移动元素
for (int i = index; i <size-1 ; i++) {
elementData[i]=elementData[i+1];
}
// 最后一个元素置为空
elementData[size-1]=null;
size--;
}
//根据元素删除
public void removeobj(Object object) {
int index = IndexOf(object);
//判断用户是否输入错误!
if(index<0){
throw new NullPointerException();
}
remove(index);
}
//根据坐标得到元素
public Object get(int index) {
return elementData[index];
}
//求集合的长度
public int size() {
return size;
}
//判断是否为空
public boolean isEmpty() {
return size == 0;
}
//根据元素找到坐标
public int IndexOf(Object object) {
int i = 0;
while(i < size){
if(elementData[i].equals(object)){
break;
}
i++;
}
return i;
}
//判断元素是否存在
public boolean contions(Object object) {
boolean flag = false;
for(int i = 0; i < size; i++){
if(elementData[i].equals(object)){
flag = true;
break;
}
}
return flag;
}
//根据坐标位置添加元素
public void add(int index, Object object) {
if(size >= elementData.length){
grow();
}
for(int i = size; i > index; i--){
elementData[i] = elementData[i - 1];
}
elementData[index] = object;
size++;
}
//修改元素
public void replase(int index, Object object) {
elementData[index] = object;
}
//重写toString
public String toString(){
StringBuilder str = new StringBuilder("[");
for(int i = 0; i < size; i++){
//判断是否到了最后一位,如果到了就不添加,
if(i == size - 1){
str.append(elementData[i]);
break;
}else{
str.append(elementData[i] + ",");
}
}
str.append("]");
return str.toString();
}
// ------- 迭代器 -------
public Ite iterator(){
return new Ite();
}
public class Ite<T>implements Iterator<T> {
int cursor = 0; //指向当前元素,默认是0
public ArrayList arr = new ArrayList();
public boolean hasNext() {
return cursor != size;
}
public T next() {
int i = cursor; //保留当前值
cursor++;//自增
// 进行判断,防止越界
if (i > size) {
throw new RuntimeException("没有元素");
}
return (T) elementData[i];
}
}
}
自定义异常(不自定义也没关系,java自带也有)
public class IndexOutOfBoundsException extends RuntimeException{
public IndexOutOfBoundsException() { }
public IndexOutOfBoundsException(String message) {
super(message);
}
}