4.双向链表

单链表的缺点分析:

  • 单向链表,查找的方向只能是一个方向,而双向链表可以向前或者向后查找;
    在这里插入图片描述
  • 单项链表不能自我删除,需要靠辅助节点辅助删除,而双向链表可以实现自我删除
    在这里插入图片描述
    在双向链表中,每个节点不仅存放了下一个节点的地址,还存放了上一个节点的地址,因此,在双向链表中,不仅可以实现顺序遍历,还可以实现逆序遍历。

双向链表的操作:

首先创建一个节点类,包含以下属性:
(1)节点值:num
(2)前驱节点:pre
(3)后继节点:next

//定义一个Node,每个Node对象就是一个节点
class Node2{
    public int num;
    public Node2 next;   //后继节点:指向下一个节点
    public Node2 pre;    //前驱节点:指向前一个节点
    public Node2(int num) {
        this.num = num;
    }
    public int getNum() {
        return num;
    }
}

其次,我们需要一个双向链表类,链表类先初始化一个头节点,并提供获取头节点的方法

//创建一个双线链表的类
class DoubleLinkedList{
    //先初始化一个头节点,头节点一般不要动,因为头节点是为了指示链表的最顶端,如果不存在就无法找到整个链表
    private Node2 head = new Node2(0);    //不存放具体的数据
    //返回头节点
    public Node2 getHead() {
        return head;
    }
}

定义完毕后,我们就能开始编写双向链表的操作功能了:

  • 1.添加

思路:
(1)先找到双向链表的最后这个节点
(2)将最后一个节点的next指向新的节点
(3)将新节点的pre指向原链表的最后一个节点

//添加节点,按序添加(不允许添加重复元素)
public void addNode(Node2 node){
    Node2 cur = head;   //令一个辅助节点从头开始向后遍历
    while (true) {
        if (cur.next == null) { //当这个节点的下一个节点为null,说明走到了链表的最后,
            node.pre = cur;     //当前节点是链表的最后一个节点,那么将新节点插入链表的最后即可
            cur.next = node;
            break;              //插入完成退出方法
        }
        else if(cur.next.num > node.getNum()){   //当某个节点的值大于新插入的节点的值时,将新节点插入
            node.pre = cur;         //将新节点的pre指向当前节点
            node.next = cur.next;   //新节点的next指向当前节点的下一个节点
            cur.next.pre = node;    //将当前节点的下一个节点的pre指向新插入的节点
            cur.next = node;        //将当前节点的next指向新插入的节点
            break;                  //插入完成退出方法
        }
        else if (cur.next.num == node.getNum()){
            System.out.println(node.getNum()+"已存在!");
            break;
        }
        cur = cur.next;
    }
}
  • 2、遍历

思路:遍历的方式和单项链表一样,既可以向前查找,也可以向后查找。

//遍历双向链表的方法
public void getList(Node2 head){
    if (head.next==null){
        System.out.println("链表空!");
        return;
    }
    Node2 cur = head.next;
    while (cur!=null){
        System.out.println(cur.getNum());
        cur = cur.next;
    }
}
  • 3.删除

思路:
(1)直接找到要删除的这个节点,
(2)将这个要被删除节点的前一个节点的next指向被删除节点的next;

  • (cur.pre.next = cur.next)

(3)将被删除节点的下一个节点的pre指向被删除节点的前一个节点,

  • (cur.next.pre = cur.pre)

但是需要注意一点,如果要删除的是最后一个节点,就不能再对最后一个节点的下一个节点的前驱进行赋值,否则会引起空指针异常,最后一个节点不需要这一步操作

//删除节点
public void delNode(int no){
    //判断当前链表是否为空
    if (head.next == null){
        System.out.println("链表空!");
        return;
    }
    Node2 cur = head.next;   //辅助节点,单项链表中,先找待删除节点的前一个节点才能再做删除,双向链表可以自删除
    while (true){
        if (cur == null){
            System.out.println("未找到值为"+no+"的节点!");
            return;
        }
        if (cur.num == no){
            cur.pre.next = cur.next;
            if(cur.next != null) {
                //此段代码不能做最后一个节点的判断,最后一个节点的下一个节点为null,会引起空指针异常,因此最后一个节点就不需要执行以下判断
                cur.next.pre = cur.pre;
            }
            return;
        }
        cur = cur.next;
    }

}

测试代码:

public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    DoubleLinkedList list = new DoubleLinkedList();
    //添加元素:
    for (int i = 0; i < 10; i++) {
        int count = new Random().nextInt(10);
        System.out.println("添加第"+i+1+"个元素:"+count);
        list.addNode(new Node2(count));
    }
    //遍历链表所有数据
    System.out.println("链表展示:");
    list.getList(list.getHead());
    //删除节点
    System.out.println("输入你要删除的节点:");
    list.delNode(sc.nextInt());
    //遍历链表所有数据
    System.out.println("链表展示:");
    list.getList(list.getHead());
}

在这里插入图片描述
到此一个双向链表的基本功能就完成了。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值