2.动态数组
2.1线性表
线性表是具有 n 个相同类型元素的有限序列( n ≥ 0 )
-
a1 是首节点(首元素), an 是尾结点(尾元素)
-
a1 是 a2 的前驱, a2 是 a1 的后继
常见的线性表有:
-
数组
-
链表
-
栈
-
队列
-
哈希表(散列表)
-
数组(Array)
数组是一种顺序存储的线性表,所有元素的内存地址是连续的在很多编程语言中,数组都有个致命的缺点: 无法动态修改容量实际开发中,我们更希望数组的容量是可以动态改变的
2.2动态数组(Dynamic Array)
动态数组接口设计,至少包含以下内容:
- int size()
- isEmpty
- contains
- add
- get
- set
- add(index)
- remove
- indexOf
- clear
动态数组的结构:
size
elements
备注
java中,成员变量会自动初始化
-
int类型自动初始化为0
-
对象类型自动初始化为null
动态数组示例:
public class ArrayList<E> {
private static final int DEFAULT_CAPACITY = 10;
private static final int ELEMENT_NOT_FOUND = -1;
private int size;
private E[] elements;
public ArrayList(){
elements = (E[]) new Object[DEFAULT_CAPACITY];
}
public ArrayList(int capaticy){
if (capaticy < DEFAULT_CAPACITY){
elements = (E[]) new Object[DEFAULT_CAPACITY];
}else {
elements = (E[]) new Object[capaticy];
}
}
public int size(){
return size;
}
public boolean isEmpty(){
return size == 0;
}
public E get(int index){
if (index < 0 || index >= size){
throw new IndexOutOfBoundsException("Index:"+index+",Size:"+size);
}
return elements[index];
}
public E set(int index,E element){
if (index < 0 || index >= size){
throw new IndexOutOfBoundsException("Index:"+index+",Size:"+size);
}
E old = elements[index];
elements[index] = element;
return old;
}
public int indexOf(E element) {
if(element == null){
for (int i = 0; i < size; i++) {
if (element[i] == null) {
return i;
}
}
}else{
for (int i = 0; i < size; i++) {
if (elements[i] == element) {
return i;
}
}
}
return ELEMENT_NOT_FOUND;
}
public boolean contains(E element){
return indexOf(element) != ELEMENT_NOT_FOUND;
}
public void clear(){
size = 0;
}
public void add(E element){
elements[size] = element;
size++;
}
public void addIndex(int Index,E element){
if (Index < 0 || Index > size){
throw new IndexOutOfBoundsException("Index:"+Index+",Size:"+size);
}
ensureCapacity(size + 1);
for (int i = size -1; i >= Index; i--) {
elements[i+1] = elements[i];
}
elements[Index] = element;
size++;
}
private void ensureCapacity(int size) {
int oldCap = elements.length;
if (oldCap >= size ){
return;
}
int newCap = oldCap + oldCap >> 1;//相当于*1.5,>>是处于2,<<是成语2
E[] newElements = (E[]) new Object[newCap];
for (int i = 0; i < size; i++) {
newElements[i] = elements[i];
}
elements = newElements;
}
public String toString(){
StringBuilder string = new StringBuilder();
string.append("size=").append(size).append(",[");
for (int i = 0; i < size; i++) {
string.append(elements[i]);
if (i != size - 1){
string.append(",");
}
}
string.append("]");
return string.toString();
}
public E remove(int index){
if (index < 0 || index >= size){
throw new IndexOutOfBoundsException("Index:"+index+",Size:"+size);
}
E num = elements[index];
for (int i = index; i < size - index; i++) {
elements[index] = elements[index+1];
}
size--;
elements[size] = null;
return num;
}
}
为了满足创建的数组不局限于某一个数据类型,所以要采用泛型结构。
还要注意,在泛型存储的对象数组的内存管理,对象不是直接存在数组里面,而是将对象数组的地址放到数组里去
而且,创建了对象数组大小并不是直接开辟这么大的空间,真正对象创建后才放入
删除呢,就置为null ,但是以前存基本数据类型的时候直接将size置为0就可以了,而存对象数组就要for循环将每一个元素置为null,否则原对象一直还存在。
还有一个要注意的是,如果在IndexOf函数里,判断elements【i】==element实际判断的是内存地址是不是相等,在java里,可以没必要判断地址相等,重写equals函数,判断某个属性相等的话也行
null问题, java里面建议可以存null值,但是当null值执行indexof函数,会执行null.equals,就会报空指针异常