单向链表
相比于链表,动态数组有一个很大的缺点,就是会造成很大的空间浪费;
链表则可以做到用多少就申请多少内存;
链表:是一种链式存储的线性表,所有元素的内存地址不一定是连续的。
对于链表,由一个个节点元素Node元素组成,其first指针指向链表的第一个元素;size表示有多少个节点;
Node节点:
- element:存放的是泛型对象
- next:指向下一个节点元素的指针
1.接口设计
- 在动态数组和链表的实现方法中,所有的接口都是可以共用的,所以可以创建一个Interface,将所有公共的接口放到这个文件中;
- 有部分例如siz(), isEmpty()等接口,可以抽象出一个类,使得ArrayList和LinkedList都继承自这个类;
interface :
public interface List {
static final int ELEMENT_NOT_FOUND = -1;
/**
* 清除所有元素
*/
void clear();
/**
* 元素的数量
* @return
*/
int size();
/**
* 是否为空
* @return
*/
boolean isEmpty();
/**
* 是否包含某个元素
* @param element
* @return
*/
boolean contains(E element);
/**
* 添加元素到尾部
* @param element
*/
void add(E element);
/**
* 获取index位置的元素
* @param index
* @return
*/
E get(int index);
/**
* 设置index位置的元素
* @param index
* @param element
* @return 原来的元素ֵ
*/
E set(int index, E element);
/**
* 在index位置插入一个元素
* @param index
* @param element
*/
void add(int index, E element);
/**
* 删除index位置的元素
* @param index
* @return
*/
E remove(int index);
/**
* 查看元素的索引
* @param element
* @return
*/
int indexOf(E element);
}
公共抽象类:AbstractList
//abstract 修饰以后可以不实现interface中的接口,或者部分实现
public abstract class AbstractList implements List{
protected int size;
/**
* 元素的数量
* **/
public int size(){
return size;
}
/*
* 判断是否为空
* **/
public boolean isEmpty() {
return size == 0;
}
/*
* 是否包含某个元素E
* **/
public boolean contains(E element) {
return indexOf(element) != ELEMENT_NOT_FOUND;
}
/*
* 添加元素到末尾
**/
public void add(E element) {
add(size,element);
}
/*
* 范围检查
* */
protected void rangeCheck(int index){
if (index < 0 || index >= size) {
throwException(index);
}
}
/*
* 添加元素范围检查
* */
protected void rangeCheckforAdd(int index){
if (index < 0 || index > size) {
throwException(index);
}
}
/*
* 抛出异常
* */
protected void throwException(int index){
throw new IndexOutOfBoundsException("Index" + index + ",Size"+ size);
}
}
注意细节:
- 允许在子类中使用:protected 关键字修饰;
- 实现interface中接口方法: implements List
; - 部分实现interface中接口方法:使用abstract关键字修饰;
- 在ArrayList及LinkedList中继承自AbstractList:extends AbstractList
2.具体方法实现
1 、获取index位置的节点:
/**获取index位置的节点
* */
private Node node(int index){
rangeCheck(index);
Node node = first;
for (int i = 0; i < index; i++) {
node = node.next;
}
return node;
}
for循环遍历index次,获得第index位置的节点;
2、 清空链表 clear()
public void clear() {
size = 0;
first = null;
}
首先size = 0,其次将first指针指向null,则后面所有的元素被指向的指针都会消失,则链表会被清空;
3、 获取指定位置元素get(int index)
public E get(int index) {
return node(index).element;
}
4、 设置指定位置元素set(int index, E element)
public E set(int index, E element) {
Node node = node(index);
E old = node.element;
node.element = element;
return old;
}
获取当前index的元素,替换其值element
5、 获取指定位置元素add(int index, E element)
public void add(int index, E element) {
if (index == 0) {
first = new Node<>(element, first);
}else{
Node prev = node(index - 1);
prev.next = new Node<>(element,prev.next);
}
size++;
}
- 当index ==0 时,创建一个新的Node节点,其next指针指向原有的第一个位置的元素,即first.next;
- 当index > 0 时;先获取前一个节点,前一个节点指向新创建的节点,新创建的节点的next指向prev.next;
6、 删除指定位置元素remove(int index)
public E remove(int index) {
Node node = first;
if (index == 0) {
first = first.next;
}else{
Node prev = node(index - 1);
node = prev.next;
prev.next = prev.next.next;
}
size --;
return node.element;
}
- 当index ==0 时,直接将first指针指向第一个节点first.next;
- 当index > 0 时;先获取前一个节点,前一个节点指index - 1位置的元素prev.next.next;
7、 获取指定位置元素的索引indexOf(E element)
public int indexOf(E element) {
Node node = first;
if (element == null) {
for (int i = 0; i < size; i++) {
if(node.element==null) return i;
node = node.next;
}
}else{
for (int i = 0; i < size; i++) {
if(element.equals(node.element)) return i;
node = node.next;
}
}
return ELEMENT_NOT_FOUND;
}
- 当element == null 时,直接for循环返回node.element == null对应的i;
- 当element != null 时;直接for循环返回node.element == element对应的i;