快捷搜索:

【数据结构】双向链表——Java实现一个简单的双向链表

前言

昨天写完单向链表和栈结构之后,看了看程杰大大的书中有介绍双向链表的部分。虽然是c语言写的,但是我还是用Java给翻译出来了。思路如下: 首先,双向链表和单向链表的最大区别就是,双向链表比单链表多了个指向前一节点的指针。代码量其实并不比单链表多很多,只是思路的转变需要克服一下。 其次就是在插入元素的时候,我们可以在链表的头部插入,也可以在链表的尾部插入(因为有两个指针嘛)

编码

代码其实和单链表差不多,如果感兴趣的话可以去看看我之前写的单链表的文章。虽然文笔很烂,但是代码货真价实。

package com.zxy.lianbiao;

/**
 * @Author Zxy
 * @Date 2021/2/4 20:11
 * @Version 1.0
 */

/**
 * 基于双向链表实现元素存取的容器
 *
 * @param <E>
 */
public class MyDoublyLinkedList<E> implements MyList<E> {
          
   


    /**
     * 定义双向链表节点对象
     */
    class Node<E> {
          
   
        E item; // 记录元素
        Node<E> prev; // 记录前一个节点对象
        Node<E> next; // 记录下一个节点对象

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

    private Node head; // 记录头节点
    private Node tail; // 记录尾节点
    private int size; // 记录元素个数

    /**
     * 向双向链表中添加元素的方法
     *
     * @param element
     */
    @Override
    public void add(E element) {
          
   
        linkLast(element);
    }

    /**
     * 将节点对象添加到双向链表的尾部
     */
    private void linkLast(E element) {
          
   
        Node t = this.tail; // 获取尾节点
        Node<E> node = new Node<>(t, element, null); // 创建节点对象
        this.tail = node; // 将新节点定义为尾节点 因为原来的尾节点被这个新节点替代了
        if (t == null) {
          
   
            // 说明一个节点都没有,这个还得是头节点
            this.head = node;
        } else {
          
   
            t.next = node;
        }
        this.size++;
    }

    /**
     * 根据指定位置获取元素
     *
     * @param index
     * @return
     */
    @Override
    public E get(int index) {
          
   
        this.checkIndex(index);
        // 根据位置查找节点对象
        Node<E> node = this.getNode(index);
        return node.item;
    }

    /**
     * 对index的合法性校验
     */
    private void checkIndex(int index) {
          
   
        if (!(index >= 0 && index < this.size)) {
          
   
            throw new IndexOutOfBoundsException();
        }
    }

    /**
     * 根据位置获取指定节点对象
     */
    private Node getNode(int index) {
          
   
        // 判断当前位置距离头或者尾哪个节点更近  使用二分法
        if (index < (this.size >> 1)) {
          
   
            Node node = this.head;
            for (int i = 0; i < index; i++) {
          
   
                node = node.next;
            }
            return node;
        } else {
          
   
            Node node = this.tail;
            for (int i = this.size - 1; i > index; i--) {
          
   
                node = node.prev;
            }
            return node;
        }
    }

    /**
     * 返回元素的个数
     *
     * @return
     */
    @Override
    public int size() {
          
   
        return this.size;
    }

    /**
     * 删除元素
     *
     * @param index
     * @return
     */
    @Override
    public E remove(int index) {
          
   
        // 对index进行合法性校验
        this.checkIndex(index);
        Node node = this.getNode(index); // 根据位置获取到节点对象
        // 获取节点对象的元素
        E item = (E) node.item;
        // 判断当前节点是否为头节点
        if (node.prev == null) {
          
   
            this.head = node.next;
        } else {
          
   
            node.prev.next = node.next;
        }
        // 判断当前节点是否为尾节点
        if (node.next == null) {
          
   
            // node.prev.next = null;
            this.tail = node.prev;
        } else {
          
   
            node.next.prev = node.prev;
        }
        // 当前节点断掉与他后继节点的连接
        node.next = null;
        // 当前节点断掉与直接前驱节点的连接
        node.prev = null;
        node.item = null;
        this.size--;
        return item;
    }

    /**
     * 在双向链表的头添加元素
     */
    public void addFirst(E element) {
          
   
        this.linkFirst(element);
    }

    /**
     * 在链表的头添加元素
     *
     * @param element
     */
    public void linkFirst(E element) {
          
   
        // 获取头节点对象
        Node head = this.head;
        Node<E> eNode = new Node<>(null, element, head);
        // 将新节点定义为头节点
        this.head = eNode;
        if (head == null) {
          
   
            // 如果为空,说明该链表中一个节点都没有 也就是该头节点也是尾节点
            this.tail = eNode;
        } else {
          
   
            head.prev = eNode;
        }
        this.size++;
    }

    /**
     * 在链表的尾部添加元素
     *
     * @param element
     */
    public void addLast(E element) {
          
   
        this.linkLast(element);
    }

    public static void main(String[] args) {
          
   
        MyDoublyLinkedList<String> list = new MyDoublyLinkedList<>();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("d");
        list.add("e");
        System.out.println(list.remove(2));
        System.out.println(list.size);
        for (int i = 0; i < list.size(); i++) {
          
   
            System.out.println(list.get(i));
        }
    }
}

谢谢您的观看。

经验分享 程序员 职场和发展