diff --git a/algorithm/单链表.md b/algorithm/单链表.md new file mode 100644 index 0000000..a9c1840 --- /dev/null +++ b/algorithm/单链表.md @@ -0,0 +1,326 @@ +单链表反转 +使用while循环,保存next节点,设置当前节点的next,保存pre,移动head,最后返回pre + +```Java +private static Node reverseLinkedList(Node head) { + Node pre = null; + Node next = null; + while (head != null) { + next = head.getNext(); + head.setNext(pre); + pre = head; + head = next; + } + return pre; +} +``` + +双链表反转 +使用while循环,保存next节点,设置当前节点的last和pre,保存pre,移动head,最后返回pre + +```Java +private static Node reverDoubleLinkedList(Node head) { + Node pre = null; + Node next = null; + while (head != null) { + next = head.getLast(); + head.setLast(pre); + head.setPre(next); + pre = head; + head = next; + } + return pre; +} +``` + +单链表实现队列和栈 + +```Java +public class CustomQueue { + + private Node head; + private Node tail; + private int size; + + public boolean isEmpty(){ + return size == 0; + } + + public void offer(V value) { + Node node = new Node<>(value); + if (tail == null) { + head = node; + tail = node; + } else { + tail.setNext(node); + tail = node; + } + size++; + } + + public V poll(){ + if (head == null) { + return null; + } + V ans = head.getValue(); + head = head.getNext(); + size--; + return ans; + } + + public V peek() { + if (head == null) { + return null; + } + return head.getValue(); + } + + private class Node { + private V value; + private Node next; + + public V getValue() { + return value; + } + + public void setValue(V value) { + this.value = value; + } + + public Node getNext() { + return next; + } + + public void setNext(Node next) { + this.next = next; + } + + public Node(V value) { + this.value = value; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Node node = (Node) o; + return value.equals(node.value) && + next.equals(node.next); + } + + @Override + public int hashCode() { + return Objects.hash(value, next); + } + } +} +``` + +```Java +public class CustomStack { + private Node head; + private int size; + + public boolean isEmpty(){ + return size == 0; + } + + public void push(V value){ + Node node = new Node<>(value); + if (head == null) { + head = node; + } else { + node.setNext(head); + head = node; + } + size++; + } + + public V pop(){ + if (head == null) { + return null; + } + V ans = null; + ans = head.getValue(); + head.setNext(head.getNext()); + size--; + return ans; + } + + public V peek() { + return head == null ? null : head.getValue(); + } + + + class Node{ + private V value; + private Node next; + + public V getValue() { + return value; + } + + public void setValue(V value) { + this.value = value; + } + + public Node getNext() { + return next; + } + + public void setNext(Node next) { + this.next = next; + } + + public Node(V value) { + this.value = value; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Node node = (Node) o; + return Objects.equals(value, node.value) && + Objects.equals(next, node.next); + } + + @Override + public int hashCode() { + return Objects.hash(value, next); + } + } +} +``` + +### 使用双链表实现双端队列 + +```Java +public class CustomDeque { + private Node head; + private Node tail; + private int size; + + public boolean isEmpty() { + return size == 0; + } + + public void pushHead(V value){ + Node node = new Node<>(value); + if (head == null) { + head = node; + tail = node; + } else { + node.setLast(head); + head.setPre(node); + head = node; + } + size++; + } + + public void pushTail(V value){ + Node node = new Node<>(value); + if (head == null) { + head = node; + tail = node; + } else { + tail.setLast(node); + node.setPre(tail); + tail = node; + } + size++; + } + + public V pollHead(){ + if (head == null) { + return null; + } + V ans = head.getValue(); + if (head.equals(tail)) { + head = null; + tail = null; + } else { + head = head.getLast(); + head.setPre(null); + } + size--; + return ans; + } + + public V pollTail(){ + if (tail == null) { + return null; + } + V ans = tail.getValue(); + if (head.equals(tail)) { + head = null; + tail = null; + } else { + tail = tail.getPre(); + tail.setLast(null); + } + size--; + return ans; + } + + public V peekHead(){ + return head == null ? null : head.getValue(); + } + + public V peekTail(){ + return tail == null ? null : tail.getValue(); + } + + class Node{ + private V value; + private Node last; + private Node pre; + + public Node(V value) { + this.value = value; + } + + public V getValue() { + return value; + } + + public void setValue(V value) { + this.value = value; + } + + public Node getLast() { + return last; + } + + public void setLast(Node last) { + this.last = last; + } + + public Node getPre() { + return pre; + } + + public void setPre(Node pre) { + this.pre = pre; + } + + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Node node = (Node) o; + return Objects.equals(value, node.value); + } + + @Override + public int hashCode() { + return Objects.hash(value); + } + } +} +``` + +单链表和双链表的新增、删除,主要注意处理好前驱和后继指针,必要的时候添加中间变量保存。双链表注意处理头尾重合、为空的边界条件。 + +K个节点的组内逆序调整 diff --git a/algorithm/时间复杂度.md b/algorithm/时间复杂度.md index dc5d302..9f88075 100644 --- a/algorithm/时间复杂度.md +++ b/algorithm/时间复杂度.md @@ -76,4 +76,43 @@ private static int binarySearchRight(int[] arr, int target) { } ``` -有序数组给定区间元素的个数 +有序数组给定区间元素的个数,二分查找上下限,然后index取差值。 + +局部最小值 +对无重复元素的无序数组,找出一个局部最小值。 +只需要找出一个存在的局部最小值,不是全部的局部最小值,也不是全局最小值。 + +```Java +public int localMin(int[] arr){ + if (arr == null || arr.length == 0) { + return -1; + } + int length = arr.length; + if (length == 1) { + return 0; + } + if (arr[length - 1] < arr[length - 2]) { + return length - 1; + } + int left = 0; + int right = length - 1; + int index = -1; + int middle; + while (left <= right) { + middle = (left + right) >> 1; + if (arr[middle - 1] < arr[middle]) { + right = middle - 1; + } else if (arr[middle + 1] < arr[middle]) { + left = middle + 1; + } else { + index = middle; + break; + } + } + return index; +} +``` + +可以确定要寻找的元素在一侧必定存在则可以使用二分搜索。 + +### 时间复杂度 diff --git a/design-pattern/设计模式.md b/design-pattern/设计模式.md new file mode 100644 index 0000000..9ce0b95 --- /dev/null +++ b/design-pattern/设计模式.md @@ -0,0 +1,7 @@ +优先选择策略模式而不是模板方法模式的场景 + +* 所有步骤都不同(而不是几个) +* 实现类需要独立的继承 +* 实现类和其他类强相关(常见于J2EE的数据访问场景) +* 实现类需要在运行时发生变化,继承不能做到,但是代理可以模板方法设计模式也是在工作类中持有抽象类的引用,可以在运行时传入不同的子类实现,为什么说不能再运行时发生变化? +* 有很多种不同的实现类或者实现类的数量会持续增长。在这种情况下,策略模式更大的灵活性几乎肯定会证明是有益的,因为它为实现提供了最大的自由度。 diff --git a/framework-source-code/spring/Spring Bean生命周期.png b/framework-source-code/spring/Spring Bean生命周期.png new file mode 100644 index 0000000..e7d30a7 Binary files /dev/null and b/framework-source-code/spring/Spring Bean生命周期.png differ diff --git a/framework-source-code/spring/spring.md b/framework-source-code/spring/spring.md index bbdf18d..e57d0e4 100644 --- a/framework-source-code/spring/spring.md +++ b/framework-source-code/spring/spring.md @@ -44,9 +44,9 @@ xxbean.method(); * BeanDefinitionReader * BeanDefinition * BeanFactory +* FactoryBean * DefaultListableBeanFactory * ClassPathXmlApplicationContext -* PostProcessor * BeanPostProcessor * BeanFactoryPostProcessor * Aware @@ -68,7 +68,7 @@ BeanDefinition描述带有属性值、构造器参数值、具体实现类的信 这个接口被持有许多bean定义的对象实现,每一个对象都由字符串唯一确定。依据bean定义,factory将返回一个容器化对象的独立实例(原型设计模式),或者一个单例的共享对象(单例设计模式的一个更好的替代方案,该实例在factory内部是单例的)。那种类型的实例会被返回依赖于factory的配置,API是相同的。从Spring2.0开始,根据具体应用上下文,更多的范围可以被使用(比如web环境中的request和session)。 -这种方法的要点是BeanFactory是应用程序组件的中央注册表,并且集中了应用程序组件的配置(例如单个对象不再需要读取属性文件)。可以通过的第4章和11章了解这种方式的优点。(到底是啥优点?) +这种方法的要点是BeanFactory是应用程序组件的中央注册表,并且集中了应用程序组件的配置(例如单个对象不再需要读取属性文件)。可以通过<Expert One-on-One J2EE Design and Development>的第4章和11章了解这种方式的优点。(到底是啥优点?) 一般来讲,依靠DI(push配置)通过set或者构造方法配置应用对象是比使用任何形式,比如查找BeanFactory拉取配置要好的。Spring的依赖注入功能是使用BeanFactory接口和它的子接口实现的。 @@ -95,6 +95,8 @@ BeanFactory的实现类应该尽可能支持标准的bean生命周期接口。 bean工厂关闭的时候,会调用DestructionAwareBeanPostProcessors的postProcessBeforeDestruction()方法,DisposableBean的destroy()方法,自定义的destroy-method方法 +#### FactoryBean + #### DefaultListableBeanFactory Spring对ConfigurableListableBeanFactory和BeanDefinitionRegistry接口的默认实现,基于 bean 定义元数据的成熟的 bean 工厂,可通过后处理器进行扩展。 @@ -115,8 +117,6 @@ Spring对ConfigurableListableBeanFactory和BeanDefinitionRegistry接口的默认 这是一个简单的、一站式便利的 ApplicationContext。考虑使用GenericApplicationContext类结合XmlBeanDefinitionReader进行更灵活的上下文设置。 -#### PostProcessor - #### BeanPostProcessor 允许自定义修改新 bean 实例的工厂钩子——例如,检查标记接口或使用代理包装 bean。