数组链表基本原理
-
数组和链表是数据结构的基石
-
很多复杂的数据结构的底层都是数组和链表
数组
-
数组是最基本的构造类型,它是一组相同类型数据的有序集合
-
在数组中,随机访问的时间复杂度为O(1),可以通过索引直接访问任何一个元素
-
插入和删除的时间复杂度为O(n)
以下是MyArrayList的Java代码实现:
public class MyArrayList<E> implements Iterable<E> {
// 真正存储数据的底层数组
private E[] data;
// 记录当前元素个数
private int size;
// 默认初始容量
private static final int INIT_CAP = 1;
public MyArrayList() {
this(INIT_CAP);
}
public MyArrayList(int initCapacity) {
data = (E[]) new Object[initCapacity];
size = 0;
}
// 增
public void add(int index, E e) {
checkPositionIndex(index);//检查索引越界
int cap = data.length;//判断data数组的容量够不够
if(size==cap){
resize(2*cap);
}
System.arraycopy(data,index,data,index+1,size-index);
data[index] = e;
size++;
}
public void addLast(E e) {
int cap = data.length;//判断data数组的容量够不够
if(size==cap){
resize(2*cap);
}
data[size] = e;
size++;
}
public void addFirst(E e) {
add(0,e);
}
// 删
public E remove(int index) {
//检查索引边界
checkElementIndex(index);
int cap = data.length;
//可以缩容,节约空间
if (size<=cap/4){
resize(cap/2);
}
E deletedValue = data[index];
System.arraycopy(data,index + 1,data,index,size-index-1);
size--;
return deletedValue;
}
public E removeFirst() {
return remove(0);
}
public E removeLast() {
if(size==0){
throw new NoSuchElementException();
}
int cap = data.length;
//可以缩容,节约空间
if (size<=cap/4){
resize(cap/2);
}
E deletedValue = data[size-1];
data[size-1] = null;
size--;
return deletedValue;
}
// 查
public E get(int index) {
checkElementIndex(index);
return data[index];
}
// 改
public E set(int index, E element) {
checkElementIndex(index);
E previousValue = data[index];
data[index] = element;
return previousValue;
}
// 工具方法
// 将 data 的容量改为 newCap
private void resize(int newCap) {
if(size>newCap){
return;
}
E[] temp = (E[])new Object[newCap];
for (int i = 0; i <size; i++) {
temp[i] = data[i];
}
//System.arrayCopy(data,0,temp,0,size)
data = temp;
}
public int size() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
private boolean isElementIndex(int index) {
return index >= 0 && index < size;
}
private boolean isPositionIndex(int index) {
return index >= 0 && index <= size;
}
/**
* 检查 index 索引位置是否可以存在元素
*/
private void checkElementIndex(int index) {
if (!isElementIndex(index))
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
}
/**
* 检查 index 索引位置是否可以添加元素
*/
private void checkPositionIndex(int index) {
if (!isPositionIndex(index))
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
}
@Override
public Iterator<E> iterator() {
return new Iterator<E>() {
private int p = 0;
@Override
public boolean hasNext() {
return p != size;
}
@Override
public E next() {
return data[p++];
}
};
}
}
链表
-
链表是一种常见的基础数据结构,它由一系列节点(Node)组成,用于存储一连串数据元素。
-
每个节点包含两部分:数据域(存储实际数据)和指针域(存储下一个节点的地址)
-
在链表中,随机访问的时间复杂度为O(n)
-
插入和删除行为本身的时间复杂度为O(1)
-
插入和删除操作本身(修改指针)非常快
-
找到插入位置的过程可能需要O(n)的时间
插入位置 时间复杂度 在头部和尾部插入 O(1) 在中间插入 O(n)
-
动手实现MyLinkedList
import java.util.Iterator;
import java.util.NoSuchElementException;
public class MyLinkedList<E> implements Iterable<E> {
// 虚拟头尾节点
final private Node<E> head, tail;
// 记录元素个数
private int size;
// 双链表节点
private static class Node<E> {
E val;
Node<E> next;
Node<E> prev;
Node(E val) {
this.val = val;
}
}
// 构造函数初始化头尾节点
public MyLinkedList() {
this.head = new Node<>(null);
this.tail = new Node<>(null);
head.next = tail;
tail.prev = head;
this.size = 0;
}
// **** 增 ****
public void addLast(E e) {
// temp <-> x <-> tail
Node<E> x = new Node<>(e);
Node<E> temp = tail.prev;
temp.next = x;
x.prev = temp;
x.next = tail;
tail.prev = x;
size++;
}
public void addFirst(E e) {
//head <-> x <-> temp
Node<E> x = new Node<>(e);
Node<E> temp = head.next;
temp.prev = x;
x.next = temp;
head.next = x;
x.prev = head;
size++;
}
public void add(int index, E element) {
checkPositionIndex(index);
if(index == size){
addLast(element);
return;
}
// 找到index对应的Node
Node<E> p = getNode(index);
Node<E> temp = p.prev;
// temp <-> p
//新要插入的Node
Node<E> x = new Node<>(element);
p.prev = x;
temp.next = x;
x.prev = temp;
x.next = p;
// temp <-> x <-> p
size++;
}
// **** 删 ****
public E removeFirst() {
if (size<1){
throw new NoSuchElementException();
}
Node<E> x = head.next;
Node<E> temp = x.next;
// head <-> x <-> temp
head.next = temp;
temp.prev = head;
x.prev = null;
x.next = null;
size--;
return x.val;
}
public E removeLast() {
if(size<1){
throw new NoSuchElementException();
}
Node<E> x = tail.prev;
Node<E> temp = x.prev;
//temp <-> x <-> tail
tail.prev = temp;
temp.next = tail;
x.next = null;
x.prev = null;
// temp <-> tail
size--;
return x.val;
}
public E remove(int index) {
checkElementIndex(index);
// 找到index所对应的Node
Node<E> x = getNode(index);
Node<E> prev = x.prev;
Node<E> next = x.next;
// prev <-> x <-> next
prev.next = next;
next.prev = prev;
x.next = next.prev = null;
size--;
return x.val;
}
// **** 查 ****
public E get(int index) {
checkElementIndex(index);
// 找到 index 对应的 Node
Node<E> p = getNode(index);
return p.val;
}
public E getFirst() {
if (size<1){
throw new NoSuchElementException();
}
return head.next.val;
}
public E getLast() {
if (size<1){
throw new NoSuchElementException();
}
return tail.prev.val;
}
// **** 改 ****
public E set(int index, E val) {
checkElementIndex(index);
// 找到 index 对应的 Node
Node<E> p = getNode(index);
E oldVal = p.val;
p.val = val;
return oldVal;
}
// **** 其他工具函数 ****
public int size() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
private Node<E> getNode(int index) {
checkElementIndex(index);
Node<E> p = head.next;
// TODO: 可以优化,通过 index 判断从 head 还是 tail 开始遍历
for (int i = 0; i < index; i++) {
p = p.next;
}
return p;
}
private boolean isElementIndex(int index) {
return index >= 0 && index < size;
}
private boolean isPositionIndex(int index) {
return index >= 0 && index <= size;
}
/**
* 检查 index 索引位置是否可以存在元素
*/
private void checkElementIndex(int index) {
if (!isElementIndex(index))
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
}
/**
* 检查 index 索引位置是否可以添加元素
*/
private void checkPositionIndex(int index) {
if (!isPositionIndex(index))
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
}
@Override
public Iterator<E> iterator() {
return new Iterator<>() {
Node<E> p = head.next;
@Override
public boolean hasNext() {
return p != tail;
}
@Override
public E next() {
E val = p.val;
p = p.next;
return val;
}
};
}
}
以上