2.3线性表的链式存储——双向链表(手工实现)

通过单链表可以看到,有了next指针,使得我们在查找下一节点的时间复杂度变为O(1),但是如果想要查找上一个结点,则需要重新从头开始遍历,最坏的时间复杂度变为O(n)。双向链表提供了这种能力,即允许向前遍历,也允许向后遍历。实现这种特性的关键在于每个链结点既有下一个链结点的引用,也有上一个链结点的引用。

双向链表

双向链表是在单链表的每个结点中,再设置一个指向其前驱结点的指针域。

 双向链表的插入和删除并不是十分复杂,不过还是要注意顺序。

插入         顺序:先搞定s结点的前驱和后继再搞定后结点的前驱,最后解决前结点的后继(遍历到插入位置的前一个结点)

删除

手写双向循环链表

类结构图

双向循环链表封装类

package com.company.datastructure;

public class MyDoubleLinkedList<E> {
    private class Node<E>{
        public E element;  //元素值
        private Node<E> prior;  //直接前驱指针
        private Node<E> next;  //直接后继指针

        public Node(){

        }
        public Node(E element) {
            this.element = element;
        }
    }
    private Node<E> head;  //头结点
    private int size;  //链表长度  默认初始化为0

    public MyDoubleLinkedList(){
        head = new Node<E>();
        head.prior = head;  //初始全为空
        head.next = head;
    }

    //插入
    /**
     * 指定位置插入结点
     * @param index 索引值
     * @param element 元素值
     */
    public void insert(int index,E element){
        rangeCheck(index);
        Node<E> newNode = new Node<>(element);
        Node<E> temp = head;
        for (int i = 0; i < index; i++) {
            temp = temp.next;
        }
        newNode.prior = temp;
        newNode.next = temp.next;
        temp.next.prior = newNode;
        temp.next = newNode;
        size++;
    }

    /**
     * 表头插入结点
     * @param element 结点元素值
     */
    public void addFirst(E element){
        Node<E> newNode = new Node<>(element);
        newNode.prior = head;
        newNode.next = head.next;
        head.next.prior = newNode;
        head.next = newNode;
        size++;
    }

    /**
     * 表尾插入结点
     * @param element 结点元素值
     */
    public void addLast(E element){
        Node<E> newNode = new Node<>(element);
        Node<E> temp = head.prior;
        newNode.prior = temp;
        newNode.next = temp.next;
        temp.next.prior = newNode;
        temp.next = newNode;
        size++;
    }

    //删除

    /**
     * 删除指定位置元素
     * @param index 索引值
     * @return 删除元素值
     */
    public E remove(int index){
        rangeCheck(index);
        Node<E> temp = head.next;
        //调用get方法获得索引位置结点时需要把0独立出来,所以就直接遍历到所需结点
        for (int i = 0; i < index; i++) {
            temp = temp.next;
        }
        temp.prior.next = temp.next;
        temp.next.prior = temp.prior;
        size--;
        return temp.element;
    }

    /**
     * 删除表头元素
     * @return 被删除元素值
     */
    public E removeFirst(){
        Node<E> temp = head.next;
        temp.prior.next = temp.next;
        temp.next.prior = temp.prior;
        size--;
        return temp.element;
    }

    /**
     * 删除表尾元素
     * @return 被删除元素值
     */
    public E removeLast(){
        Node<E> temp = head.prior;
        temp.prior.next = temp.next;
        temp.next.prior = temp.prior;
        size--;
        return temp.element;
    }
    //查找

    /**
     * 根据索引值查找元素
     * 索引小于链表长度一半时从前往后遍历,否则从后往前遍历
     * @param index 索引
     * @return 索引处元素值
     */
    public E get(int index){
        rangeCheck(index);
        if(index<=size/2){
            Node<E> temp = head.next;
            for (int i = 0; i < index; i++) {
                temp = temp.next;
            }
            return temp.element;
        }else{
            Node<E> temp = head.prior;
            for (int i = size-1; i >index ; i--) {
                temp = temp.prior;
            }
            return temp.element;
        }
    }

    /*---------------------------------------------------------------------*/
    /**
     * 获得链表长度
     * @return 链表长度
     */
    public int getSize(){
        return size;
    }

    /**
     * 判断链表是否为空
     * @return true为空,false非空
     */
    public boolean isEmpty(){
        return size==0?true:false;
    }

    /**
     * 清空链表
     */
    public void clear(){
        Node<E> temp = head.next;
        for (int i = 0; i < size; i++) {
            Node<E> next = temp.next;
            temp.element = null;
            temp.prior = null;
            temp.next = null;
            temp = next;
        }
        head.next = head;
        head.prior = head;
        size = 0;
    }


    /*---------------------------------------------------------------------*/
    /**
     * 索引检查
     * @param index 索引
     */
    private void rangeCheck(int index){
        if (index <0|| index >= size){
            throw new IndexOutOfBoundsException("索引不合法"+index);
        }
    }
}

双向循环链表测试

package com.company.datastructure;

public class TestMyDoubleLinkedList {
    public static void main(String[] args) {
        MyDoubleLinkedList<String> mdl = new MyDoubleLinkedList<>();
        mdl.addLast("chen2");
        mdl.addLast("chen3");
        mdl.addLast("chen4");
        mdl.addFirst("chen0");
        mdl.insert(1,"chen1");
        System.out.println(mdl.getSize());
        for (int i = 0; i < mdl.getSize(); i++) {
            System.out.println(mdl.get(i));
        }
        mdl.remove(1);
        mdl.removeFirst();
        mdl.removeLast();
        System.out.println(mdl.getSize());
        for (int i = 0; i < mdl.getSize(); i++) {
            System.out.println(mdl.get(i));
        }
        mdl.clear();
        System.out.println(mdl.getSize());
        System.out.println(mdl.isEmpty());
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_39722922/article/details/86536467