JAVA数据结构-05 双向链表的实现

JAVA数据结构-04 双向链表

​ 双向链表的结构与单向链表相同,包含数据域和指针域.区别在于双向链表同时包含指向下一个节点的next指针和指向上一个节点的pre指针.

  • 单向链表只能从前往后进行遍历,双向链表可以从前和后两个方向进行遍历
  • 单向链表不能自我删除,需要靠辅助节点进行,所以单向链表的删除需要找到前一个节点.而双向链表可以进行自我删除.

双向链表的结构

数据节点:

//每一个数据节点就是一个music对象
class Music2{
    
    
    public int no;
    public String name;
    public Music2 next;   //指向下一个节点
    public Music2 pre;

    public Music2(int no, String name) {
    
    
        this.no = no;
        this.name = name;
    }

    @Override
    public String toString() {
    
    
        return "Music2{" +
                "no=" + no +
                ", name='" + name + '\'' +
                '}';
    }
}

链表结构:

class DoubleLinkedList{
    
    
    private Music2 head = new Music2(0,"");
    
     public int getLength(){
    
    
        int length = 0;
        Music2 temp = head;
        while(temp.next != null){
    
    
            length ++;
            temp = temp.next;
        }
        return length;
    }
}

双向链表的操作

遍历:

  • 双向链表的遍历与单向链表相同.
public void showList(){
    
    
    if(head.next == null){
    
    
        System.out.println("链表为空");
        return;
    }
    Music2 temp = head.next;
    while(temp != null){
    
    
        System.out.println(temp);
        temp = temp.next;
    }
}

添加(到链表尾部):

  • 遍历到链表的尾部;
  • 修改待插入数据结点的前后指针,完成添加
//添加到尾部
public void add(Music2 musicNode){
    
    
    Music2 temp = head;
    while(temp.next != null){
    
    
        temp = temp.next;
    }
    temp.next = musicNode;
    musicNode.pre = temp;
}

插入:(根据下标index,数据节点从1开始)

  • 遍历到待插入的index节点前一个位置,使temp指针指向index-1;

  • 先将待插入链表的前后指针指向index-1和index位置(没破坏原有链表结构)

    • musicNode.next = temp.next;
      musicNode.pre = temp;
      
  • 修改index-1位置的节点,使其next指针指向待插入节点;修改index位置的节点,使其pre指针指向待插入节点

    • temp.next.pre = musicNode;
      temp.next = musicNode;
      
 public void insertIndex(Music2 musicNode,int index){
    
    
        int length = getLength();
        if(index > length+1 || index <0){
    
    
            System.out.println("index错误");
            return ;
        }
        Music2 temp = head;
        while ((--index) >0){
    
    
            temp = temp.next;
        }   //指向index位前一个位置
        if(temp.next == null){
    
     //temp是最后一个节点,执行add操作
            temp.next = musicNode;
            musicNode.pre = temp;
        }else {
    
    
            musicNode.next = temp.next;
            musicNode.pre = temp;
            temp.next.pre = musicNode;
            temp.next = musicNode;
        }

    }

删除:

  • 因为双向链表可以进行自我删除,所以不需要找到待删除节点的前一个节点位置,直接找到待删除位置即可.
public Music2 delete(int index){
    
    
    int length = getLength();
    if(index > length || index <0){
    
    
        System.out.println("index错误");
        return new Music2(-1,"error");
    }
    Music2 temp = head;
    while (index >0){
    
    
        temp = temp.next;
        index --;
    }   //指向index位,双向链表可以自我删除,不需要定位到前一个位置

    temp.pre.next = temp.next;
    if(temp.next != null){
    
      //只有当待删除节点是最后一个节点时不需要执行, 否则会报空指针异常
        temp.next.pre = temp.pre;
    }
    return temp;
}

测试完整代码:

public class DoubleLinkedListDemo {
    
    
    public  static void main(String args[]){
    
    
        DoubleLinkedList list = new DoubleLinkedList();
        list.add(new Music2(1,"再见杰克"));
        list.add(new Music2(4,"西湖"));
        list.showList();
        System.out.println(list.getLength());

        list.insertIndex(new Music2(2,"给你唱首歌"),3);
        list.showList();

        System.out.println(list.delete(3));
        list.showList();
    }
}

class DoubleLinkedList{
    
    
    private Music2 head = new Music2(0,"");

    public int getLength(){
    
    
        int length = 0;
        Music2 temp = head;
        while(temp.next != null){
    
    
            length ++;
            temp = temp.next;
        }
        return length;
    }

    public void showList(){
    
    
        if(head.next == null){
    
    
            System.out.println("链表为空");
            return;
        }
        Music2 temp = head.next;
        while(temp != null){
    
    
            System.out.println(temp);
            temp = temp.next;
        }
    }
    //添加到尾部
    public void add(Music2 musicNode){
    
    
        Music2 temp = head;
        while(temp.next != null){
    
    
            temp = temp.next;
        }
        temp.next = musicNode;
        musicNode.pre = temp;
    }

    public void insertIndex(Music2 musicNode,int index){
    
    
        int length = getLength();
        if(index > length+1 || index <0){
    
    
            System.out.println("index错误");
            return ;
        }
        Music2 temp = head;
        while ((--index) >0){
    
    
            temp = temp.next;
        }   //指向index位前一个位置
        if(temp.next == null){
    
    
            temp.next = musicNode;
            musicNode.pre = temp;
        }else {
    
    
            musicNode.next = temp.next;
            musicNode.pre = temp;
            temp.next.pre = musicNode;
            temp.next = musicNode;
        }

    }

    public Music2 delete(int index){
    
    
        int length = getLength();
        if(index > length || index <0){
    
    
            System.out.println("index错误");
            return new Music2(-1,"error");
        }
        Music2 temp = head;
        while (index >0){
    
    
            temp = temp.next;
            index --;
        }   //指向index位,双向链表可以自我删除,不需要定位到前一个位置

        temp.pre.next = temp.next;
        if(temp.next != null){
    
      //只有当待删除节点是最后一个节点时不需要执行, 否则会报空指针异常
            temp.next.pre = temp.pre;
        }
        return temp;
    }

}


//每一个数据节点就是一个music对象
class Music2{
    
    
    public int no;
    public String name;
    public Music2 next;   //指向下一个节点
    public Music2 pre;

    public Music2(int no, String name) {
    
    
        this.no = no;
        this.name = name;
    }

    @Override
    public String toString() {
    
    
        return "Music2{" +
                "no=" + no +
                ", name='" + name + '\'' +
                '}';
    }
}

JAVA 中 LinkedList 类源码解析

LinkedList内置的数据节点:

private static class Node<E> {
    
    
    E item;
    Node<E> next;
    Node<E> prev;

    Node(Node<E> prev, E element, Node<E> next) {
    
    
        this.item = element;
        this.next = next;
        this.prev = prev;
    }
}

LinkedList数据结构的实现:

  • LinkedList包含三个字段:
    • size记录双向链表的长度
    • first记录双向链表的头指针
    • last记录双向链表的尾指针
transient int size = 0;

/**
 * Pointer to first node.
 * Invariant: (first == null && last == null) ||
 *            (first.prev == null && first.item != null)
 */
transient Node<E> first;

/**
 * Pointer to last node.
 * Invariant: (first == null && last == null) ||
 *            (last.next == null && last.item != null)
 */
transient Node<E> last;

猜你喜欢

转载自blog.csdn.net/weixin_44634197/article/details/108431051