自己动手实现java数据结构(二) 链表
| 从概率的角度上来看,下标访问是随机的,因此find方法的时间复杂度被认为是O(n)。 3.4.2 链表的插入方法实现 add(E e) {
        :::将新的数据 插入到列表末尾 ==> 作为last节点的前一个节点插入
        this.last.linkAsLeft((e));
        :::size自增
        this.size++;
        true:::插入时,下标越界检查
        rangeCheckForAdd(index);
        :::查询出下标对应的 目标节点
        Node<E> targetNode = find(index);
        :::将新的数据节点 作为目标节点的前一个节点插入
        targetNode.linkAsLeft((e));
        ;
    }插入方法的时间复杂度:尾部插入: 尾部插入方法中,由于我们维护了一个last哨兵节点,通过直接将新节点插入last哨兵的左边,完成尾部数据的插入。 因此,尾部插入方法的时间复杂度为O(1)。 下标插入: 下标插入方法中,依赖find方法查询出下标对应的节点,然后将新节点进行插入。 因此,下标插入方法的时间复杂度为O(n);对于头部,尾部节点的插入,时间复杂度为O(1)。 3.4.3 删除方法的实现 remove(E e) {
        .first;删除方法的时间复杂度:特定元素删除: 链表特定元素的删除和find方法类似,通过一次遍历获得目标节点,然后进行删除。 因此,特定元素的删除方法时间复杂度为O(n)。 下标删除: 下标删除方法中,依赖find方法查询出下标对应的节点,然后将目标节点进行删除。 因此,下标删除方法的时间复杂度为O(n);对于头部,尾部节点的删除,时间复杂度为O(1)。 3.4.4?修改/查询方法实现public E set(:::先暂存要被替换的"data"
        E oldValue = targetNode.data;
        :::将当前下标对应的"data"替换为"e"
        targetNode.data = e;
        :::返回被替换的data
         oldValue;
    }
    @Override
    public E get( targetNode.data;
    }修改/查询方法的时间复杂度:可以看到,链表基于下标的修改和查询都依赖于find方法。 因此,修改/查询方法的时间复杂度为O(n);对于头部,尾部节点的修改和查询,时间复杂度为O(1)。 3.5 链表其它接口3.5.1 clear方法clear方法用于清空链表内的元素,初始化链表。  clear() {
        :::当头部哨兵节点不和尾部哨兵节点直接相连时
        while(this.first.right != .last){
            :::删除掉头部哨兵节点后的节点
            remove(0);
        }
        :::执行完毕后,代表链表被初始化,重置size
        ;
    }3.5.2 toString方法 String toString() {
        Iterator<E> iterator = .iterator();
        :::空列表
        if(!iterator.hasNext()){
            return "[]";
        }
        :::列表起始使用"["
        StringBuilder s = new StringBuilder("[");
        :::反复迭代
        :::获得迭代的当前元素
            E data = iterator.next();
            :::判断当前元素是否是最后一个元素
            iterator.hasNext()){
                :::是最后一个元素,用"]"收尾
                s.append(data).append("]");
                :::执行完毕 返回拼接完成的字符串
                 s.toString();
            }{
                :::不是最后一个元素
                :::使用","分割,拼接到后面
                s.append(data).append(",");
            }
        }
    }链表的toString方法在之前"向量篇"的基础上进行了优化。基于列表List的Iterator接口进行遍历,实现了同样的功能。事实上,改进之后的toString方法也同样可以适用于向量。 在jdk的Collection框架中,框架设计者要求所有的单值数据结构容器都必须实现Iterator接口,因而将toString方法在AbstractCollection这一顶层抽象类中进行了实现,达到统一单值数据结构容器toString方法默认行为的目的,增强了代码的可重用性。 4.链表的Iterator(迭代器)   
     * 链表迭代器实现
     * class Itr implements Iterator<E>
         * 当前迭代器光标位置
         * 初始化指向 头部哨兵节点
         * private Node<E> currentNode = LinkedList..first;
        
         * 最近一次迭代返回的数据
         *  lastReturned;
        @Override
         hasNext() {
            :::判断当前节点的下一个节点 是否是 尾部哨兵节点
            this.currentNode.right != LinkedList..last);
        }
        @Override
         E next() {
            :::指向当前节点的下一个节点
            this.currentNode = .currentNode.right;
            :::设置最近一次返回的节点
            this.lastReturned = currentNode;
            :::返回当前节点的data
            .currentNode.data;
        }
        @Override
         remove() {
            if(this.lastReturned == new IteratorStateErrorException("迭代器状态异常: 可能在一次迭代中进行了多次remove操作");
            }
            :::当前光标指向的节点要被删除,先暂存引用
            Node<E> nodeWillRemove = .currentNode;
            :::由于当前节点需要被删除,因此光标前移,指向当前节点的上一个节点
            .currentNode.left;
            :::移除操作需要将最近一次返回设置为null,防止多次remove
            this.lastReturned = :::将节点从链表中移除
            nodeWillRemove.unlinkSelf();
        }
    }迭代器在实现时需要满足接口的行为定义,remove方法在一次next迭代中不能被重复调用,否则会产生古怪的异常。 5.链表性能链表作为线性表的一种,一般被用来和同为线性表的向量进行比较。 空间效率:比起向量,链表的单位数据是存储在内部节点之中的。而内部节点除了含有数据域,还包括了左右节点的引用,因此链表的空间效率比向量稍差。 时间效率:在有些书籍或者博客中会笼统地介绍:"比起向量,链表的插入,删除操作时间复杂度较低(向量O(n),链表O(1));查询,修改操作时间复杂度较高(向量O(1),链表O(n))"。 链表插入,删除操作的时间复杂度本身确实是O(1)(仅需要修改节点引用),因为不用和向量一样批量的移动内部元素。 (编辑:锡盟站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! | 

