数据结构(四) --- 双向链表

双向链表


什么是双向链表: 在之前我们提到过,每一个节点只有一个指针域的叫做单链表,所以在这里就是每一个节点有两个指针域的叫做双链表;一个指向直接前驱,一个指向直接后继;

为什么需要双向链表: 因为在单链表中,查找直接后继的时间复杂度为O(1),而查找直接前驱的时间复杂度为O(n),为了克服这一缺点,就诞生了 双向链表(Double Linked List)

ps:如果有不正确之处,望各位看官不吝赐教,毕竟我还是菜鸟



双向链表的实现


链表的初始化:

/**
* 首元素
*/
private Node first;

/**
* 尾元素
*/
private Node last;

/**
* 临时节点,用于遍历链表
*/
private Node temp;

/**
* 双链表中的元素个数
*/
private int size;

添加元素操作:

  • 末尾处加入节点:

    /**
    * 在链表的末尾处加入元素
    * @param element   元素值
    */
    public void add(E element) {
        // 创建新的节点
        Node<E> node = new Node<>(element);
        // 先判断是否是空链表,直接加入
        if (size == 0) {
            first = node;
            last = node;
        } else {
            last.next = node;
            node.prior = last;
            last = node;
        }
        size ++;
    }
    

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jJq4ejS6-1576167201429)(G:\学习笔记\数据结构\图片\末尾添加.png)]

  • 插入节点:

    /**
    * 在指定的位置处插入给定的数据元素
    * @param index     指定的位置
    * @param element   数据元素
    */
    public void insert(int index, E element) {
        // 检查索引
        checkIndex(index);
        // 创建新的节点
        Node<E> node = new Node<>(element);
        temp = first;  // 临时节点
        if (temp != null) {
            if (index == 0) { // 插入的位置是首节点
                node.next = temp;
                temp.prior = node;
                first = node;
            } else if (index == size) { // 插入的位置是尾节点
                add(element);
            } else {
                // 获取指定位置处的节点
                temp = getNode(index);
                // 插入数据
                temp.next.prior = node;
                node.next = temp.next;
                temp.next = node;
                node.prior = temp;
            }
        }
        size ++;
    }
    

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YxK6v99k-1576167201431)(G:\学习笔记\数据结构\图片\双向链表-插入操作.png)]

获取操作:

  • 根据索引获取元素:

    /**
    * 根据给定的索引位置返回节点
    * @param index 指定的索引位置
    * @return
    */
    public Node getNode(int index) {
        checkIndex(index);
        if (index < (size >> 1)) { // 在左半部分,从first开始往后遍历
            temp = first;
            for (int i = 0; i < index; i++) {
                temp = temp.next;
            }
        } else { // 右半部分,从last开始往前遍历
            temp = last;
            for (int i = size - 1; i > index; i--) {
                temp = temp.prior;
            }
        }
        return temp;
    }
    
    

  • 根据元素获取索引:

    /**
    * 找到所给元素的索引
    * @param element   需要匹配的元素
    * @return          返回匹配到的索引值
    */
    public int getIndex(E element) {
        temp = first;
        for (int i = 0; i < size; i++) {
            if (temp.element.equals(element))
                return i;
            temp = temp.next;
        }
        return -1;
    }
    
    

删除操作:

  • 根据索引删除节点:

    /**
    * 删除指定位置处的节点
    * @param index 需要删除的节点位置
    */
    public void delete(int index) {
        checkIndex(index);
        if (index == 0) {
            first = first.next;
            first.next.prior = null;
        } else if (index == size -1) {
            last.prior.next = null;
            last = last.prior;
        } else {
            // 获取需要删除的节点
            temp = getNode(index);
            temp.prior.next = temp.next;
            temp.next.prior = temp.prior;
        }
        size --;
    }
    
    

  • 根据元素值删除节点:

    /**
    * 删除指定的元素
    * @param element   需要删除的元素
    */
    public void remove(E element) {
        // 获取该元素的索引
        int index = getIndex(element);
        // 删除元素
        delete(index);
    }
    

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L4CkvB70-1576167201433)(G:\学习笔记\数据结构\图片\双向链表-删除操作.png)]

修改操作:

/**
* 修改指定位置的元素
* @param index     需要修改的位置
* @param element   需要替换的元素
*/
public void set(int index, E element) {
    checkIndex(index);
    // 根据index找到节点
    temp = getNode(index);
    // 修改元素
    temp.element = element;
}

辅助方法:

/**
* 检查所给的索引位置是否合法
* @param index     链表中的位置
*/
private void checkIndex(int index) {
    if (index < 0 || index >= size) {
        throw new RuntimeException("索引不合法:" + index);
    }
}

@Override
public String toString() {
    Node temp = first;
    StringBuilder sb = new StringBuilder("[");
    if (temp != null) {
        for (int i = 0; i < size; i++) {
            sb.append(temp.element).append(",");
            temp = temp.next;
        }
    }
    sb.setCharAt(sb.length() - 1, ']');
    return sb.toString();
}

节点类:

/**
* 节点类
* @param <E>
*/
public static class Node<E>{
    /**
         * 前指针域
         */
    Node prior;

    /**
         * 数据域
         */
    E element;

    /**
         * 后指针域
         */
    Node next;

    public Node() {}

    public Node(E element) {
        this.prior = null;
        this.element = element;
        this.next = null;
    }
}
发布了22 篇原创文章 · 获赞 0 · 访问量 355

猜你喜欢

转载自blog.csdn.net/Yi__Ying/article/details/103518947