概览
1.List
List是一个接口继承于Collection接口,数据结构上List代表的是一个线性表
那么对于List接口中的方法有:
- boolean add(E e) :尾插
- void add(int index, E element) :将 e 插入到 index 位置,同时index之后的元素,必须逻辑向后移
- E remove(int index):删除 index 位置元素,同时,index之后的所有元素必须逻辑前移
- boolean remove(Object o) :删除遇到的第一个o元素(本质上是使用equals进行比较)
- E get(int index):获取下标 index 位置元素
- E set(int index, E element) :将下标index位置元素设置为element
- int size():返回元素个数
- void clear():清空线性表
- boolean isEmpty():返回是否是一个空的线性表
- boolean contains(Object o):判断o是否在线性表中(本质上是使用equals进行比较)
- int indexOf(Object o) :返回第一个o所在下标(本质上是使用equals进行比较)
- int lastIndexOf(Object o):返回最后一个o的下标(本质上是使用equals进行比较)
- List < E > subList(int fromIndex, int toIndex):截取部分list,不会影响原来的线性表
- sort (Comparator <?super E>c):对线性表进行排序,根据传入的比较器排序,可以使用匿名内部类
- iterator():返回迭代器,进行从前往后的遍历
- listIterator():效果等同于listIterator(0)
- listIterator(int index):从index位置开始遍历,下标的计算特殊一点
- toArray()系列:list转数组
- Arrays.asList():数组转list
对于方法使用的注意:
- remove:如果是 Integer 类型,则remove(int)就是当下标使用,返回删除的元素。如果是remove((Integer)int),则当元素使用,返回boolean值
- 对于引用类型的删除,需要在类中重写equals方法
- 所有的ArrayList或者List其实都可以看做Collection
2. ArrayList
ArrayList 是一个顺序表,是容器,实现了List接口,通过泛型表现变化的元素类型。
除了继承到的方法,ArrayList增加的额外方法有:
- ArrayList():无参构造
- ArrayList(Collection<? extends E> c) :利用其他 Collection 构建ArrayList
- ArrayList(int initialCapacity):指定顺序表初始容量
对ArrayList进行手动的实现:
2.1 仿写真实的List接口
/**
* 仿写真实的List
*/
public interface List extends Iterable{
//添加元素
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);
int size();
void clear();
boolean isEmpty();
//包含
boolean contains(Integer e);
int indexOf(Integer e);
int lastIndexOf(Integer e);
}
2.2 仿写真实的ArrayList
public class ArrayList implements List {
private int[] array;//数组
private int size;//元素个数
private int capacity;
public ArrayList(){
this.capacity=10;
this.array = new int[this.capacity];
this.size=0;
}
public ArrayList(int capacity) {
this.capacity = capacity;
this.array = new int[capacity];
this.size=0;
}
public ArrayList(List other){
array = new int[other.size()];
for(int i=0;i<other.size();i++){
array[i] = other.get(i);
}
this.size = other.size();
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder("[");
for(int i=0;i<this.size;i++){
if(i==this.size-1){
sb.append(array[i]);
}else{
sb.append(array[i]+", ");
}
}
sb.append("]");
return sb.toString();
}
/**
* 扩容
* 时间复杂度O(n)
*/
public void dilatation(){
if(this.size==this.capacity){
this.capacity*=2;
//定义新数组 并将老数组内容搬到新数组
int[] newArray = Arrays.copyOf(this.array,this.capacity);
this.array = newArray;
}
}
/**
* 时间复杂度:平均 O(1)
* @param e
* @return
*/
@Override
public boolean add(Integer e) {
dilatation();
this.array[size++] = e;
return true;
}
/**
* 时间复杂度:O(n)
*要把index及之后的所有元素,全部向后移
* 为了元素不被覆盖,从后往前搬
* @param index
* @param e
*/
@Override
public void add(int index, Integer e) {
if(index<0 || index>this.size){
throw new IndexOutOfBoundsException("下标不合法!");
}
dilatation();
for(int i=this.size;i>index;i--){
array[i] = array[i-1];
}
array[index] = e;
size++;
}
/**
* 时间复杂度:O(n)
* 从后往前覆盖
* @param index
* @return
*/
@Override
public Integer remove(int index) {
if(index<0 || index>=this.size){
throw new IndexOutOfBoundsException("下标不合法!");
}
int e = array[index];
for(int i = index;i<this.size-1;i++){
array[i] = array[i+1];
}
this.size--;
return e;
}
/**
* 时间复杂度:O(n)
* @param e
* @return
*/
@Override
public boolean remove(Integer e) {
int index = indexOf(e);
if(index!=-1){
remove(index);
return true;
}else{
return false;
}
}
/**
* 时间复杂度:O(1)
* @param index
* @return
*/
@Override
public Integer get(int index) {
if(index<0||index>=this.size){
throw new IndexOutOfBoundsException("下标不合法!");
}
return array[index];
}
/**
* 时间复杂度:O(1)
* @param index
* @param e
* @return
*/
@Override
public Integer set(int index, Integer e) {
if(index<0||index>=this.size){
throw new IndexOutOfBoundsException("下标不合法!");
}
Integer oldData = array[index];
array[index] = e;
return oldData;
}
/**
* 时间复杂度:O(1)
* @return
*/
@Override
public int size() {
return this.size;
}
/**
* 时间复杂度:O(n)
*/
@Override
public void clear() {
//-1代表无效值
Arrays.fill(array,-1);
this.size=0;
}
/**
* 时间复杂度:O(1)
* @return
*/
@Override
public boolean isEmpty() {
return this.size==0;
}
/**
* 时间复杂度:O(n)
* @param e
* @return
*/
@Override
public boolean contains(Integer e) {
return indexOf(e)!=-1;
}
/**
* 时间复杂度:O(n)
* @param e
* @return
*/
@Override
public int indexOf(Integer e) {
for(int i=0;i<this.size;i++){
if(array[i]==e){
return i;
}
}
return -1;
}
/**
* 时间复杂度:O(n)
* @param e
* @return
*/
@Override
public int lastIndexOf(Integer e) {
for(int i=this.size-1;i>=0;i--){
if(array[i]==e){
return i;
}
}
return -1;
}
@Override
public Iterator iterator() {
//返回一个Iterator接口的实现类的对象
return new ArrayListIterator(this);
}
}
2.3 仿写真实的Iterator接口(迭代器)
- 迭代器互相之间独立
- 迭代遍历的同时,不允许修改list的结构
- 如果确实需要删除,需要使用迭代器中的remove方法,可以删除当前迭代到的位置
/**
* 仿写真实的Iterator接口
* 迭代器
*/
public interface Iterator {
//返回true,表示本次迭代还没有把所有的数据遍历完
boolean hasNext();
//返回要遍历的下一个元素
Integer next();
void remove();
}
2.4 仿写真实的Iterable接口
iterate迭代,一个一个遍历
- 如果一个类实现了Iterable接口,则表示这个类具备迭代的能力,隐含着,这个类的对象实际上表示一个容器
- 该类通过返回一个迭代器(Iterator),可以通过这个迭代器进行容器内的元素的迭代
/**
* 仿写真实的Iterable接口
* 具备迭代能力 使用了依赖了Iterator接口
*/
public interface Iterable {
Iterator iterator();
}
2.5 Iterator的实现类ArrayListIterator
/**
Iterator的实现类 用于给ArrayList中传递
*/
public class ArrayListIterator implements Iterator{
private int index;
private ArrayList list;
//对一个顺序表做迭代,关键是控制下标
public ArrayListIterator(ArrayList list) {
this.index = 0;
this.list = list;
}
@Override
public boolean hasNext() {
return index<list.size();
}
@Override
public Integer next() {
return list.get(index++);
}
@Override
public void remove() {
//TODO
}
}
2.6 泛型的ArrayList
重点对于构造方法、两种toArray方法、indexOf、clear进行实现
/**
* 泛型的ArrayList
* clear或者其他删除的时候,除了修改size,一定要把从List中删除掉的元素置为null,以免内存泄露
* contains/indexOf/lastIndexOf等方法,都随时可能调用元素的equals方法
* toArray的两种实现
*/
public class MyArrayList<E> implements List<E> {
private E[] array;
private int size;
public MyArrayList() {
//无法直接定义泛型数组,所以只能定义Object类型数组 然后强转
this.array = (E[])new Object[10];
this.size = 0;
}
@Override
public int size() {
return this.size;
}
@Override
public boolean isEmpty() {
return this.size==0;
}
@Override
public boolean contains(Object o) {
return indexOf(o)!=-1;
}
@Override
public Iterator<E> iterator() {
return null;
}
/**
*
* @return
*/
@Override
public Object[] toArray() {
Object[] a = new Object[size];
for(int i=0;i<this.size;i++){
a[i] = array[i];
}
return a;
}
/**
* 传进来的数组 长度小于size创建一个新数组返回
* 大于size将元素放进去,并将size处元素置为null
* 等于size,将元素放进去返回
* @param a
* @param <T>
* @return
*/
@Override
public <T> T[] toArray(T[] a) {
if(a.length<size){
//创建一个数组直接返回
T[] newArray = (T[])new Object[size];
for(int i=0;i<size;i++){
newArray[i] = (T)array[i];
}
return newArray;
}else if(a.length==size){
//把元素放入并返回
for(int i=0;i<size;i++){
a[i] = (T)array[i];
}
return a;
}else{
//把元素放入并返回
//把超过的第一个位置设置为null
for(int i=0;i<size;i++){
a[i] = (T)array[i];
}
a[size] = null;
return a;
}
}
@Override
public boolean add(E e) {
array[size++] = e;
return true;
}
@Override
public boolean remove(Object o) {
int i = indexOf(o);
if(i==-1){
return false;
}else{
remove(i);
return true;
}
}
@Override
public boolean containsAll(Collection<?> c) {
return false;
}
@Override
public boolean addAll(Collection<? extends E> c) {
return false;
}
@Override
public boolean addAll(int index, Collection<? extends E> c) {
return false;
}
@Override
public boolean removeAll(Collection<?> c) {
return false;
}
@Override
public boolean retainAll(Collection<?> c) {
return false;
}
@Override
public void clear() {
//如果是基本类型,数组中元素是否需要清理成无效值其实无所谓
//但如果是引用类型,必须把数组中的元素修改为null,这样不会内存泄露
Arrays.fill(array,null);
this.size=0;
}
@Override
public E get(int index) {
return array[index];
}
@Override
public E set(int index, E element) {
E oldData = array[index];
array[index] = element;
return oldData;
}
@Override
public void add(int index, E element) {
}
@Override
public E remove(int index) {
return null;
}
/**
*
* @param o
* @return
*/
@Override
public int indexOf(Object o) {
for(int i=0;i<this.size;i++){
if(o==null){
if(array[i]==o){
return i;
}
}else{
if(array[i].equals(o)){
return i;
}
}
}
return -1;
}
@Override
public int lastIndexOf(Object o) {
return 0;
}
@Override
public ListIterator<E> listIterator() {
return null;
}
@Override
public ListIterator<E> listIterator(int index) {
return null;
}
@Override
public List<E> subList(int fromIndex, int toIndex) {
return null;
}
}
3. LinkedList
List的实现类,数据结构是链表(双向链表,记录了第一个和最后一个节点)
除了继承的方法外,新增的方法只有一个无参的构造方法
对于LinkedList的手动实现:前面的List接口、Iterator接口、Iterable接口直接使用
3.1 节点类(Node)
public class Node {
public Node prev;
public Node next;
public Integer element;
public Node(Integer element) {
this.element = element;
}
}
3.2 仿写真实的LinkedList
public class LinkedList implements List{
public Node head; //指向第一个节点
public Node last;//指向最后一个节点
public int size;
@Override
public String toString() {
StringBuilder sb = new StringBuilder("[");
for(Node cur = this.head;cur!=null;cur = cur.next){
sb.append(cur.element);
if(cur!=last){
sb.append(", ");
}
}
sb.append("]");
return sb.toString();
}
/**
* 尾插 时间复杂度 O(1)
* @param e
* @return
*/
@Override
public boolean add(Integer e) {
Node node = new Node(e);
if(size==0){//判空
this.head = this.last = node;
}else{
this.last.next = node;
node.prev = this.last;
this.last = node;
}
size++;
return true;
}
/**
* O(n)
* @param index
* @param e
*/
@Override
public void add(int index, Integer e) {
if(index<0 || index>size){
throw new IndexOutOfBoundsException("下标越界!");
}
Node node = new Node(e);
//index==0 头插
if(index==0){
if(this.size==0){
this.head = node;
this.last = node;
}else{
node.next = this.head;
this.head.prev = node;
this.head = node;
}
this.size++;
return;
}else if(index==this.size){ //index==size 调用尾插
add(e);
}else{
//中间插入
//跳index不部找插入位置,也可以跳index-1步找前驱位置
Node cur = null;
if(index<size/2){
cur = this.head;
while(index>0){
cur = cur.next;
index--;
}
}else{
cur = this.last;
while(this.size-1-index>0){
cur = cur.prev;
index++;
}
}
node.next = cur;
cur.prev.next = node;
node.prev = cur.prev;
cur.prev = node;
this.size++;
}
}
/**
* O(n)
* @param index
* @return
*/
@Override
public Integer remove(int index) {
if(index<0 || index>=this.size){
throw new IndexOutOfBoundsException("下标非法!");
}
Integer v = 0;
//index==0 头删
if(index==0){
if(this.head!=null&&this.head.next==null){
v = this.head.element;
this.head = null;
this.last = null;
}else{
v = this.head.element;
this.head = this.head.next;
this.head.prev = null;
}
size--;
}else if(index==this.size-1){// 尾删
v = this.last.element;
this.last = this.last.prev;
this.last.next = null;
size--;
if(size==0){
head=null;
}
}else{
Node cur = null;
if(index<size/2){
cur = this.head;
while(index>0){
cur = cur.next;
index--;
}
}else{
cur = this.last;
while(this.size-1-index>0){
cur = cur.prev;
index++;
}
}
v = cur.element;
cur.prev.next = cur.next;
cur.next.prev = cur.prev;
size--;
}
return v;
}
/**
* O(n)
* @param e
* @return
*/
@Override
public boolean remove(Integer e) {
for(Node cur = this.head;cur!=null;cur = cur.next){
if(cur.element.equals(e)){
if(cur.prev==null){
remove(0);
}else if(cur.next==null){
remove(this.size-1);
}else{
cur.prev.next = cur.next;
cur.next.prev = cur.prev;
size--;
}
return true;
}
}
return false;
}
/**
* O(n)
* @param index
* @return
*/
@Override
public Integer get(int index) {
if(index<0 || index>=this.size){
throw new IndexOutOfBoundsException("下标非法!");
}
Node cur = this.head;
for(int i=0;i<this.size;i++){
cur = cur.next;
}
return cur.element;
}
/**
* O(n)
* @param index
* @param e
* @return
*/
@Override
public Integer set(int index, Integer e) {
if(index<0 || index>=this.size){
throw new IndexOutOfBoundsException("下标非法!");
}
Node cur = this.head;
for(int i=0;i<this.size;i++){
cur = cur.next;
}
Integer v = cur.element;
cur.element = e;
return v;
}
/**
* O(1)
* @return
*/
@Override
public int size() {
return this.size;
}
@Override
public void clear() {
this.head = this.last = null;
this.size = 0;
}
@Override
public boolean isEmpty() {
return this.size==0;
}
@Override
public boolean contains(Integer e) {
return indexOf(e)!=-1;
}
/**
* O(n)
* @param e
* @return
*/
@Override
public int indexOf(Integer e) {
Node cur = this.head;
int index=0;
while(cur!=null){
if(cur.element.equals(e)){
return index;
}
index++;
cur = cur.next;
}
return -1;
}
/**
* O(n)
* @param e
* @return
*/
@Override
public int lastIndexOf(Integer e) {
Node cur = this.last;
int index=0;
while(cur!=null){
if(cur.element.equals(e)){
return this.size-index-1;
}
index++;
cur = cur.prev;
}
return -1;
}
@Override
public Iterator iterator() {
//返回一个Iterator的实现类
return new LinkedListIterator(this);
}
}
3.3 Iterator的实现类LinkedListIterator
public class LinkedListIterator implements Iterator{
private LinkedList list;
private Node cur;
public LinkedListIterator(LinkedList list) {
this.list = list;
this.cur = list.head;
}
@Override
public boolean hasNext() {
return cur!=null;
}
@Override
public Integer next() {
Integer v = cur.element;
cur = cur.next;
return v;
}
@Override
public void remove() {
//TODO
}
}
4. ArrayList 和LinkedList的区别
从以下几方面考虑:
- 每个方法做什么用,参数列表和返回值是什么
- 大概描述每个方法的具体实现
- 每个方法的时间复杂度
- 有些方法有部分特殊点