Java实现双向链表的基本操作

Posted 一朵花花

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java实现双向链表的基本操作相关的知识,希望对你有一定的参考价值。

介绍:
双向链表比单链表多了一个 prev(前驱) 域,指向前一个节点

data:数据
next:后继信息
prev:前驱信息

.
无头双向链表图解:

双向链表节点的定义

class Node{
    public int data;//数据
    public Node next;//后继信息
    public Node prev;//前驱信息

    //提供构造方法
    public Node(int data){
        this.data = data;
    }
}

1.链表的打印

直接上代码:

public void print(){
    Node cur = this.head;
    while(cur != null){
        System.out.print(cur.data+" ");
        cur = cur.next;
    }
    System.out.println();
}

2.头插法

思考:

  • 首先判断是不是第一次插入
  • 若是第一次插入,让 head 和 tail 都指向 待插入节点node
  • 若不是第一次插入,修改对应的值实现头插即可
  • 图解:

代码实现:

public void addFirst(int data){
    Node node = new Node(data);
    //第一次插入
    if(this.head == null){
        this.head = node;
        this.tail = node;
    }
    //不是第一次插入
    else{
        node.next = this.head;
        this.head.prev = node;
        this.head = node;
    }
}

3.尾插法

思考:
思考过程与头插法一样,参考头插法

  • 过程图解:

代码实现:

public void addLast(int data){
    Node node = new Node(data);
    //第一次插入
    if(this.head == null){
        this.head = node;
        this.tail = node;
    }
    //不是第一次插入
    else{
        this.tail.next = node;
        node.prev = this.tail;
        this.tail = node;
    }
}

4.任意位置插入

思考:

  • 判断Index的合法性
  • 首先判断是否是第一次插入—头插
  • 若不是,再判断是否插入到最后位置—尾插
  • 中间位置插入,需要考虑四个位置,如下图:
  • 图解:

代码实现:

private void checkIndex(int index){
    if(index < 0 || index > len()){
        throw new RuntimeException("index不合法!!");
    }
}
private Node searchIndex(int index){
    Node cur = this.head;
    while(index != 0) {
        cur = cur.next;
        index--;
    }
    return cur;
}
    
public void addIndex(int index,int data){
    checkIndex(index);
        if(index == 0){
        addFirst(data);
        return;
    }
    if(index == len()){
        addLast(data);
        return;
    }
    Node node = new Node(data);
    Node cur = searchIndex(index);
    node.next = cur;
    node.prev = cur.prev;
    cur.prev.next = node;
    cur.prev = node;
}

5.查找链表中是否包含关键字 key

比较简单,直接贴代码:

public boolean containKey(int key){
    Node cur = this.head;
    while(cur != null){
        if(cur.data == key){
            return true;
        }
        cur = cur.next;
    }
    return false;
}

6.删除第一次出现关键字为 key 的节点

思考

  • 直接上图解:

代码实现:

public void deleteKey(int key){
    Node cur = this.head;
    while(cur != null){
        if(cur.data == key){
            //头节点
            if(cur == this.head){
                this.head = this.head.next;
                this.head.prev = null;
            }
            //中间节点
            else{
                cur.prev.next = cur.next;
                if(cur.next != null){
                    cur.next.prev = cur.prev;
                }
                //删除的是尾节点,只需要移动tail
                else{
                    this.tail = cur.prev;
                }
            }
        }
        cur = cur.next;
    }
}

7.删除所有出现关键字为 key 的节点

思考:
根据删除第一次出现关键字为 key 的节点,修改代码即可,考虑特殊情况

代码实现:

public void deleteAllKey(int key){
    Node cur = this.head;
    while(cur != null){
        if(cur.data == key){
            //头节点
            if(cur == this.head){
                this.head = this.head.next;
                if(this.head != null){
                    this.head.prev = null;
                }
            }
            //中间节点
            else{
                cur.prev.next = cur.next;
                if(cur.next != null){
                    cur.next.prev = cur.prev;
                }
                //删除的是尾节点,只需要移动tail
                else{
                    this.tail = cur.prev;
                }
            }
        }
        cur = cur.next;
    }
}

8.链表长度

比较简单,直接贴代码:

public int len(){
    int count = 0;
    Node cur = this.head;
    while(cur != null){
        count++;
        cur = cur.next;
    }
    return count;
}

9.链表清空

首先会想到以下代码:

 public void clear(){
     this.head = null;
 }

测试打断点调试:

System.out.println("===============");
DoubleLinkedList doubleLinkedList3 = new DoubleLinkedList();
doubleLinkedList3.addLast(1);
doubleLinkedList3.addLast(2);
doubleLinkedList3.addLast(3);
doubleLinkedList3.addLast(4);
doubleLinkedList3.print();
doubleLinkedList3.clear();
System.out.println("!!!!!!!!!!!!!!!!!!!!!");



