数据结构与算法之四(链表)

链表的概念在学c++的时候就接触了,就是一个个节点,每个节点里存在对下一个节点的引用。大概结构如下:

class Node{
   //节点的其他属性    
   ...
   //引用下一个节点
   Node next;
}

这样一个个节点上一个连下一个就形成了链表,概念很简单。如果知道第一个节点的内存地址,那么可以顺藤摸瓜找到其他节点。这种存储方式的好处是插入和删除时不需要做移动操作,只要改一下next的指向即可。缺陷也很明显,查找Node得从第一个节点依次遍历。

这里有几个概念:单链表,双端双向链表,循环链表等可以查一下。跟队列有点像,但是队列我们之前见过的那种是用数组存储的,实际上也可以用这种链表来存储。

java中链表比较典型的实现是LinkedList。

public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable

//AbstractSequentialList
public abstract class AbstractSequentialList<E> extends AbstractList<E> 

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E>

从这里可以看出AbstractSequentialList包含了collectionlist的实现.
我们上一节了解了collection中包含了各种操作以及迭代器。而list中其实也是collection
public interface List<E> extends Collection<E>

注意这里还有Deque,前面聊过这个是双端队列,所以这个LinkedList实际上是一个双端链表。通过firstlast维护首尾节点
transient Node<E> first;
transient Node<E> last;

从addAll方法可以看到这个链表的构建过程。核心代码如下:
public boolean addAll(int index, Collection<? extends E> c) {
        checkPositionIndex(index);

        Object[] a = c.toArray();
        int numNew = a.length;
        if (numNew == 0)
            return false;

        Node<E> pred, succ;
        if (index == size) {
            succ = null;
            pred = last;
        } else {
            succ = node(index);
            pred = succ.prev;
        }

        //通过for循环将所有node通过next连接起来
        for (Object o : a) {
            @SuppressWarnings("unchecked") E e = (E) o;
            Node<E> newNode = new Node<>(pred, e, null);
            if (pred == null)
                first = newNode;
            else
                pred.next = newNode;
            pred = newNode;
        }

        if (succ == null) {
            last = pred;
        } else {
            pred.next = succ;
            succ.prev = pred;
        }

        size += numNew;
        modCount++;
        return true;
    }

说白了就是开头我画的那点东西。

猜你喜欢

转载自blog.csdn.net/kkae8643150/article/details/78291167