数据结构之双向链表的实现

一、双向链表的简单介绍

双向链表,顾名思义和单向链表很相似,均为链表,两者之间的操作也十分相近,最明显的不同之处就是双向链表的单个结点带有两个指针域,分别指向前后两个元素。

二、双向链表的实现

1.基本框架的构建

节点的结构如图:
在这里插入图片描述
首先,在实现各项操作前,应该首先实现结点的构建,以静态内部类来实现。
代码如下:

    //实现静态内部类,用于实现结点
    static class ListNode{
        public int val;

        //定义存放头尾结点的域
        public ListNode next;
        public ListNode prev;

        public ListNode(int val){
            this.val = val;
        }
    }

接下来,我们需要了解应该实现哪些不同的方法,如下:

1.打印链表
2.查找链表长度
3.头插法
4.尾插法
5.任意位置插入
6.查找是否包含关键词key
7.删除第一次出现的key结点
8.删除全部key结点
9.清空链表

注:
首先定义出 head 指针和 tail 指针,分别指向头尾。

    public ListNode head;
    public ListNode tail;

下面,我将会详细进行逐一实现。

2.打印链表

      public void display(){
            ListNode cur = head;
            while(cur != null){
                System.out.print(cur.val+" ");
                cur = cur.next;
            }
        }

3.查找链表长度

        public int size(){
            int count = 0;
            ListNode cur = head;
            while(cur != null){
                count++;
                cur = cur.next;
            }
            return count;
        }

4.头插法

简单分析:
这里有两个需要考虑的地方。

1.当链表起始时为空时
2.当链表有元素时

代码如下:

        public void addFirst(int data){
        //申请一个新的节点
            ListNode node = new ListNode(data);
            //当不存在元素时
            if(head == null){
                head = node;
                tail = node;
            }else{
            //当存在元素时
                head.prev = node;
                node.next = head;
                head = node;
            }
        }

详细分析:
这里主要分析情况 2。
分析如图:
在这里插入图片描述

5.尾插法

简单分析:
同样,这里也有两个需要考虑的地方。

1.当链表为空时。
2.当链表中存在元素时。

代码实现

        public void addLast(int data){
            ListNode node = new ListNode(data);
            if(head == null){
                head = node;
                tail = node;
            }else{
                tail.next = node;
                node.prev = tail;
                tail = node;
            }
        }

详细分析
这里主要分析情况 2 。
在这里插入图片描述

6.任意位置插入

简单分析
这里有需要考虑的三个地方。

1.插入的位置 index 是否合法
2.插入的 index 位置是否在头尾
3.插入的 index 位置位于一般位置

代码如下:

        public void addIndex(int index,int data){
            ListNode node = new ListNode(data);
            //1.判断index的合法性
            if(index < 0 || index > size()){
                System.out.println("index不合法");
                throw new IndexWrongFulException("index不合法");
            }
            //2.判断是头插还是尾插
            if(index == 0){
                addFirst(data);
                return;
            }
            if(index == size()){
                addLast(data);
                return;
            }
            //3.找到index位置的结点地址
            ListNode cur = find(index);
            cur.prev.next = node;
            node.prev = cur.prev;
            node.next = cur;
            cur.prev = node;
        }

注:
1.这里判断合法性使用了异常判断类
代码如下:

public class IndexWrongFulException extends RuntimeException{
    public IndexWrongFulException(String message) {
        super(message);
    }
}

2.在寻找 index 位置时,定义了 find 方法,
代码如下:

        private ListNode find(int index){
            ListNode cur = head;
            while(index-1 != 0){
                cur = cur.next;
                index--;
            }
            return cur;
        }

详细分析:
这里主要分析一般情况下在链表中间插入的情况
在这里插入图片描述
注:紫色数字为指针顺序。

7.查找是否存在关键词key

简单分析:
这个方法难度不大,只需要遍历寻找即可。

代码如下

        public boolean contains(int key){
            ListNode cur = head;
            while(cur != null){
                if(cur.val == key){
                    return true;
                }
                cur = cur.next;
            }
            return false;
        }

8.删除第一次出现的关键词key

简单分析:
这里有三个地方需要考虑。

1.当要删除的结点为一个单独的头结点
2.要删除的节点恰好为尾部结点
3.要删除的结点的位置为链表中的一般位置

代码如下:

        public void remove(int key){
            ListNode cur = head;
            while(cur != null){
            //循环寻找 key 的值
                if(cur.val == key){
                	//当要删除的值是头节点
                    if(cur == head){
                        head = head.next;
                        //判断删除的是不是单独的一个头节点
                        if(head != null){
                            head.prev = null;
                        }else{
                            tail = null;
                        }
                    }else{
                    //一般情况删除
                        cur.prev.next = cur.next;
                        //判断删除的是否为尾部结点
                        if(cur.next != null){
                            cur.next.prev = cur.prev;
                        }else{
                            this.tail = cur.prev;
                        }
                    }
                    return;
                }
                cur = cur.next;
            }
        }

详细分析:
1.删除头节点
在这里插入图片描述
2.删除中间节点
在这里插入图片描述
3.删除尾部结点
在这里插入图片描述

9.删除所有关键词key

简单分析:
这个方法实现非常简单,只要将上一个方法中的 return 删除即可。

代码实现:

        public void remove(int key){
            ListNode cur = head;
            while(cur != null){
                if(cur.val == key){
                    if(cur == head){
                        head = head.next;
                        if(head != null){
                            head.prev = null;
                        }else{
                            tail = null;
                        }
                    }else{
                        cur.prev.next = cur.next;
                        if(cur.next != null){
                            cur.next.prev = cur.prev;
                        }else{
                            this.tail = cur.prev;
                        }
                    }
                }
                cur = cur.next;
            }
        }

10、清空链表

简单分析:

双向链表的清空并非是简单的将 head 和 tail 置为 null ,而是要将所有结点的指向全部置为 null

代码如下:

        public void clear(){
            ListNode cur = head;
            ListNode pre = cur.next;
            while(cur != null){
                cur.next = null;
                cur.prev = null;
                cur = pre;
                pre = pre.next;
            }
            head = null;
            tail = null;
        }

至此,所有的方法实现结束。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值