线性表的特点
如上图所示,a2是a1的后继,a1是a2的前驱,其中a1没有前驱,an没有后继,n为线性表的长度,当n==0时,线性表为空
其中顺序存储方式的表称为顺序表,链式存储方式的表称为链表
一、顺序表
存储位置连续,可以很方便计算各个元素的地址,查询效率高,增删效率低
代码实现add、remove等操作
public class MyArrayList {
private final int DEFAULT_SIZE = 3; // 默认初始数组大小
private Object[] arr = new Object[DEFAULT_SIZE]; // 初始化数组
private final int n = 1; // 数组动态增长的倍数
private int size = 0; // 长度
/**
* 添加数据
* @param obj 要添加的值
*/
public void add(Object obj) {
if(size == arr.length) {
Object[] temp = new Object[DEFAULT_SIZE + n*DEFAULT_SIZE];
for (int i = 0; i < arr.length; i++) {
temp[i] = arr[i];
}
arr = temp;
}
arr[size++] = obj;
}
/**
* 移除下标为index元素
* @param index 第几个元素
* @return 是否移除成功
*/
public boolean remove(int index) {
if(index < 0 || index> size()) {
return false;
}
for (int j = 0; j < size(); j++) {
if(index == j) {
for(int k = j; k < size() - 1; k++ ) {
arr[j] = arr[j+1];
}
size--;
return true;
}
}
return false;
}
/**
* 获取指定索引上的元素
* @param index
* @return 第index上的索引的元素
*/
public Object get(int index) {
return index < 0 || index > size() ? null : arr[index];
}
/**
* 获取元素个数
* @return
*/
public int size() {
return size;
}
}
二、链表
线性表的链式存储结构的特点是用一组任意的存储单元存储线性表的数据元素,这组存储单元可以是连续的,也可以是不连续的,增删效率高,查询效率相对低
代码实现add、remove等操作
public class MyLinkedList<E> implements Iterable<E> {
private int theSize;
private int modCount = 0;
private Node<E> beginMarker;
private Node<E> endMarker;
private static class Node<E>{
public E data;
public Node<E> prev;
public Node<E> next;
public Node(E d,Node<E> p,Node<E> n) {
data = d;
prev = p;
next = n;
}
}
public MyLinkedList() {
doClear();
}
public void clear(){
doClear();
}
public int size(){
return theSize;
}
public boolean isEmpty(){
return size()==0;
}
/**
* 直接在链表后端插入元素
* @param x
*/
public void add(E x){
add(size(),x);
}
/**
* 根据索引取到元素,在元素后面插入新元素
* @param index
* @param x
*/
public void add(int index,E x){
addBefore(getNode(index,0,size()),x);
}
/**
* 根据下标移除元素
* @param index
* @return
*/
public E remove(int index){
return remove(getNode(index));
}
/**
* 通过获取一个新节点,然后按照指示的顺序改变指针而完成一个双链表中的插入操作
* @param p
* @param x
*/
public void addBefore(Node<E> p,E x){
Node<E> newNode = new Node<>(x,p.prev,p);
p.prev.next = newNode;
p.prev = newNode;
theSize++;
modCount++;
}
/**
* 将p前一个节点指向后一个节点,后一个节点指向前一个节点
* @param p
* @return
*/
private E remove(Node<E> p){
p.next.prev = p.prev;
p.prev.next = p.next;
theSize--;
modCount++;
return p.data;
}
/**
* 根据下标取元素
* @param index
* @return
*/
private Node<E> getNode(int index){
return getNode(index,0,size()-1);
}
private Node<E> getNode(int index,int lower,int upper){
Node<E> p;
if (index < lower || index > upper)
throw new IndexOutOfBoundsException();
if (index < size() / 2){
p = beginMarker.next;
for (int i = 0;i < index;i++)
p = p.next;
}else {
p = endMarker;
for (int i = size();i > index;i--)
p = p.prev;
}
return p;
}
private void doClear(){
beginMarker = new Node<>(null,null,null);
endMarker = new Node<>(null,beginMarker,null);
beginMarker.next = endMarker;
theSize = 0;
modCount++;
}
@Override
public Iterator<E> iterator() {
return new LinkedListIterator();
}
private class LinkedListIterator implements Iterator<E>{
private Node<E> current = beginMarker.next;
private int expectedModCount = modCount;
private boolean okToRemove = false;
@Override
public boolean hasNext() {
return current != endMarker;
}
@Override
public E next() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
if (!hasNext())
throw new NoSuchElementException();
E nextItem = current.data;
current = current.next;
okToRemove = true;
return nextItem;
}
@Override
public void remove() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
if (!okToRemove)
throw new IllegalStateException();
MyLinkedList.this.remove(current.prev);
expectedModCount++;
okToRemove = false;
}
}
}