上次文章我们实现了单向链表,链接如下 : 单向链表的实现与讲解 而这篇文章博主就对双向链表如何实现以及实现原理进行讲解; 双向链表和单向链表本质上区别不大,双向链表就比单向链表每个节点多了一个先驱prev,以实现链表能够逆向链接: 双向链表需要有一个头结点引用head 以及一个尾结点引用last 而有力单向链表的知识基础,双向链表实现以及理解上就会容易很多,讲解如下 :
1.节点类实现
class ListNode{
public int val;
public ListNode prev;
public ListNode next;
public ListNode(int val){
this.val=val;
}
}
2. 双向链表各个模块功能实现
2.1 头插法
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;
this.head.prev = node;
this.head = node;
}
}
2.2 尾插法
public void addLast(int data) {
ListNode node = new ListNode(data);
if (head == null) {
this.head = node;
this.last = node;
} else {
this.last.next = node;
node.prev = this.last;
this.last = node;
}
}
2.3 查找关键字key是否在单链表当中
public boolean contains(int key){
ListNode cur=this.head;
while (cur!=null){
if (cur.val==key){
return true;
}
cur=cur.next;
}
return false;
}
2.4 删除第一次出现关键字为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){
head.prev=null;
}else{
last=null;
}
}else if(cur==last){
cur.prev.next=cur.next;
last=last.prev;
}else{
cur.prev.next=cur.next;
cur.next.prev=cur.prev;
}
return;
}else{
cur=cur.next;
}
}
}
2.5 删除所有值为key的节点
步骤与删除一次key相同 只是在删除操作后不return 继续进行遍历删除
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){
head.prev=null;
}else{
last=null;
}
}else if(cur==last){
cur.prev.next=cur.next;
last=last.prev;
}else{
cur.prev.next=cur.next;
cur.next.prev=cur.prev;
}
}else{
cur=cur.next;
}
}
}
2.6 得到单链表的长度
public int size(){
ListNode cur=this.head;
int count=0;
while (cur!=null){
count++;
cur=cur.next;
}
return count;
}
2.7 打印单链表
public void display(){
ListNode cur=this.head;
while(cur!=null){
System.out.print(cur.val+" ");
cur=cur.next;
}
System.out.println();
}
2.8任意位置插入,第一个数据节点为0号下标
回顾上次的单向链表,我们要在index位置插入需要找到index位置前面一个节点,而这里的双向链表 我们要在index插入 就只需要找到index位置的节点进行操作 首先我们要完成一个查找index位置节点的方法
public ListNode searchIndex(int index){
ListNode cur=this.head;
while (index!=0){
cur=cur.next;
index--;
}
return cur;
}
进行插入操作 :
public void addIndex(int index,int data){
ListNode node=new ListNode(data);
if (index<0 || index>size()){
System.out.println("index位置不合法!");
return;
}
if (index==0){
addFirst(data);
return;
}
if (index==size()){
addLast(data);
return;
}
ListNode cur=searchIndex(index);
node.next=cur.prev.next;
cur.prev.next=node;
node.prev=cur.prev;
cur.prev=node;
}
需要改变的4个引用域就是蓝色圈起来的4个引用域 具体改变代码 :
node.next=cur.prev.next;
cur.prev.next=node;
node.prev=cur.prev;
cur.prev=node;
照着进行画图就能很容易理解 ~
2.9 清空链表
public void clear(){
ListNode cur=this.head;
while(cur!=null){
ListNode curNext=cur.next;
cur.prev=null;
cur.next=null;
cur=curNext;
}
this.head=null;
this.last=null;
}
清空成功 !
3. 整体 MyLinkedList 代码展示
class ListNode{
public int val;
public ListNode prev;
public ListNode next;
public ListNode(int val){
this.val=val;
}
}
public class MyLinkedList {
ListNode head;
ListNode last;
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;
this.head.prev = node;
this.head = node;
}
}
public void addLast(int data) {
ListNode node = new ListNode(data);
if (head == null) {
this.head = node;
this.last = node;
} else {
this.last.next = node;
node.prev = this.last;
this.last = node;
}
}
public ListNode searchIndex(int index){
ListNode cur=this.head;
while (index!=0){
cur=cur.next;
index--;
}
return cur;
}
public void addIndex(int index,int data){
ListNode node=new ListNode(data);
if (index<0 || index>size()){
System.out.println("index位置不合法!");
return;
}
if (index==0){
addFirst(data);
return;
}
if (index==size()){
addLast(data);
return;
}
ListNode cur=searchIndex(index);
node.next=cur.prev.next;
cur.prev.next=node;
node.prev=cur.prev;
cur.prev=node;
}
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 remove(int key){
ListNode cur=this.head;
while(cur!=null){
if (cur.val==key){
if (cur==head){
head=head.next;
if(head!=null){
head.prev=null;
}else{
last=null;
}
}else if(cur==last){
cur.prev.next=cur.next;
last=last.prev;
}else{
cur.prev.next=cur.next;
cur.next.prev=cur.prev;
}
return;
}else{
cur=cur.next;
}
}
}
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){
head.prev=null;
}else{
last=null;
}
}else if(cur==last){
cur.prev.next=cur.next;
last=last.prev;
}else{
cur.prev.next=cur.next;
cur.next.prev=cur.prev;
}
}else{
cur=cur.next;
}
}
}
public int size(){
ListNode cur=this.head;
int count=0;
while (cur!=null){
count++;
cur=cur.next;
}
return count;
}
public void display(){
ListNode cur=this.head;
while(cur!=null){
System.out.print(cur.val+" ");
cur=cur.next;
}
System.out.println();
}
public void clear(){
ListNode cur=this.head;
while(cur!=null){
ListNode curNext=cur.next;
cur.prev=null;
cur.next=null;
cur=curNext;
}
this.head=null;
this.last=null;
}
}
4. 部分测试 test 代码展示 :
public class TestDemo {
public static void main(String[] args) {
MyLinkedList myLinkedList=new MyLinkedList();
myLinkedList.addFirst(1);
myLinkedList.addFirst(2);
myLinkedList.addFirst(3);
myLinkedList.display();
System.out.println("-------------------");
myLinkedList.clear();
myLinkedList.display();
}
}
5. 总结
讲解到这里 双向链表的实现就已经完成了 对于链表的学习我们一定要多画图理解 多思考 多写代码 才能真正学好链表
如果觉得博主的文章对自己有所帮助 欢迎大家多多点赞收藏 ~
|