春水初生,春林初盛,春风十里,不如你
大家好,这里是新一,请多关照🙈🙉🙊。在本篇博客中,新一将带大家了解双向链表的增删查改(以下结果均在IDEA中编译)希望在方便自己复习的同时也能帮助到大家。😜😜😜🥇🥈🥉
废话不多说,直接进入我们的文章。
一.🥇 概念与结构
双向链表在存储上跟单向链表一样,只不过它多了每个元素的数据域,多了一个引用,也就是prev域指向这个元素的前驱。此外我们再加个尾指针last
二.🥇 双向链表接口实现
以下即为各接口实现。
class ListNode{
public int val;
public ListNode prev;
public ListNode next;
public ListNode(int val){
this.val = val;
}
}
public class DoubleLinkedList {
ListNode head = new ListNode(-1);
ListNode last;
//打印
public void display(){
ListNode cur = this.head;
while (cur != null){
System.out.print(cur.val + " ");
cur = cur.next;
}
System.out.println();
}
//链表长度
public int size(){
ListNode cur = this.head.next;
int count = 0;
while (cur != null){
count++;
cur = cur.next;
}
return count;
}
//查找是否包含关键字key节点是否在单链表中
public boolean contains(int key){
ListNode cur = this.head;
while (cur != null){
if (cur.val == key){
return true;
}
cur = cur.next;
}
return false;
}
//头插法
public void addFirst(int data){
ListNode node = new ListNode(data);
if (head.next == null){
head.next = node;
node.prev = head;
node.next = null;
last = node;
} else {
node.next = head.next;
head.next.prev = node;
head.next = node;
node.prev = head;
}
}
//尾插法
public void addLast(int data){
ListNode node = new ListNode(data);
if (this.head.next == null){
head.next = node;
node.prev = head;
last = node;
} else{
last.next = node;
node.prev = last;
last = node;
}
}
//删除第一次关键字为key的节点
public void remove(int key){
if (this.head.next == null){
System.out.println("链表为空!");
return;
}
ListNode cur = this.head;
while (cur != null){
if (cur.val == key){
if (cur.prev == head){
head.next = cur.next;
if (cur.next == null){
last = null;
return;
}
cur.next.prev = head;
return;
}
if (cur.next == null){
last = last.prev;
last.next = null;
return;
}
cur.prev.next = cur.next;
cur.next.prev = cur.prev;
return;
}
cur = cur.next;
}
if (cur == null){
System.out.println("未找到关键字为k的节点");
}
}
//删除所有值为key的节点
public void removeAllKey(int key){
if (this.head.next == null){
System.out.println("链表为空!");
return;
}
ListNode cur = this.head;
while (cur != null){
if (cur.val == key){
if (cur.prev == head){
head.next = cur.next;
if (cur.next == null){
last = null;
return;
}
cur.next.prev = head;
}
if (cur.next == null){
last = last.prev;
last.next = null;
}
cur.prev.next = cur.next;
cur.next.prev = cur.prev;
}
cur = cur.next;
}
if (cur == null){
System.out.println("未找到关键字为k的节点");
}
}
public ListNode search(int index){
ListNode cur = this.head.next;
while (index != 0){
cur = cur.next;
index--;
}
return cur;
}
//任意位置插入,第一个数据节点为0号下标
public void addIndex(int index, int data){
if (index < 0 || index > size()){
System.out.println("插入位置不合法!");
return;
}
ListNode node = new ListNode(data);
if (index == 0){
addFirst(data);
return;
}
if (index == size()){
addLast(data);
return;
}
ListNode cur = search(index);
node.next = cur;
cur.prev.next = node;
node.prev = cur.prev;
cur.prev = node;
}
//清空链表
public void clear(){
ListNode newHead = this.head.next;
while (newHead != null){
ListNode curNext = newHead.next;
newHead.next = null;
newHead.prev = null;
newHead = curNext;
}
last = null;
head.next = null;
}
}
如有错误,希望大家随时在评论区指正。
三.🥇 面试问题
我们遇到面试问******与 *****区别的时候我们该怎么回答呢?
这两个数据结构的共同点无非就是对数据的组织方式和描述方法不一样,我们只需要从以下两个方面回答即可:
组织:
1.顺序表底层是一个十组,他是一个逻辑上和物理上都是连续的
2.链表是一个由若干节点组成的一个数据结构,逻辑上是连续的,但在物理上是不连续
操作:
1.顺序表适合查找相关的操作,因为可以使用下标,直接获取到某个位置的元素
2.链表适合于频繁的插入删除操作,此时你不需要像顺序表一样,需要移动元素。链表的插入只需要修改指向即可
3.顺序表还有不好的地方,就是你需要看满不满,满了要扩容,扩容之后,不一定能放完所以空间利用率不高
想对大家说的话
家人们,到这儿我们已经了解了双向链表的各种接口操作🥳🥳🥳,后续新一会持续更新JAVA数据结构的有关内容,学习永无止境,技术宅,拯救世界!