zoukankan      html  css  js  c++  java
  • JDK源码阅读-------自学笔记(二十四)(java.util.LinkedList 再探 自定义讲解)

    一、实现get方法

    1、一般思维实现思路

    • 1)、将对象的值放入一个中间变量中。
    • 2)、遍历索引值,将中间量的下一个元素赋值给中间量。
    • 3)、返回中间量中的元素值。
    • 4)、示意图
    • get(2),传入角标,循环两次获取到[1]元素,如图.

    2、实现思路实现

    • 1)、核心方法
     /**
         * 最基本的写法
         *
         * <p>按照角标循环元素,获取最后一个元素的值</p>
         *
         * <p>存在问题:效率不高</p>
         *
         * @param index 元素的角标
         * @return 角标代表的元素
         */
        public Object get(int index) {
    
            Node node = firstNode;
    
            for (int i = 0; i < index; i++) {
    
                node = node.next;
            }
    
    
            return node.elements;
        }
    
    
    • 2)、测试
    /**
     * @author liuyangos8888
     */
    public class TestGet {
    
    
        public static void main(String[] args) {
            testGetBase();
    
        }
    
        private static void testGetBase() {
            MyGetLinkedList001 myGetLinkedList001 = new MyGetLinkedList001();
            myGetLinkedList001.add("A");
            myGetLinkedList001.add("B");
            myGetLinkedList001.add("C");
            myGetLinkedList001.add("D");
            myGetLinkedList001.add("E");
            myGetLinkedList001.add("F");
    
            System.out.println(myGetLinkedList001.get(4));
        }
     }
    
    

    3、思路缺少的条件

    • 1)、判断索引范围问题
            // 判断索引范围
            if (index < 0 || index > size - 1) {
                throw new RuntimeException("索引不合法!" + index);
            }
    
    • 2)、查找方式的优化问题(获取第888个索引时候,效率极低,建议使用折半查找)
    /**
         * 优化版,提高查找效率,折半判断
         *
         * @param index 索引角标
         * @return 索引对应的值
         */
        public Object get1(int index) {
    
            // 判断索引范围
            if (index < 0 || index > size - 1) {
                throw new RuntimeException("索引不合法!" + index);
            }
    
            Node node = null;
    
            // size>>1 除以2
            if (index <= (size >> 1)) {
                node = firstNode;
    
                for (int i = 0; i < index; i++) {
    
                    node = node.next;
                }
            } else {
                node = lastNode;
    
                for (int i = size - 1; i > index; i--) {
    
                    node = node.previous;
                }
            }
    
    
            return node.elements;
        }
    
    
    • 3)、发现的其他问题(采用此方式get时候,add需要size++)
    
       // 不做size++,在get判断范围的时候就会出现错误
       public void add(Object o) {
            Node node = new Node(o);
    
    
            if (firstNode == null) {
                firstNode = node;
            } else {
                node.previous = lastNode;
                node.next = null;
                lastNode.next = node;
            }
    
            lastNode = node;
    
            size++;
        }
    
    
    

    二、实现remove方法

    1、一般思维实现思路

    • 1)、把前一个元素的next元素,变为next.next元素
    • 2)、把最后一个元素的previous元素,变为previous.previous元素
    • 3)、size值减少操作
    • 4)、示意图
    • 有A、B、C三个节点,以链表形式存储(如上图)
    • 现在要删除节点B,A、C不变(如上图)
    • 方法就是截断A、C跟B的连接,A和C重新建立新的连接,JAVA的实现方式就是,用对象覆盖B节点的值。

    2、实现思路实现

    • 1)、核心方法
    
     /**
         * 根据索引,删除数组中元素
         *
         * @param index 索引角标
         */
        public void remove(int index) {
       
            Node temp = getNode(index);
    
            if (temp != null) {
                Node up = temp.previous;
                Node down = temp.next;
    
                if (up != null) {
                    up.next = down;
                }
    
                if (down != null) {
                    down.previous = up;
                }
    
                size--;
            }
    
        }
    
    
    • 2)、测试
    /**
     * @author liuyangos8888
     */
    public class TestRemove {
    
    
        public static void main(String[] args) {
    
            MyGetLinkedList002 myGetLinkedList002 = new MyGetLinkedList002();
            myGetLinkedList002.add("A");
            myGetLinkedList002.add("B");
            myGetLinkedList002.add("C");
            myGetLinkedList002.add("D");
            myGetLinkedList002.add("E");
            myGetLinkedList002.add("F");
    
            System.out.println(myGetLinkedList002);
            myGetLinkedList002.remove(3);
            System.out.println(myGetLinkedList002);
            myGetLinkedList002.remove(0);
            System.out.println(myGetLinkedList002);
            myGetLinkedList002.remove(3);
            System.out.println(myGetLinkedList002);
    
        }
    }
    
    

    3、思路缺少的条件

    • 1)、判断索引范围问题
            // 判断索引范围
            if (index < 0 || index > size - 1) {
                throw new RuntimeException("索引不合法!" + index);
            }
    
    • 2)、第一个元素删除和最后一个元素删除问题
    
                // 删除第一个元素的时候
                if (index == 0) {
                    firstNode = down;
                }
    
                // 删除最后一个元素的时候
                if (index == size - 1) {
                    lastNode = up;
                }
    
    

    三、实现insert(add)方法

    1、一般思维实现思路

    • 1)、获取索引的元素值,得到元素的前一个节点
    • 2)、把前节点的后一个节点设置为加入的节点
    • 3)、新节点的前一个节点设置为索引值节点的前节点
    • 4)、前一个节点的后一个节点是索引值节点
    • 5)、索引值节点的前一个节点是新节点
    • 6)、示意图
    • 有A、B、C三个节点,以链表形式存储,现在要添加D节点,到链表中.
    • 切断A、B的节点连接,A和D,D和B重新建立连接,生成新的链表

    2、实现思路实现

    • 1)、核心方法
    • 方法一:
    
        /**
         * 插入一个元素在指定位置
         *
         * @param index 指定位置索引
         * @param o     插入的元素
         */
        public void insert(int index, Object o) {
    
            Node newNode = new Node(o);
    
            // 判断范围
            checkRound(index);
    
            Node temp = getNode(index);
    
            if (temp != null) {
    
                // 第一个元素和最后一个元素的时候
                if (index == 0 || index == size - 1) {
                    temp.elements = newNode.elements;
                } else {
                    Node up = temp.previous;
                    isNull(up == null, "前一个元素为空");
                    up.next = newNode;
                    newNode.previous = up;
    
                    newNode.next = temp;
                    temp.previous = newNode;
                }
            }
    
        }
    
    
    • 方法二:
    
    /**
         * 插入一个元素在指定位置
         *
         * @param index 指定位置索引
         * @param o     插入的元素
         */
        public void insert1(int index, Object o) {
    
            Node newNode = new Node(o);
    
            // 判断范围
            checkRound(index);
    
            Node temp = getNode(index);
    
            if (temp != null) {
    
                // 第一个元素和最后一个元素的时候
                if (index == 0) {
                    firstNode = newNode;
                    newNode.next = temp.next;
                } else if (index == size - 1) {
                    Node up = temp.previous;
                    isNull(up == null, "前一个元素为空");
                    up.next = newNode;
                    newNode.previous = up;
                } else {
                    Node up = temp.previous;
                    isNull(up == null, "前一个元素为空");
                    up.next = newNode;
                    newNode.previous = up;
    
                    newNode.next = temp;
                    temp.previous = newNode;
                }
            }
    
        }
    
    
    • 2)、测试
    
    public class TestInsert {
    
    
        public static void main(String[] args) {
            MyInsertLinkedList003 myInsertLinkedList003 = new MyInsertLinkedList003();
            myInsertLinkedList003.add("A");
            myInsertLinkedList003.add("B");
            myInsertLinkedList003.add("C");
            myInsertLinkedList003.add("D");
            myInsertLinkedList003.add("E");
            myInsertLinkedList003.add("F");
    
    
            myInsertLinkedList003.insert1(1,"G");
    
            System.out.println(myInsertLinkedList003);
    
        }
    }
    
    
    

    3、思路缺少的条件

    • 1)、判断索引范围问题
    
       private void checkRound(int index) {
            // 判断索引范围
            isNull(index < 0 || index > size - 1, "索引不合法!" + index);
        }
    
        /**
         * 判断空指针问题
         *
         * @param b      判断条件
         * @param string 抛出异常的原因
         */
        private void isNull(boolean b, String string) {
            if (b) {
                throw new RuntimeException(string);
            }
        }
    
    
    
    • 2)、第一个元素删除和最后一个元素删除问题
    
    if (temp != null) {
    
                // 第一个元素和最后一个元素的时候
                if (index == 0) {
                    firstNode = newNode;
                    newNode.next = temp.next;
                } else if (index == size - 1) {
                    Node up = temp.previous;
                    isNull(up == null, "前一个元素为空");
                    up.next = newNode;
                    newNode.previous = up;
                } else {
                    Node up = temp.previous;
                    isNull(up == null, "前一个元素为空");
                    up.next = newNode;
                    newNode.previous = up;
    
                    newNode.next = temp;
                    temp.previous = newNode;
                }
            }
    
    

    四、实现泛型和全部代码

    
    package com.synway.test.collections.version3.finallist;
    
    import com.synway.test.collections.version3.basesimple.Node;
    
    /**
     * 最终手写版,添加泛型
     *
     * @author liuyangos8888
     */
    public class MyLinkedListFinal<T> {
    
    
        /**
         * 第一个节点
         */
        private Node firstNode;
    
    
        /**
         * 最后一个节点
         */
        private Node lastNode;
    
    
        /**
         * 链表大小
         */
        private int size;
    
    
        /**
         * 添加节点到数组中
         *
         * @param o 节点数据
         */
        public void add(T o) {
            Node node = new Node(o);
    
    
            if (firstNode == null) {
                firstNode = node;
            } else {
                node.previous = lastNode;
                node.next = null;
                lastNode.next = node;
            }
    
            lastNode = node;
    
            size++;
        }
    
    
        /**
         * 根据索引,删除数组中元素
         *
         * @param index 索引角标
         */
        public void remove(int index) {
            checkRound(index);
    
            Node temp = getNode(index);
    
            if (temp != null) {
                Node up = temp.previous;
                Node down = temp.next;
    
                if (up != null) {
                    up.next = down;
                }
    
                if (down != null) {
                    down.previous = up;
                }
    
                // 删除第一个元素的时候
                if (index == 0) {
                    firstNode = down;
                }
    
                // 删除最后一个元素的时候
                if (index == size - 1) {
                    lastNode = up;
                }
    
                size--;
            }
    
        }
    
    
        /**
         * 插入一个元素在指定位置
         *
         * @param index 指定位置索引
         * @param o     插入的元素
         */
        public void insert(int index, T o) {
    
            Node newNode = new Node(o);
    
            // 判断范围
            checkRound(index);
    
            Node temp = getNode(index);
    
            if (temp != null) {
    
                // 第一个元素和最后一个元素的时候
                if (index == 0) {
                    firstNode = newNode;
                    newNode.next = temp.next;
                } else if (index == size - 1) {
                    Node up = temp.previous;
                    isNull(up == null, "前一个元素为空");
                    up.next = newNode;
                    newNode.previous = up;
                } else {
                    Node up = temp.previous;
                    isNull(up == null, "前一个元素为空");
                    up.next = newNode;
                    newNode.previous = up;
    
                    newNode.next = temp;
                    temp.previous = newNode;
                }
            }
    
        }
    
    
        /**
         * 优化版,提高查找效率,折半判断
         *
         * @param index 索引角标
         * @return 索引对应的值
         */
        public T get(int index) {
            checkRound(index);
    
            Node node = getNode(index);
    
            return node != null ? (T) node.elements : null;
        }
    
    
        /**
         * 根据角标,获取节点
         *
         * @param index 传入角标
         * @return 获取节点
         */
        private Node getNode(int index) {
            Node node;
            // size>>1 除以2
            if (index <= (size >> 1)) {
                node = firstNode;
    
                for (int i = 0; i < index; i++) {
    
                    node = node.next;
                }
            } else {
                node = lastNode;
    
                for (int i = size - 1; i > index; i--) {
    
                    node = node.previous;
                }
            }
            return node;
        }
    
        /**
         * 审核传入的角标范围是否越界
         *
         * @param index 传入角标
         */
        private void checkRound(int index) {
            // 判断索引范围
            isNull(index < 0 || index > size - 1, "索引不合法!" + index);
        }
    
        /**
         * 判断空指针问题
         *
         * @param b      判断条件
         * @param string 抛出异常的原因
         */
        private void isNull(boolean b, String string) {
            if (b) {
                throw new RuntimeException(string);
            }
        }
    
        /**
         * 获取数组中元素
         *
         * @return 元素数组
         */
        @Override
        public String toString() {
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.append("[");
    
            Node temp = firstNode;
    
            while (temp != null) {
                stringBuilder.append(temp.elements).append(",");
                temp = temp.next;
            }
    
            stringBuilder.setCharAt(stringBuilder.length() - 1, ']');
    
            return stringBuilder.toString();
        }
    
    
    }
    
    
    
  • 相关阅读:
    数据结构:图 (总结)
    排序算法总结(此篇文章是14年写作,代码难看,请看我新发表的排序总结)
    no identifier specified for entity错误
    哈夫曼编码算法思想总结
    线索二叉树
    ORACLE 错误 ora-01830 解决方法
    (转)web会话管理方式
    (转)C3P0配置
    分页技术()
    简易 DBUtil 封装
  • 原文地址:https://www.cnblogs.com/liuyangfirst/p/13838118.html
Copyright © 2011-2022 走看看