目录
🥇一:无头双向链表
🎒二、无头双向链表的实现
📘1.创建节点类
📒2.创建链表
📗3.打印链表
📕4.查找是否包含关键字key是否在单链表当中
📙5.得到单链表的长度
📒6.任意位置插入,第一个数据节点为0号下标
📘7.删除第一次出现关键字为key的节点
📗8.删除所有值为key的节点
📕9.清空链表
🥇一:无头双向链表
🎒二、无头双向链表的实现
📘1.创建节点类
🌈节点由val域(数据域),prev(前驱),next(后继),对于prev域,其是引用类型,存放上一个节点的地址;对于next域,其是引用类型,存放下一个节点的地址。
static class ListNote {
public int val;
public ListNote prev;//前驱
public ListNote next;//后继
public ListNote(int val) {
this.val = val;
}
}
public ListNote head;
📒2.创建链表
1️⃣头插法:头插法是指在链表的头节点的位置插入一个新节点,定义一个node表示该节点,然后就是对node的next进行赋值
此时我们需要用到prev(前驱),如图所示:
双向链表和单向链表有一点不同的是:双向链表会有一个改良——会新增一个引用(last:永远指向最后一个节点),如果只有一个节点,那么head和last同时指向这个节点
新增的最后一个节点的好处就是:在进行尾插法的时候直接可以找到尾部进行插入
public ListNote last;//定义最后一个节点
//头插法
public void addFirst(int data){
ListNote node = new ListNote(data);
if(head == null) {
head = node;
last = node;
}else {
node.next = head;
head.prev = node;
node = head;
}
}
3️⃣尾插法:尾插法是指在链表的尾节点的位置插入一个新节点,定义一个node表示该节点,然后就是对原来最后一个节点的next进行赋值。
🔑如果只有一个节点,即node=head=last;如果多个节点在最后插入需要改两个数据,如图所示
📗3.打印链表
➡️为了使head一直存在且有意义,我们在display()函数中定义一个cur:Node cur = head;来替代head。
public void display(){
ListNote cur = head;
if(cur != null) {
System.out.print(cur.val + " ");
cur = cur.next;
}
System.out.println();
}
❓做在这里我们并没有使用到prev(前驱),即如果用不到就不需要使用了
📕4.查找是否包含关键字key是否在单链表当中
//查找是否包含关键字key是否在单链表当中
public boolean contains(int key){
ListNote cur = head;
while (cur != null) {
if(cur.val == key) {
return true;
}
cur = cur.next;
}
return false;
}
📙5.得到单链表的长度
//得到单链表的长度
public int size(){
int len = 0;
ListNote cur = head;
if (cur != null) {
len++;
cur = cur.next;
}
return len;
}
📒6.任意位置插入,第一个数据节点为0号下标
1️⃣首先,在头部插入一个节点——头插法;2️⃣在最后一个位置插入——尾插法
3️⃣在中间位置插入,需要改变4个位置,如图所示
//任意位置插入,第一个数据节点为0号下标
public void addIndex(int index,int data){
if(index < 0 || index > size()) {
throw new ListIndexOutOfExpection();
}
if(index == 0) {
addFirst(data);
return;
}
if(index == size()) {
addLast(data);
return;
}
ListNote cur = findIndex(index);
ListNote node = new ListNote(data);
node.next = cur;
cur.prev.next = node;
//注意顺序不能变
node.prev = cur.prev;
cur.prev = node;
}
private ListNote findIndex(int index) {
ListNote cur = head;
while (index != 0) {
cur = cur.next;
index--;
}
return cur;
}
📘7.删除第一次出现关键字为key的节点
1️⃣首先,删除头节点:head = head.next;;2️⃣在删除中间和尾巴节点时,如图所示
//删除第一次出现关键字为key的节点
public void remove(int key){
ListNote cur = head;
while (cur != null) {
//开始删除
if(cur.val == key) {
//1.删除头节点
if(cur == head) {
head = head.next;
//只有一个节点
if(head != null) {
head.prev = null;
}
}else {
//中间 尾巴
cur.prev.next = cur.next;
//不是尾巴节点
if(cur.next != null) {
cur.next.prev = cur.prev;
}else {
//是尾巴节点
last = last.next;
}
}
return;
}
cur = cur.next;
}
}
📗8.删除所有值为key的节点
//删除所有值为key的节点
public void removeAllKey(int key){
ListNote cur = head;
while (cur != null) {
//开始删除
if(cur.val == key) {
//1.删除头节点
if(cur == head) {
head = head.next;
//只有一个节点
if(head != null) {
head.prev = null;
}
}else {
//中间 尾巴
cur.prev.next = cur.next;
//不是尾巴节点
if(cur.next != null) {
cur.next.prev = cur.prev;
}else {
//是尾巴节点
last = last.next;
}
}
}
cur = cur.next;
}
}
📕9.清空链表
🔑双向列表不可以把头和尾置为null;需要把每个节点都置为null
➡️定义一个cur:ListNode cur = head;在定义一个curNext,为了方便到找cur的下一个链表,并且置为null
public void clear(){
ListNote cur = head;
while (cur != null) {
ListNote curNext = cur.next;
cur.prev = null;
cur.next = null;
cur = curNext;
}
head = null;
last = null;
}