【数据结构】链表LinkedList分析与关键实现

链表之双向链表图例

这里写图片描述

  1. 图例是Java中对链表实现概念图。从图中可以知道,链表对基础单位是节点(Node),而节点(Node)又有三部分组成:首节点(First Node)、若干中间节点(Node)与尾节点(Last Node)。
  2. 节点是链表对基础单位,每个节点包含三部分前一个节点引用(Pre Node)、数据(Data)以及后一个节点引用(Next Node)。而首节点前一个节点引用(Pre Node)为空,同样尾节点后一个节点引用(Last Node)为空。java通过这种形式实现了自上向下或者自下向上遍历数据。

链表之双向链表添加、删除Node操作

这里写图片描述

  1. 当删除一个节点当时候,其后节点当前一节点引用(Pre Node)更新为该节点前一节点引用;而其前一节点当引用更新为该节点当后一节点引用。如图节点B删除后,尾节点当前一节点引用更新为NodeA,而NodeA节点更新其后一节点引用为Last Node。
  2. 而添加操作则正好是删除操作当反向处理。
  3. 当然链表添加、删除节点还要考虑添加在首节点之前与尾节点之后两种情况这里就加篇幅说明。

链表之代码实现(实现添加操作)

通过上述分析,我们可以实现双向链表当基本要素是节点。由此我们需要一个节点对象Node,而节点对象包含3个属性:前一节点引用(prev)、数据(data)、后一节点引用(next):

public class Node<E> {
    public E data;
    public Node<E> next;
    public Node<E> prev;
}

通过对链表对分析与理解,只要告诉我们头节点(First Node)我们就可以自上而下遍历出所有节点,或者只要告诉我们尾节点(Last Node)我们就可以自下而上遍历出所有节点。
由此我们需要创建链表对象当时候,我们只需要知道头节点与尾节点即可。因此,链表中当成员也只要这两个节点。

/**
 * 链表:这里继承AbstractList模版是为了使用其迭代器测试
 */
public class LQHLinkedList extends AbstractList<E>{
    private int size = 0;// 节点个数

    private Node<E> first;// 节点头部
    private Node<E> last;// 节点尾部

    /**
     * 根据索引获取Node
     */ 
    @Override
    public E get(int index) {
        if (index > size() || index < 0) {
            throw new IndexOutOfBoundsException("index 超出范围");
        }
        Node<E> node = first;
        for (int i = 0; i < size(); i++) {
            if (index == i) {
                return node.item;
            }
            node = node.next;
        }
        return null;
    }

    /**
     * 根据索引index,添加Node
     */
    @Override
    public void add(int index, E element) {
        if (index > size() || index < 0)
            throw new IndexOutOfBoundsException("index 超出范围");

        if (index == 0) {// 在头部添加节点
            addFirst(element);
        } else if (size() == index) {// 在尾部添加节点
            addLast(element);
        } else {
            Node<E> indexNode = null;
            if (index < (size() >> 1)) {// 正向查找:从头部开始查
                indexNode = first;
                for (int i = 0; i < index; i++) {
                    if (i == index) {
                        break;
                    }
                    indexNode = indexNode.next;
                }
            } else { // 反向查找:从尾部开始查
                indexNode = last;
                for (int i = size() - 1; i > index; i--) {
                    if (i == index) {
                        break;
                    }
                    indexNode = indexNode.prev;
                }
            }
            // 当前节点、当前节点前一节点、当前节点后一节点引用替换
            Node<E> insertNode = new Node<E>();
            insertNode.item = element;
            insertNode.next = indexNode;
            insertNode.prev = indexNode.prev;

            indexNode.prev.next = insertNode;
            indexNode.prev = insertNode;
        }
        this.size++;
    }

    /**
     * 头部添加节点操作
     */
    private void addFirst(E element) {
        Node<E> node = new Node<E>();
        node.item = element;
        node.next = first;

        first = node;
    }

    /**
     * 尾部添加节点操作
     */
    private void addLast(E element) {
        Node<E> newNode = new Node<E>();
        newNode.item = element;
        if (last == null) {
            last = newNode;
            last.prev = first;
            first.next = last;
        } else {
            newNode.prev = this.last;
            this.last.next = newNode;

            this.last = newNode;
        }
    }

    @Override
    public int size() {
        return this.size;
    }

}

链表验证

    public static void main(String[] args) {
        LQHLinkedList<String> list = new LQHLinkedList<>();
        list.add("第一个");
        list.add("第二个");
        list.add("第三个");
        System.out.println(list.toString());// 输出(out):[第一个, 第二个, 第三个]

        list.add(2, "我要当老三");
        System.out.println(list);// 输出(out):[第一个, 第二个, 我要当老三, 第三个]
    }

结束语

此篇博文主要是为了加深自己对链表对理解,以及对自己所学表述能力提升为目标写对。博文对与链表对细节描述并不详尽,旨在正确表达链表核心思想以及关键实现。后续还会抽时间分析与遍历链表息息相关对迭代器。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值