第一部分:基础知识了解
1、数组是什么?
数组是同类型元素的集合
2、数组有什么特点?
内存中连续;
创建时要明确大小;
索引访问元素;(索引是下标或者指针的偏移量)
数组创建后大小不能改变;
3、数组可以干什么?
数组可以快速查询,适用于解决有些索引有语义的实际问题(比如用学生学号的大小创建数组大小,空间浪费十分严重)
第二部分:如何封装一个自定义数组
1、封装就是写类,数组就是类的对象
2、加成员,基本数组、实际元素个数、最大容量
3、加方法,增删改查和其它
样例代码见本页末
第三部分:扩容缩容和泛型(重点重点中的重点)
在我们完成基本数组类的定义之后,会有以下三个问题需要我们去解决:
数组要创建成多类型数组——泛型
数组空间不够——扩容
数组空间浪费——缩容
泛型:类型作为参数的类型,参数类型可以有多个
使用格式:
扩容:添加元素时数组空间不够,将其容量扩大为原来的多少倍,以2倍为例:
核心代码:
该方法可以实现对数组空间大小进行改变,是扩容和缩容的核心
缩容:元素在数组空间中分布稀疏,浪费空间,于是通过缩容对空间进行回收,此处以回收为原来的1/2为例
问题:在使用了1/2数组空间的情况下回收另一半没使用的空间可以吗?
可以但不好,因为当不断在数组空间的元素不断进行增加和删除元素时会使得扩容和缩容不断循环,浪费时间
解决措施:当元素个数仅占1/4时再进行回收一半数组空间的缩容操作
封装数组源代码:
package com.algo.lesson.lesson1;
import java.util.Arrays;
public class MyArray<T> {
private T[] data;//保存数据
private int size;//大小
private int capacity;//体积
public MyArray(int capacity) {
if (capacity <= 0) {
this.capacity = 10;
} else {
this.capacity = capacity;
}
this.data = (T[]) new Object[this.capacity];
this.size = 0;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder("[");
for (int i = 0; i < this.size; i++) {
sb.append(this.data[i]);
if (i != this.size - 1) {
sb.append(",");
}
}
sb.append("]");
return sb.toString();//*
}
/*
其它
*/
//1、判断数组是否为空
public boolean isEmpty() {
return this.size == 0;
}
/*
一、增
*/
//1、在指定位置上添加元素
public void addInIndex(int index, T val) {
//解决数组满的问题---扩容
if (this.size == this.capacity) {
resize(this.capacity * 2);
}
if (index < 0 || index > this.size) {
throw new IllegalArgumentException("index is invalid.");
}
for (int i = this.size - 1; i >= index; i--) {
this.data[i + 1] = this.data[i];
}
this.data[index] = val;
this.size++;
}
public void resize(int newCapacity) {
T[] newData = (T[]) new Object[newCapacity];
//*Arrays里面的copyof方法
for (int i = 0; i < this.size; i++) {
newData[i] = this.data[i];
}
//改变数组容积
this.data = newData;
this.capacity = newCapacity;
}
//2、向数组头部添加元素
public void addHead(T item) {
addInIndex(0, item);
}
//3、向数组尾部添加元素
public void add(T item) {
// //*写法1加判断
// this.data[this.size]=item;
// this.size++;
// 写法2
addInIndex(this.size, item);
}
/*
二、删
*/
//1、根据索引从数组中删除元素
public T removeByIndex(int index) {
//数组空间浪费问题--缩容
//如果是缩容一半的话容易在中间位置前后添加和删除元素时反复进行扩容和缩容,于是采取在1/4处缩容
if (this.size <= this.capacity / 4 && this.capacity / 2 > 0) {
resize(this.capacity / 2);
}
if (index < 0 || index >= this.size) {
throw new IllegalArgumentException("index is invalid");//*
}
T delValue = this.data[index];
for (int i = index + 1; i < this.size; i++) {
this.data[i - 1] = this.data[i];
}
this.size--;
return delValue;
}
/*
三、改
*/
//1、修改指定位置的元素
public void modifyValueByIndex(int index, T value) {
if (index < 0 || index >= this.size) {
throw new IllegalArgumentException("index is invalid");//*
}
this.data[index] = value;
}
/*
查
*/
//1、获取数组中实际有效元素的个数
public int getSize() {
return this.size;
}
//2、获取数组容积
public int getCapacity() {
return this.capacity;
}
//3、获取指定位置的元素
public T getValueByIndex(int index) {
if (index < 0 || index >= this.size) {
throw new IllegalArgumentException("index is invalid");//*
}
return this.data[index];
}
//4、查询指定值在数组中是否存在 存在返回索引 不存在返回-1
public int containValue(T value) {
for (int i = 0; i < this.size; i++) {
if (this.data[i].equals(value)) {//*
return i;
}
}
return -1;
}
}