--------------------------------------------------------------------------------------------------------------------------------------------------------- 学习Java就上哪吒社区,干货满满,内有每日打卡,Java资料,Java学习路线,福利多多哦,既能学习又能获得小礼物,岂不美哉? 【哪吒社区】点此进入. ---------------------------------------------------------------------------------------------------------------------------------------------------------
【前言】在《通过Java理解和实现——顺序表和单链表》一文中已经讲完了顺序表和单链表,接下来就是双向链表了,其实和单链表非常相似,需要注意的就是一些小细节
【Java数据结构】通过Java理解和实现——无头双向链表
🍉无头双向链表
🌵双链表概念及结构
【为什么引入双链表?】 ?单链表的结点中只有一个指向其后继的指针,使得单链表要访问某个结点的前驱结点时,只能从头开始遍历,访问后驱结点的复杂度为O(1),访问前驱结点的复杂度为O(n)。为了克服上述缺点,引入了双链表。 ?双链表的结点中有两个指针prev和next,分别指向前驱结点和后继结点。
🍌无头双向非循环链表接口实现(注释非常详细,我👴👴都能看懂)
先写两个类,一个是链表类(包含有一个【可变的头结点】和【可变尾节点】和【实现各种功能的接口】,因为是无头链表,所以这个头结点和尾节点是可变的),另一个是节点类(成员属性有value和prev(前驱)和next(后驱)) 接下来的接口都是写在链表类里的,因为链表是一个对象,我们要实现的就是一个链表对象所有的功能
🍈打印双链表
打印链表其实和打印顺序表类似,遍历链表就好了,不过要注意一个点,这里需要引入一个局部变量cur来代替头节点去遍历,因为头结点在没添加或者删除节点之前是固定的,不要让头结点变来变去
public void display() {
ListNode cur = this.head;
while (cur != null){
System.out.print(cur.val+" ");
cur = cur.next;
}
System.out.println();
}
🍈头插法插入
顾名思义,头插法就是从头部插入节点,使新创建的节点成为新的头结点,这里需要额外考虑一个点,就是头结点是否存在(链表是否为空),(注意,不光要设置后驱还要注意前驱,这比单链表多一个前驱节点)
public void addFirst(int data) {
ListNode node = new ListNode(data);
if (this.head==null){
this.head=node;
this.last=node;
}else{
node.next=this.head;
head.prev=node;
this.head=node;
}
}
🍈尾插法插入
尾插法和头插法类似,必须先判断链表是否为空(判断头结点是否为null),双链表区别于单链表,不用每次遍历来找尾节点,双链表本身就有一个尾节点last,我们只需要找到这个last,然后将新节点插入即可
public void addLast(int data){
ListNode node = new ListNode(data);
if (this.head==null){
this.head=node;
this.last=node;
}else{
this.last.next=node;
node.prev=last;
this.last=node;
}
}
🍈查找是否包含关键字key在双链表当中
传入关键字key,依旧是引入局部变量cur遍历链表,哪个节点的value等于key了,说明链表里有这个关键字,返回true,否则返回false,和单链表一模一样
public boolean contains(int key){
ListNode cur = this.head;
while(cur != null){
if(cur.val==key){
return true;
}
cur = cur.next;
}
return false;
}
🍈得到双链表的长度
依旧采取引用局部变量cur来遍历链表,还要多设置一个局部变量size来计数,只要节点不为null,size就+1,最后返回size的值就是链表长度了(其实和单链表也一模一样)
public int size() {
int size=0;
ListNode cur = this.head;
while (cur != null){
size++;
cur = cur.next;
}
return size;
}
🍈任意位置插入,第一个数据节点为0号下标
插入原理:临时变量cur代替头结点,cur先走到要插入的位置,然后将新节点插到cur和cur前一节点的中间,替代了cur的原位置,实现按位置插入节点
public void addIndex(int index,int data){
ListNode node = new ListNode(data);
ListNode cur = this.head;
if (index > 0 && index <size()) {
for (int i = 0; i < index; i++){
cur = cur.next;
}
cur.prev.next=node;
node.prev=cur.prev;
node.next=cur;
}
if (index ==size()){
addLast(data);
}
if (index==0){
addFirst(data);
}
display();
}
🍈删除第一次出现关键字为key的节点
首先判断头结点是否为null(链表是否为空),然后找要删除的节点,要删除的节点有三种情况 ①关键字在头节点:将头节点下一个节点设置为新头节点 ②关键字在尾巴结点:将尾节点上一个节点设置为新尾节点 ③关键字不在头结点:则将key节点的前一个节点的后驱指向key节点的后一个节点,key节点的后一节点的前驱指向key节点前一节点
public void remove(int key){
ListNode cur = this.head;
while(cur != null){
if(cur.val==key){
if(cur==head){
head=head.next;
if (head==null) {
break;
}
head.prev=null;
break;
}
if (cur==last){
last=last.prev;
last.next=null;
break;
} > if (cur.prev!=null && cur.next!=null){
cur.prev.next=cur.next;
cur.next.prev=cur.prev;
break;
}
}
cur=cur.next;
}
display();
}
🍈删除所有值为key的节点
和上边删除第一次出现的key类似(注释可以看上边删除第一次出现的key),只不过在删除节点过后不要break,让遍历循环继续进行
public void removeAllKey(int key){
ListNode cur = this.head;
while(cur != null){
if(cur.val==key){
if(cur==head){
head=head.next;
if (head==null) {
break;
}
head.prev=null;
}
if (cur==last){
last=last.prev;
last.next=null;
}
if (cur.prev!=null && cur.next!=null){
cur.prev.next=cur.next;
cur.next.prev=cur.prev;
}
}
cur=cur.next;
}
display();
}
🍈清空链表
暴力清空,直接将头尾结点置空,这样整个链表就无法找到了
public void clear() {
head=null;
last=null;
}
🍉单链表和双链表到底有啥区别
一、指代不同 1、双向链表:也叫双链表,是链表的一种,每个数据结点中都有两个指针,分别指向直接后继和直接前驱 2、单向链表:是链表的一种,其特点是链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始。 二、优点不同 1、双向链表:从双向链表中的任意一个结点开始,都可以很方便地访问前驱结点和后继结点。 2、单向链表:单个结点创建非常方便,普通的线性内存通常在创建的时候就需要设定数据的大小,结点的访问方便,可以通过循环或者递归的方法访问到任意数据。 三、缺点不同 1、双向链表:增加删除节点复杂,需要多分配一个指针存储空间。 2、单向链表:结点的删除非常方便,不需要像线性结构那样移动剩下的数据,但是平均的访问效率低于线性表。
🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙 ????????原创不易,如有错误,欢迎评论区留言指出,感激不尽? ???????????????????????如果觉得内容不错,给个三连不过分吧~ ?????? ? ????????????????????????????????????看到会回访~ ??????????????? ???????????????????? ? 🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙
|