以下是学习恋上数据结构与算法的记录,本篇主要内容是Java实现动态数组
◼ 数据结构是计算机存储、组织数据的方式。是指相互之间存在一种或多种特定关系的数据元素的集合。
◼精心选择的数据结构可以带来更高的运行或者存储效率,所以在实际应用中,往往会根据使用场景来选择最合适的数据结构。
◼线性表是最基本、最简单、也是最常用的一种数据结构(数组,链表,栈,队列,哈希表等)。
线性表是具有n个相同类型元素的有限序列(n>=0)
a1是首节点(首元素),an是尾结点(尾元素)
a1是a2的前驱,而a2是a1的后继
◼数组是一种顺序存储的线性表,所有元素的内存地址是连续的。
在很多编程语言中,数组都有个致命的缺点,那就是无法动态修改容量
实际开发中,我们更希望数组的容量是可以动态改变的。而JDK也内置了动态数组java.util.ArrayList
动态数组 设计:
size:元素个数;
elements:所有的元素
// 元素的数量
private int size;
// 所有的元素
private E[] elements;//使用泛型来表示数组类型,从而能保证复用性
//默认容量
private static final int DEFAULT_CAPACITY = 10;
//索引错误值
private static final int ELEMENT_NOT_FOUND = -1;
//有参构造方法 如果赋值小于默认容量值 则选取默认容量来构造数组
public ArrayList(int capaticy) {
capaticy = (capaticy < DEFAULT_CAPACITY) ? DEFAULT_CAPACITY : capaticy;
elements = (E[]) new Object[capaticy];
}
//无参构造 就是构造默认容量动态数组
public ArrayList() {
this(DEFAULT_CAPACITY);
}
◼void add(E element);// 添加元素到最后面
思路:将新元素添加到数组的size位置上, size++
public void add(E element) {
add(size, element);
}
◼void add(intindex, E element);// 往index位置添加元素
思路:将index之后的元素往后移动,则会空出index位置空间
移动时先要从后向前移动元素,如果从前向后移动元素, 那么会进行元素覆盖
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacity(size + 1);
for (int i = size; i > index; i--) {
elements[i] = elements[i - 1];
}
elements[index] = element;
size++;
}
◼E remove(intindex);// 删除index位置对应的元素
思路:将index后面元素前移顺序覆盖,size–
public E remove(int index) {
rangeCheck(index);
E old = elements[index];
for (int i = index + 1; i < size; i++) {
elements[i - 1] = elements[i];
}
elements[--size] = null;
return old;
}
◼E get(intindex);// 返回index指定索引位置对应的元素
public E get(int index) {
rangeCheck(index);
return elements[index];
}
◼E set(intindex, E element);// 设置index位置的元素
public E set(int index, E element) {
rangeCheck(index);
E old = elements[index];
elements[index] = element;
return old;
}
◼int indexOf(E element);// 查看元素的位置
可以通过循环, 查找元素在数组中的位置
public int indexOf(E element) {
//设计的动态数组允许null值
if (element == null) {
for (int i = 0; i < size; i++) {
if (elements[i] == null) return i;
}
} else {
for (int i = 0; i < size; i++) {
if (element.equals(elements[i])) return i;
}
}
return ELEMENT_NOT_FOUND;
}
◼void clear();// 清除所有元素,将所有的元素置为null, 然后size置为0
public void clear() {
for (int i = 0; i < size; i++) {
elements[i] = null;
}
size = 0;
}
◼void ensureCapacity(int capacity);//扩容 保证容量
思路:复制:新建一个新的动态数组,将旧数组数据插入新数组即可
采用位运算是为了提高运算效率,因为取模,乘除等运算比较浪费性能
须注意的是在扩容和缩容中要注意复杂度震荡
如果他们的相乘是1(扩容的新容量是旧容量的2倍,缩容的容量也压缩2倍,那就是2*1/2=1),就会频繁触发复杂度震荡,所以这里采用的是扩容1.5倍,缩容一半就是缩两倍,以此避免复杂度震荡。
private void ensureCapacity(int capacity) {
int oldCapacity = elements.length;
if (oldCapacity >= capacity) return;
// 新容量为旧容量的1.5倍 ,位运算则每左移一位,相当于该数乘以2
int newCapacity = oldCapacity + (oldCapacity >> 1);
E[] newElements = (E[]) new Object[newCapacity];
for (int i = 0; i < size; i++) {
newElements[i] = elements[i];
}
elements = newElements;
System.out.println(oldCapacity + "扩容为" + newCapacity);
}
◼void trim();//缩容为了减小浪费内存,其思路与扩容相同
private void trim() {
int oldCapacity = elements.length;
int newCapacity = oldCapacity >> 1;
if (size > (newCapacity) || oldCapacity <= DEFAULT_CAPACITY) return;
E[] newElements = (E[]) new Object[newCapacity];
for (int i = 0; i < size; i++) {
newElements[i] = elements[i];
}
elements = newElements;
System.out.println(oldCapacity + "缩容为" + newCapacity);
}
◼检查索引及处理(抛异常)索引检查是为了防止索引不能越界, 即不能小于0, 也不能大于等于size。
private void outOfBounds(int index) {
//当用户传索引值不对时,我们对它的处理是抛异常
throw new IndexOutOfBoundsException("Index:" + index + ", Size:" + size);
}
//检查索引正确方法
private void rangeCheck(int index) {
if (index < 0 || index >= size) {
outOfBounds(index);
}
}
//这是对添加方法设计的检查索引方法
private void rangeCheckForAdd(int index) {
if (index < 0 || index > size) {
outOfBounds(index);
}
}
◼toString等其他方法
// 元素的数量
public int size() {
return size;
}
// 是否为空 ,size==0即无任务元素
public boolean isEmpty() {
return size == 0;
}
// 是否包含某个元素
//思路:用indexOf()查询索引 ,若索引为-1,则不存在。
public boolean contains(E element) {
return indexOf(element) != ELEMENT_NOT_FOUND;
}
//重写toString方法将元素拼接成字符串打印输出
@Override
public String toString() {
StringBuilder string = new StringBuilder();//字符串拼接建议使用StringBuilder
string.append("size=").append(size).append(", [");
for (int i = 0; i < size; i++) {
if (i != 0) {
string.append(", ");
}
string.append(elements[i]);
}
string.append("]");
return string.toString();
}