数据结构|顺序表及Java实现
1. 认识线性表和顺序表
线性表(linear list)是n个具有相同特征的数据元素的有限序列。线性表是一种在实际中广泛使用的数据结构,常见的线性表有:顺序表、链表、栈、队列、字符串…
线性表在逻辑上是线性结构的,但是在物理结构上并不一定是连续的。
1.1 顺序表
逻辑上线性,在内存中存储时,也是严格按照逻辑上的次序保存起来的。
1.2 链表
逻辑上线性,在内存中存储时,不保证连续性。
1.2 数组
数组就是一种“不是非常完备”的顺序表。
数组中存在的问题:
a. 无法严格区分容量和已有元素个数;
b. 数组无法做到自行扩容。
long[] array = new long[5];
- array 中一共可以放5个 long 元素,无法明确得知目前 array 中有多少个有效的元素(容量)。
- 一直往 array 中放元素,最多只能放5个,再放就会下标越界。
2. 顺序表
2.1 结构及命名
注意:顺序表中一定要区分两个概念容量(capacity) vs 元素个数(size),线性表的所有下标只和元素个数相关,和容量无关。
2.2 顺序表(ArrayList)的常见方法
- 增(向容量中添加元素): add
- 删(从容量中删除元素): remove
- 查(不修改容量的情况下获取元素): get/ contains/ indexof/ lastIndexof
- 改(修改个别元素): set
add(element);
add(index,element);
remove(index);
boolean add(element);
get(index);
set(index,element);
boolean contains(element);
int indexof(element);
int lastindexof(element);
void clear();
int size();
boolean isEmpty();
2.3 关于 jdk 中如何组织 ArrayList 类
哪个可以实例化对象?
只有类(并且不能是抽象类)才可以实例化对象,只有 ArrayList 可以实例化对象。
2.4 如何实例化对象
ArrayList<Integer> list = new ArrayList<>();
a. ArrayList 是一个泛型类 - 元素类型用泛型表示;
b. 使用默认构造方法(无参构造方法),后面 <> 中由于类型推导,可不写。
3. Java 实现自己的 ArrayList 类
定义 MyLIst 接口
public interface MyList {
boolean add(Integer e);
void add(int index, Integer e);
Integer remove(int index);
boolean remove(Integer e);
Integer get(int index);
Integer set(int index, Integer e);
boolean contains(Integer e);
int indexOf(Integer e);
int lastIndexOf(Integer e);
void clear();
int size();
boolean isEmpty();
}
MyArrayList 实现 MyList 接口
import java.util.Arrays;
public class MyArrayList implements MyList{
private Integer[] array;
private int size;
public MyArrayList(){
array = new Integer[16];
size = 0;
}
// 供内部扩容
private void ensureCapacity(){
if (size < array.length){
return;
}
// 进行扩容
// 1. 找到一个新的房子,一般来说,房子大小按 2 倍进行扩容
Integer[] newArray = new Integer[array.length * 2];
// 2.把原来房子中的东西全部搬到新房子中
for (int i = 0; i < array.length; i++){
newArray[i] = array[i];
}
// 3. 公布新房子的位置
this.array = newArray;
}
@Override
public boolean add(Integer e) {
ensureCapacity();
array[size] = e;
size++;
return true;
}
@Override
public void add(int index, Integer e) {
ensureCapacity();
if (index < 0 || index > size){
throw new ArrayIndexOutOfBoundsException("Index:" + index + ", Size:" + size);
}
for (int to = size + 1; to > index; to--){
array[to] = array[to - 1];
}
array[index] = e;
size++;
}
@Override
public Integer remove(int index) {
if (index < 0 || index >= size){
throw new ArrayIndexOutOfBoundsException("Index:" + index + ", Size:" + size);
}
Integer e = array[index];
for (int to = index; to < size - 1; to++){
array[to] = array[to + 1];
}
array[size - 1] = null;
size--;
return e;
}
@Override
public boolean remove(Integer e) {
int i = indexOf(e);
if (i < 0){
return false;
}
remove(i);
return true;
}
@Override
public Integer get(int index) {
if (index < 0 || index >= size){
throw new ArrayIndexOutOfBoundsException("Index:" + index + ", Size:" + size);
}
return array[index];
}
@Override
public Integer set(int index, Integer e) {
if (index < 0 || index >= size){
throw new ArrayIndexOutOfBoundsException("Index:" + index + ", Size:" + size);
}
Integer oldElement = array[index];
array[index] = e;
return oldElement;
}
@Override
public boolean contains(Integer e) {
if (indexOf(e) >= 0){
return true;
}
return false;
}
@Override
public int indexOf(Integer e) {
for (int i = 0; i < size; i++){
if (e.equals(array[i])){
return i;
}
}
return -1;
}
@Override
public int lastIndexOf(Integer e) {
for (int i = size - 1; i >= 0; i--){
if (e.equals(array[i])){
return i;
}
}
return -1;
}
@Override
public void clear() {
Arrays.fill(array, null);
size = 0;
}
@Override
public int size() {
return size;
}
@Override
public boolean isEmpty() {
return size == 0;
}
@Override
public String toString() {
Integer[] toShow = Arrays.copyOf(array, size);
return Arrays.toString(toShow);
}
}