递归实现单链表
链表也是天然的递归结构
递归三要素:
1.大问题能拆分为子问题的解
2拆分后的子问题和原问题除了数据规模不同,解决思路完全相同
3.存在递归的终止条件。不借助任何外部函数的特殊值,直接得出答案
插入
private Node addInternal(Node head, int index, E element) {
// 1.base case
if (index == 0) {
// 头插
Node node = new Node(element);
node.next = head;
head = node;
size ++;
return head;
}
// index不在头结点插入
head.next = addInternal(head.next,index - 1,element);
return head;
}
双链表
单链表只能从头遍历到结束,只能从一个结点走到下一个节点。
因此,我们引入了双向链表的概念,从任意节点既能向前又能向后!
增删查改
插入
头插
public void addFirst(E element) {
DoubleNode node = new DoubleNode(element);
size ++;
if(tail == null){
tail = node;
}else{
node.next = head;
head.prev = node;
}
head = node;
}
尾插
public void add(E element) {
DoubleNode node = new DoubleNode(element);
size++;
if(head == null){
head = node;
}else{
node.prev = tail;
tail.next = node;
}
tail = node;
}
任意位置插入
public void add(int index, E element) {
if (index < 0 || index > size) {
throw new IllegalArgumentException("add index illegal!");
}
if (index == 0) {
addFirst(element);
return;
}
if (index == size) {
add(element);
return;
}
DoubleNode prev = node(index - 1);
DoubleNode next = prev.next;
DoubleNode node = new DoubleNode(prev,element,next);
// 先处理左半边
// node.prev = prev;
prev.next = node;
// 再处理右半边
// node.next = next;
next.prev = node;
size ++;
}
删除
public E removeByIndex(int index) {
if (!rangeCheck(index)) {
throw new IllegalArgumentException("remove index illegal!");
}
DoubleNode node = node(index);
unlink(node);
return node.val;
}
public void removeByValue(E element) {
DoubleNode node = head;
for (int i = 0; i < size; i++) {
if (node.val.equals(element)) {
unlink(node);
return;
}
node = node.next;
}
}
public void removeAllValue(E element) {
DoubleNode node = head;
int length = this.size;
for (int i = 0; i < length; i++) {
DoubleNode next = node.next;
if (node.val.equals(element)) {
unlink(node);
}
node = next;
}
}
private void unlink(DoubleNode node) {
DoubleNode prev = node.prev;
DoubleNode next = node.next;
// 先处理左边
if (prev == null) {
this.head = next;
}else {
node.prev = null;
prev.next = next;
}
// 在处理右边
if (next == null) {
this.tail = prev;
}else {
node.next = null;
next.prev = prev;
}
size --;
}
修改
public E set(int index, E element) {
// 合法性校验
if (!rangeCheck(index)) {
throw new IllegalArgumentException("set index illegal!");
}
// 遍历走到index对应的元素
DoubleLinkedList.DoubleNode x = head;
for (int i = 0; i < index; i++) {
x = x.next;
}
// 此时x就落在了待修改的节点位置
E oldVal = (E) x.val;
x.val = element;
return oldVal;
}
查询
public E get(int index) {
if (!rangeCheck(index)) {
throw new IllegalArgumentException("get index illegal!");
}
return node(index).val;
}
总结
递归实现单链表,使得插入删除等操作变得更加简便,这里注意递归思想的适用于理解。
双链表的增删查改与单链表相似,在工程中一般使用双链表。