双链表
- 1.双链表
- 2.双链表的创建
- 3.双链表的头插节点
- 4.双链表尾插
- 5.双链表根据索引找节点
- 6.双链表根据索引插入节点
- 7.双链表删除值为key的节点
- 8.删除所有值为key的节点
- 9.双链表是否包含值为key节点
- 10.双链表大小
- 11.清空双链表
- 12.打印双链表
1.双链表
双链表是一种数据结构,其中每个节点包含一个指向前一个节点的指针和一个指向后一个节点的指针。由于链表没有将元素存储在连续的空间中,元素存储在单独的节点中,然后通过引用将节点连接起来,因此双链表可以任意且快速的插入和删除元素。
2.双链表的创建
引用接口IList,在把IList接口里面的方法进行重写,实现双链表的功能。把双链表封装成一个类,类中封装一个节点类ListNode,里面的节点类有当前节点的值val、指向前一个节点的ListNode prev和指向后一个节点的变量ListNode next。最后在外部类中定义头节点、尾节点,利用外部类的构造器中就可以对头尾节点的初始化。
public class MyLinkedList implements IList{
static class ListNode {
public int val;
public ListNode next;
public ListNode prev;
public ListNode(int val) {
this.val = val;
}
}
public ListNode head;
public ListNode last;
}
3.双链表的头插节点
头插node节点,如果链表为空,直接把插入的节点设为头尾节点,不为空把node的下一个节点指向head头节点,再把head的前节点指向node,最后把head指向node。
public void addFirst(int data) {
ListNode node = new ListNode(data);
if (head == null) {
head = node;
last = node;
}else {
node.next = head;
head.prev = node;
head = node;
}
}
4.双链表尾插
尾插node节点,如果链表为空,直接把插入的节点设为头尾节点,不为空把last尾节点的next(即后节点)指向node,再把node的前节点prev指向last,最后把尾节点last指向node。
@Override
public void addLast(int data) {
ListNode node = new ListNode(data);
if (head == null) {
head = node;
last = node;
}else {
last.next = node;
node.prev = last;
last = node;
}
}
5.双链表根据索引找节点
定义一个count变量来计数,从头节点开始遍历,当计数值为索引值退出循环,返回cur为插入节点的后节点。
private ListNode findIndex(int index) {
int count = 0;
ListNode cur = head;
while (count != index) {
count++;
cur = cur.next;
}
return cur;
}
6.双链表根据索引插入节点
根据索引插入可分三种情况:
- 当在最前面插入节点时为头插法
- 在最后一个位置插入则是尾插法
- 中间插入时遍历链表找到插入节点为node的下标,然后1:把node的后节点指向cur 即node.next = cur;2:把cur前节点的后节点指向node,即cur.prev.next = node;3:把node的前节点指向cur的前节点,即node.prev = cur.prev;4:把cur的前节点指向node,即cur.prev = node。
@Override
public void addIndex(int index, int data) throws IndexException{
if (index < 0 || index > size()) {
throw new IndexException("双向链表插入,index不合法"+index);
}
ListNode node = new ListNode(data);
// 在0位置就是头插法
if(index == 0) {
addFirst(data);
return;
}
// 在最后一个位置插入
if (index == size()) {
addLast(data);
return;
}
// 中间
ListNode cur = findIndex(index);
node.next = cur;
cur.prev.next = node;
node.prev = cur.prev;
cur.prev = node;
}
}
7.双链表删除值为key的节点
遍历链表,若cur.val为key,删除cur节点
- 若cur为head头节点时,把head指向head的后节点,当head不为空时,把head的前节点直接置为null,只有一个节点时直接把last指向null。
- 当cur不等于头节点head时,把cur前节点的后节点指向cur的后节点,即:cur.prev.next = cur.next。若cur的后节点不为空即删除中间节点时:把cur的后节点的前节点指向cur的前节点,即:cur.next.prev = cur.prev,若cur为尾节点时,把last指向last的前节点,即:last = last.prev。
@Override
public void remove(int key) {
ListNode cur = head;
while (cur != null) {
if (cur.val == key) {
if (cur == head) {
head = head.next;
if (head != null) {
head.prev = null;
}else {
//只有一个节点 且是需要删除的节点
last = null;
}
}else {
cur.prev.next = cur.next;
//删除中间节点
if (cur.next != null) {
//cur.prev.next = cur.next;
cur.next.prev = cur.prev;
}else {
// 删除尾巴节点
//cur.next.prev = cur.next;
last = last.prev;
}
}
return;
}
cur = cur.next;
}
}
8.删除所有值为key的节点
即上面删除完第一个key的节点之后不跳出循环,接着删除。
@Override
public void removeAllKey(int key) {
ListNode cur = head;
while (cur != null) {
if (cur.val == key) {
if (cur == head) {
head = head.next;
if (head != null) {
head.prev = null;
}else {
//只有一个节点 且是需要删除的节点
last = null;
}
}else {
cur.prev.next = cur.next;
//删除中间节点
if (cur.next != null) {
//cur.prev.next = cur.next;
cur.next.prev = cur.prev;
}else {
// 删除尾巴节点
//cur.next.prev = cur.next;
last = last.prev;
}
}
}
cur = cur.next;
}
}
9.双链表是否包含值为key节点
@Override
public boolean contains(int key) {
ListNode cur = head;
while (cur != null) {
if (cur.val == key) {
return true;
}
cur = cur.next;
}
return false;
}
10.双链表大小
@Override
public int size() {
int count = 0;
ListNode cur = head;
while (cur != null) {
count++;
cur = cur.next;
}
return count;
}
11.清空双链表
@Override
public void clear() {
ListNode cur = head;
while (cur != null) {
ListNode curNext = cur.next;
cur.next = null;
cur.prev = null;
cur = curNext;
}
this.head = null;
this.last = null;
}
12.打印双链表
@Override
public void display() {
ListNode cur = head;
while (cur != null) {
System.out.print(cur.val + " ");
cur = cur.next;
}
System.out.println();
}