然后打开 cmd:

  1. 输入jps
  2. 重定义到一个文本文件
  3. 找到 log.txt 所在目录,打开 log.txt
  4. 双击打开后,ctrl + f,搜索Node


    仍然有4个,说明插入的4个数据没有被回收掉!
    故:仅仅将 head 置为null,不能实现链表清空

解决方法:

大家可以按照上述调试检测,数据是否被回收~

public void clear(){
    //一个一个节点进行释放
    while(this.head != null){
        Node cur = this.head.next;
        this.head.prev = null;
        this.head.next = null;
        this.head = cur;
    }
    this.tail = null;
}

附全部代码:

class Node{
    public int data;//数据
    public Node next;//后继信息
    public Node prev;//前驱信息

    //提供构造方法
    public Node(int data){
        this.data = data;
    }
}

public class DoubleLinkedList {
    public Node head; //表示双向链表的头
    public Node tail; //表示当前双向链表的尾
    //1.打印链表
    public void print(){
        Node cur = this.head;
        while(cur != null){
            System.out.print(cur.data+" ");
            cur = cur.next;
        }
        System.out.println();
    }
    //2.头插法
    public void addFirst(int data){
        Node node = new Node(data);
        //第一次插入
        if(this.head == null){
            this.head = node;
            this.tail = node;
        }
        //不是第一次插入
        else{
            node.next = this.head;
            this.head.prev = node;
            this.head = node;
        }
    }
    //3.尾插法
    public void addLast(int data){
        Node node = new Node(data);
        //第一次插入
        if(this.head == null){
            this.head = node;
            this.tail = node;
        }
        //不是第一次插入
        else{
            this.tail.next = node;
            node.prev = this.tail;
            this.tail = node;
        }
    }

    private void checkIndex(int index){
        if(index < 0 || index > len()){
            throw new RuntimeException("index不合法!!");
        }
    }
    private Node searchIndex(int index){
        Node cur = this.head;
        while(index != 0) {
            cur = cur.next;
            index--;
        }
        return cur;
    }
    //4.任意位置插入,第一个数据节点为0号下标
    public void addIndex(int index,int data){
        checkIndex(index);
        if(index == 0){
            addFirst(data);
            return;
        }
        if(index == len()){
            addLast(data);
            return;
        }
        Node node = new Node(data);
        Node cur = searchIndex(index);
        node.next = cur;
        node.prev = cur.prev;
        cur.prev.next = node;
        cur.prev = node;
    }
    //5.查找链表中是否包含关键字 key
    public boolean containKey(int key){
        Node cur = this.head;
        while(cur != null){
            if(cur.data == key){
                return true;
            }
            cur = cur.next;
        }
        return false;
    }
    //6.删除第一次出现关键字为 key 的节点
    public void deleteKey(int key){
        Node cur = this.head;
        while(cur != null){
            if(cur.data == key){
                //头节点
                if(cur == this.head){
                    this.head = this.head.next;
                    this.head.prev = null;
                }
                //中间节点
                else{
                    cur.prev.next = cur.next;
                    if(cur.next != null){
                        cur.next.prev = cur.prev;
                    }
                    //删除的是尾节点,只需要移动tail
                    else{
                        this.tail = cur.prev;
                    }
                }
            }
            cur = cur.next;
        }
    }
    //7.删除所有关键字为 key 的节点
    public void deleteAllKey(int key){
        Node cur = this.head;
        while(cur != null){
            if(cur.data == key){
                //头节点
                if(cur == this.head){
                    this.head = this.head.next;
                    if(this.head != null){
                        this.head.prev = null;
                    }
                }
                //中间节点
                else{
                    cur.prev.next = cur.next;
                    if(cur.next != null){
                        cur.next.prev = cur.prev;
                    }
                    //删除的是尾节点,只需要移动tail
                    else{
                        this.tail = cur.prev;
                    }
                }
            }
            cur = cur.next;
        }
    }

    //8.链表长度
    public int len(){
        int count = 0;
        Node cur = this.head;
        while(cur != null){
            count++;
            cur = cur.next;
        }
        return count;
    }
    //9.链表清空
    public void clear(){
        //一个一个节点进行释放
        while(this.head != null){
            Node cur = this.head.next;
            this.head.prev = null;
            this.head.next = null;
            this.head = cur;
        }
        this.tail = null;
    }
}

快下来试着敲敲叭~

以上是关于Java实现双向链表的基本操作的主要内容,如果未能解决你的问题,请参考以下文章

链表的java实现(单向双向链表,单向链表的反转)

Java中双向链表的代码实现

双向链表的原理与实现

双向链表的java实现

java实现双向链表

Java数据结构—— 双向链表及带傀儡节点双向链表的实现