线性表的定义:零个或多个元素的有限序列
a1-a2-....-a(i-1)-a(i)-a(i+1)-....a(n-1)-an
线性表的特点:
- a(i-1)是a(i)的直接前驱;
- a(i+1)是a(i)的直接后继;
- 除了第一个元素外,其余元素均有直接前驱;
- 除了最后一个元素外,其余元素都有直接后继;
n表示线性表的长度,当n=0时,称为空表。
底层既可以用数组实现,也可以用链表实现,都是增删改查,具体的实现方法不同。
List接口的定义
既然线性结构可以由顺序存储结构和链式存储结构实现,那么将两者对线性结构共同的操作进行抽取,定义出线性结构的接口
public interface List<E> extends Iterable<E> {
public void add(E el ement);
public void add(int index, E element) throws IllegalAccessException;
public void remove(E element);
public E remove(int index);
public E get(int index);
public E set(int index, E element);
public int size();
public int indexOf(E element);
public boolean contains(E element);
public boolean isEmpty();
public void clear();
public void sort(Comparator<E> c);
public void swap(int i, int j);
public List<E> sublist(int fromIndex, int toIndex);
}
线性表的实现ArrayList
ArrayList就是线性结构顺序存储结构方式的具体实现,称为线性表
创建ArrayList类实现List接口
定义相关成员属性和构造函数
ArrayList(E[] arr)的问题
data不能直接引用外部传入的数组arr,否则外部对arr的修改会引起ArrayList内部的一些问题
add(int index,E element)
1.直接从表尾添加元素
2.从下标为2添加元素,过程:
且只能插入0到size之间,否则抛出异常
如果size的长度等于表的长度,就要进行扩容
从size-1开始,将下标为i的值赋给下标为i+1,以此类推
public void add(int index, E element) {
if (index < 0 || index > size) {
throw new IllegalArgumentException("add index out of range");
}
if (size == data.length) {
resize(data.length * 2);
}
for (int i = size - 1; i >= index; i--) {
data[i + 1] = data[i];
}
data[index] = element;
size++;
}
//扩容O(n)
private void resize(int newLen) {
E[] newData = (E[]) new Object[newLen];
for (int i = 0; i < size; i++) {
newData[i] = data[i];
}
data = newData;
}
remove(int index),根据角标删除元素
让i从index+1开始,将i的值赋给i-1,i要小于size,size--
public E remove(int index) {
if (index < 0 || index >= size) {
throw new IllegalArgumentException("remove index out of range");
}
E ret = data[index];
for (int i = index + 1; i < size; i++) {
data[i - 1] = data[i];
}
size--;
if (size == data.length / 4 && data.length > 10) {
resize(data.length / 2);
}
return ret;
}
缩容:当有效元素达到数组的1/4,且数组的长度大于10,才可以缩容,且缩到原来的1/4
不能缩容到原来的1/2原因是如果添加的元素超过原来的1/2,就要扩容
remove(E elememt),删除指定元素
要删除指定元素,首先要知道指定元素的角标,即遍历数组找角标
不能使用==,原因是要比较两个对象的内容是相等,且不能让传入的参数和已存在的比较,如果传入的参数是空的,就会发生空指针异常。
public int indexOf(E element) {
for (int i = 0; i < size; i++) {
if (data[i].equals(element)) {//比较两个对象的内容是否相等
return i;
}
}
return -1;
}
public void remove(E element) {
//删除全部
// while(true){
// int index = indexOf(element);
// if (index != -1) {
// remove(index);
// }
// }else{
// break;
// }
// }
//删除指定
int index = indexOf(element);
if (index != -1) {
remove(index);
}
}
size(),获取有效元素的个数
public int size() {
return size;
}
contains(E element),判断元素是否存在,这里可以做一个循环遍历数组,但是也可以通过找角标的函数,如果不存在,令它返回-1
public boolean contains(E element) {
return indexOf(element) != -1;
}
isEmpty(),判空,返回值是如果size==0,即空
public boolean isEmpty(){
return size == 0;
}
clear(),清空,新建一个数组,令size=0
public void clear(){
data = (E[]) new Object[DEFAULT_CAPACITY];
size = 0;
}
toString(),打印出数组,使用stringBuilder
public String toString() {
//打印出数组
StringBuilder sb = new StringBuilder();
sb.append('[');
if (isEmpty()) {
sb.append(']');
} else {
for (int i = 0; i < size; i++) {
sb.append(data[i]);
if (i == size - 1) {
sb.append(']');
} else {
sb.append(',');
sb.append(' ');
}
}
}
return sb.toString();
}
get(int index),获取指定角标处元素
public E get(int index){
if(index < 0 || index > size){
throw new IllegalArgument1Exception("get index out of range");
}
return data[index];
}
compare()返回值,负数表示第一个小于第二个,0表示相同,正数表示第一个大于第二个
测试
package com.openlab.dataStruce.p1动态数组;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Random;
public class TestArrayList {
public static void main(String[] args) {
Random random = new Random();
ArrayList<Integer> list = new ArrayList<>();
System.out.println(list);
for (int i = 0; i < 12; i++) {
list.add(random.nextInt(20));
}
System.out.println(list);
list.sort(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
System.out.println(list);
for (Integer num: list
) {
}
}
}