美文网首页Java_集合
实现自定义的 LinkedList

实现自定义的 LinkedList

作者: 大海孤了岛 | 来源:发表于2017-03-10 14:55 被阅读22次

    1.实现思路:通过双链表来实现,并且保留该表两端的引用。

    2.实现设计:


    a. MyLinkedList类:包含到两端的链,表的大小以及一些方法。
    b. Node类:一个节点包含数据以及前一个节点的链和下一个节点的链,以及其构造方法。
    c. LinkedListIterator类:实现接口Iterator,提供next,hasNext,remove方法的实现。


    3. 具体实现过程---Coding:


    a. 实现Node类:

    //定义节点,类型为AnyType
        private static class Node<AnyType>{
            //通过构造函数,创建一个节点
            public Node(AnyType d, Node<AnyType> p, Node<AnyType> n){
                data = d;
                prev = p;
                next = n;
            }
            //当前结点数据
            public AnyType data;
            //向前驱点
            public Node<AnyType> prev;
            //向后驱点
            public Node<AnyType> next;
        }
    

    b. 定义一些常量:

    public class MyLinkedList<Object> implements Iterable<Object> {
        //定义当前长度
        private int theSize;
        //定义操作次数,增加,删除等影响结构的操作
        private int modCount = 0;
        //定义开始标记
        private Node<Object> beginMarker;
        //定义结束标记
        private Node<Object> endMarker;
    }
    

    c.构造函数以及初始化操作:

    //创建时,清空所有之前的数据
        public MyLinkedList(){
            doClear();
        }
    
        //清空操作
        public void clear(){
            doClear();
        }
    
        //实现具体的清空操作
        public void doClear() {
            //定义开始节点
            beginMarker = new Node<Object>(null,null,null);
            //定义结束节点,注意这里将开始节点作为结束节点的向前节点
            endMarker = new Node<Object>(null, beginMarker, null);
            //将结束节点作为开始节点的向后节点
            beginMarker.next = endMarker;
            //初始化大小为0
            theSize = 0;
            //操作加1
            modCount ++;
        }
    
        //返回当前长度
        public int size(){
            return theSize;
        }
    
        //判断当前链表是否为空
        public boolean isEmpty(){
            return theSize == 0;
        }
    

    d. get操作,获取到节点以及节点数据等

        /**
         * 根据链表位置获取到对应的数据:通过调用getNode方法获取到当前结点,
         * 再获取到当前结点的数据
         * @param idx 传入的位置
         * @return
         */
        public Object get(int idx){
            return getNode(idx).data;
        }
    
        /**
         * 获取到对应位置的节点:调用具体的getNode方法去获取
         * @param idx
         * @return
         */
        private Node<Object> getNode(int idx){
            return getNode(idx, 0 , size());
        }
    
        /**
         * 实现根据位置获取到节点
         * @param idx 当前位置
         * @param lower 开始位置
         * @param upper 结束位置
         * @return
         */
        private Node<Object> getNode(int idx, int lower, int upper){
            //定义一个临时节点
            Node<Object> p;
            //若传入的位置超出范围,则抛出异常
            if (idx < lower || idx > upper)
                throw new IndexOutOfBoundsException();
            //若当前位置在左边,则从开始出进行向后遍历
            if (idx < size() / 2){
                //移动到开始处
                p = beginMarker;
                //遍历直到到达所要求的位置
                for (int i = 0; i < idx; i ++){
                    p = p.next;
                }
            }
            //若当前位置在右边,则从尾部开始进行向前遍历
            else {
                p = endMarker;
                for (int i = size(); i > idx; i --){
                    p = p.prev;
                }
            }
            return p;
        }
    

    e. set操作,用于更新节点数据:

        /**
         * 更新数据操作
         * @param idx 传入的链表位置
         * @param newVal 更新的数据
         * @return
         */
        public Object set(int idx, Object newVal){
            //获取到对应位置的节点
            Node<Object> p = getNode(idx);
            //获取到当前数据
            Object oldVal = p.data;
            p.data = newVal;
            //返回原来的数据
            return oldVal;
        }
    

    f. 添加操作:主要理解addBefore操作

        /**
         * 实现默认方式添加元素
         * @param x
         * @return
         */
        public boolean add(Object x){
            //调用add方法,添加到尾部
            add(size(), x);
            return true;
        }
    
        /**
         * 实现添加到具体的某个位置中
         * @param idx
         * @param x
         */
        public void add(int idx, Object x) {
            addBefore(getNode(idx), x);
        }
    
        /**
         * 实现具体的添加操作
         * @param p 当前位置的节点
         * @param x 节点数据
         */
        private void addBefore(Node<Object> p , Object x){
            //根据p节点创建一个新的节点
            Node<Object> newNode = new Node<Object>(x, p.prev, p);
            //连接新节点与前后两个节点
            newNode.prev.next = newNode;
            p.prev = newNode;
            //长度和操作次数++
            theSize ++;
            modCount ++;
        }
    

    添加操作示意图:

    add_node
     //实际上,通过构造函数,便完成了示意图中的1和2操作
     Node<Object> newNode = new Node<Object>(x, p.prev, p);
     //实现了操作3
     newNode.prev.next = newNode;
     //实现了操作4
     p.prev = newNode;
    

    g. 实现删除节点操作:

        /**
         * 实现移除某个位置的节点
         * @param idx
         * @return
         */
        public Object remove(int idx){
            return remove(getNode(idx));
        }
    
        /**
         * 具体移除节点操作
         * @param p 传入要移除的节点
         * @return
         */
        private Object remove(Node<Object> p){
            //移除当前节点
            p.next.prev = p.prev;
            p.prev.next = p.next;
            //长度--
            theSize --;
            //操作次数++
            modCount ++;
            //返回移除节点的数据
            return p.data;
        }
    

    删除示意图:

    delete_node.png

    h. 实现查找元素位置操作:

    /**
         * 实现查找链表中首先出现的元素位置
         * @param x
         * @return
         */
        public int indexOf(Object x){
            int index = 0;
            //若传入的数据为空
            if (x == null){
                //遍历链表,查找是否含有数据为null的节点,找到后立即返回当前位置
                for (Node<Object> node = beginMarker.next; node != endMarker; node = node.next){
                    if (node.data == null){
                        return index;
                    }
                    index ++;
                }
            }
            //数据不为空时,使用equals方法进行比较
            else {
                for (Node<Object> node = beginMarker.next; node != endMarker; node = node.next){
                    if (x.equals(node.data)){
                        return index;
                    }
                    index ++;
                }
            }
            return -1;
        }
    
        /**
         * 实现查找链表中元素最后出现的位置
         * 从尾节点开始向前遍历搜查
         * @param x
         * @return
         */
        public int lastIndexOf(Object x){
            int index = size() - 1;
            if (x == null){
                for (Node<Object> node = endMarker.prev; node != beginMarker; node = node.prev){
                    if (node.data == null){
                        return index;
                    }
                    index --;
                }
            } else {
                for (Node<Object> node = endMarker.prev; node != beginMarker; node = node.prev){
                    if (x.equals(node.data)){
                        return index;
                    }
                    index --;
                }
            }
            return -1;
        }
    
    

    i. 实现LinkedListIterator类:

    private class LinkedListIterator implements Iterator<Object>{
            //定义当前结点为始节点的下一个节点
            private Node<Object> current = beginMarker.next;
            //定义操作次数
            private int expectedModCount = modCount;
            //判断是否可以进行删除
            private boolean okToRemove = false;
    
            //判断是否存在下一个节点
            @Override
            public boolean hasNext() {
                return current != endMarker;
            }
    
            //获取到下一个节点数据
            @Override
            public Object next() {
                //操作次数不一致抛出异常
                if (modCount != expectedModCount)
                    throw new ConcurrentModificationException();
                //不存在下一个节点,抛出异常
                if (!hasNext())
                    throw new NoSuchElementException();
                //获取到下一个节点的数据,并设置okToRemove为true,表示可以进行删除
                Object nextItem = current.data;
                current = current.next;
                okToRemove = true;
                return nextItem;
            }
    
            //进行删除操作
            public void remove(){
                //操作次数不一致,抛出异常
                if (modCount != expectedModCount)
                    throw new ConcurrentModificationException();
                //无法进行删除操作,必须先进行next,才可以进行remove操作
                if (!okToRemove)
                    throw new IllegalStateException();
                //调用链表中的remove方法进行删除操作,注意传入的是current.pre节点
                MyLinkedList.this.remove(current.prev);
                //操作次数++
                expectedModCount ++;
                okToRemove = false;
            }
        }
    

    完整代码如下:

    /**
     * Created by Administrator on 2017/3/5/005.
     * 实现自定义LinkedList
     */
    public class MyLinkedList<Object> implements Iterable<Object> {
        //定义当前长度
        private int theSize;
        //定义操作次数,增加,删除等影响结构的操作
        private int modCount = 0;
        //定义开始标记
        private Node<Object> beginMarker;
        //定义结束标记
        private Node<Object> endMarker;
    
        //定义节点,类型为AnyType
        private static class Node<AnyType>{
            //通过构造函数,创建一个节点
            public Node(AnyType d, Node<AnyType> p, Node<AnyType> n){
                data = d;
                prev = p;
                next = n;
            }
            //当前结点数据
            public AnyType data;
            //向前驱点
            public Node<AnyType> prev;
            //向后驱点
            public Node<AnyType> next;
        }
    
        //创建时,清空所有之前的数据
        public MyLinkedList(){
            doClear();
        }
    
        //清空操作
        public void clear(){
            doClear();
        }
    
        //实现具体的清空操作
        public void doClear() {
            //定义开始节点
            beginMarker = new Node<Object>(null,null,null);
            //定义结束节点,注意这里将开始节点作为结束节点的向前节点
            endMarker = new Node<Object>(null, beginMarker, null);
            //将结束节点作为开始节点的向后节点
            beginMarker.next = endMarker;
            //初始化大小为0
            theSize = 0;
            //操作加1
            modCount ++;
        }
    
        //返回当前长度
        public int size(){
            return theSize;
        }
    
        //判断当前链表是否为空
        public boolean isEmpty(){
            return theSize == 0;
        }
    
        /**
         * 根据链表位置获取到对应的数据:通过调用getNode方法获取到当前结点,
         * 再获取到当前结点的数据
         * @param idx 传入的位置
         * @return
         */
        public Object get(int idx){
            return getNode(idx).data;
        }
    
        /**
         * 更新数据操作
         * @param idx 传入的链表位置
         * @param newVal 更新的数据
         * @return
         */
        public Object set(int idx, Object newVal){
            //获取到对应位置的节点
            Node<Object> p = getNode(idx);
            //获取到当前数据
            Object oldVal = p.data;
            p.data = newVal;
            //返回原来的数据
            return oldVal;
        }
    
        /**
         * 获取到对应位置的节点:调用具体的getNode方法去获取
         * @param idx
         * @return
         */
        private Node<Object> getNode(int idx){
            return getNode(idx, 0 , size());
        }
    
        /**
         * 实现根据位置获取到节点
         * @param idx 当前位置
         * @param lower 开始位置
         * @param upper 结束位置
         * @return
         */
        private Node<Object> getNode(int idx, int lower, int upper){
            //定义一个临时节点
            Node<Object> p;
            //若传入的位置超出范围,则抛出异常
            if (idx < lower || idx > upper)
                throw new IndexOutOfBoundsException();
            //若当前位置在左边,则从开始出进行向后遍历
            if (idx < size() / 2){
                //移动到开始处
                p = beginMarker;
                //遍历直到到达所要求的位置
                for (int i = 0; i < idx; i ++){
                    p = p.next;
                }
            }
            //若当前位置在右边,则从尾部开始进行向前遍历
            else {
                p = endMarker;
                for (int i = size(); i > idx; i --){
                    p = p.prev;
                }
            }
            return p;
        }
    
        /**
         * 实现默认方式添加元素
         * @param x
         * @return
         */
        public boolean add(Object x){
            //调用add方法,添加到尾部
            add(size(), x);
            return true;
        }
    
        /**
         * 实现添加到具体的某个位置中
         * @param idx
         * @param x
         */
        public void add(int idx, Object x) {
            addBefore(getNode(idx), x);
        }
    
        /**
         * 实现具体的添加操作
         * @param p 当前位置的节点
         * @param x 节点数据
         */
        private void addBefore(Node<Object> p , Object x){
            //实际上,通过构造函数,便完成了示意图中的1和2操作
            Node<Object> newNode = new Node<Object>(x, p.prev, p);
            //实现了操作3
            newNode.prev.next = newNode;
            //实现了操作4
            p.prev = newNode;
            //长度和操作次数++
            theSize ++;
            modCount ++;
        }
    
        /**
         * 实现移除某个位置的节点
         * @param idx
         * @return
         */
        public Object remove(int idx){
            return remove(getNode(idx));
        }
    
        /**
         * 具体移除节点操作
         * @param p 传入要移除的节点
         * @return
         */
        private Object remove(Node<Object> p){
            //移除当前节点
            p.next.prev = p.prev;
            p.prev.next = p.next;
            //长度--
            theSize --;
            //操作次数++
            modCount ++;
            //返回移除节点的数据
            return p.data;
        }
    
        /**
         * 获取到第一个节点数据
         * @return
         */
        public Object getFirst(){
            //先判断链表是否为空,为空则抛出异常
            if (isEmpty()){
                throw new NoSuchElementException();
            }
            return beginMarker.next.data;
        }
    
        //获取到链表中的最后一个节点数据
        public Object getLast(){
            if (isEmpty()){
                throw new NoSuchElementException();
            }
            return endMarker.prev.data;
        }
    
        //移除链表中第一个节点
        public Object removeFirst(){
            if (isEmpty()){
                throw new NoSuchElementException();
            }
            //调用remove方法,移除开始节点的下一个节点即可
            return remove(beginMarker.next);
        }
    
        //移除链表中的最后一个节点
        public Object removeLast(){
            if (isEmpty()){
                throw new NoSuchElementException();
            }
            //调用remove方法,移除结束节点的上一个节点即可
            return remove(endMarker.prev);
        }
    
        //从头部开始添加节点
        public void addFirst(Object x){
            //将添加节点设置为头节点即可
            addBefore(beginMarker.next, x);
        }
    
        //从尾部添加节点
        public void addLast(Object x){
            add(x);
        }
    
        //添加一个Collection集合
        public void addAll(Collection<Object> collection){
            //添加集合为空,则抛出异常
            if (collection == null){
                throw new NullPointerException();
            }
            //遍历集合,并逐个添加到链表中
            for (Object aCollection : collection) {
                add(aCollection);
            }
        }
    
        //判断链表中是否含有某个元素,调用indexOf方法即可
        public boolean contains(Object x){
            return indexOf(x) != -1;
        }
    
        /**
         * 实现查找链表中首先出现的元素位置
         * @param x
         * @return
         */
        public int indexOf(Object x){
            int index = 0;
            //若传入的数据为空
            if (x == null){
                //遍历链表,查找是否含有数据为null的节点,找到后立即返回当前位置
                for (Node<Object> node = beginMarker.next; node != endMarker; node = node.next){
                    if (node.data == null){
                        return index;
                    }
                    index ++;
                }
            }
            //数据不为空时,使用equals方法进行比较
            else {
                for (Node<Object> node = beginMarker.next; node != endMarker; node = node.next){
                    if (x.equals(node.data)){
                        return index;
                    }
                    index ++;
                }
            }
            return -1;
        }
    
        /**
         * 实现查找链表中元素最后出现的位置
         * 从尾节点开始向前遍历搜查
         * @param x
         * @return
         */
        public int lastIndexOf(Object x){
            int index = size() - 1;
            if (x == null){
                for (Node<Object> node = endMarker.prev; node != beginMarker; node = node.prev){
                    if (node.data == null){
                        return index;
                    }
                    index --;
                }
            } else {
                for (Node<Object> node = endMarker.prev; node != beginMarker; node = node.prev){
                    if (x.equals(node.data)){
                        return index;
                    }
                    index --;
                }
            }
            return -1;
        }
    
        /**
         * 实现链表的遍历
         * @return
         */
        public Iterator<Object> iterator(){
            return new LinkedListIterator();
        }
    
        private class LinkedListIterator implements Iterator<Object>{
            //定义当前结点为始节点的下一个节点
            private Node<Object> current = beginMarker.next;
            //定义操作次数
            private int expectedModCount = modCount;
            //判断是否可以进行删除
            private boolean okToRemove = false;
    
            //判断是否存在下一个节点
            @Override
            public boolean hasNext() {
                return current != endMarker;
            }
    
            //获取到下一个节点数据
            @Override
            public Object next() {
                //操作次数不一致抛出异常
                if (modCount != expectedModCount)
                    throw new ConcurrentModificationException();
                //不存在下一个节点,抛出异常
                if (!hasNext())
                    throw new NoSuchElementException();
                //获取到下一个节点的数据,并设置okToRemove为true,表示可以进行删除
                Object nextItem = current.data;
                current = current.next;
                okToRemove = true;
                return nextItem;
            }
    
            //进行删除操作
            public void remove(){
                //操作次数不一致,抛出异常
                if (modCount != expectedModCount)
                    throw new ConcurrentModificationException();
                //无法进行删除操作,必须先进行next,才可以进行remove操作
                if (!okToRemove)
                    throw new IllegalStateException();
                //调用链表中的remove方法进行删除操作,注意传入的是current.pre节点
                MyLinkedList.this.remove(current.prev);
                //操作次数++
                expectedModCount ++;
                okToRemove = false;
            }
        }
    }
    

    测试代码:

    public class LinkedListTest {
    
        public static void main(String[] args){
            //进行添加操作
            MyLinkedList<String> myLinkedList = new MyLinkedList<>();
            myLinkedList.add("Java");
            myLinkedList.add("C++");
            myLinkedList.add("Python");
            myLinkedList.add(2, "PHP");
            //遍历结果
            printLinkedList(myLinkedList.iterator());
    
            //进行删除和更新操作
            myLinkedList.remove(2);
            myLinkedList.set(1,"JavaScript");
            printLinkedList(myLinkedList.iterator());
    
            //获取到首尾元素
            System.out.println("first data : " + myLinkedList.getFirst());
            System.out.println("last data : " + myLinkedList.getLast());
    
            //移除首尾节点
            myLinkedList.removeFirst();
            myLinkedList.removeLast();
            printLinkedList(myLinkedList.iterator());
    
            //分别从首尾部添加
            myLinkedList.addFirst("C#");
            myLinkedList.addLast("CSS");
            printLinkedList(myLinkedList.iterator());
    
            //清空操作
            myLinkedList.clear();
            printLinkedList(myLinkedList.iterator());
    
            //addAll方法
            List<String> list = new ArrayList<>();
            list.add("JAVA");
            list.add("C++");
            list.add("C");
            list.add("JavaScript");
            list.add("C");
            list.add("HTML");
            myLinkedList.addAll(list);
            printLinkedList(myLinkedList.iterator());
    
            //查找元素
            System.out.println("是否存在CSS教程: " + myLinkedList.contains("CSS"));
            System.out.println("是否存在HTML教程: " + myLinkedList.contains("HTML"));
            System.out.println("C教程开始的位置为: " + myLinkedList.indexOf("C"));
            System.out.println("C教程最后的位置为: " + myLinkedList.lastIndexOf("C"));
        }
    
        private static void printLinkedList(Iterator<String> iterator){
            System.out.print("当前链表为: ");
            while (iterator.hasNext()){
                System.out.print(iterator.next() + " ");
            }
            System.out.println();
        }
    }
    

    输出结果:

    当前链表为: Java C++ PHP Python 
    当前链表为: Java JavaScript Python 
    first data : Java
    last data : Python
    当前链表为: JavaScript 
    当前链表为: C# JavaScript CSS 
    当前链表为: 
    当前链表为: JAVA C++ C JavaScript C HTML 
    是否存在CSS教程: false
    是否存在HTML教程: true
    C教程开始的位置为: 2
    C教程最后的位置为: 4
    

    相关文章

      网友评论

        本文标题:实现自定义的 LinkedList

        本文链接:https://www.haomeiwen.com/subject/cuongttx.html