简谈JAVA基础--双向链表(LinkedList)

来源:互联网 发布:数学手册 知乎 编辑:程序博客网 时间:2024/06/05 06:52
双向链表其实与单链表类似,只是存储结构略有不同。单链表采用指针指向下一个节点的方式,而双向链表多了一个指针指向前一个节点。

单链表的原理与实现参考:简谈JAVA基础--单链表

双链表与单链表相比多了一个指针变量来指向下一个节点的地址。

每个节点包含三部分:  prev前一个节点的指针变量,data节点数据, next 后一个节点的指针变量

在单链表中,由于只有next,所以每个节点的数据地址由上一个节点所知,而对链表的所有操作,都需要通过一个头节点来开始进行。

而双向链表中,由于有了prev的存在,所以可以通过尾节点和头节点来开始进行操作。知道了某个节点,就得到了前后的节点所在位置。

在java中,LinkedList底层就是通过一个双向链表来实现的。有时间可以看一下源码,写的很精妙。




下面是根据LinkedList自己实现的双链表。
下面的图片来源:http://blog.csdn.net/wangzhen209/article/details/8180462
结点结构:



链表的存储结构:


插入操作

删除操作

实现双向链表源码( 可以看一下JDK中的LinkedList ):

package Chapter1;import java.lang.reflect.Array;import java.util.Collection;/** * 实现双向链表。 * Created by yukaiji on 2017/9/13. */public class MyLinkedList<T> implements java.io.Serializable {    private static final long serialVersionUID = -8247167820457785557L;    /** List长度 **/    private int     size;    /** 操作次数 **/    private int     count;    /** 头节点 **/    private Node<T> head;    /** 尾节点 **/    private Node<T> last;    /**     * 节点类     */    private class Node<T> {        private T data;        private Node<T> prev;        private Node<T> next;        public Node(Node<T> prev, T data, Node<T> next) {            this.data = data;            this.prev = prev;            this.next = next;        }    }    /**     * 构造方法     */    public MyLinkedList() {    }    /**     * 添加对象到表头     */    public void addFirst(T data) {        Node<T> headNode = head;        // 创建一个新的节点        Node<T> newNode = new Node<>(null, data, headNode);        // 将头节点指向新的节点        head = newNode;        // 如果原先的头节点是null 代表新添加的该链表的第一个节点。        // 将尾节点指向新节点,因为该链表只存在一个节点,头尾相同        if (headNode == null) {            last = newNode;        } else {            // 如果不是第一个节点。则将前一个节点的perv指向新添加的节点            headNode.prev = newNode;        }        size++;        count++;    }    /**     * 添加对象到表尾     */    public void addLast(T data) {        Node<T> lastNode = last;        // 创建一个新的节点        Node<T> newNode = new Node<T>(lastNode, data, null);        // 将尾节点指向新的节点        last = newNode;        // 如果原先的尾节点为空,代表该节点为该链表的第一个节点        // 头节点也为新节点,首尾相同        if (lastNode == null) {            head = newNode;        } else {            // 如果不是第一个节点。则将前一个节点的next指向新添加的节点            lastNode.next = newNode;        }        size++;        count++;    }    /**     * 从链表头部删除一个节点     */    public void removeFirst() {        // 创建头节点的下一个节点对象        Node<T> headNext = head.next;        // 因为要将该头结点删除,所以把数据和下个节点的指针置为空        head.data = null;        head.next = null;        // 头节点指向该节点的下一个 (也就是删除头结点)        head = headNext;        // 如果头结点的下一个为空,说明要删除的节点是链表中唯一的节点。        // 将尾节点置为null        if (headNext == null) {            last = null;        } else {            // 否则将删除后的头节点的prev置为null  (头节点perv永远为null)            head.prev = null;        }        size--;        count++;    }    /**     * 从链表尾部删除一个节点(内容与removeFirst相反,参考removeFirst)     */    public void removeLast() {        Node<T> lastPrev = last.prev;        last.data = null;        last.prev = null;        last = lastPrev;        if (lastPrev == null) {            head = null;        } else {            last.next = null;        }        size--;        count++;    }    /**     * 打印链表     */    public void printList() {        for (Node node = head; node != null; node = node.next) {            System.out.print(node.data + " ");        }        System.out.println();    }    /**     * 链表长度     */    public int size() {        return size;    }    /**     * 链表是否为空     */    public boolean isEmpty() {        return head == null && last == null;    }    /**     * 链表是否包含对象o     */    public boolean contains(Object o) {        return indexOf(o) != -1;    }    /**     * 链表转换为数组     */    public Object[] toArray() {        Object[] array = new Object[size];        int i = 0;        for (Node node = head; node != null; node = node.next) {            array[i++] = node.data;        }        return array;    }    /**     * 链表转换为指定类型数组     */    public <E> E[] toArray(E[] arr) {        // 如果传递的数组长度小于链表的长度,创建一个指定类型、链表长度的新数组        if (arr.length < size) {            arr = (E[]) Array.newInstance(arr.getClass().getComponentType(), size);        }        Object[] array = arr;        int i = 0;        for (Node node = head; node != null; node = node.next) {            array[i++] = node.data;        }        // 将最后一位置为null代表数组结束        if (arr.length > size) {            array[size] = null;        }        return arr;    }    /**     * 获得传递对象所在的索引位置     */    public int indexOf(Object o) {        int index = 0;        if (o == null) {            for (Node node = head; node != null; node = node.next) {                if (node.data == null) {                    return index;                }                index++;            }        } else {            for (Node node = head; node != null; node = node.next) {                if (o.equals(node.data)) {                    return index;                }                index++;            }        }        return -1;    }    /**     * 添加操作,默认采用表尾插入     */    public void add(T t) {        addLast(t);    }    /**     * 删除指定节点。     * 这里有四种情况:     * 1.节点在头部     * 2.节点在尾部     * 3.节点在中间     * 4.无节点     */    public T removeNode(Node<T> node) {        T data = node.data;        Node<T> nodeNext = node.next;        Node<T> nodePrev = node.prev;        if (nodePrev == null) {            head = nodeNext;        } else {            nodePrev.next = nodeNext;        }        if (nodeNext == null) {            last = nodePrev;        } else {            nodeNext.prev = nodePrev;        }        size--;        count++;        return data;    }    /**     * 根据传递对象删除第一个遇到的元素。     */    public boolean remove(Object o) {        if (o == null) {            for (Node<T> node = head; node != null; node = node.next) {                if (node.data == null) {                    removeNode(node);                    return true;                }            }        } else {            for (Node<T> node = head; node != null; node = node.next) {                if (o.equals(node.data)) {                    removeNode(node);                    return true;                }            }        }        return false;    }    /**     * 删除c列表中所有在链表中对应的第一个相同元素。     */    public boolean removeAll(Collection<?> c) {        Object[] objs = c.toArray();        for (Object o : objs) {            T t = (T) o;            remove(t);        }        return true;    }    /**     * 删除index位置的节点     */    public T remove(int index) {        return removeNode(node(index));    }    /**     * 清空链表     */    public void clear() {        for (Node<T> node = head; node != null; ) {            Node<T> nodeNext = node.next;            node.data = null;            node.next = null;            node.prev = null;            node = nodeNext;        }        head = last = null;        size = 0;        count++;    }    /**     * 将c插入到链表尾部     */    public boolean addAll(Collection<? extends T> c) {        // 直接调用在链表尾部插入c        return addAll(size, c);    }    /**     * 将c插入到链表的index节点前     */    public boolean addAll(int index, Collection<? extends T> c) {        indexIsException(index);        Object[] array = c.toArray();        int num = array.length;        if (num == 0) {            return false;        }        Node<T> pred, succ;        // 这里判断是否从尾部插入        if (index == size) {            succ = null;            pred = last;        } else {            // 获得index位置的节点            succ = node(index);            // 记录该节点的前一个节点。            pred = succ.prev;        }        for (Object o : array) {            // 类型转换            T t = (T) o;            // 创建新的节点,前节点指针指向index的前节点。            Node<T> node = new Node<>(pred, t, null);            // 如果index前节点为null ,代表index 为头节点            if (pred == null) {                // 这样将头结点指向新插入的节点                head = node;            } else {                // 将index前节点的后节点指针指向新的节点(因为插入的新节点在指定index的前面)                pred.next = node;            }            pred = node;        }        if (succ == null) {            last = pred;        } else {            pred.next = succ;            succ.prev = pred;        }        size += num;        count++;        return true;    }    /**     * 获取index节点数据     */    public T get(int index) {        return node(index).data;    }    public boolean retainAll(Collection<?> c) {        return false;    }    /**     * 在索引index处添加一个对象     */    public void add(int index, T element) {        indexIsException(index);        if (index == size) {            addLast(element);        } else {            Node<T> succ = node(index);            Node<T> prev = succ.prev;            Node<T> node = new Node<>(prev, element, succ);            succ.prev = node;            if (prev == null) {                head = node;            } else {                prev.next = node;            }        }        size++;        count++;    }    /**     * 判断索引是否小于0     */    public Boolean indexIsException(int index) {        if (index < 0) {            System.out.println("索引小于0");            return false;        }        return true;    }    /**     * 返回指定对象最后出现的位置     */    public int lastIndexOf(Object o) {        int count = size;        if (o == null) {            for (Node<T> node = last; node != null; node = node.prev) {                count--;                if (node.data == null) {                    return count;                }            }        } else {            for (Node<T> node = last; node != null; node = node.prev) {                count--;                if (o.equals(node.data)) {                    return count;                }            }        }        return -1;    }    /**     * 获取index位置的节点     */    Node<T> node(int index) {        // 这里为什么判断传过来的index 是否小于链表长度的一半呢?        // 因为这里涉及到效率问题,如果小于一半,从前向后遍历,如果大于一般从后向前遍历。        if (index < (size >> 1)) {            Node<T> x = head;            // 从前向后遍历,x每次为当前节点的下一个,直到找到index节点            for (int i = 0; i < index; i++)                x = x.next;            return x;        } else {            Node<T> x = last;            // 从后向前遍历,x每次为当前节点的前一个,直到找到index节点            for (int i = size - 1; i > index; i--)                x = x.prev;            return x;        }    }}



测试函
public static void main(String[] args) {        MyLinkedList<String> myLinkedList = new MyLinkedList<String>();        myLinkedList.add("a");        myLinkedList.add("b");        myLinkedList.add("c");        myLinkedList.add("d");        myLinkedList.add("e");        myLinkedList.printList();        myLinkedList.remove("c");        myLinkedList.printList();        myLinkedList.addFirst("1");        myLinkedList.printList();        myLinkedList.addLast("2");        myLinkedList.printList();        List<String> addList = new ArrayList<String>();        addList.add("A");        addList.add("B");        myLinkedList.addAll(addList);        myLinkedList.printList();        System.out.println(myLinkedList.get(3));        System.out.println(myLinkedList.contains("d"));        System.out.println(myLinkedList.indexOf("e"));        myLinkedList.removeFirst();        myLinkedList.printList();        myLinkedList.removeLast();        myLinkedList.printList();        myLinkedList.clear();        myLinkedList.printList();    }


原创粉丝点击