顺序表(ArrayList)
1.顺序表的原理
2.Java中提供得顺序表(ArrayList)的主要用法(增删查改)
3.ArrayList的继承链条
可以被迭代的(Iterable)
interface Iterble<T>{
Iterator<T> iterator();
}
//通过iterator()方法,返回迭代器
//通过迭代器,可进一步的进行迭代(Iterator)
迭代器(Iterator)
interface Iterator<E>{
boolean hasnext();
E next();
}
// hasnext()——ture :还有下一个/没有迭代完 false: 没有下一个了/迭代完了
//next() :1.返回下一个元素 2.同时跳过该元素(这个元素被迭代过了) 这两条都是基于hasnext() 返回ture的前提;
// Iterator的用法类似于以前的Scanner
package demo;
import java.util.ArrayList;
import java.util.Iterator;
public class IterableDemo {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("我");
list.add("你");
list.add("他");
list.add("谁");
for (String e : list) {
System.out.println(e);
}
Iterable<String> r1 = list;
// 假如不知道 r1 中一共有多少元素
Iterator<String> it = r1.iterator();
while (it.hasNext()) {
// 能进到循环中来,代表 it.hasNext() => true 了,所以,迭代器中还有元素
// 所以,正确地掉用 next() 方法
String s = it.next();
System.out.println(s);
}
// r1 指向的对象,具备迭代能力
// 迭代其中的每一个元素
// 1. 通过 r1 得到迭代器对象(Iterator)
Iterator<String> it = r1.iterator();
// 2. 利用迭代器对象,进行遍历
System.out.println(it.hasNext()); // true
String s1 = it.next(); // 返回 "我",iterator 内部走到了 "你"
System.out.println(s1); // 我
System.out.println(it.hasNext()); // true
String s2 = it.next(); // 返回 "你",iterator 内部走到了 "他"
System.out.println(s2); // 你
System.out.println(it.hasNext()); // true
String s3 = it.next(); // 返回 "他",iterator 内部全部走完了
System.out.println(s3); // 他
System.out.println(it.hasNext()); // false
}
}
package demo;
import java.util.ArrayList;
import java.util.Collection;
public class CollectionDemo {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("我");
list.add("你");
list.add("他");
list.add("谁");
Collection<String> collection = list;
System.out.println(collection);
for (String e : collection) {
System.out.println(e);
}
collection.add("不是我");
System.out.println(collection);
collection.remove("你");
System.out.println(collection);
System.out.println(collection.isEmpty());
System.out.println(collection.size());
collection.clear();
System.out.println(collection);
System.out.println(collection.isEmpty());
System.out.println(collection.size());
}
}
interface Collection<E>{
boolean add(E e);
}
//把元素e放入集合中
//在Collection的语境下,可以说是尾插吗?
//不行!Collection代表的不一定是线性表,所以就没有次序的概念,没有头和尾的概念
//add 的时候,可能会出现放不进去的时候,所以通过返回值,来判断是否放入成功。
//在Collection的语境下,add可以返回false
//在list的语境下,add一定返回ture
复习多态的知识:
1.通过引用可以执行哪些方法?
由引用类型决定
2.通过引用执行方法后,真正执行的是哪个类的方法
由引用指向的对象类型决定
class Person{....}
class Teacher extends Person{...}
Teacher t = new Teacher();
Person p = t;
//让p指向t目前指向的对象
//由于p的类型是Person
//t 目前指向的对象的类型是Teacher
//所以允许指向
顺序表
1.学会顺序表的原理(逻辑上的理解)
2.重点学习Java中的顺序表(ArrayList)的使用
—————— 常见方法的含义+用法
—————— 继承链条+能力来自谁
3.实现自己的ArrayList
简化次要目标
1.不再追求泛型作为元素类型,使用Integer类型作为元素类型(不用基本类型,主要为了体现equals这些特点)
2.不会出现null元素
角色转换:顺序表的使用者 —>顺序表的实现者
我们需要关心容量的问题了(capacity)
capacity —— size
3.实现的方法(常见方法)+迭代器
实现过程中关注
1.原理
2.代码
3.性能——复杂度
package my_arraylist;
/**
* Program: Created with IntelliJ IDEA
* <p>
* Description:
* <p>
* Author: Wan9N1n9
* <p>
* Time:2021-03-17 21:05
**/
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();
}
package my_arraylist;
import java.util.Arrays;
/**
* Program: Created with IntelliJ IDEA
* <p>
* Description:
* <p>
* Author: Wan9N1n9
* <p>
* Time:2021-03-17 21:16
**/
public class MyArrayList implements MyList {
private Integer[] array;
private int size;
public MyArrayList(){
array = new Integer[16];
size = 0;
}
// O(n)
// 供内部进行容量控制
// 这个方法一旦执行结束后,可以保证,顺序表内部的数组中,至少还可以放一个元素
private void ensureCapacity() {
if (size < array.length) {
// 当前元素个数 < 容量:至少还能放一个元素
return;
}
// 否则进行扩容 —— 搬家的过程
// 1. 找到一个新的房子,一般来说,房子大小往 2 倍进行扩容(经验值)
// 如果新房子太大,意味着很多空间在闲置,浪费了
// 如果新房子太小,意味着需要经常扩容
// 所以,经过经验看,扩大 2 倍相对比较合适
// 原来的房子大小是 array.length,新的房子的大小就是 array.length * 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; // 修改了对象中的属性,以后再操作顺序表,就操作 newArray 指向的对象了
}
// 数据规模 n是什么?元素个数 (size)
//O(1)
// 虽然最坏情况下,确实是 O(n)
// 但由于扩容的机会非常少,所以,一般还是认为尾插是 O(1)
@Override
public boolean add(Integer e) {
//TODO:暂时不考虑容量不足的情况
ensureCapacity();
array[size] = e;// 尾插,放入元素 O(1)
size++; // o(1)
return true;
}
//O(n)
@Override
public void add(int index, Integer e) {
//TODO:暂时不考虑容量不足的情况
ensureCapacity(); // O(n)
//1.判断index下标是否合法
if (index < 0 || index > size){
throw new ArrayIndexOutOfBoundsException("index:"+ index + "size:" + size);
}
//2.进行插入.[index,size)
for (int from = size - 1;from >= index; from--){
int to = from + 1;
array[to] = array[from];
}
// for (int to = index +1; to <= size; to++){
// int from = to -1;
// array[to] =array[from];
//
// }
//把元素放入index 位置
array[index] = e;
//size 增加
size++;
}
//O(n)
@Override
public Integer remove(int index) {
// 判断下标是否合法
if (index < 0 || index >= size){
throw new ArrayIndexOutOfBoundsException("index:"+ index + "size:" + size);
}
//1.把[index + 1,size - 1]的元素往前移一格
Integer e = array[index];
for (int from = index + 1;from < size; from++){
int to = from - 1;
array[to] = array[from];
}
//2.把size-1 置为null
array[size-1] = null;
//3.size 减一
size--;
return e;
}
//O(n)
@Override
public boolean remove(Integer e) {
int i = indexOf(e);
if (i < 0) {
return false;
}
remove(i);
return true;
}
//O(1)
@Override
public Integer get(int index) {
//判断下标的合法性
if (index < 0 || index >= size){
throw new ArrayIndexOutOfBoundsException("index:"+ index + "size:" + size);
}
return array[index];
}
//O(1)
@Override
public Integer set(int index, Integer e) {
if (index < 0 || index >= size){
throw new ArrayIndexOutOfBoundsException("index:"+ index + "size:" + size);
}
int oldE = array[index];
array[index] = e;
return oldE;
}
@Override
public boolean contains(Integer e) {
return indexOf(e) >=0;
}
@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 String toString() {
Integer[] toShow = Arrays.copyOf(array, size);
//toShow.length = size
return Arrays.toString(toShow);
}
@Override
public boolean isEmpty() {
return size == 0;
}
}
package my_arraylist;
/**
* Program: Created with IntelliJ IDEA
* <p>
* Description:
* <p>
* Author: Wan9N1n9
* <p>
* Time:2021-03-18 15:00
**/
public class MyArrayListTest {
public static void main(String[] args) {
MyList list = new MyArrayList();
System.out.println(list); // []
list.add(1);
list.add(2);
list.add(3);
System.out.println(list); // [1, 2, 3]
list.add(0, 100);
list.add(0, 200);
list.add(0, 300);
System.out.println(list); // [300, 200, 100, 1, 2, 3]
Integer remove = list.remove(2);
System.out.println(list); // [300, 200, 1, 2, 3]
System.out.println(remove); // 100
boolean r = list.remove((Integer)1); // 通过类型转换,确认调用的是 remove(Integer) 而不是 remove(int)
System.out.println(r); // true
System.out.println(list); // [300, 200, 2, 3]
System.out.println(list.size());
System.out.println(list.isEmpty());
list.clear();
System.out.println(list.size());
System.out.println(list.isEmpty());
}
}