双链表是一种数据结构,其中每个节点包含一个指向前一个节点的指针和一个指向后一个节点的指针。由于链表没有将元素存储在连续的空间中,元素存储在单独的节点中,然后通过引用将节点连接起来,因此双链表可以任意且快速的插入和删除元素。
引用接口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;
}
头插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;
}
}
尾插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;
}
}
定义一个count变量来计数,从头节点开始遍历,当计数值为索引值退出循环,返回cur为插入节点的后节点。
private ListNode findIndex(int index) {
int count = 0;
ListNode cur = head;
while (count != index) {
count++;
cur = cur.next;
}
return cur;
}
根据索引插入可分三种情况:
@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;
}
}
遍历链表,若cur.val为key,删除cur节点
@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;
}
}
即上面删除完第一个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;
}
}
@Override
public boolean contains(int key) {
ListNode cur = head;
while (cur != null) {
if (cur.val == key) {
return true;
}
cur = cur.next;
}
return false;
}
@Override
public int size() {
int count = 0;
ListNode cur = head;
while (cur != null) {
count++;
cur = cur.next;
}
return count;
}
@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;
}
@Override
public void display() {
ListNode cur = head;
while (cur != null) {
System.out.print(cur.val + " ");
cur = cur.next;
}
System.out.println();
}