├── .gitignore ├── cLearning ├── cal.sh ├── a.out ├── helo.c ├── two_function.c ├── changeNum.c └── pnt_add.c ├── algorithm ├── a.out ├── Student.h ├── UnionFind.cpp ├── SortTestHelper.h ├── Graph.cpp ├── Heap.cpp ├── Sort.cpp ├── TreeAlgorithm.cpp └── AVLTree.cpp ├── src ├── duty_chain │ ├── Level.java │ ├── Response.java │ ├── Request.java │ ├── ConcreteHandler1.java │ ├── ConcreteHandler2.java │ ├── ConcreteHandler3.java │ ├── Client.java │ └── Handler.java ├── adapter │ ├── Target.java │ ├── Role.java │ ├── Adapter.java │ ├── ConcreteTarget.java │ └── Client.java ├── observer │ ├── Observer.java │ ├── ConcreteSubject.java │ ├── ConcreteObserver.java │ ├── Client.java │ └── Subject.java ├── observe │ ├── Observer.java │ ├── BinaryObserver.java │ ├── ObserverPatternDemo.java │ └── Subject.java ├── factory │ ├── Creator.java │ ├── Product.java │ ├── ConcreteProduct1.java │ ├── ConcreteProduct2.java │ ├── Client.java │ └── ConcreteCreator.java ├── sword_offer │ ├── ListNode.java │ ├── JZ9.java │ ├── TreeNode.java │ ├── RandomListNode.java │ ├── JZ8.java │ ├── JZ11.java │ ├── JZ29.java │ ├── JZ38.java │ ├── JZ10.java │ ├── JZ7.java │ ├── JZ3.java │ ├── JZ34.java │ ├── JZ48.java │ ├── JZ30.java │ ├── JZ2.java │ ├── JZ31.java │ ├── JZ39.java │ ├── JZ17.java │ ├── JZ14.java │ ├── JZ20.java │ ├── JZ33.java │ ├── JZ24.java │ ├── JZ15.java │ ├── JZ28.java │ ├── JZ18.java │ ├── JZ22.java │ ├── JZ1.java │ ├── JZ36.java │ ├── JZ37.java │ ├── JZ25.java │ ├── JZ32.java │ ├── JZ26.java │ ├── JZ5.java │ ├── JZ16.java │ ├── JZ41.java │ ├── JZ59.java │ ├── JZ21.java │ ├── JZ27.java │ ├── JZ4.java │ ├── JZ23.java │ ├── JZ6.java │ ├── JZ35.java │ ├── JZ19.java │ ├── JZ12.java │ └── JZ13.java ├── Singleton.java ├── PinType.java ├── AsyncCallback.java ├── BestStopTheory.java └── AVL.java ├── pic └── FH-fib(4).png ├── .idea ├── vcs.xml ├── .gitignore ├── misc.xml └── modules.xml ├── free_learning.iml ├── README.md ├── basic_notes ├── 经典算法笔记.md ├── 高斯模糊效果的实现原理.md ├── introduce_to_gaussian_blur.md ├── 操作系统.md ├── 计算机组成原理.md └── 计算机网络.md └── android_notes ├── 使用wsl2编译aosp步骤.md ├── Android面试笔记.md ├── Java基础知识.md ├── 事件分发.md └── 侧滑删除.md /.gitignore: -------------------------------------------------------------------------------- 1 | /out -------------------------------------------------------------------------------- /cLearning/cal.sh: -------------------------------------------------------------------------------- 1 | i=0 2 | while [ $i -lt 100000 ] 3 | do 4 | ((i++)) 5 | done 6 | -------------------------------------------------------------------------------- /algorithm/a.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jdroida/free_learning/HEAD/algorithm/a.out -------------------------------------------------------------------------------- /cLearning/a.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jdroida/free_learning/HEAD/cLearning/a.out -------------------------------------------------------------------------------- /src/duty_chain/Level.java: -------------------------------------------------------------------------------- 1 | package duty_chain; 2 | 3 | public class Level { 4 | } 5 | -------------------------------------------------------------------------------- /pic/FH-fib(4).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jdroida/free_learning/HEAD/pic/FH-fib(4).png -------------------------------------------------------------------------------- /src/duty_chain/Response.java: -------------------------------------------------------------------------------- 1 | package duty_chain; 2 | 3 | public class Response { 4 | } 5 | -------------------------------------------------------------------------------- /cLearning/helo.c: -------------------------------------------------------------------------------- 1 | #include 2 | int main(){ 3 | printf("helo world!\n"); 4 | return 0; 5 | } 6 | -------------------------------------------------------------------------------- /src/adapter/Target.java: -------------------------------------------------------------------------------- 1 | package adapter; 2 | 3 | public interface Target { 4 | public void request(); 5 | } 6 | -------------------------------------------------------------------------------- /src/observer/Observer.java: -------------------------------------------------------------------------------- 1 | package observer; 2 | 3 | public interface Observer { 4 | public void update(); 5 | } 6 | -------------------------------------------------------------------------------- /cLearning/two_function.c: -------------------------------------------------------------------------------- 1 | #include 2 | void helo(){ 3 | printf("helo world\n"); 4 | } 5 | int main(){ 6 | helo(); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /src/observe/Observer.java: -------------------------------------------------------------------------------- 1 | package observe; 2 | public abstract class Observer { 3 | protected Subject subject; 4 | public abstract void update(); 5 | } -------------------------------------------------------------------------------- /src/duty_chain/Request.java: -------------------------------------------------------------------------------- 1 | package duty_chain; 2 | 3 | public class Request { 4 | public Level getRequestLevel() { 5 | return null; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/factory/Creator.java: -------------------------------------------------------------------------------- 1 | package factory; 2 | 3 | public abstract class Creator { 4 | public abstract T createProduct(Class c); 5 | } 6 | -------------------------------------------------------------------------------- /src/adapter/Role.java: -------------------------------------------------------------------------------- 1 | package adapter; 2 | 3 | //源角色 4 | public class Role { 5 | public void method() { 6 | System.out.println("im nobody."); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/factory/Product.java: -------------------------------------------------------------------------------- 1 | package factory; 2 | 3 | public abstract class Product { 4 | public void method1(){ 5 | 6 | } 7 | public abstract void method2(); 8 | } 9 | -------------------------------------------------------------------------------- /src/factory/ConcreteProduct1.java: -------------------------------------------------------------------------------- 1 | package factory; 2 | 3 | public class ConcreteProduct1 extends Product{ 4 | @Override 5 | public void method2() { 6 | 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/factory/ConcreteProduct2.java: -------------------------------------------------------------------------------- 1 | package factory; 2 | 3 | public class ConcreteProduct2 extends Product{ 4 | @Override 5 | public void method2() { 6 | 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/observer/ConcreteSubject.java: -------------------------------------------------------------------------------- 1 | package observer; 2 | 3 | public class ConcreteSubject extends Subject { 4 | public void method() { 5 | super.notifyObservers(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/sword_offer/ListNode.java: -------------------------------------------------------------------------------- 1 | package sword_offer; 2 | 3 | public class ListNode { 4 | int val; 5 | ListNode next = null; 6 | 7 | ListNode(int val) { 8 | this.val = val; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Datasource local storage ignored files 5 | /dataSources/ 6 | /dataSources.local.xml 7 | # Editor-based HTTP Client requests 8 | /httpRequests/ 9 | -------------------------------------------------------------------------------- /src/adapter/Adapter.java: -------------------------------------------------------------------------------- 1 | package adapter; 2 | 3 | //适配器角色 4 | public class Adapter extends Role implements Target { 5 | @Override 6 | public void request() { 7 | super.method(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/adapter/ConcreteTarget.java: -------------------------------------------------------------------------------- 1 | package adapter; 2 | 3 | public class ConcreteTarget implements Target { 4 | @Override 5 | public void request() { 6 | System.out.println("im concrete target."); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/sword_offer/JZ9.java: -------------------------------------------------------------------------------- 1 | package sword_offer; 2 | 3 | //一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。 4 | public class JZ9 { 5 | public int JumpFloorII(int target) { 6 | return 1 << (target - 1); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/sword_offer/TreeNode.java: -------------------------------------------------------------------------------- 1 | package sword_offer; 2 | 3 | //通用二叉树结构 4 | class TreeNode { 5 | int val = 0; 6 | TreeNode left = null; 7 | TreeNode right = null; 8 | 9 | public TreeNode(int val) { 10 | this.val = val; 11 | 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/factory/Client.java: -------------------------------------------------------------------------------- 1 | package factory; 2 | 3 | //场景类 4 | public class Client { 5 | public static void main(String[] args) { 6 | Creator creator = new ConcreteCreator(); 7 | Product product = creator.createProduct(ConcreteProduct1.class); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/sword_offer/RandomListNode.java: -------------------------------------------------------------------------------- 1 | package sword_offer; 2 | 3 | public class RandomListNode { 4 | int label; 5 | RandomListNode next = null; 6 | RandomListNode random = null; 7 | 8 | RandomListNode(int label) { 9 | this.label = label; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/adapter/Client.java: -------------------------------------------------------------------------------- 1 | package adapter; 2 | 3 | //场景类 4 | public class Client { 5 | public static void main(String[] args) { 6 | Target target = new ConcreteTarget(); 7 | target.request(); 8 | //适配器角色 9 | Target target1 = new Adapter(); 10 | target1.request(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/sword_offer/JZ8.java: -------------------------------------------------------------------------------- 1 | package sword_offer; 2 | 3 | //一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。 4 | public class JZ8 { 5 | public int JumpFloor(int target) { 6 | if (target < 4) 7 | return target; 8 | return JumpFloor(target - 1) + JumpFloor(target - 2); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/sword_offer/JZ11.java: -------------------------------------------------------------------------------- 1 | package sword_offer; 2 | 3 | //输入一个整数,输出该数32位二进制表示中1的个数。其中负数用补码表示。 4 | public class JZ11 { 5 | public int NumberOf1(int n) { 6 | int count = 0; 7 | while (n != 0) { 8 | count++; 9 | n = n & (n - 1); 10 | } 11 | return count; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/sword_offer/JZ29.java: -------------------------------------------------------------------------------- 1 | package sword_offer; 2 | 3 | import java.util.ArrayList; 4 | 5 | //输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4。 6 | public class JZ29 { 7 | //todo 有点无聊 暂时跳过 8 | public ArrayList GetLeastNumbers_Solution(int[] input, int k) { 9 | 10 | return null; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/duty_chain/ConcreteHandler1.java: -------------------------------------------------------------------------------- 1 | package duty_chain; 2 | 3 | public class ConcreteHandler1 extends Handler { 4 | @Override 5 | protected Level getHandlerLevel() {//定义自己处理级别 6 | return null; 7 | } 8 | 9 | @Override 10 | protected Response echo(Request request) {//完成自己处理逻辑 11 | return null; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/duty_chain/ConcreteHandler2.java: -------------------------------------------------------------------------------- 1 | package duty_chain; 2 | 3 | public class ConcreteHandler2 extends Handler { 4 | @Override 5 | protected Level getHandlerLevel() {//定义自己处理级别 6 | return null; 7 | } 8 | 9 | @Override 10 | protected Response echo(Request request) {//完成自己处理逻辑 11 | return null; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/duty_chain/ConcreteHandler3.java: -------------------------------------------------------------------------------- 1 | package duty_chain; 2 | 3 | public class ConcreteHandler3 extends Handler { 4 | @Override 5 | protected Level getHandlerLevel() {//定义自己处理级别 6 | return null; 7 | } 8 | 9 | @Override 10 | protected Response echo(Request request) {//完成自己处理逻辑 11 | return null; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/sword_offer/JZ38.java: -------------------------------------------------------------------------------- 1 | package sword_offer; 2 | 3 | //二叉树的深度 4 | public class JZ38 { 5 | 6 | public int TreeDepth(TreeNode root) { 7 | if (root == null) 8 | return 0; 9 | int left = TreeDepth(root.left); 10 | int right = TreeDepth(root.right); 11 | return Math.max(left, right) + 1; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/sword_offer/JZ10.java: -------------------------------------------------------------------------------- 1 | package sword_offer; 2 | //我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法? 3 | //比如n=3时,2*3的矩形块有3种覆盖方法: 4 | public class JZ10 { 5 | public int RectCover(int target) { 6 | if (target < 4) 7 | return target; 8 | return RectCover(target - 1) + RectCover(target - 2); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Singleton.java: -------------------------------------------------------------------------------- 1 | public class Singleton { 2 | //这是一般写法 其实更推荐枚举实现 3 | private static final Singleton singleton = new Singleton(); 4 | 5 | //限制产生多个对象 6 | private Singleton() { 7 | } 8 | 9 | public static Singleton getInstance() { 10 | return singleton; 11 | } 12 | 13 | public static void doSomething() { 14 | 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/observer/ConcreteObserver.java: -------------------------------------------------------------------------------- 1 | package observer; 2 | 3 | public class ConcreteObserver implements Observer { 4 | public String name; 5 | 6 | public ConcreteObserver(String name) { 7 | this.name = name; 8 | } 9 | 10 | @Override 11 | public void update() { 12 | System.out.println("Im " + name + " and I saw message updated"); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/sword_offer/JZ7.java: -------------------------------------------------------------------------------- 1 | package sword_offer; 2 | 3 | 4 | public class JZ7 { 5 | public int Fibonacci(int n) { 6 | if (n == 0 || n == 1) { 7 | return n; 8 | } 9 | return Fibonacci(n - 1) + Fibonacci(n - 2); 10 | } 11 | 12 | public static void main(String[] args) { 13 | System.out.println(new JZ7().Fibonacci(6)); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /cLearning/changeNum.c: -------------------------------------------------------------------------------- 1 | #include 2 | void switchNumByForm(int a,int b); 3 | void switchNumByLocation(int *a,int *b); 4 | int main(){ 5 | int a=1,b=2; 6 | switchNumByLocation(&a,&b); 7 | printf("a=%d,b=%d\n",a,b); 8 | return 0; 9 | } 10 | void switchNumByForm(int a,int b){ 11 | int temp=a; 12 | a=b; 13 | b=temp; 14 | } 15 | void switchNumByLocation(int *a,int *b){ 16 | int temp=*a; 17 | *a=*b; 18 | *b=temp; 19 | } 20 | -------------------------------------------------------------------------------- /src/observe/BinaryObserver.java: -------------------------------------------------------------------------------- 1 | package observe; 2 | 3 | public class BinaryObserver extends Observer{ 4 | 5 | public BinaryObserver(Subject subject){ 6 | this.subject = subject; 7 | this.subject.attach(this); 8 | } 9 | 10 | @Override 11 | public void update() { 12 | System.out.println( "Binary String: " 13 | + Integer.toBinaryString( subject.getState() ) ); 14 | } 15 | } -------------------------------------------------------------------------------- /src/observe/ObserverPatternDemo.java: -------------------------------------------------------------------------------- 1 | package observe; 2 | 3 | public class ObserverPatternDemo { 4 | public static void main(String[] args) { 5 | Subject subject = new Subject(); 6 | new BinaryObserver(subject); 7 | 8 | System.out.println("First state change: 15"); 9 | subject.setState(15); 10 | System.out.println("Second state change: 10"); 11 | subject.setState(10); 12 | } 13 | } -------------------------------------------------------------------------------- /src/duty_chain/Client.java: -------------------------------------------------------------------------------- 1 | package duty_chain; 2 | 3 | //场景类 4 | public class Client { 5 | public static void main(String[] args) { 6 | Handler handler1 = new ConcreteHandler1(); 7 | Handler handler2 = new ConcreteHandler2(); 8 | Handler handler3 = new ConcreteHandler3(); 9 | handler1.setNext(handler2); 10 | handler2.setNext(handler3); 11 | Response response = handler1.handleMessage(new Request()); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /free_learning.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /algorithm/Student.h: -------------------------------------------------------------------------------- 1 | #ifndef SELECTIONSORT_STUDENT_H 2 | #define SELECTIONSORT_STUDENT_H 3 | #include 4 | #include 5 | using namespace std; 6 | struct Student{ 7 | string name; 8 | int score; 9 | bool operator<(const Student &otherStudent){ 10 | return score printListFromTailToHead(ListNode listNode) { 9 | ArrayList result = new ArrayList<>(); 10 | while (listNode != null) { 11 | result.add(listNode.val); 12 | listNode = listNode.next; 13 | } 14 | Collections.reverse(result); 15 | return result; 16 | } 17 | } 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/observer/Subject.java: -------------------------------------------------------------------------------- 1 | package observer; 2 | 3 | import java.util.Vector; 4 | 5 | //被观察者 6 | public abstract class Subject { 7 | //观察者数组 8 | private Vector observers = new Vector<>(); 9 | 10 | public void addObserver(Observer o) { 11 | this.observers.add(o); 12 | } 13 | 14 | public void removeObserver(Observer observer) { 15 | this.observers.remove(observer); 16 | } 17 | 18 | public void notifyObservers() { 19 | for (Observer observer : observers) { 20 | observer.update(); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/sword_offer/JZ34.java: -------------------------------------------------------------------------------- 1 | package sword_offer; 2 | 3 | 4 | //在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 5 | // 如果没有则返回 -1(需要区分大小写).(从0开始计数) 6 | public class JZ34 { 7 | public int FirstNotRepeatingChar(String str) { 8 | int[] words = new int[58]; 9 | for (int i = 0; i < str.length(); i++) { 10 | words[((int) str.charAt(i)) - 65]++; 11 | } 12 | for (int i = 0; i < str.length(); i++) { 13 | if (words[((int) str.charAt(i)) - 65] == 1) 14 | return i; 15 | } 16 | return -1; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/sword_offer/JZ48.java: -------------------------------------------------------------------------------- 1 | package sword_offer; 2 | 3 | //不用加减乘除做加法 4 | public class JZ48 { 5 | 6 | public int add(int num1, int num2) { 7 | int result = num1 ^ num2; //不带进位的加法 8 | int carry = (num1 & num2) << 1;//进位 9 | // 进位不为0则继续执行加法处理进位 10 | while (carry != 0) { 11 | result = num1 ^ num2; 12 | carry = (num1 & num2) << 1; 13 | num1 = result; 14 | num2 = carry; 15 | } 16 | 17 | return result; 18 | } 19 | 20 | public static void main(String[] args) { 21 | System.out.println(new JZ48().add(45, 56)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/factory/ConcreteCreator.java: -------------------------------------------------------------------------------- 1 | package factory; 2 | 3 | public class ConcreteCreator extends Creator { 4 | @Override 5 | public T createProduct(Class c) { 6 | Product product = null; 7 | try { 8 | product = (Product) Class.forName(c.getName()).newInstance(); 9 | } catch (InstantiationException e) { 10 | e.printStackTrace(); 11 | } catch (IllegalAccessException e) { 12 | e.printStackTrace(); 13 | } catch (ClassNotFoundException e) { 14 | e.printStackTrace(); 15 | } 16 | return (T) product; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/sword_offer/JZ30.java: -------------------------------------------------------------------------------- 1 | package sword_offer; 2 | 3 | //HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中, 4 | // 常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。 5 | // 但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢? 6 | // 例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。 7 | // 给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1) 8 | public class JZ30 { 9 | public int FindGreatestSumOfSubArray(int[] array) { 10 | int max = array[0]; 11 | for (int i = 1; i < array.length; i++) { 12 | array[i] += array[i - 1] > 0 ? array[i - 1] : 0; 13 | max = Math.max(max, array[i]); 14 | } 15 | return max; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /cLearning/pnt_add.c: -------------------------------------------------------------------------------- 1 | //指针地址 2 | #include 3 | #define SIZE 4 4 | int main(){ 5 | short dates[SIZE];//数组名是该数组首元素的地址 dates==&dates[0] *dates==dates[0] 6 | short *pti; 7 | short index; 8 | double bills[SIZE]; 9 | double *ptf; 10 | pti=dates; 11 | ptf=bills; 12 | printf("%23s %15s\n","short","double"); 13 | for(index=0;index 1) 19 | return false; 20 | return true; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/observe/Subject.java: -------------------------------------------------------------------------------- 1 | package observe; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class Subject { 7 | 8 | private List observers 9 | = new ArrayList(); 10 | private int state; 11 | 12 | public int getState() { 13 | return state; 14 | } 15 | 16 | public void setState(int state) { 17 | this.state = state; 18 | notifyAllObservers(); 19 | } 20 | 21 | public void attach(Observer observer){ 22 | observers.add(observer); 23 | } 24 | 25 | public void notifyAllObservers(){ 26 | for (Observer observer : observers) { 27 | observer.update(); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /src/sword_offer/JZ17.java: -------------------------------------------------------------------------------- 1 | package sword_offer; 2 | 3 | //输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构) 4 | public class JZ17 { 5 | public boolean HasSubtree(TreeNode root1, TreeNode root2) { 6 | if (root1 == null || root2 == null) return false; 7 | return doesTree1HasTree2(root1, root2) || HasSubtree(root1.left, root2) 8 | || HasSubtree(root1.right, root2); 9 | } 10 | 11 | private boolean doesTree1HasTree2(TreeNode root1, TreeNode root2) { 12 | if (root2 == null) return true; 13 | if (root1 == null) return false; 14 | return root1.val == root2.val && doesTree1HasTree2(root1.left, root2.left) 15 | && doesTree1HasTree2(root1.right, root2.right); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/sword_offer/JZ14.java: -------------------------------------------------------------------------------- 1 | package sword_offer; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | 6 | //输入一个链表,输出该链表中倒数第k个结点。 7 | public class JZ14 { 8 | public ListNode FindKthToTail(ListNode head, int k) { 9 | if (head == null || k == 0) { 10 | return null; 11 | } 12 | ArrayList list = new ArrayList<>(); 13 | list.add(head); 14 | while (head.next != null) { 15 | list.add(head.next); 16 | head = head.next; 17 | } 18 | Collections.reverse(list); 19 | if (k > list.size()) 20 | return null; 21 | return list.get(k - 1); 22 | //或者可以快慢指针,快指针fast先走k步,慢指针slow再和快指针fast一起走,但fast==null时,slow就是所求的值 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/sword_offer/JZ20.java: -------------------------------------------------------------------------------- 1 | package sword_offer; 2 | 3 | import java.util.Stack; 4 | 5 | //定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。 6 | public class JZ20 { 7 | Stack all = new Stack<>(); 8 | Stack min = new Stack<>(); 9 | 10 | public void push(int node) { 11 | all.push(node); 12 | if (min.empty()) { 13 | min.push(node); 14 | } else if (node < min()) { 15 | min.push(node); 16 | } 17 | } 18 | 19 | public void pop() { 20 | int pop = all.pop(); 21 | if (pop == min()) 22 | min.pop(); 23 | } 24 | 25 | public int top() { 26 | return all.peek(); 27 | } 28 | 29 | public int min() { 30 | return min.peek(); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/sword_offer/JZ33.java: -------------------------------------------------------------------------------- 1 | package sword_offer; 2 | 3 | //把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 4 | // 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。 5 | public class JZ33 { 6 | public int GetUglyNumber_Solution(int index) { 7 | if (index < 7) return index; 8 | int[] ret = new int[index]; 9 | ret[0] = 1; 10 | int t2 = 0, t3 = 0, t5 = 0; 11 | for (int i = 1; i < index; i++) { 12 | ret[i] = min(min(ret[t2] * 2, ret[t3] * 3), ret[t5] * 5); 13 | if (ret[i] == ret[t2] * 2) t2++; 14 | if (ret[i] == ret[t3] * 3) t3++; 15 | if (ret[i] == ret[t5] * 5) t5++; 16 | } 17 | return ret[index - 1]; 18 | } 19 | 20 | public static int min(int a, int b) { 21 | return a < b ? a : b; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /algorithm/UnionFind.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | class UnionFind{ 5 | private: 6 | int *parent; 7 | int count; 8 | public: 9 | UnionFind(int count){ 10 | parent=new int[count]; 11 | this->count=count; 12 | for(int i=0;i=0&&p> result = new ArrayList<>(); 9 | private ArrayList list = new ArrayList<>(); 10 | 11 | public ArrayList> FindPath(TreeNode root, int target) { 12 | if (root == null) return result; 13 | list.add(root.val); 14 | target = target - root.val; 15 | if (target == 0 && root.left == null && root.right == null) 16 | result.add(new ArrayList<>(list)); 17 | FindPath(root.left, target); 18 | FindPath(root.right, target); 19 | list.remove(list.size() - 1); 20 | return result; 21 | } 22 | 23 | 24 | } -------------------------------------------------------------------------------- /src/sword_offer/JZ15.java: -------------------------------------------------------------------------------- 1 | package sword_offer; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | 6 | //输入一个链表,反转链表后,输出新链表的表头。 7 | public class JZ15 { 8 | @SuppressWarnings("DuplicatedCode") 9 | public ListNode ReverseList(ListNode head) { 10 | if (head == null) { 11 | return null; 12 | } 13 | ArrayList list = new ArrayList<>(); 14 | list.add(head.val); 15 | while (head.next != null) { 16 | list.add(head.next.val); 17 | head = head.next; 18 | } 19 | Collections.reverse(list); 20 | ListNode iterator = head; 21 | for (int i = 1; i < list.size(); i++) { 22 | ListNode temp = new ListNode(list.get(i)); 23 | iterator.next = temp; 24 | iterator = temp; 25 | } 26 | return head; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/sword_offer/JZ28.java: -------------------------------------------------------------------------------- 1 | package sword_offer; 2 | 3 | //数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。 4 | // 例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次, 5 | // 超过数组长度的一半,因此输出2。如果不存在则输出0。 6 | public class JZ28 { 7 | public int MoreThanHalfNum_Solution(int[] array) { 8 | int length = array.length / 2; 9 | int count; 10 | int result = 0; 11 | for (int i = 0; i < array.length; i++) { 12 | count = 1; 13 | for (int j = i + 1; j < array.length; j++) { 14 | if (array[i] == array[j]) 15 | count++; 16 | } 17 | if (count > length) { 18 | result = array[i]; 19 | } 20 | } 21 | return result; 22 | } 23 | 24 | public static void main(String[] args) { 25 | System.out.println(new JZ28().MoreThanHalfNum_Solution(new int[]{1, 3, 4, 5, 2, 2, 2, 2, 2})); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # free_learning 2 | 3 | 阿松的笔记本,开始支棱起来了
4 | [Android零散复习](android_notes/Android面试笔记.md)
5 | [Android事件分发](android_notes/事件分发.md)
6 | [Java基础](android_notes/Java基础知识.md)
7 | [使用wsl2编译aosp步骤](android_notes/使用wsl2编译aosp步骤.md)
8 | [操作系统](basic_notes/操作系统.md)
9 | [简单测试mac性能(娱乐)](cLearning/cal.sh)
10 | [计算机组成原理](basic_notes/计算机组成原理.md)
11 | [计算机网络](basic_notes/计算机网络.md)
12 | [使用wsl2编译aosp步骤](android_notes/使用wsl2编译aosp步骤.md)
13 | [高斯模糊效果的实现原理](basic_notes/introduce_to_gaussian_blur.md)
14 | [如何结合recycler view实现滑动侧边栏功能](android_notes/侧滑删除.md)
15 | 16 | ### 数据结构 17 | [稠密图与稀疏图](algorithm/Graph.cpp)
18 | [cpp大顶堆](algorithm/Heap.cpp)
19 | [cpp排序算法集合](algorithm/Sort.cpp)
20 | [cpp排序算法辅助工具类](algorithm/SortTestHelper.h)
21 | [cpp二叉搜索树](algorithm/TreeAlgorithm.cpp)
22 | [cpp二叉平衡树](algorithm/AVLTree.cpp)
23 | [Java二叉树算法](src/AVL.java)
24 | [经典算法笔记](basic_notes/经典算法笔记.md) 25 | -------------------------------------------------------------------------------- /src/sword_offer/JZ18.java: -------------------------------------------------------------------------------- 1 | package sword_offer; 2 | 3 | //操作给定的二叉树,将其变换为源二叉树的镜像。 4 | public class JZ18 { 5 | public void Mirror(TreeNode root) { 6 | if (root == null) 7 | return; 8 | if (root.left == null && root.right == null) 9 | return; 10 | TreeNode temp = root.left; 11 | root.left = root.right; 12 | root.right = temp; 13 | Mirror(root.left); 14 | Mirror(root.right); 15 | } 16 | 17 | //删除链表的节点 18 | public ListNode deleteNode(ListNode head, int val) { 19 | ListNode dummy = new ListNode(-1); 20 | dummy.next = head; 21 | ListNode node = dummy; 22 | while (node.next != null) { 23 | if (node.next.val == val) { 24 | node.next = node.next.next; 25 | break; 26 | } 27 | node = node.next; 28 | } 29 | return dummy.next; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/sword_offer/JZ22.java: -------------------------------------------------------------------------------- 1 | package sword_offer; 2 | 3 | import java.util.ArrayList; 4 | import java.util.LinkedList; 5 | import java.util.Queue; 6 | 7 | public class JZ22 { 8 | public ArrayList PrintFromTopToBottom(TreeNode root) { 9 | ArrayList result = new ArrayList<>(); 10 | if (root == null) { 11 | return result; 12 | } 13 | Queue queue = new LinkedList<>(); 14 | queue.offer(root); 15 | while (!queue.isEmpty()) { 16 | TreeNode iterator = queue.poll(); 17 | if (iterator != null) { 18 | result.add(iterator.val); 19 | } 20 | if (iterator.left != null) { 21 | queue.offer(iterator.left); 22 | } 23 | if (iterator.right != null) { 24 | queue.offer(iterator.right); 25 | } 26 | } 27 | return result; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/sword_offer/JZ1.java: -------------------------------------------------------------------------------- 1 | package sword_offer; 2 | 3 | //二维数组中的查找 4 | public class JZ1 { 5 | /** 6 | * 在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序, 7 | * 每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数, 8 | * 判断数组中是否含有该整数。 9 | * 10 | * @param target 11 | * @param array 12 | * @return 13 | */ 14 | public boolean Find(int target, int[][] array) { 15 | int rows = array.length; 16 | int cols = array[0].length; 17 | if (rows == 0 || cols == 0) 18 | return false; 19 | //从左下角开始找 左下角是每一行做小的数也是每一列最大的数 20 | int row = rows - 1; 21 | int col = 0; 22 | while (row >= 0 && col < cols) { 23 | if (target > array[row][col]) { 24 | col++; 25 | } else if (target < array[row][col]) { 26 | row--; 27 | } else { 28 | return true; 29 | } 30 | } 31 | return false; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/duty_chain/Handler.java: -------------------------------------------------------------------------------- 1 | package duty_chain; 2 | 3 | 4 | public abstract class Handler { 5 | private Handler nextHandler; 6 | 7 | //处理者对请求作出处理 8 | public final Response handleMessage(Request request) { 9 | Response response = null; 10 | //判断处理级别 11 | if (this.getHandlerLevel().equals(request.getRequestLevel())) { 12 | response = this.echo(request); 13 | } else { 14 | //下一个处理者进行操作 15 | if (this.nextHandler != null) { 16 | response = this.nextHandler.handleMessage(request); 17 | } else { 18 | //没有处理者了 业务自行处理 19 | } 20 | } 21 | return response; 22 | } 23 | 24 | //设置下一个处理者是谁 25 | public void setNext(Handler handler) { 26 | this.nextHandler = handler; 27 | } 28 | 29 | //处理者有自己的处理级别 30 | protected abstract Level getHandlerLevel(); 31 | 32 | //每个处理者都必须实现处理任务 33 | protected abstract Response echo(Request request); 34 | } 35 | -------------------------------------------------------------------------------- /src/PinType.java: -------------------------------------------------------------------------------- 1 | 2 | public enum PinType { 3 | 4 | REGISTER(100000, "注册使用"), 5 | FORGET_PASSWORD(100001, "忘记密码使用"), 6 | UPDATE_PHONE_NUMBER(100002, "更新手机号码使用"); 7 | 8 | private final int code; 9 | private final String message; 10 | 11 | PinType(int code, String message) { 12 | this.code = code; 13 | this.message = message; 14 | } 15 | 16 | public int getCode() { 17 | return code; 18 | } 19 | 20 | public String getMessage() { 21 | return message; 22 | } 23 | 24 | @Override 25 | public String toString() { 26 | return "PinType{" + 27 | "code=" + code + 28 | ", message='" + message + '\'' + 29 | '}'; 30 | } 31 | 32 | public static void main(String[] args) { 33 | System.out.println(PinType.FORGET_PASSWORD.getCode()); 34 | System.out.println(PinType.FORGET_PASSWORD.getMessage()); 35 | System.out.println(PinType.FORGET_PASSWORD.toString()); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/sword_offer/JZ36.java: -------------------------------------------------------------------------------- 1 | package sword_offer; 2 | 3 | import java.util.Stack; 4 | //输入两个链表,找出它们的第一个公共结点。 5 | // (注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的) 6 | public class JZ36 { 7 | public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) { 8 | if (pHead1 == null || pHead2 == null) { 9 | return null; 10 | } 11 | Stack stack1 = new Stack<>(); 12 | Stack stack2 = new Stack<>(); 13 | 14 | while (pHead1 != null) { 15 | stack1.push(pHead1); 16 | pHead1 = pHead1.next; 17 | } 18 | 19 | while (pHead2 != null) { 20 | stack2.push(pHead2); 21 | pHead2 = pHead2.next; 22 | } 23 | 24 | ListNode commonListNode = null; 25 | 26 | while (!stack1.isEmpty() && !stack2.isEmpty() && stack1.peek() == stack2.peek()) { 27 | stack2.pop(); 28 | commonListNode = stack1.pop(); 29 | } 30 | 31 | return commonListNode; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/sword_offer/JZ37.java: -------------------------------------------------------------------------------- 1 | package sword_offer; 2 | 3 | //统计一个数字在升序数组中出现的次数。 4 | public class JZ37 { 5 | 6 | public int GetNumberOfK(int[] array, int k) { 7 | //二分查找先找到位置 然后左右方向分别统计次数 8 | if (array == null || array.length == 0) 9 | return 0; 10 | int left = 0, right = array.length - 1, mid = (left + right) / 2; 11 | while (left < right) { 12 | if (k > array[mid]) { 13 | left = mid + 1; 14 | } else if (k < array[mid]) { 15 | right = mid - 1; 16 | } 17 | mid = (left + right) / 2; 18 | if (array[mid] == k) 19 | break; 20 | } 21 | if (k != array[mid]) 22 | return 0; 23 | int count = -1; 24 | for (int i = mid; i >= 0 && array[i] == k; i--) { 25 | count++; 26 | } 27 | for (int i = mid; i < array.length && array[i] == k; i++) { 28 | count++; 29 | } 30 | return count; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/sword_offer/JZ25.java: -------------------------------------------------------------------------------- 1 | package sword_offer; 2 | 3 | import java.util.HashMap; 4 | 5 | //输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点, 6 | // 另一个特殊指针random指向一个随机节点),请对此链表进行深拷贝,并返回拷贝后的头结点。 7 | // (注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空) 8 | public class JZ25 { 9 | //仔细一看这好像就是二叉树…… 10 | public RandomListNode Clone(RandomListNode pHead) { 11 | HashMap map = new HashMap<>(); 12 | RandomListNode p = pHead; 13 | //第一次遍历 新建立节点 14 | while (p != null) { 15 | RandomListNode newNode = new RandomListNode(p.label); 16 | map.put(p, newNode); 17 | p = p.next; 18 | } 19 | //第二次遍历 赋值映射关系 20 | p = pHead; 21 | while (p != null) { 22 | RandomListNode node = map.get(p); 23 | node.next = (p.next == null) ? null : map.get(p.next); 24 | node.random = (p.random == null) ? null : map.get(p.random); 25 | p = p.next; 26 | } 27 | //最后的返回值 28 | return map.get(pHead); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/sword_offer/JZ32.java: -------------------------------------------------------------------------------- 1 | package sword_offer; 2 | 3 | //输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。 4 | // 例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。 5 | public class JZ32 { 6 | //比较两个字符串s1, s2大小的时候,先将它们拼接起来,比较s1+s2,和s2+s1那个大, 7 | //如果s1+s2大,那说明s2应该放前面,所以按这个规则,s2就应该排在s1前面 8 | public String PrintMinNumber(int[] numbers) { 9 | if (numbers == null || numbers.length == 0) return ""; 10 | for (int i = 0; i < numbers.length; i++) { 11 | for (int j = i + 1; j < numbers.length; j++) { 12 | int sum1 = Integer.valueOf(numbers[i] + "" + numbers[j]); 13 | int sum2 = Integer.valueOf(numbers[j] + "" + numbers[i]); 14 | if (sum1 > sum2) { 15 | int temp = numbers[j]; 16 | numbers[j] = numbers[i]; 17 | numbers[i] = temp; 18 | } 19 | } 20 | } 21 | String str = ""; 22 | for (int i = 0; i < numbers.length; i++) 23 | str = str + numbers[i]; 24 | return str; 25 | 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/AsyncCallback.java: -------------------------------------------------------------------------------- 1 | public class AsyncCallback { 2 | interface IClient { 3 | String receiveAnswer(String answer); 4 | } 5 | 6 | static class Client implements IClient, Runnable { 7 | Server server; 8 | 9 | public Client(Server server) { 10 | this.server = server; 11 | } 12 | 13 | void ask(String question) { 14 | server.answer(this, question); 15 | } 16 | 17 | @Override 18 | public String receiveAnswer(String answer) { 19 | System.out.println(answer); 20 | return answer; 21 | } 22 | 23 | @Override 24 | public void run() { 25 | 26 | } 27 | } 28 | 29 | static class Server { 30 | String answer(IClient client, String question) { 31 | return client.receiveAnswer("question is " + question + "\tand I don't know it"); 32 | } 33 | } 34 | 35 | public static void main(String[] args) { 36 | Server server = new Server(); 37 | Client client = new Client(server); 38 | client.ask("How are you"); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/sword_offer/JZ26.java: -------------------------------------------------------------------------------- 1 | package sword_offer; 2 | 3 | import java.util.ArrayList; 4 | 5 | //输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点, 6 | // 只能调整树中结点指针的指向。 7 | public class JZ26 { 8 | //这个中序遍历再修改节点真是绝了 太实用了 9 | public TreeNode Convert(TreeNode pRootOfTree) { 10 | if(pRootOfTree == null){ 11 | return null; 12 | } 13 | ArrayList list = new ArrayList<>(); 14 | Convert(pRootOfTree, list); 15 | return Convert(list); 16 | 17 | } 18 | //中序遍历,在list中按遍历顺序保存 19 | public void Convert(TreeNode pRootOfTree, ArrayList list){ 20 | if(pRootOfTree.left != null){ 21 | Convert(pRootOfTree.left, list); 22 | } 23 | 24 | list.add(pRootOfTree); 25 | 26 | if(pRootOfTree.right != null){ 27 | Convert(pRootOfTree.right, list); 28 | } 29 | } 30 | //遍历list,修改指针 31 | public TreeNode Convert(ArrayList list){ 32 | for(int i = 0; i < list.size() - 1; i++){ 33 | list.get(i).right = list.get(i + 1); 34 | list.get(i + 1).left = list.get(i); 35 | } 36 | return list.get(0); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/sword_offer/JZ5.java: -------------------------------------------------------------------------------- 1 | package sword_offer; 2 | 3 | import java.util.Stack; 4 | 5 | //两个栈实现队列 6 | public class JZ5 { 7 | Stack stack1 = new Stack<>(); 8 | Stack stack2 = new Stack<>(); 9 | 10 | public void push(int node) { 11 | stack1.push(node); 12 | } 13 | 14 | public int pop() { 15 | int size1 = stack1.size(); 16 | for (int i = 0; i < size1; i++) { 17 | stack2.push(stack1.pop()); 18 | } 19 | int result = stack2.pop(); 20 | int size2 = stack2.size(); 21 | for (int i = 0; i < size2; i++) { 22 | stack1.push(stack2.pop()); 23 | } 24 | return result; 25 | } 26 | 27 | public static void main(String[] args) { 28 | JZ5 solution = new JZ5(); 29 | solution.push(1); 30 | solution.push(2); 31 | solution.push(3); 32 | System.out.println(solution.pop()); 33 | System.out.println(solution.pop()); 34 | solution.push(4); 35 | System.out.println(solution.pop()); 36 | solution.push(5); 37 | System.out.println(solution.pop()); 38 | System.out.println(solution.pop()); 39 | } 40 | } -------------------------------------------------------------------------------- /src/sword_offer/JZ16.java: -------------------------------------------------------------------------------- 1 | package sword_offer; 2 | 3 | //输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。 4 | public class JZ16 { 5 | public ListNode Merge(ListNode list1, ListNode list2) { 6 | ListNode result = new ListNode(0);//随便一个开头 只是为了不报错 7 | ListNode iterator = result; 8 | while (list1 != null && list2 != null) { 9 | if (list1.val <= list2.val) { 10 | iterator.next = list1; 11 | list1 = list1.next; 12 | } else if (list1.val > list2.val) { 13 | iterator.next = list2; 14 | list2 = list2.next; 15 | } 16 | iterator = iterator.next; 17 | } 18 | if (list1 == null) { 19 | while (list2 != null) { 20 | iterator.next = list2; 21 | list2 = list2.next; 22 | iterator = iterator.next; 23 | } 24 | } 25 | if (list2 == null) { 26 | while (list1 != null) { 27 | iterator.next = list1; 28 | list1 = list1.next; 29 | iterator = iterator.next; 30 | } 31 | } 32 | return result.next; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/sword_offer/JZ41.java: -------------------------------------------------------------------------------- 1 | package sword_offer; 2 | 3 | import java.util.ArrayList; 4 | 5 | //找出所有和为S的连续正数序列 6 | public class JZ41 { 7 | public ArrayList> findContinuousSequence(int sum) { 8 | ArrayList> result = new ArrayList<>(); 9 | for (int i = 1; i <= sum / 2; i++) { 10 | int start = i; 11 | int target = i; 12 | int counter = 0; 13 | ArrayList partResult = new ArrayList<>(); 14 | while (target < sum) { 15 | counter++; 16 | target = target + start + counter; 17 | } 18 | if (target == sum) { 19 | for (int j = start; j <= start + counter; j++) { 20 | partResult.add(j); 21 | } 22 | result.add(partResult); 23 | } 24 | } 25 | System.out.println("continuous list result:"); 26 | for (ArrayList list : result) { 27 | System.out.println(list); 28 | } 29 | return result; 30 | } 31 | 32 | public static void main(String[] args) { 33 | new JZ41().findContinuousSequence(1000); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/BestStopTheory.java: -------------------------------------------------------------------------------- 1 | import java.util.Random; 2 | 3 | public class BestStopTheory { 4 | //最优停止理论 5 | public static void main(String[] args) { 6 | /** 7 | *假设有100个人,分数在1到1000之间 8 | * 面试官要在这些人中找到最合适的 9 | * 已经面试过的 没录取的 不能再录取 10 | * 理论上说37%以后遇到的第一个比之前都好的人 11 | * 就是最合理的选择 12 | * 下面验证一下 13 | */ 14 | for (int count = 0; count < 20; count++) { 15 | int candidate[] = new int[100]; 16 | for (int i = 0; i < 100; i++) { 17 | candidate[i] = (int) (Math.random() * 1000); 18 | } 19 | int maxInTop37 = candidate[0]; 20 | for (int i = 0; i < 37; i++) { 21 | maxInTop37 = candidate[i] > maxInTop37 ? candidate[i] : maxInTop37; 22 | } 23 | int bestMatch = maxInTop37; 24 | for (int i = 37; i < 100; i++) { 25 | if (candidate[i] > maxInTop37) { 26 | bestMatch = maxInTop37; 27 | break; 28 | } 29 | } 30 | int rank = 1; 31 | for (int i = 0; i < 100; i++) { 32 | if (candidate[i] > bestMatch) 33 | rank++; 34 | } 35 | System.out.println("最优停止理论最后选出的候选人实际的排名是(一共100人):" + rank); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/sword_offer/JZ59.java: -------------------------------------------------------------------------------- 1 | package sword_offer; 2 | 3 | import java.util.ArrayList; 4 | import java.util.LinkedList; 5 | 6 | /** 7 | * 给定一个长度为 n 的数组 num 和滑动窗口的大小 size ,找出所有滑动窗口里数值的最大值。 8 | *

9 | * 例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。 10 | *

11 | * 窗口大于数组长度或窗口长度为0的时候,返回空。 12 | */ 13 | public class JZ59 { 14 | public ArrayList maxInWindows(int[] num, int size) { 15 | if (num == null || num.length == 0 || size <= 0 || num.length < size) { 16 | return new ArrayList<>(); 17 | } 18 | ArrayList result = new ArrayList<>(); 19 | //双端队列,用来记录每个窗口的最大值下标 20 | LinkedList qmax = new LinkedList<>(); 21 | for (int i = 0; i < num.length; i++) { 22 | while (!qmax.isEmpty() && num[qmax.peekLast()] < num[i]) { 23 | qmax.pollLast(); 24 | } 25 | qmax.addLast(i); 26 | //判断队首元素是否过期 27 | if (qmax.peekFirst() <= i - size) { 28 | qmax.pollFirst(); 29 | } 30 | //向result列表中加入元素 31 | if (i >= size - 1) { 32 | result.add(num[qmax.peekFirst()]); 33 | } 34 | } 35 | return result; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/sword_offer/JZ21.java: -------------------------------------------------------------------------------- 1 | package sword_offer; 2 | 3 | import java.util.ArrayList; 4 | 5 | //输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。 6 | // 假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序, 7 | // 序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。 8 | // (注意:这两个序列的长度是相等的) 9 | public class JZ21 { 10 | public boolean IsPopOrder(int[] pushA, int[] popA) { 11 | ArrayList stack = new ArrayList<>(); 12 | for (int i = 0; i < pushA.length; i++) { 13 | stack.add(pushA[i]); 14 | } 15 | for (int i : popA) { 16 | if (!stack.contains(i)) 17 | return false; 18 | } 19 | int indexPushA; 20 | int indexPopA; 21 | for (int i = 1; i < popA.length; i++) { 22 | indexPushA = stack.indexOf(popA[i]); 23 | indexPopA = stack.indexOf(popA[i - 1]); 24 | //符合要求的情况 另外第一个元素不受这个限制 25 | if (Math.abs(indexPushA - indexPopA) == 1 || i == 1) { 26 | stack.remove(indexPopA); 27 | } else { 28 | return false; 29 | } 30 | } 31 | return true; 32 | } 33 | 34 | public static void main(String[] args) { 35 | ArrayList stack = new ArrayList<>(); 36 | stack.add(2); 37 | stack.add(4); 38 | stack.add(6); 39 | stack.add(8); 40 | stack.add(9); 41 | System.out.println(stack.indexOf(4)); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/sword_offer/JZ27.java: -------------------------------------------------------------------------------- 1 | package sword_offer; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | 6 | //输入一个字符串,按字典序打印出该字符串中字符的所有排列。 7 | // 例如输入字符串abc,则按字典序打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。 8 | public class JZ27 { 9 | public ArrayList PermutationHelp(StringBuilder str) { 10 | ArrayList result = new ArrayList<>(); 11 | if (str.length() == 1) { 12 | result.add(str.toString()); 13 | return result; 14 | } 15 | for (int i = 0; i < str.length(); i++) { 16 | if (i == 0 || str.charAt(i) != str.charAt(0)) { 17 | char temp = str.charAt(i); 18 | str.setCharAt(i, str.charAt(0)); 19 | str.setCharAt(0, temp); 20 | ArrayList newResult = PermutationHelp(new StringBuilder(str.substring(1))); 21 | for (int j = 0; j < newResult.size(); j++) 22 | result.add(str.substring(0, 1) + newResult.get(j)); 23 | //用完还是要放回去的 24 | temp = str.charAt(0); 25 | str.setCharAt(0, str.charAt(i)); 26 | str.setCharAt(i, temp); 27 | } 28 | 29 | } 30 | Collections.sort(result); 31 | return result; 32 | } 33 | 34 | public ArrayList Permutation(String str) { 35 | StringBuilder strBuilder = new StringBuilder(str); 36 | return PermutationHelp(strBuilder); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /algorithm/SortTestHelper.h: -------------------------------------------------------------------------------- 1 | #ifndef SELECTIONSORT_SORTTESTHELPER_H 2 | #define SELECTIONSORT_SORTTESTHELPER_H 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | namespace SortTestHelper{ 8 | //生成有n个元素的随机数组 e范围是l到r之间 9 | int* generateRandomArray(int n,int rangeL,int rangeR){ 10 | assert(rangeL<=rangeR); 11 | int *arr=new int[n]; 12 | srand(time(NULL)); 13 | for(int i=0;i 31 | void printArray(T arr[],int n){ 32 | for(int i=0;i 37 | bool isSorted(T arr[],int n){ 38 | for(int i=0;iarr[i+1]) 40 | return false; 41 | } 42 | return true; 43 | } 44 | 45 | template 46 | void testSort(string sortName,void(*sort)(T[],int),T arr[],int n){ 47 | clock_t startTime=clock(); 48 | sort(arr,n); 49 | clock_t endTime=clock(); 50 | assert(isSorted(arr,n)); 51 | cout< sequence[sequence.length - 1]) 31 | return false; 32 | } 33 | for (int i = 0; i < rightSize; i++) { 34 | right[i] = sequence[leftSize + i]; 35 | if (right[i] < sequence[sequence.length - 1]) 36 | return false; 37 | } 38 | return normalAnswer(left) && normalAnswer(right); 39 | } 40 | 41 | public static void main(String[] args) { 42 | for (int i = 0; i < 0; i++) { 43 | System.out.println(111); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /algorithm/Graph.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | //稠密图 邻接矩阵 6 | class DenseGraph{ 7 | private: 8 | int n,m;//n是点数m是边数 9 | bool directed; 10 | vector> g; 11 | public: 12 | DenseGraph(int n,bool directed){ 13 | this->n=n; 14 | this->m=0; 15 | this->directed=directed; 16 | for(int i=0;i(n,false)); 18 | } 19 | ~DenseGraph(){ 20 | } 21 | void addEdge(int v,int w){ 22 | assert(v>=0&&v=0&&w=0&&v=0&&w> g; 43 | public: 44 | SparseGraph(int n,bool directed){ 45 | this->n=n; 46 | this->m=0; 47 | this->directed=directed; 48 | for(int i=0;i()); 50 | } 51 | ~SparseGraph(){ 52 | } 53 | int V(){ 54 | return n; 55 | } 56 | int E(){ 57 | return m; 58 | } 59 | void addEdge(int v,int w){ 60 | assert(v>=0&&v=0&&w=0&&v=0&&w 4 | 5 | ``` 6 | private static int fibRecursion(int num){ 7 | if(num==1||num==2){ 8 | return 1; 9 | } 10 | return fibRecursion(num-1)+fibRecursion(num-2); 11 | } 12 | ``` 13 | 14 | 递归过程可以用这张图表示:
![avatar](pic/FH-fib(4).png)
可以看到fib(2)重复计算了。改用动态规划法,增加记忆机制即可。 15 |
16 | 17 | ``` 18 | private static int[] output=new int[1000]; 19 | private static int fibDynamic(int num){ 20 | int result=output[num]; 21 | //没有算过就递归去算 22 | if(result==0){ 23 | if(num==1||num==2){ 24 | return 1; 25 | }else{ 26 | return fibDynamic(num-1)+fibDynamic(num-2); 27 | } 28 | } 29 | //算过的话就不用算了 30 | output[num]=result; 31 | return result; 32 | } 33 | ``` 34 | 35 | ###### 回溯法 36 | 37 | 一旦发现不正确的数值,就不进入下一层而是回溯到上一层。已经走过的路径用链表存储,即将走入的节点放入堆栈。 38 | 39 | ```java 40 | class Node { 41 | int x; 42 | int y; 43 | Node next; 44 | 45 | public Node(int x, int y) { 46 | this.x = x; 47 | this.y = y; 48 | this.next = null; 49 | } 50 | } 51 | 52 | public class TraceRecord { 53 | public Node first; 54 | public Node last; 55 | 56 | public boolean isEmpty() { 57 | return first == null; 58 | } 59 | 60 | public void insert(int x, int y) { 61 | Node newNode = new Node(x, y); 62 | if (this.isEmpty()) { 63 | first = newNode; 64 | last = newNode; 65 | } else { 66 | last.next = newNode; 67 | last = newNode; 68 | } 69 | } 70 | 71 | public void delete() { 72 | Node newNode; 73 | if (this.isEmpty()) { 74 | System.out.print("[路径已经空了]\n"); 75 | return; 76 | } 77 | newNode = first; 78 | while (newNode.next != last) 79 | newNode = newNode.next; 80 | newNode.next = last.next; 81 | last = newNode; 82 | 83 | } 84 | } 85 | ``` 86 | -------------------------------------------------------------------------------- /src/sword_offer/JZ6.java: -------------------------------------------------------------------------------- 1 | package sword_offer; 2 | 3 | import java.util.Stack; 4 | 5 | public class JZ6 { 6 | /** 7 | * 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 8 | * 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。 9 | * 例如数组[3,4,5,1,2]为[1,2,3,4,5]的一个旋转,该数组的最小值为1。 10 | * NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。 11 | */ 12 | public int minNumberInRotateArray(int[] array) { 13 | switch (array.length) { 14 | case 0: 15 | return 0; 16 | case 1: 17 | return array[0]; 18 | case 2: 19 | return array[1]; 20 | } 21 | int left = 0, right = array.length - 1; 22 | int mid = array.length / 2; 23 | while (array[mid] > array[mid - 1] || array[mid] > array[mid + 1]) { 24 | /** 25 | * 这里想象成两个递增的数组连在一起,目标是找到第二个数组开头的数字 26 | * 第二个数组的每一个元素都是比第一个数组任意元素小的 27 | * 所以如果mid比0号元素还大,那肯定还在第一个数组,所以要找右半边 28 | */ 29 | if (array[mid] > array[0]) { 30 | left = mid; 31 | } else { 32 | if (array[mid] > array[mid - 1]) { 33 | right = mid; 34 | } else if (array[mid] > array[mid + 1]) { 35 | left = mid; 36 | } 37 | } 38 | mid = (left + right) / 2; 39 | } 40 | return array[mid]; 41 | } 42 | 43 | //剑指 Offer 06. 从尾到头打印链表 44 | //输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。 45 | 46 | public int[] reversePrint(ListNode head) { 47 | Stack stack = new Stack<>(); 48 | ListNode iteration = head; 49 | int elementCount = 0; 50 | while (iteration != null) { 51 | stack.push(iteration.val); 52 | iteration = iteration.next; 53 | elementCount++; 54 | } 55 | int[] res = new int[elementCount]; 56 | for (int i = 0; i < res.length; i++) { 57 | res[i] = stack.pop(); 58 | } 59 | return res; 60 | } 61 | 62 | 63 | public static void main(String[] args) { 64 | int a[] = {4, 5, 6, 1, 2, 3}; 65 | System.out.println(new JZ6().minNumberInRotateArray(a)); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/sword_offer/JZ35.java: -------------------------------------------------------------------------------- 1 | package sword_offer; 2 | 3 | //在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。 4 | // 输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007 5 | public class JZ35 { 6 | /*归并排序的改进,把数据分成前后两个数组(递归分到每个数组仅有一个数据项), 7 | 合并数组,合并时,出现前面的数组值array[i]大于后面数组值array[j]时;则前面 8 | 数组array[i]~array[mid]都是大于array[j]的,count += mid+1 - i 9 | 参考剑指Offer,但是感觉剑指Offer归并过程少了一步拷贝过程。 10 | 还有就是测试用例输出结果比较大,对每次返回的count mod(1000000007)求余 11 | */ 12 | public int InversePairs(int[] array) { 13 | if (array == null || array.length == 0) { 14 | return 0; 15 | } 16 | int[] copy = new int[array.length]; 17 | for (int i = 0; i < array.length; i++) { 18 | copy[i] = array[i]; 19 | } 20 | int count = InversePairsCore(array, copy, 0, array.length - 1);//数值过大求余 21 | return count; 22 | 23 | } 24 | 25 | private int InversePairsCore(int[] array, int[] copy, int low, int high) { 26 | if (low == high) { 27 | return 0; 28 | } 29 | int mid = (low + high) >> 1; 30 | int leftCount = InversePairsCore(array, copy, low, mid) % 1000000007; 31 | int rightCount = InversePairsCore(array, copy, mid + 1, high) % 1000000007; 32 | int count = 0; 33 | int i = mid; 34 | int j = high; 35 | int locCopy = high; 36 | while (i >= low && j > mid) { 37 | if (array[i] > array[j]) { 38 | count += j - mid; 39 | copy[locCopy--] = array[i--]; 40 | if (count >= 1000000007)//数值过大求余 41 | { 42 | count %= 1000000007; 43 | } 44 | } else { 45 | copy[locCopy--] = array[j--]; 46 | } 47 | } 48 | for (; i >= low; i--) { 49 | copy[locCopy--] = array[i]; 50 | } 51 | for (; j > mid; j--) { 52 | copy[locCopy--] = array[j]; 53 | } 54 | for (int s = low; s <= high; s++) { 55 | array[s] = copy[s]; 56 | } 57 | return (leftCount + rightCount + count) % 1000000007; 58 | } 59 | 60 | public static void main(String[] args) { 61 | System.out.println(7 % 1000000007); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/sword_offer/JZ19.java: -------------------------------------------------------------------------------- 1 | package sword_offer; 2 | 3 | import java.util.ArrayList; 4 | //输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 5 | // 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10. 6 | public class JZ19 { 7 | public ArrayList printMatrix(int[][] matrix) { 8 | /** 9 | * 定义四个变量代表范围,up、down、left、right 10 | * 11 | * 向右走存入整行的值,当存入后,该行再也不会被遍历,代表上边界的 up 加一,同时判断是否和代表下边界的 down 交错 12 | * 向下走存入整列的值,当存入后,该列再也不会被遍历,代表右边界的 right 减一,同时判断是否和代表左边界的 left 交错 13 | * 向左走存入整行的值,当存入后,该行再也不会被遍历,代表下边界的 down 减一,同时判断是否和代表上边界的 up 交错 14 | * 向上走存入整列的值,当存入后,该列再也不会被遍历,代表左边界的 left 加一,同时判断是否和代表右边界的 right 交错 15 | */ 16 | ArrayList list = new ArrayList<>(); 17 | if (matrix == null || matrix.length == 0 || matrix[0].length == 0) { 18 | return list; 19 | } 20 | int up = 0; 21 | int down = matrix.length - 1; 22 | int left = 0; 23 | int right = matrix[0].length - 1; 24 | while (true) { 25 | // 最上面一行 26 | for (int col = left; col <= right; col++) { 27 | list.add(matrix[up][col]); 28 | } 29 | // 向下逼近 30 | up++; 31 | // 判断是否越界 32 | if (up > down) { 33 | break; 34 | } 35 | // 最右边一列 36 | for (int row = up; row <= down; row++) { 37 | list.add(matrix[row][right]); 38 | } 39 | // 向左逼近 40 | right--; 41 | // 判断是否越界 42 | if (left > right) { 43 | break; 44 | } 45 | // 最下面一行 46 | for (int col = right; col >= left; col--) { 47 | list.add(matrix[down][col]); 48 | } 49 | // 向上逼近 50 | down--; 51 | // 判断是否越界 52 | if (up > down) { 53 | break; 54 | } 55 | // 最左边一列 56 | for (int row = down; row >= up; row--) { 57 | list.add(matrix[row][left]); 58 | } 59 | // 向右逼近 60 | left++; 61 | // 判断是否越界 62 | if (left > right) { 63 | break; 64 | } 65 | } 66 | System.out.println("Practice makes perfect!\n"); 67 | return list; 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /algorithm/Heap.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | template 6 | class Heap{ 7 | private: 8 | T* data; 9 | int count; 10 | int capacity; 11 | public: 12 | Heap(int capacity){ 13 | data=new T[capacity+1]; 14 | count=0; 15 | this->capacity=capacity; 16 | } 17 | Heap(T arr[],int n){ 18 | data=new T[n+1]; 19 | capacity=n; 20 | count=n; 21 | for(int i=0;i=1;j--){ 24 | int i=j; 25 | while(2*i<=count){ 26 | //如果有右孩子并且左右孩子里大的那个比根节点更大 交换 27 | if(2*i+1<=count){ 28 | int biggerIndex=data[i*2]>data[i*2+1]?2*i:i*2+1; 29 | if(data[biggerIndex]>data[i]){ 30 | swap(data[i],data[biggerIndex]); 31 | i=biggerIndex; 32 | }else//如果左右孩子都比根节点小 终点 33 | break; 34 | }else {//没有右孩子的时候只要和左孩子比较即可 35 | if(data[i]1&&data[tempCount]>data[tempCount/2]){ 59 | swap(data[tempCount],data[tempCount/2]); 60 | tempCount=tempCount/2; 61 | } 62 | } 63 | T remove(){ 64 | assert(count>0); 65 | T item=data[1]; 66 | swap(data[1],data[count]); 67 | count--; 68 | int i=1; 69 | while(2*i<=count){ 70 | //如果有右孩子并且左右孩子里大的那个比根节点更大 交换 71 | if(2*i+1<=count){ 72 | int biggerIndex=data[i*2]>data[i*2+1]?2*i:i*2+1; 73 | if(data[biggerIndex]>data[i]){ 74 | swap(data[i],data[biggerIndex]); 75 | i=biggerIndex; 76 | }else//如果左右孩子都比根节点小 终点 77 | break; 78 | }else {//没有右孩子的时候只要和左孩子比较即可 79 | if(data[i] heap=Heap(arr,7); 97 | heap.show(); 98 | return 0; 99 | } 100 | -------------------------------------------------------------------------------- /src/sword_offer/JZ12.java: -------------------------------------------------------------------------------- 1 | package sword_offer; 2 | 3 | public class JZ12 { 4 | //给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。 5 | //保证base和exponent不同时为0 6 | public double Power(double base, int exponent) { 7 | double result = 1; 8 | for (int i = 0; i < Math.abs(exponent); i++) { 9 | result *= base; 10 | } 11 | return exponent > 0 ? result : 1 / result; 12 | } 13 | 14 | /** 15 | * 请设计一个函数,用来判断在一个n乘m的矩阵中是否存在一条包含某长度为len的字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始, 16 | * 每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。 17 | * a b c e 18 | * 例如 s f c s 19 | * a d e e 20 | * 矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后, 21 | * 路径不能再次进入该格子。 22 | */ 23 | /** 24 | * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 25 | * 26 | * @param matrix char字符型二维数组 27 | * @param word string字符串 28 | * @return bool布尔型 29 | */ 30 | public boolean hasPath(char[][] matrix, String word) { 31 | char[] words = word.toCharArray(); 32 | for (int i = 0; i < matrix.length; i++) { 33 | for (int j = 0; j < matrix[0].length; j++) { 34 | //从[i,j]这个坐标开始查找 35 | if (dfs(matrix, words, i, j, 0)) 36 | return true; 37 | } 38 | } 39 | return false; 40 | } 41 | 42 | boolean dfs(char[][] matrix, char[] word, int i, int j, int index) { 43 | //边界的判断,如果越界直接返回false。index表示的是查找到字符串word的第几个字符, 44 | //如果这个字符不等于matrix[i][j],说明验证这个坐标路径是走不通的,直接返回false 45 | if (i >= matrix.length || i < 0 || j >= matrix[0].length || j < 0 || 46 | matrix[i][j] != word[index]) 47 | return false; 48 | //如果word的每个字符都查找完了,直接返回true 49 | if (index == word.length - 1) 50 | return true; 51 | //把当前坐标的值保存下来,为了在最后复原 52 | char tmp = matrix[i][j]; 53 | //然后修改当前坐标的值 54 | matrix[i][j] = '.'; 55 | //走递归,沿着当前坐标的上下左右4个方向查找 56 | boolean res = dfs(matrix, word, i + 1, j, index + 1) 57 | || dfs(matrix, word, i - 1, j, index + 1) 58 | || dfs(matrix, word, i, j + 1, index + 1) 59 | || dfs(matrix, word, i, j - 1, index + 1); 60 | //递归之后再把当前的坐标复原 61 | matrix[i][j] = tmp; 62 | return res; 63 | } 64 | 65 | public static void main(String[] args) { 66 | System.out.println(new JZ12().Power(2, -3)); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/sword_offer/JZ13.java: -------------------------------------------------------------------------------- 1 | package sword_offer; 2 | 3 | //输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分, 4 | // 所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。 5 | public class JZ13 { 6 | public void reOrderArray(int[] array) { 7 | int[] result = new int[array.length]; 8 | int index = 0; 9 | for (int i : array) { 10 | if (i % 2 != 0) { 11 | result[index] = i; 12 | index++; 13 | } 14 | } 15 | for (int i : array) { 16 | if (i % 2 == 0) { 17 | result[index] = i; 18 | index++; 19 | } 20 | } 21 | for (int i = 0; i < result.length; i++) { 22 | array[i] = result[i]; 23 | } 24 | } 25 | 26 | //地上有一个 rows 行和 cols 列的方格。坐标从 [0,0] 到 [rows-1,cols-1] 。一个机器人从坐标 [0,0] 的格子开始移动, 27 | // 每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于 threshold 的格子。 28 | // 例如,当 threshold 为 18 时,机器人能够进入方格 [35,37] ,因为 3+5+3+7 = 18。但是,它不能进入方格 [35,38] , 29 | // 因为 3+5+3+8 = 19 。请问该机器人能够达到多少个格子? 30 | public int movingCount(int threshold, int rows, int cols) { 31 | if (rows <= 0 || cols <= 0 || threshold < 0) 32 | return 0; 33 | 34 | boolean[][] isVisited = new boolean[rows][cols];//标记 35 | int count = movingCountCore(threshold, rows, cols, 0, 0, isVisited); 36 | return count; 37 | } 38 | 39 | private int movingCountCore(int threshold, int rows, int cols, 40 | int row, int col, boolean[][] isVisited) { 41 | if (row < 0 || col < 0 || row >= rows || col >= cols || isVisited[row][col] 42 | || cal(row) + cal(col) > threshold) 43 | return 0; 44 | isVisited[row][col] = true; 45 | return 1 + movingCountCore(threshold, rows, cols, row - 1, col, isVisited) 46 | + movingCountCore(threshold, rows, cols, row + 1, col, isVisited) 47 | + movingCountCore(threshold, rows, cols, row, col - 1, isVisited) 48 | + movingCountCore(threshold, rows, cols, row, col + 1, isVisited); 49 | } 50 | 51 | private int cal(int num) { 52 | int sum = 0; 53 | while (num > 0) { 54 | sum += num % 10; 55 | num /= 10; 56 | } 57 | return sum; 58 | } 59 | 60 | public static void main(String[] args) { 61 | int[] a = {2, 4, 6, 1, 3, 5}; 62 | new JZ13().reOrderArray(a); 63 | for (int i : a) { 64 | System.out.println(i); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /android_notes/使用wsl2编译aosp步骤.md: -------------------------------------------------------------------------------- 1 | 1. 首先安装并启动wsl2,这里我选的是Ubuntu20.04 2 | 2. 替换清华源,科学上网: 3 | `sudo vim /etc/apt/sources.list` 4 | 将内容替换为: 5 | 6 | ``` 7 | #添加清华源 8 | deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal main restricted universe multiverse 9 | # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal main restricted universe multiverse 10 | deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-updates main restricted universe multiverse 11 | # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-updates main restricted universe multiverse 12 | deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-backports main restricted universe multiverse 13 | # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-backports main restricted universe multiverse 14 | deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-security main restricted universe multiverse 15 | # deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-security main restricted universe multiverse multiverse 16 | ``` 17 | 18 | 然后执行 19 | `sudo apt update` 20 | 21 | 3. 开始准备aosp代码 22 | 23 | ``` 24 | mkdir aosp 25 | cd aosp 26 | #准备repo 27 | curl https://mirrors.tuna.tsinghua.edu.cn/git/git-repo -o repo 28 | chmod +x repo 29 | export REPO_URL='https://mirrors.tuna.tsinghua.edu.cn/git/git-repo' 30 | #建立仓库 这里我选了Android13 31 | ./repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest -b android-13.0.0_r1 32 | #另外也可以选Android10r41 33 | ./repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest -b android-10.0.0_r41 34 | #同步代码 35 | ./repo sync 36 | ``` 37 | 38 | 4. 编译aosp 39 | 40 | ``` 41 | # 配置aosp脚本环境 42 | source build/envsetup.sh 43 | # 选择镜像(这里我试过65和67,不同的镜像可能会遇到不同的问题)(如果是Android10的话可以选26,这个我试过) 44 | lunch 45 | # 开始编译 46 | m 47 | # 可选项 google推荐安装的一些包 48 | sudo apt install git-core gnupg flex bison build-essential zip curl zlib1g-dev libc6-dev-i386 x11proto-core-dev libx11-dev lib32z1-dev libgl1-mesa-dev libxml2-utils xsltproc unzip fontconfig 49 | # 缺少so库的情况 比如libncurses5,注意i386可能找不到,但这个经我测试也是非必须的 50 | sudo add-apt-repository universe 51 | sudo apt-get install libncurses5 libncurses5:i386 52 | # 如果是Android10的话还需要python2 53 | sudo apt install python2 54 | # 并且aosp里有python脚本需要用到python命令,这里搞个符号链接 55 | sudo ln -sfn /usr/bin/python2 /usr/bin/python 56 | # 启动模拟器 57 | emulator 58 | # 在wsl下会因为缺少kvm加速报错 59 | # emulator -no-accel 60 | ``` 61 | 62 | 5. 删除launcher search搜索框 63 | ``` 64 | # 打开aosp中这个文件:packages/apps/Launcher3/src/com/android/launcher3/Workspace.java 删除这些代码 65 | CellLayout.LayoutParams lp = new CellLayout.LayoutParams(0, 0, firstPage.getCountX(), 1); 66 | lp.canReorder = false; 67 | if (!firstPage.addViewToCellLayout(qsb, 0, R.id.search_container_workspace, lp, true)) { 68 | Log.e(TAG, "Failed to add to item at (0, 0) to CellLayout"); 69 | } 70 | # 打开aosp中这个文件:packages/apps/Launcher3/res/layout/search_container_workspace.xml 删除这些代码 71 | 76 | # 现在重新运行 m -j16或者m,然后运行emulator,现在搜索栏就已经被删掉了 77 | ``` 78 | 6. 使用AIDEGEN 79 | ``` 80 | # 使用AIDEGEN调用Android Studio打开Settings模块 81 | aidegen Settings -i s -p /snap/android-studio/current/bin/studio.sh 82 | # 参考:将Android Studio添加进环境变量 83 | export PATH=$PATH:/snap/android-studio/current/bin 84 | # 最后设置下SDK和JDK就可以了 85 | ``` -------------------------------------------------------------------------------- /algorithm/Sort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include"Student.h" 3 | #include"SortTestHelper.h" 4 | using namespace std; 5 | //选择排序 6 | template 7 | void selectionSort(T arr[],int n){ 8 | for(int i=0;i 20 | void insertionSort(T arr[],int n){ 21 | for(int i=1;i0&&arr[j-1]>e;j--){ 25 | arr[j]=arr[j-1]; 26 | } 27 | arr[j]=e; 28 | } 29 | } 30 | //冒泡排序 31 | template 32 | void bubbleSort(T arr[],int n){ 33 | for(int i=0;i 42 | void shellSort(T arr[],int n){ 43 | int gap=n/2; 44 | while(gap>1){ 45 | for(int i=0;iarr[i+gap]) 47 | swap(arr[i],arr[i+gap]); 48 | } 49 | gap=gap/2; 50 | } 51 | insertionSort(arr,n); 52 | } 53 | //归并排序 54 | template 55 | void mergeSort(T arr[],int l,int r){ 56 | if(r-l<1) 57 | return;//递归终点 58 | int m=(l+r)/2; 59 | mergeSort(arr,l,m); 60 | mergeSort(arr,m+1,r); 61 | T temp[r-l+1]; 62 | for(int i=l;im){ 67 | arr[k]=temp[j-l]; 68 | j++; 69 | }else if(j>r){ 70 | arr[k]=temp[i-l]; 71 | i++; 72 | } 73 | else if(temp[i-l] 83 | void mergeSort(T arr[],int n){ 84 | mergeSort(arr,0,n-1); 85 | } 86 | //快速排序 87 | template 88 | void quickSort(T arr[],int l,int r){ 89 | if(r-l<1) 90 | return; 91 | T v=arr[l]; 92 | int j=l; 93 | for(int i=l+1;i<=r;i++){ 94 | if(arr[i] 104 | void quickSort(T arr[],int n){ 105 | quickSort(arr,0,n-1); 106 | } 107 | 108 | int main(){ 109 | int a[10]={10,9,8,7,6,5,4,3,2,1}; 110 | selectionSort(a,10); 111 | for(int i=0;i<10;i++){ 112 | cout<K(x,y)=12πσ2ex2+y22σ2 24 | 25 | LaTeX代码: 26 | `K(x, y) = \\frac{1}{2\\pi \\sigma^2} e^{-\\frac{x^2 + y^2}{2\\sigma^2}} ` 27 | 28 | 变量解释:**(**x**,**y**)**:像素相对于核中心的坐标 29 | **σ**:标准差,控制模糊强度(**σ**>**0**)。 30 | 数学原理在此不做展开解释 31 | 32 | ###### 构造一个3*3的卷积核 33 | 34 | $$ 35 | K = \frac{1}{16} 36 | \begin{bmatrix} 37 | 1 & 2 & 1 \\ 38 | 2 & 4 & 2 \\ 39 | 1 & 2 & 1 \\ 40 | \end{bmatrix} 41 | $$ 42 | 43 | 详细说明这个卷积核是如何构造出来的: 44 | 45 | 1. 确定采样点:对于 3×3 的核,我们取 x 和 y 在 [-1, 0, 1] 上的整数值。因此需要计算以下9个点的值: 46 | (x,y) = (-1,-1), (-1,0), (-1,1), 47 | (0,-1), (0,0), (0,1), 48 | (1,-1), (1,0), (1,1) 49 | 2. 计算各点的高斯值: 50 | G(-1,-1) = (1/2π)e^(-(1+1)/2) = (1/2π)e^-1 ≈ 0.0585 51 | G(-1,0) = (1/2π)e^(-(1+0)/2) = (1/2π)e^-0.5 ≈ 0.0965 52 | G(-1,1) = 同 G(-1,-1) ≈ 0.0585 53 | G(0,-1) = 同 G(-1,0) ≈ 0.0965 54 | G(0,0) = (1/2π)e^0 = 1/2π ≈ 0.1592 55 | G(0,1) = 同 G(0,-1) ≈ 0.0965 56 | G(1,-1) = 同 G(-1,-1) ≈ 0.0585 57 | G(1,0) = 同 G(-1,0) ≈ 0.0965 58 | G(1,1) = 同 G(-1,-1) ≈ 0.0585 59 | 3. 将上述值排列成矩阵: 60 | 61 | $$ 62 | \begin{bmatrix}0.0585 & 0.0965 & 0.0585 \\0.0965 & 0.1592 & 0.0965 \\0.0585 & 0.0965 & 0.0585 \\ 63 | \end{bmatrix} 64 | $$ 65 | 66 | 4. 计算归一化系数:总和 ≈ 4×0.0585 + 4×0.0965 + 0.1592 ≈ 0.234 + 0.386 + 0.159 ≈ 0.779。归一化系数为 1/0.779 ≈ 1.2837 67 | 5. 归一化后的核:将每个元素乘以归一化系数: 68 | 0.0585×1.2837 ≈ 0.075 69 | 0.0965×1.2837 ≈ 0.124 70 | 0.1592×1.2837 ≈ 0.204 71 | 6. 近似为整数:为了简化计算,通常会将核中的值近似为最接近的整数比例: 72 | 0.075 ≈ 1/16 73 | 0.124 ≈ 2/16 74 | 0.204 ≈ 4/16 75 | 76 | 因此得到常用的整数比例核: 77 | 78 | $$ 79 | K = \frac{1}{16} 80 | \begin{bmatrix} 81 | 1 & 2 & 1 \\ 82 | 2 & 4 & 2 \\ 83 | 1 & 2 & 1 \\ 84 | \end{bmatrix} 85 | $$ 86 | 87 | ##### 矩阵运算实现高斯模糊效果 88 | 89 | 假设有一个 3×3 的 RGB 图像和一个 3×3 高斯核。图像的像素矩阵为: 90 | 91 | ``` 92 | [ 93 | [[100, 50, 20], [200, 100, 30], [50, 60, 70]], 94 | [[80, 90, 10], [150, 120, 80], [90, 80, 70]], 95 | [[70, 60, 50], [110, 100, 90], [40, 30, 20]] 96 | ] 97 | ``` 98 | 99 | 高斯核为: 100 | 101 | $$ 102 | K = \frac{1}{16} 103 | \begin{bmatrix} 104 | 1 & 2 & 1 \\ 105 | 2 & 4 & 2 \\ 106 | 1 & 2 & 1 \\ 107 | \end{bmatrix} 108 | $$ 109 | 110 | 那么计算步骤可表示为(以R通道为例): 111 | 112 | 1. 提取 R 通道的 3×3 区域: 113 | 114 | ``` 115 | [[100, 200, 50], 116 | [80, 150, 90], 117 | [70, 110, 40]] 118 | ``` 119 | 120 | 2. 逐元素乘以核权重并求和: 121 | 122 | ``` 123 | 100 * 0.0625 + 200 * 0.125 + 50 * 0.0625 + 124 | 80 * 0.125 + 150 * 0.25 + 90 * 0.125 + 125 | 70 * 0.0625 + 110 * 0.125 + 40 * 0.0625 = 122.5 126 | ``` 127 | 128 | 3. 对 G、B 通道重复上述操作,得到输出像素 `[122, 92, 52]`。那么,一个3*3像素的区域,在与卷积核矩阵运算后,就变为单个像素。 129 | 4. 最后,需要注意的是,对于一个4 * 4像素的图像,需要操作的矩阵运算次数为4次。原理很容易理解,将卷积核理解为一个窗口,对左上角9个像素进行矩阵运算后,将这个“窗口”向右平移一个单位,再进行矩阵运算。每次平移一个单位,如此往复,最终就是进行4次矩阵运算,输出一个2*2像素的图像。 130 | 131 | -------------------------------------------------------------------------------- /basic_notes/introduce_to_gaussian_blur.md: -------------------------------------------------------------------------------- 1 | #### GitHub上markdown的显示效果有些和我在线编辑的有些出入。需要更好的阅读体验可以通过在线预览markdown的方式:https://markdown.lovejade.cn/ 2 | #### 高斯模糊效果的实现原理 3 | 4 | 极简总结步骤: 5 | 6 | 1. 将图片转为像素矩阵 7 | 2. 确认卷积核并进行矩阵运算 8 | 接下来分步骤详细拆解 9 | 10 | ##### 将图片转为像素矩阵 11 | 12 | 所有图片均由像素点组成。每个像素都由颜色通道值组成。对于最常见的三通道像素值(rgb三通道),每个通道占一个字节,也就是8个二进制位,计算机中也经常用3个16进制表示。例如:红色像素 `(255, 0, 0)` → 字节表示为 `[0xFF, 0x00, 0x00]`。 13 | 那么对于一个2*2像素的rgb图像,可以被转为这样的像素矩阵: 14 | 15 | ``` 16 | [(R1,G1,B1), (R2,G2,B2)] // 第一行像素 17 | [(R3,G3,B3), (R4,G4,B4)] // 第二行像素 18 | ``` 19 | 20 | ##### 高斯核的构造 21 | 22 | 高斯模糊效果所用的卷积核的公式: 23 | 24 | K(x,y)=12πσ2ex2+y22σ2 25 | 26 | LaTeX代码: 27 | `K(x, y) = \\frac{1}{2\\pi \\sigma^2} e^{-\\frac{x^2 + y^2}{2\\sigma^2}} ` 28 | 29 | 变量解释:**(**x**,**y**)**:像素相对于核中心的坐标 30 | **σ**:标准差,控制模糊强度(**σ**>**0**)。 31 | 数学原理在此不做展开解释 32 | 33 | ###### 构造一个3*3的卷积核 34 | 35 | $$ 36 | K = \frac{1}{16} 37 | \begin{bmatrix} 38 | 1 & 2 & 1 \\ 39 | 2 & 4 & 2 \\ 40 | 1 & 2 & 1 \\ 41 | \end{bmatrix} 42 | $$ 43 | 44 | 详细说明这个卷积核是如何构造出来的: 45 | 46 | 1. 确定采样点:对于 3×3 的核,我们取 x 和 y 在 [-1, 0, 1] 上的整数值。因此需要计算以下9个点的值: 47 | (x,y) = (-1,-1), (-1,0), (-1,1), 48 | (0,-1), (0,0), (0,1), 49 | (1,-1), (1,0), (1,1) 50 | 2. 计算各点的高斯值: 51 | G(-1,-1) = (1/2π)e^(-(1+1)/2) = (1/2π)e^-1 ≈ 0.0585 52 | G(-1,0) = (1/2π)e^(-(1+0)/2) = (1/2π)e^-0.5 ≈ 0.0965 53 | G(-1,1) = 同 G(-1,-1) ≈ 0.0585 54 | G(0,-1) = 同 G(-1,0) ≈ 0.0965 55 | G(0,0) = (1/2π)e^0 = 1/2π ≈ 0.1592 56 | G(0,1) = 同 G(0,-1) ≈ 0.0965 57 | G(1,-1) = 同 G(-1,-1) ≈ 0.0585 58 | G(1,0) = 同 G(-1,0) ≈ 0.0965 59 | G(1,1) = 同 G(-1,-1) ≈ 0.0585 60 | 3. 将上述值排列成矩阵: 61 | 62 | $$ 63 | \begin{bmatrix}0.0585 & 0.0965 & 0.0585 \\0.0965 & 0.1592 & 0.0965 \\0.0585 & 0.0965 & 0.0585 \\ 64 | \end{bmatrix} 65 | $$ 66 | 67 | 4. 计算归一化系数:总和 ≈ 4×0.0585 + 4×0.0965 + 0.1592 ≈ 0.234 + 0.386 + 0.159 ≈ 0.779。归一化系数为 1/0.779 ≈ 1.2837 68 | 5. 归一化后的核:将每个元素乘以归一化系数: 69 | 0.0585×1.2837 ≈ 0.075 70 | 0.0965×1.2837 ≈ 0.124 71 | 0.1592×1.2837 ≈ 0.204 72 | 6. 近似为整数:为了简化计算,通常会将核中的值近似为最接近的整数比例: 73 | 0.075 ≈ 1/16 74 | 0.124 ≈ 2/16 75 | 0.204 ≈ 4/16 76 | 77 | 因此得到常用的整数比例核: 78 | 79 | $$ 80 | K = \frac{1}{16} 81 | \begin{bmatrix} 82 | 1 & 2 & 1 \\ 83 | 2 & 4 & 2 \\ 84 | 1 & 2 & 1 \\ 85 | \end{bmatrix} 86 | $$ 87 | 88 | ##### 矩阵运算实现高斯模糊效果 89 | 90 | 假设有一个 3×3 的 RGB 图像和一个 3×3 高斯核。图像的像素矩阵为: 91 | 92 | ``` 93 | [ 94 | [[100, 50, 20], [200, 100, 30], [50, 60, 70]], 95 | [[80, 90, 10], [150, 120, 80], [90, 80, 70]], 96 | [[70, 60, 50], [110, 100, 90], [40, 30, 20]] 97 | ] 98 | ``` 99 | 100 | 高斯核为: 101 | 102 | $$ 103 | K = \frac{1}{16} 104 | \begin{bmatrix} 105 | 1 & 2 & 1 \\ 106 | 2 & 4 & 2 \\ 107 | 1 & 2 & 1 \\ 108 | \end{bmatrix} 109 | $$ 110 | 111 | 那么计算步骤可表示为(以R通道为例): 112 | 113 | 1. 提取 R 通道的 3×3 区域: 114 | 115 | ``` 116 | [[100, 200, 50], 117 | [80, 150, 90], 118 | [70, 110, 40]] 119 | ``` 120 | 121 | 2. 逐元素乘以核权重并求和: 122 | 123 | ``` 124 | 100 * 0.0625 + 200 * 0.125 + 50 * 0.0625 + 125 | 80 * 0.125 + 150 * 0.25 + 90 * 0.125 + 126 | 70 * 0.0625 + 110 * 0.125 + 40 * 0.0625 = 122.5 127 | ``` 128 | 129 | 3. 对 G、B 通道重复上述操作,得到输出像素 `[122, 92, 52]`。那么,一个3*3像素的区域,在与卷积核矩阵运算后,就变为单个像素。 130 | 4. 最后,需要注意的是,对于一个4 * 4像素的图像,需要操作的矩阵运算次数为4次。原理很容易理解,将卷积核理解为一个窗口,对左上角9个像素进行矩阵运算后,将这个“窗口”向右平移一个单位,再进行矩阵运算。每次平移一个单位,如此往复,最终就是进行4次矩阵运算,输出一个2*2像素的图像。 131 | 132 | -------------------------------------------------------------------------------- /basic_notes/操作系统.md: -------------------------------------------------------------------------------- 1 | # 操作系统 2 | 3 | ## 线程 4 | 5 | 进程的一条执行路径,调度的基本单位 6 | 7 | ### 单线程出现的问题 8 | 9 | 进程切换开销大,进程通信开销大。 10 | 11 | ### 状态 12 | 13 | 运行,就绪和睡眠,无挂起。 14 | 15 | ### 多线程 16 | 17 | - 内核级多线程(klt) 18 | 19 | 进程中的一个线程被阻塞了,内核能调度同一进程的其他线程占有处理器。线程通信开销小,调度开销大。 20 | 21 | - 用户级多线程(ult) 22 | 23 | 用户空间中线程切换不需要内核模式,可以节省模式切换开销和内核资源。不能利用多处理器,物理并行性不好。一个UTL的阻塞可以引起整个进程的阻塞。 24 | 25 | - 混合式策略 26 | 27 | 线程调度和同步在程序中进行,开销小。多个用户级线程被映射到一些内核级线程上。 28 | 29 | ### 调度层次 30 | 31 | 高级调度:决定能否加入到执行的线程池中 32 | 低级调度:决定哪个可用进程占用处理器执行 33 | 中级调度:决定主存中的可用进程集合 34 | 35 | ### 处理器调度算法 36 | 37 | - 优先数调度算法 38 | 39 | - 确定准则 40 | 41 | 任务的紧迫程度;进程的交互性;使用外设的频度。 42 | 43 | - 短作业优先 44 | - 剩余时间短优先 45 | - 响应比优先 46 | 47 | 响应比=等待时间/估计计算时间 48 | 49 | - 先来先服务 50 | 51 | - 抢占式 52 | - 非抢占式 53 | 54 | - 时间片轮转调度算法 55 | - 分级调度算法 56 | 57 | - 基本思想 58 | 59 | 建立多个不同优先级的就绪进程队列 60 | 多个就绪进程队列按照优先数调度 61 | 高优先级就绪进程分配的时间片短 62 | 单个就绪进程队列中进程的优先数和时间片相同 63 | 64 | - 一般分级原则 65 | 66 | 外设访问,交互性,时间紧迫程度,系统效率,用户立场 67 | 68 | - 彩票调度算法 69 | 70 | ## 进程 71 | 72 | (os管理运行程序的)数据结构P 73 | (运行程序的)内存代码C 74 | (运行程序的)内存数据D 75 | (运行程序的)通用寄存器信息R 76 | (os控制程序执行的)程序状态字信息PSW 77 | 78 | ### 进程状态 79 | 80 | - 运行态 81 | - 就绪态 82 | - 等待态 83 | 84 | 不具备运行条件 85 | 86 | - 挂起 87 | 88 | 运行资源不足时表现为性能低和死锁两种情况。不具备任何资源。这时候就挂起了。 89 | 90 | ### 进程映像(内存映像) 91 | 92 | - 控制块 93 | 94 | - 标识信息 95 | 96 | 存放标识号,进程组标识号等 97 | 98 | - 现场信息 99 | 100 | 用户可见寄存器内容:数据寄存器,地址寄存器 101 | 控制与状态寄存器内容 102 | 栈指针内容:核心栈与用户栈指针 103 | 104 | - 控制信息 105 | 106 | 调度相关信息 107 | 进程组成信息 108 | 队列指引元 109 | 进程特权信息 110 | 通信相关信息 111 | 处理器实用信息 112 | 113 | - 程序块 114 | - 数据块 115 | - 核心栈 116 | 117 | ### 进程切换 118 | 119 | - 原语 120 | 121 | 由若干条指令构成的完成某种特定功能的程序,具有不可分割性。 122 | 123 | - 过程 124 | 125 | 保存中断程序上下文 126 | 转向进程调度 127 | 恢复待运行进程上下文 128 | 129 | - 模式切换 130 | 131 | 处理器状态(用户模式/内核模式)切换 132 | 133 | ## 作业级接口 134 | 135 | ### 脱机作业控制方式 136 | 137 | ### 联机作业控制方式 138 | 139 | ## 存储管理 140 | 141 | ### 基本模式 142 | 143 | 单连续存储管理 144 | 段式存储管理 145 | 页式存储管理 146 | 段页式存储管理 147 | 主存空间已满又需要装入新页时,页式虚拟存储器需要把已在主存的一些页调出去。 148 | 缺页中断率=失败访问次数/总访问次数。 149 | 150 | - LRU(最近最少用)算法 151 | 152 | - LFU(最不常用)算法 153 | - 时钟clock算法 154 | 155 | 页面调入主存时标志位为1,访问主存页面时标志位为1.淘汰页面时,扫描循环队列,跳过标志位为1的页面并清0,淘汰标志位为0的页面并推进指针。 156 | 157 | - FIFO(先进先出)算法 158 | - 内存管理单元MMU 159 | 160 | 管理内存时需要用到反置页表。按照页架号寻找页号和进程号。 161 | 162 | ### 地址转换(重定位) 163 | 164 | 把逻辑地址转换成绝对地址 165 | 166 | ### 虚拟存储器 167 | 168 | 把主存进程信息保存在辅存中,随用随加载,对用户透明。 169 | 170 | ## 设备管理 171 | 172 | ### 总线与IO 173 | 174 | - 三级总线模型 175 | 176 | cpu+cache——主存——io设备 177 | 178 | - 南桥北桥模型 179 | 180 | 北桥连cpu与主存,走pci总线,南桥连比较慢的io接口,比较慢的isa总线。 181 | 182 | - IO缓冲技术 183 | 184 | 解决cpu与设备速度不匹配的问题,协调逻辑记录大小和物理记录大小不一致的问题,提高cpu和设备的并行性。 185 | 186 | ### 设备独立性 187 | 188 | 不指定物理设备而是指定逻辑设备,建立逻辑设备和物理设备之间的映射。 189 | 190 | ## 文件 191 | 192 | ### 组织 193 | 194 | - 逻辑方法 195 | 196 | 流式文件与记录式文件 197 | 198 | - 物理结构 199 | 200 | 顺序文件/连接文件/直接文件/索引文件 201 | 202 | ### 存取 203 | 204 | 顺序存取,直接存取,索引存取 205 | 206 | ### 控制 207 | 208 | 逻辑的控制系统与物理的控制系统 209 | 210 | ### 使用 211 | 212 | 打开,关闭,读,写,控制 213 | 214 | ## 并发程序设计 215 | 216 | 并行性,共享性,交往性(并发时的限制) 217 | 218 | ### 顺序程序设计 219 | 220 | 顺序性,封闭性,确定性,可再见性 221 | 222 | ### 进程协同与进程互斥 223 | 224 | ### 互斥与临界区 225 | 226 | 临界资源:互斥共享变量所代表的资源。多个并发进程访问临界资源时,存在竞争制约关系。 227 | 228 | - 临界区的设计要求 229 | 230 | 一次至多允许一个进程停留 231 | 不能无限制的停留 232 | 其他进程不能无限制的等待进入 233 | 234 | - 临界区的实现方法 235 | 236 | 用一条指令完成测试并占领临界区。 237 | 238 | - 开关中断 239 | 240 | 进临界区关中断,出临界区开中断。用户程序不应该使用开关中断。 241 | 242 | ### 信号量 243 | 244 | - 记录型信号量 245 | 246 | 每个信号量建立一个等待进程队列 247 | 每个信号量相关一个整数值 248 | 正值表示资源可复用次数 249 | 0表示无资源且无进程等待 250 | 负数表示等待队列中进程个数 251 | 252 | - PV原语 253 | 254 | p减去进程v增加进程 255 | 256 | - 生产者消费者问题 257 | 258 | ### 管程 259 | 260 | 管程由若干公共变量及其说明和所有访问这些变量的过程所组成。进程只能互斥的调用管程中的过程。 261 | 262 | - 哲学家就餐问题 263 | - 读者写者问题 264 | 265 | ### 进程通信 266 | 267 | 信号量操作时一种低级通信方式 268 | 269 | - 基于信件 270 | - 基于字节流 271 | 272 | 例如管道,socket 273 | 274 | - 基于RPC 275 | 276 | ### 死锁 277 | 278 | 互相等待,永远阻塞。 279 | 280 | - 条件 281 | 282 | 互斥条件;占有和等待条件;不剥夺条件;循环等待条件 283 | 284 | - 防止 285 | 286 | 破坏四个条件之一即可。 287 | 1.把独占性资源变为共享性资源 288 | 2.采用剥夺式调度方法 289 | 290 | - 静态分配(常用) 291 | - 层次分配 292 | 293 | - 避免 294 | 295 | 银行家算法:首先检查最大需求量,满足时才分配资源。 296 | 297 | - 检测和恢复 298 | 299 | 看等待资源表和占有资源表。 300 | 301 | *XMind: ZEN - Trial Version* -------------------------------------------------------------------------------- /android_notes/Android面试笔记.md: -------------------------------------------------------------------------------- 1 | ##### Android八股 2 | 3 | ##### 常见的锁有哪些?lock和sync的区别是什么 4 | sync关键字,读写锁,可重入锁,信号量;lock灵活性更高,需要手动控制锁的释放; 5 | 6 | ##### 关于surface view与texture view 7 | surface view处理高帧率的人物场景,texture view处理裁剪旋转小窗这些场景 8 | 9 | ##### AIDL如何实现接口安全 10 | 1. 信息内容加密 11 | 2. 校验包名和签名 12 | 3. 使用signature级别的自定义权限 13 | 14 | ##### AIDL如何实现双向通信 15 | 通过“接口回调”实现,客户端定义的回调接口,服务端使用 16 | 17 | ##### Webview打开网页慢如何优化 18 | 1. 预加载优化 19 | 2. 合理配置 WebSettings(包括缓存策略) 20 | 3. 注入JavaScript代码,延迟加载非关键资源 21 | 22 | ###### socket和aidl在应用间交换消息时的区别 23 | 24 | 操作不一样,socket需要建立连接关闭连接这些操作,aidl不需要;能传输的数据不一样,按理说socket啥都能传,aidl能传的数据类型是固定的, 具体看文档;aidl有Linux的进程ID概念更加安全 25 | 26 | ###### activity生命周期 27 | 28 | onCreate;onStart 可见状态 还没有显示 不能交互;onResume 可见 可交互;onPause;onStop;onDestroy; onRestart 正常启动不会被调用; 29 | 30 | ###### activity异常情况生命周期补充 31 | 32 | onSaveInstanceState;onRestoreInstanceState bundle在这个方法里不为空,在onStart里面可能为空;bundle是散列形式 33 | 34 | ###### activity状态 35 | 36 | active:处于栈顶 可见 可交互;paused:可见 不可交互;stop:不可见 ;killed:系统回收 37 | 38 | ###### activity启动模式 39 | 40 | standard;singleTop(栈顶复用);singleTask(栈内复用 会销毁目标上面所有activity); singleInstance(全局唯一性,复用性,独占任务栈); 41 | 42 | ###### 支持不同像素密度 43 | 44 | px=dp*dpi/160。dpi是ppi的近似,最初取160的整数倍做近似处理,方便适配。 45 | 46 | ###### okhttp上传一个文件 47 | 48 | ``` 49 | OkHttpClient client = new OkHttpClient(); 50 | 51 | RequestBody requestBody = new MultipartBody.Builder() 52 | .addFormDataPart("new", "This is my new TODO") 53 | .addFormDataPart("image", "attachment.png", 54 | RequestBody.create(new File("path/of/attachment.png"), MediaType.parse("image/png")) 55 | ) 56 | .setType(MultipartBody.FORM) 57 | .build(); 58 | 59 | Request postRequest = new Request.Builder() 60 | .url("https://mytodoserver.com/new") 61 | .post(requestBody) 62 | .build(); 63 | 64 | try { 65 | Response response = client.newCall(postRequest).execute(); 66 | System.out.println(response.body().string()); 67 | } catch (IOException e) { 68 | e.printStackTrace(); 69 | } 70 | 71 | ``` 72 | 73 | ###### activity与fragment通信 74 | 75 | bundle getArgument可以获取bundle;直接在activity定义方法; 76 | 77 | ###### fragment与activity通信 78 | 79 | 接口回调 1.在fragment中定义内部回调方法 2.attach方法中检查 3.detach方法释放activity 80 | 81 | ###### activity与service通信 82 | 83 | 1 绑定服务 利用service_connection接口(自己实现binder内部类);2简单通信 intent传值;3定义callback接口(自己实现binder内部类) 84 | 85 | ###### service与thread 86 | 87 | thread就是正常的线程生命周期,缺陷在于**无法控制**。service运行在主线程。 88 | ###### service生命周期 89 | startService:onCreate onStartCommand(执行多次) onDestroy; 90 | bindService:onCreate onBind onUnbind onDestroy;如果已经绑定service,在解绑之前无法销毁。 91 | ###### service与intentService 92 | intentService自动停止,内部有子线程处理耗时操作。源码层面上,intentService继承了service,在onCreate内创建handlerThread,并且 93 | 绑定looper。 94 | ###### 启动服务和绑定服务 95 | 启动优先级比绑定高,无论哪种状态都可以直接开启服务。启动服务后即使相关activity被销毁,service也不会销毁。 96 | ###### 序列化 97 | 98 | 把内存中的对象写入磁盘。parcelable接口与serializable接口。 99 | 100 | ###### AIDL 101 | 102 | 创建AIDL;服务端新建service,创建binder对象;客户端:实现service_connection,bindService 103 | 104 | ###### handler 105 | 106 | handler获取当前线程looper,looper取出messageQueue,完成三者绑定。messageQueue内部是链表实现。threadLocal获取当前线程looper。 107 | 创建looper的时候(构造函数)创建了messageQueue。handler获取looper是用的myLooper方法,点进去就是threadLocal的get方法。在looper 108 | 的loop方法里面有一个死循环,消息不为空的时候回调dispatchMessage方法,最后handler调用handleMessage方法。looper是在主线程的,因此 在子线程中不能直接new handler。 109 | 110 | ###### asyncTask 111 | 112 | 本质是handler和线程池的封装,实例只能在主线程中创建。最大线程数=cpu核心数*2+1。 113 | 114 | ###### aidl 115 | 116 | 服务端创建aidl;
117 | 服务端实现aidl并向客户端开放接口(创建service ,声明ibinder,实现stub实例。stub实例中实现的方法就是后面供客户端调用的方法); 118 |
客户端调用aidl(包目录保持一致,然后绑定服务即可,绑定的时候走stub的asinterface方法); 119 | 120 | ###### butterKnife原理 121 | 122 | 1 扫描所有Java代码中的butterKnife注解 2 ButterKnifeProcessor会根据className生成viewBinder 3 调用bind方法加载生成的viewBinder类、 123 | 124 | ##### 网络基础八股 125 | 126 | ##### 浏览器输入地址到返回结果发生了什么 127 | 128 | 1、DNS解析,此外还有DNSy优化(DNS缓存、DNS负载均衡) ;2、TCP连接 ;3、发送HTTP请求 ;4、服务器处理请求并返回HTTP报文 ; 5、浏览器解析渲染页面 ;6、连接结束 129 | 130 | ###### socket连接与http连接 131 | 132 | 一般socket建立起来的是tcp连接,HTTP连接使用的是“请求—响应”的方式,socket连接适用于服务器主动向客户端发送数据的场景。http连接可以是 长连接也可以是短连接,看实际业务需求,短连接就是一次交互之后就会断开。 133 | 134 | ###### https四次握手 135 | 136 | 1 客户端请求建立SSL链接,并向服务端发送一个随机数–Client random和客户端支持的加密方法,比如RSA公钥加密,此时是明文传输。
137 | 2 服务端回复一种客户端支持的加密方法、一个随机数–Server random、授信的服务器证书和非对称加密的公钥。
138 | 3 客户端收到服务端的回复后利用服务端的公钥,加上新的随机数–Premaster secret 通过服务端下发的公钥及加密方法进行加密,发送给服务器。
139 | 4 服务端收到客户端的回复,利用已知的加解密方式进行解密,同时利用Client random、Server random和Premaster secret通过一定的算法 生成HTTP链接数据传输的对称加密key – session 140 | key。
141 |
个人总结和tcp三次握手基本一样,发送的随机数作用就和syn和ack的作用差不多,区别就是每次携带了支持的加密类型或者公钥。最后多出来的一次 握手其实就是服务端做的解密工作。 142 | 143 | ###### 对称加密与非对称加密 144 | 145 | AES与DES都是对称加密,DES因为密钥太短已被弃用。非对称加密的加密算法和解密算法是相同的,只是公钥和私钥不同。数字签名就是签名方使用私钥加密, 146 | 各解密方用公钥解密。签名算法也可以用更简便的方式(对哈希值签名)。主流算法是RSA与DSA。 147 | 148 | ###### 常见编码 149 | 150 | base64:将二进制数据转换成由64个字符组成的字符串的编码算法;urlencoding:将URL中的保留字符使用百分号"%"进行编码,为了消除歧义。 151 | 152 | ##### 操作系统八股 153 | 154 | ###### 软连接与硬链接 155 | 156 | 软连接就是快捷方式,硬链接就是路径别名。当所有硬链接全删掉时,文件才真正被删除 -------------------------------------------------------------------------------- /basic_notes/计算机组成原理.md: -------------------------------------------------------------------------------- 1 | # 计算机组成原理 2 | 3 | ## 基本概念 4 | 5 | ### 冯诺依曼 6 | 7 | 运算器,输入设备,输出设备,存储器,控制器。其余四个逻辑模块都要与控制器传输状态信息。 8 | cpu由运算器和控制器组成。运算器主要负责算术运算和逻辑运算组成,由alu(算数逻辑单元)组成。 9 | 10 | ### 数字代码 11 | 12 | 电平信号:高电平表示1 低电平表示0 13 | 脉冲信号:有脉冲表示1 无脉冲表示0 14 | 优点:物理上易于实现和存储;抗干扰,可靠;数值范围大,精度高;可表示的信息类型广泛;数字逻辑进行处理 15 | 源码就是只关注符号位,正数的反码就是自己,负数的反码符号位是1,数值位按位取反。正数的补码就是自己,负数的补码就是符号位仍然为1,数值位按位取反再加一。 16 | 正数的移码就是源码符号位取反,负数的移码就是源码连同符号位一起取反,末位再加一 17 | 浮点数的尾数规格化,导致精度有所缺失(所以浮点数在编程里一般都是比较大小) 18 | 19 | ### 发展历史 20 | 21 | 1946-1957:电子管器件,速度低体积大价格贵不可靠 22 | 1958-1964:晶体管器件,体积小可靠,可用于数据处理 23 | 1965-1971:中小规模集成电路器件,更小体积更强算力,拓展到民用领域 24 | 1971至今:超大规模集成电路器件,微型计算机出现 25 | 26 | ### 性能指标 27 | 28 | 基本字长:一次数据操作的基本位数 29 | 外频:系统时钟频率 30 | 带宽:位宽*工作频率/8,表示单位时间内数据的传输量 31 | 内存:可编址的存储单元个数*存储单元的位宽 32 | 33 | ## 总线与IO系统 34 | 35 | 总线:连接各功能部件并承载信息传送 36 | (分时共享) 37 | IO接口:主机和外设的衔接部分。基本功能是设备寻址(接受cpu的地址码选择接口中的寄存器供cpu访问)与数据缓冲(实现主机与外设的速度匹配) 38 | PCI总线(外围组件互联):高性能同步总线,地址信号和数据信号复用 39 | 40 | ### IO接口分类 41 | 42 | - 按数据传送格式 43 | 44 | 串行接口:接口与外设一侧串行传送(传的远) 45 | 并行接口:接口两侧均并行传输数据(传的近) 46 | 47 | - 按时序控制 48 | 49 | 同步接口与异步接口(接口与系统总线的信息传送) 50 | 51 | - 操作控制方式 52 | 53 | PIO接口 54 | 中断接口 55 | DMA接口 56 | IOP/PPU接口 57 | 58 | ### 总线结构 59 | 60 | - 单总线结构 61 | 62 | 部件之间信息交互的唯一通路 63 | 64 | - 多总线结构 65 | 66 | ### 总线设计要素 67 | 68 | - 带宽与传输模式 69 | - 控制方式 70 | 71 | 同步总线:统一的时序信号控制总线上的传送操作 72 | 异步总线:无固定的时钟周期划分,总线周期由传送的实际需要决定,异步应答方式控制总线传送操作 73 | 74 | - 仲裁方式 75 | 76 | 解决总线控制权的争夺问题。 77 | 78 | ### 中断方式与接口 79 | 80 | - 软硬件组织 81 | 82 | - 软件 83 | 84 | 中断服务程序,中断向量表(通过中断向量表找到程序地址,然后在软件层面操作) 85 | 86 | - 硬件 87 | 88 | 接口方面:请求,屏蔽,传递,判优等逻辑 89 | cpu:对中断请求的响应逻辑 90 | 91 | - 中断的全过程 92 | 93 | 产生中断:外设有中断请求需要;该中断没有被屏蔽 94 | 传送中断请求:使用单独请求线;公共请求线;混合方式传送 95 | 96 | - CPU对中断请求的响应 97 | 98 | - 响应条件 99 | 100 | 有未被屏蔽的中断请求到达; 101 | cpu处于开中断模式; 102 | 中断源优先级比当前程序优先级更高; 103 | cpu刚执行完一条指令 104 | 105 | - 形成中断服务程序入口地址 106 | 107 | 取决于中断方式 108 | 向量中断:将所有中断源的中断服务程序入口地址组织在公共查询程序中,cpu执行此查询程序确定入口地址 109 | 非向量中断:将入口地址组织在中断向量表中,cpu由硬件产生向量地址,再根据中断向量表查询程序入口地址 110 | 111 | - 中断的响应过程 112 | 113 | 执行中断隐指令——中断服务程序 114 | 115 | ### DMA与磁盘接口 116 | 117 | DMA(直接内存权限)直接依靠硬件系统控制主存与外设之间的数据传送,无需cpu干预,传送之后以中断方式通知CPU。 118 | 119 | - DMA数据传送模式 120 | 121 | 单字传送,成组连续传送。区别在于每次分配的总线周期数量。 122 | 123 | - DMA传送操作过程 124 | 125 | 空闲——已请求——接管——读——写——判别。 126 | 读写操作不能在一个时钟周期完成的话就进入延长阶段。 127 | 判别之后单字传送方式会回到空闲状态,成组传送方式会回到接管状态。 128 | 129 | ### iop与ppu模式 130 | 131 | iop:输入输出处理器 132 | ppu:外围处理单元 133 | 134 | - 通道类型 135 | 136 | 选择型通路(单路),多路型通道。多路型通道又分为字节多路型和数组多路型。都可以连接多路外设每个通路仅连接一个外设。区别在于字节多路型每次只传输一个字节,数组多路型每次连续传输多个字节(定长数据块)。 137 | 138 | - 通道结构与工作原理 139 | 140 | 连接系统总线接口与IO总线接口,核心是通道控制器。 141 | 通道的工作过程: 142 | 1.程序提出io请求,cpu响应后组织通道程序并存储到主存,保存首地址(caw)和数据传输量 143 | 2.初始化通道和设备号,发出启动命令 144 | 3.通道接收启动命令,读取caw 145 | 4.通道对外设寻址,连接到外设 146 | 5.读取通道程序首条ccw,启动外设 147 | 6.继续执行ccw控制io操作,更新cswr 148 | 7.io结束,通道发出结束命令,中断请求,将cswr保存到主存单元 149 | 8.cpu响应中断,切换到服务程序进行io善后管理 150 | 151 | ## CPU 152 | 153 | ### 主要部件 154 | 155 | 时序系统,控制部件,缓存部件,寄存器,运算部件 156 | 157 | ### 指令 158 | 159 | CISC(复杂指令集)与risc(精简指令集)。简单指令(约占20%)约占80%使用频率。简单指令数量多,长度可以不固定,指令格式和寻址方式多样。 160 | 指令格式分为操作码+地址码/操作数。 161 | 162 | ### 寻址方式 163 | 164 | 立即寻址:指令中包含操作数 165 | 直接寻址:指令中给出操作数的地址码。包含主存直接寻址和寄存器直接寻址。 166 | 间接寻址:指令给出操作数的间接地址,包含存储单元地址或者寄存器编号 167 | 变址寻址:指令给出一个寄存器号和一个地址量,寄存器内容与地址和为有效地址 168 | 基址寻址:指令给出一个寄存器号和一个地址量,寄存器内同与地址量之和为有效地址。与变址寻址的区别在于,变址寻址是指令提供基准量寄存器提供偏移量,基址寻址是指令提供偏移量寄存器提供基准量 169 | pc相对寻址:指令给出偏移量,pc当前值(程序指针寄存器)(隐含指定)与偏移量相加得到有效地址 170 | 页面寻址:指令给出位移量,pc高位部分与位移量拼接,形成有效地址 171 | 172 | ### mips32指令集 173 | 174 | 按字节编址,可用寄存器32个,位宽32位,risc架构。 175 | 单周期cpu:指令固定在一个时钟周期内完成,时间效率低,时钟宽度由单指令最长时间决定 176 | 多周期cpu:指令分散在多个时钟周期内完成,时钟宽度由单步最长时间决定 177 | (数据通路设计不在这做笔记) 178 | (控制系统设计不在这做笔记) 179 | 180 | ### 流水技术 181 | 182 | 指令过程分解为若干子过程,每个子过程都可以在专用功能段上与其他子过程重叠执行 183 | 184 | ## 校验算法 185 | 186 | ### 奇偶校验 187 | 188 | 在原始码流后面加上校验位,校验位只有一位。偶校验就是加上校验位之后有偶数个1,奇校验就是加上校验位之后有奇数个1.奇偶校验只能检测出奇数个错误 189 | 190 | ### 海明校验 191 | 192 | 带分组的奇偶校验,不止能检测出错误还能检测出错误的位置 193 | 194 | ### 循环冗余校验 195 | 196 | 假设信息码字为11100011,生成多项式 197 | G(X)=X^5+X^4+X+1,计算CRC码字。 198 | 199 | G(X) = X^5+X^4+X+1,也就是110011,因为最高次是5,所以,在信息码字后补5个0,变为1110001100000。用1110001100000模二除法除以110011,余数为11010,即为所求的冗余位。 200 | 因此发送出去的CRC码字为原始码字11100011末尾加上冗余位11010,即 1110001111010。接收端收到码字后,采用同样的方法验证,即将收到的码字用模二除法除以110011(是G(X)对应的二进制生成码),发现余数是0,则认为码字在传输过程中没有出错。 201 | 202 | ## 存储子系统 203 | 204 | 层次结构:CPU(cache)(L1-L2-L3)-主存-外存 205 | 内存主要存档CPU当前使用的指令和数据,可以随机访问(访问地址和访问时间没有关系),工作速度快,有足够的存储容量 206 | 207 | ### 按存储介质分类 208 | 209 | - 半导体存储器 210 | 211 | 静态存储器和动态存储器(主存) 212 | 动态存储器需要刷新,定期向电容补充电荷。重写是破坏性读出后的自动操作,刷新与读写操作无关。 213 | 214 | - 光盘存储器 215 | 216 | 原理:用激光照射存储介质,使其发生物理化学变化,据此记录信息 217 | 218 | - 磁表面存储器 219 | 220 | 利用磁层上不同方向的磁化区域表示信息,容量大,非破坏性读出,长期保存信息,速度慢(外存) 221 | 存储介质:磁层材料 222 | 写入方式:不归零1制:写0电流不变,写1电流翻转。调频制:每次起始处写入电流跳变1次,以作为同步信号,在中间位置写0则不变写1则跳变 223 | 224 | - 信息分布 225 | 226 | 盘组:多个盘片,双面记录 227 | 圆柱面:各记录面上相同序号的磁道构成一个圆柱面(柱面数=/道数/面) 228 | 数据块:扇区(定长记录格式)+记录块(不定长记录格式) 229 | 230 | - 寻址路径 231 | 232 | 驱动器号——圆柱面号——磁头号——扇区号——字节序号 233 | 234 | ### 技术指标 235 | 236 | - 存取时间 237 | - 存取周期 238 | 239 | 存取时间+恢复期 240 | 241 | - 数据传输率 242 | 243 | 单位时间内输入或者读出数据的量 244 | 245 | ### cache替换算法 246 | 247 | 最不经常使用(LFU):将一段时间内被访问次数最少的部分从cache中置换出去 248 | 近期最久未使用(LRU):将近期内最久违背访问过的cache块置换出去 249 | 随机置换:随机确定将哪块cache置换出去 250 | 251 | ## io设备 252 | 253 | ### 键盘及其接口 254 | 255 | 触点式,无触点式,虚拟式。键盘扫描程序包含逐行骚猫,行列扫描。 256 | 257 | ### 显示设备及接口 258 | 259 | 显示方式:字符方式(以字符为显示单位),图像模式(以像素为显示单位) 260 | 261 | *XMind: ZEN - Trial Version* -------------------------------------------------------------------------------- /android_notes/Java基础知识.md: -------------------------------------------------------------------------------- 1 | ##### Java八股 2 | 3 | ###### 序列化 4 | 5 | 把内存中的数据变成可以被存储、传输的格式 6 | 7 | ###### equals与hashcode 8 | 9 | hashcode表示指纹信息,hash里面有内存地址 10 | 11 | ###### 按行读取文件 12 | 13 | ``` 14 | private static void readFile1(File fin) throws IOException { 15 | FileInputStream fis = new FileInputStream(fin); 16 | 17 | //Construct BufferedReader from InputStreamReader 18 | BufferedReader br = new BufferedReader(new InputStreamReader(fis)); 19 | 20 | String line = null; 21 | while ((line = br.readLine()) != null) { 22 | System.out.println(line); 23 | } 24 | 25 | br.close(); 26 | } 27 | ``` 28 | 29 | ###### get与post的区别 30 | 31 | 本质上没区别,都是tcp链接。给GET加上request body,给POST带上url参数,技术上是完全行的通的。只是HTTP的规定和浏览器/服务器的限制, 导致他们在应用过程中体现出一些不同。 restful 32 | api的要求是get请求用来从服务器上获得资源,而post是用来向服务器提交数据。另外,对于GET 方式的请求,浏览器会把http 33 | header和data一并发送出去,服务器响应200(返回数据);而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 34 | ok(返回数据)。在网络环境好的情况下,发一次包的时间和发两次包的时间差别基本可以无视。 而在网络环境差的情况下,两次包的TCP在验证数据包完整性上,有非常大的优点。并且,也不是所有浏览器post都发两次,firefox就只发一次。 35 | 36 | ###### hashmap与hashtable 37 | 38 | 二者没有本质区别,hash算法大致相同。无非是继承Dictionary类或者实现map接口,对null的容忍度,是否本身限制Synchronized这些区别。 39 | 40 | #### hashmap源码解读 41 | 42 | 哈希表的核心原理是基于和哈希值的桶和链表,缺陷是哈希碰撞。另外linked hashmap就是增加了双向链表的hashmap,用来保持键值对的插入顺序。 43 | 44 | ##### hashmap的经典实现(jdk1.7) 45 | 46 | ###### hashmap初始容量是多少?为什么是这个数字? 47 | 48 | 初始容量是16,负载因子是0.75。容量是2的幂,如果不是2的幂会向上取幂。默认的哈希桶有16个,hash值有42E个,如何把42E个hash值放进16个 49 | hash桶?首先想到的是取模。取模的问题有两点:第一是负数求模还是正数,第二是效率不如位运算。负载因子是一个在时间与空间开销上折衷的选择。 过高的负载因子可以减少空间使用,但是会增加查找消耗。 50 | 51 | ###### 为什么容量一定是2的幂? 52 | 53 | 确定hash桶的方式是长度-1然后与hash值进行按位与运算:(length-1)&hash。只有容量是2的n次方的时候,-1操作才能拿到全部都是1的值,这样 进行按位与操作的时候才能快速拿到分布均匀的数组下标。 54 | PS:为了减少哈希碰撞,1.7的hash值做了很多的异或运算,在1.8被废弃。 55 | 56 | ###### 扩容原理 57 | 58 | 已使用超过容量*负载因子数量的时候就会产生很多哈希碰撞,开始扩容:对所有元素重新计算hash值,同时容量翻倍。另外即使容量减少也不会出现 缩容操作。 59 | 60 | ###### jdk1.7的问题 61 | 62 | 不是线程安全,容易碰到死锁。潜在的安全隐患,致命的哈希碰撞(哈希表变链表,复杂度变成o(n))(能生成大量相同的hash值) 63 | 64 | ##### jdk1.8里的hashmap 65 | 66 | 数组+链表的组合变成了数组+红黑树的组合。注释上说哈希桶容量超过8之后会变成红黑树,在随机产生hashcode的条件下这个概率小于千万分之一, 67 | 因此这个很少被用到。hash值的计算变成了和高16位直接进行的异或运算。1.8不会产生死锁,具体分析待查(酷客上找找) 68 | 69 | ##### array list扩容机制 70 | 71 | ###### 极简总结 72 | 73 | 初始容量为10,扩容时每次增加当前容量一半。 74 | 75 | ###### 详细分析 76 | 77 | 1 初始化方法:以无参数构造方法创建 ArrayList 时,实际上初始化赋值的是一个空数组。当真正对数组进行添加元素操作时,才真正分配容量。 2 add方法:ArrayList添加元素的实质就相当于为数组赋值 3 78 | 判断是否需要扩容:minCapacity(最小扩容量) - elementData.length > 0 4 最小扩容量 添加元素时会比较minCapacity与DEFAULT_CAPACITY,返回较大值。 5 实际扩容操作 int 79 | newCapacity = oldCapacity + (oldCapacity >> 1);然后会比较minCapacity与newCapacity,取较大值作为实际扩容量。 80 | 如果minCapacity大于最大容量(MAX_ARRAY_SIZE),则新容量则为Integer.MAX_VALUE。 6 最后简单复制一下数组:elementData = Arrays.copyOf(elementData, 81 | newCapacity); 82 | 83 | ###### ConcurrentHashMap为什么是线程安全的 84 | 85 | 采用 CAS 和 synchronized 来保证并发安全,synchronized 只锁定当前链表或红黑二叉树的首节点,这样只要 hash 不冲突,就不会产生并发。 关于锁和并发的知识以后再补,这里先打个记号 86 | 87 | ###### 补充一点平衡二叉树的笔记 88 | 89 | 平衡因子被破坏的节点记作根节点
90 | RR旋转: 1.右子树变成新的根节点 2.旧的根节点变成左子树 3.右子树的左子树变成原本根节点的右子树
91 | LL旋转: 1.左子树变成新的根节点 2.旧的根节点变成右子树 3.左子树的右子树变成原本根节点的左子树
92 | LR旋转: 1.根节点的左子树进行右旋转 2.根节点进行左旋转
93 | RL旋转: 1.根节点的右子树进行左旋转 2.根节点进行右旋转
94 | 删除操作: 若左孩子非空,右孩子为空,那么把根节点直接赋值为左子树。若右孩子非空,左孩子为空,那么把根节点直接赋值为右子树。左右子树都不为空时,用左子树最大节点或者右子树最小节点代替根节点 95 | 96 | ###### 多线程操作时为什么调用start而不是run? 97 | 98 | 调用 start 方法方可启动线程并使线程进入就绪状态,而 run 方法只是 thread 的一个普通方法调用,还是在主线程里执行。 99 | 100 | ###### sleep和wait最主要的区别是什么? 101 | 102 | sleep不会释放锁,wait会释放锁。 103 | 104 | ###### 数据库的四大特征 105 | 106 | 原子性,一致性,隔离性,持久性 107 | 108 | ##### 关于MySQL事务隔离级别 109 | 110 | 对于两个并发执行的事务,如果涉及到操作同一条记录的时候,可能会发生问题。因为并发操作会带来数据的不一致性,包括脏读、不可重复读、幻读等。 数据库系统提供了隔离级别来让我们有针对性地选择事务的隔离级别,避免数据不一致的问题。 111 | 112 | ###### Read Uncommitted 113 | 114 | 隔离级别最低的一种事务级别。在这种隔离级别下,一个事务会读到另一个事务更新后但未提交的数据,如果另一个事务回滚, 那么当前事务读到的数据就是脏数据,这就是脏读(Dirty Read)。 115 | 116 | ###### Read Committed 117 | 118 | 在Read Committed隔离级别下,一个事务可能会遇到不可重复读(Non Repeatable Read)的问题。 119 | 不可重复读是指,在一个事务内,多次读同一数据,在这个事务还没有结束时,如果另一个事务恰好修改了这个数据,那么,在第一个事务中, 两次读取的数据就可能不一致。 120 | 121 | ###### Repeatable Read 122 | 123 | 在Repeatable Read隔离级别下,一个事务可能会遇到幻读(Phantom Read)的问题。幻读是指,在一个事务中,第一次查询某条记录, 124 | 发现没有,但是,当试图更新这条不存在的记录时,竟然能成功,并且,再次读取同一条记录,它就神奇地出现了。 125 | 126 | ###### Serializable 127 | 128 | Serializable是最严格的隔离级别。在Serializable隔离级别下,所有事务按照次序依次执行,因此,脏读、不可重复读、幻读都不会出现。 129 | 虽然Serializable隔离级别下的事务具有最高的安全性,但是,由于事务是串行执行,所以效率会大大下降,应用程序的性能会急剧降低。 如果没有特别重要的情景,一般都不会使用Serializable隔离级别。 130 | 131 | ###### cache和buffer的区别 132 | 133 | cache:之前已经用过,等会可以复用;buffer:上游存储,下游消费。区别在于buffer只消费一次。 134 | 135 | ###### ==和equals的区别: 136 | 137 | ==的作用是判断两个对象的地址是否相等,如果是基本数据类型的话就是比较两个值。equals默认的方法等价于==。String的equals方法被重写过了, 138 | 比较的是值。创建String类行的对象的时候,虚拟机会在常量池中查找有没有已经存在的值和要创建的值相同的对象,如果有就把它赋给当前引用。 如果没有就在常量池中重新创建一个 String 对象。 139 | 140 | public class test1 { 141 | public static void main(String[] args) { 142 | String a = new String("ab"); // a 为一个引用 143 | String b = new String("ab"); // b为另一个引用,对象的内容一样 144 | String aa = "ab"; // 放在常量池中 145 | String bb = "ab"; // 从常量池中查找 146 | if (aa == bb) // true 147 | System.out.println("aa==bb"); 148 | if (a == b) // false,非同一对象 149 | System.out.println("a==b"); 150 | if (a.equals(b)) // true 151 | System.out.println("aEQb"); 152 | if (42 == 42.0) { // true 153 | System.out.println("true"); 154 | } 155 | } 156 | } 157 | 158 | ###### 关于常量池的一点代码 159 | 160 | Java 基本类型的包装类的大部分都实现了常量池技术。character缓存相关源码: 161 | 162 | private static class CharacterCache { 163 | private CharacterCache(){} 164 | 165 | static final Character cache[] = new Character[127 + 1]; 166 | static { 167 | for (int i = 0; i < cache.length; i++) 168 | cache[i] = new Character((char)i); 169 | } 170 | } 171 | 172 | ###### hashCode()与 equals() 173 | 174 | hashCode()的默认行为是对堆上的对象产生独特值。hashCode() 所使用的杂凑算法也许刚好会让多个对象传回相同的杂凑值,如果 HashSet在对比 的时候,同样的 hashcode 有多个对象,它会使用 equals() 175 | 来判断是否真的相同。也就是说 hashcode 只是用来缩小查找成本。另外hashcode 只有在散列表中才有用。 176 | 177 | ###### try-catch注意事项 178 | 179 | 如果try和finally里面都有return,那么程序最后会返回finally里面的return语句。面对必须要关闭的资源,我们总是应该优先使用 try-with- resources 而不是try-finally 180 | 181 | ###### 线程的基本状态 182 | 183 | new runnable waiting time-waiting(可以自动返回) terminated blocked(阻塞状态,被锁了) 184 | 185 | ###### 既然有了字节流,为什么还要有字符流 186 | 187 | 不管是文件读写还是网络发送接收,信息的最小存储单元都是字节,但是将字节流转换成字符流的过程非常耗时。 188 | 189 | ###### 线程池 190 | 191 | 主要就是减少线程开销,有固定线程池(核心线程数和最大线程数相等),带缓冲的线程池(核心线程数为0,每次有新的runnable进来就再创建线程), 192 | 单线程线程池(保证线程顺序执行)等等。执行线程的时候execute没有返回值,submit会返回future。 193 | -------------------------------------------------------------------------------- /algorithm/TreeAlgorithm.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | template 5 | int binarySearch(T arr[],int n,T target){ 6 | int l=0,r=n; 7 | int mid=(l+r)/2; 8 | while(ltarget){ 12 | r=mid; 13 | }else{ 14 | l=mid; 15 | } 16 | mid=(l+r)/2; 17 | 18 | } 19 | return -1; 20 | } 21 | //二分搜索树 22 | template 23 | class BST{ 24 | private: 25 | struct Node{ 26 | Key key; 27 | Value value; 28 | Node *left; 29 | Node *right; 30 | Node *father; 31 | Node(Key key,Value value){ 32 | this->key=key; 33 | this->value=value; 34 | this->left=NULL; 35 | this->right=NULL; 36 | this->father=NULL; 37 | } 38 | }; 39 | Node *root; 40 | int count; 41 | public: 42 | BST(){ 43 | root=NULL; 44 | count=0; 45 | } 46 | ~BST(){ 47 | destroy(root); 48 | } 49 | Node* getRoot(){ 50 | return root; 51 | } 52 | 53 | void destroy(Node* node){ 54 | if(node!=NULL){ 55 | destroy(node->left); 56 | destroy(node->right); 57 | delete node; 58 | count--; 59 | } 60 | } 61 | 62 | int size(){ 63 | return count; 64 | } 65 | bool isEmpty(){ 66 | return count==0; 67 | } 68 | void insert(Key key,Value value){ 69 | count++; 70 | if(root==NULL){ 71 | root=new Node(key,value); 72 | return; 73 | } 74 | Node* start=root; 75 | Node* end=new Node(key,value); 76 | while(start->left!=NULL||start->right!=NULL){ 77 | //如果比节点小 看看有没有左孩子 如果没有左孩子就加在左孩子上 78 | //如果比节点大 看看与没有右孩子 如果没有右孩子就加在右孩子上 79 | //如果有左(右)孩子就迭代下去 80 | //start必须保持是end的父节点 81 | if(keykey){ 82 | if(start->left==NULL){ 83 | start->left=end; 84 | break; 85 | }else 86 | start=start->left; 87 | }else if(key>start->key){ 88 | if(start->right==NULL){ 89 | start->right=end; 90 | break; 91 | }else 92 | start=start->right; 93 | }else{ 94 | cout<<"此节点已存在"<key){ 99 | start->left=end; 100 | }else if(key>start->key){ 101 | start->right=end; 102 | } 103 | end->father=start; 104 | } 105 | Node* search(Key key){ 106 | if(root==NULL){ 107 | cout<<"现在这是个空树"<left!=NULL||start->right!=NULL){ 113 | if(keykey){ 114 | if(start->left==NULL){ 115 | cout<<"找不到节点"<left; 119 | }else if(key>start->key){ 120 | if(start->right==NULL){ 121 | cout<<"找不到节点"<right; 125 | }else{ 126 | return start; 127 | } 128 | } 129 | if(key==start->key){ 130 | cout<<"2此节点的value是"<value< 132 | father->value<key<<" "; 144 | preOrder(node->left); 145 | preOrder(node->right); 146 | } 147 | } 148 | //中序遍历 149 | void midOrder(Node* node){ 150 | if(node!=NULL){ 151 | midOrder(node->left); 152 | cout<key<<" "; 153 | midOrder(node->right); 154 | } 155 | } 156 | //后续遍历 157 | void endOrder(Node *node){ 158 | if(node!=NULL){ 159 | endOrder(node->left); 160 | endOrder(node->right); 161 | cout<key<<" "; 162 | } 163 | } 164 | //层序遍历 165 | void layerOrder(){ 166 | queue q; 167 | q.push(root); 168 | while(!q.empty()){ 169 | Node *node=q.front(); 170 | q.pop(); 171 | if(node!=NULL) 172 | cout<<"key:"<key<<" value:"<value<<" 地址:"<left!=NULL) 174 | q.push(node->left); 175 | if(node->right!=NULL) 176 | q.push(node->right); 177 | } 178 | } 179 | void remove(Key key){ 180 | //有左孩子没右孩子:左孩子替代被删除节点 181 | //有右孩子没左孩子:右孩子替代被删除节点 182 | //既有右孩子也有左孩子:左孩子的最大值或者 183 | //右孩子的最小值替代被删除节点 184 | //没有右孩子也没有左孩子:直接删除 185 | Node* start=search(key); 186 | if(start==NULL){ 187 | //cout<<"找不到节点"<left!=NULL&&start->right==NULL){ 191 | if(start->keyfather->key) 192 | start->father->left=start->left; 193 | else 194 | start->father->right=start->left; 195 | //这里如果要释放目标节点所占内存的话 196 | //应该先找到目标节点的父节点 197 | //然后存储目标节点的左子树 198 | //并记录目标节点和父节点的关系(左孩子还是右孩子) 199 | //然后删除目标节点 200 | //最后顺着目标节点和父节点的关系(左孩子还是右孩子) 201 | //把原来存储的左子树插进去 202 | }else if(start->right!=NULL&&start->left==NULL){ 203 | if(start->keyfather->key) 204 | start->father->left=start->right; 205 | else 206 | start->father->right=start->right; 207 | //释放目标节点所占内存方法同上 208 | }else if(start->left!=NULL&&start->right!=NULL){ 209 | //这里找右孩子的最小值 210 | Node* minRight=start->right; 211 | while(minRight->left!=NULL){ 212 | minRight=minRight->left; 213 | } 214 | Node* disappear=minRight;//用这个指针删除右孩子最小值 215 | cout<<"右孩子最小值的key:"<key 216 | <<" 父节点的key:"<father->key<father!=NULL&&start->keyfather->key) 222 | start->father->left=minRight; 223 | else if(start->father!=NULL&&start->key>start->father->key) 224 | start->father->right=minRight; 225 | else 226 | root=minRight; 227 | //在这里删除右孩子的最小值 228 | if(disappear->keyfather->key){ 229 | disappear->father->left=NULL; 230 | delete disappear->father->left; 231 | }else{ 232 | disappear->father->right=NULL; 233 | delete disappear->father->right; 234 | } 235 | minRight->left=start->left; 236 | minRight->right=start->right; 237 | }else{ 238 | if(start->keyfather->key){ 239 | start->father->left=NULL; 240 | }else if(start->key>start->father->key){ 241 | start->father->right=NULL; 242 | } 243 | } 244 | delete start; 245 | start=NULL; 246 | 247 | } 248 | }; 249 | int main(){ 250 | //int arr[]={1,2,3,4,5,6,7}; 251 | //cout<<"我查的元素是7,位置是:"< bst=BST(); 253 | bst.insert(4,'a'); 254 | bst.insert(2,'b'); 255 | bst.insert(6,'c'); 256 | bst.insert(1,'d'); 257 | bst.insert(3,'e'); 258 | bst.insert(5,'f'); 259 | bst.insert(7,'g'); 260 | bst.preOrder(bst.getRoot()); 261 | cout< 1) { 62 | //节点比左子树小 就是在左子树的左子树 LL操作 63 | if (data < node.left.data) { 64 | node = rotationLL(node); 65 | } else { 66 | //旋转lR 67 | node = rotationLR(node); 68 | } 69 | } 70 | } else if (data > node.data) { 71 | //目标节点大于当前节点 则插入当前节点的右子树 72 | node.right = insert(node.right, data); 73 | int leftHeight = getHeight(node.left); 74 | int rightHeight = getHeight(node.right); 75 | //如果插入导致右子树失衡,即右子树比左子树高2 76 | if (rightHeight - leftHeight > 1) { 77 | if (data > node.right.data) { 78 | //插入的结点比右孩子的键值大 79 | //那么一定是插入到右孩子的右子树上,故进行RR旋转 80 | node = rotationRR(node); 81 | } else {//否则是插入到右孩子的左子树上,故要进行RL旋转 82 | node = rotationRL(node); 83 | } 84 | } 85 | } 86 | node.height = (getHeight(node.left) > getHeight(node.right) ? getHeight(node.left) : getHeight(node.right)) + 1; 87 | return node; 88 | } 89 | 90 | /** 91 | * @param node 根节点 92 | * @param data 要被删除的节点数据 93 | * @return 旋转后的根节点 94 | */ 95 | AVL delete(AVL node, int data) { 96 | if (node == null) 97 | return null; 98 | //比当前节点小就去左子树找 99 | if (data < node.data) { 100 | node.left = delete(node.left, data); 101 | int leftHeight = getHeight(node.left); 102 | int rightHeight = getHeight(node.right); 103 | //右子树比较高 打破平衡 104 | if (rightHeight - leftHeight > 1) { 105 | if (data > node.right.data) { 106 | //旋转RR 107 | node = rotationRR(node); 108 | } else { 109 | //旋转RL 110 | node = rotationRL(node); 111 | } 112 | } 113 | } else if (data > node.data) { 114 | node.right = delete(node.right, data); 115 | int leftHeight = getHeight(node.left); 116 | int rightHeight = getHeight(node.right); 117 | //左子树比较高 打破平衡 118 | if (leftHeight - rightHeight > 1) { 119 | if (data < node.left.data) { 120 | //旋转LL 121 | node = rotationLL(node); 122 | } else { 123 | //旋转LR 124 | node = rotationLR(node); 125 | } 126 | } 127 | } else { 128 | //左右子树都不为空时用右子树最小节点代替被删除节点 129 | if (node.left != null && node.right != null) { 130 | AVL tmp = findMin(node.right); 131 | node.data = tmp.data; 132 | //删除这个节点 133 | tmp.data = DELETED_NODE_DATA; 134 | tmp.left = null; 135 | tmp.right = null; 136 | //delete(node.right, data); 137 | } else if (node.left == null) { 138 | node = node.right; 139 | } else if (node.right == null) { 140 | node = node.left; 141 | } 142 | } 143 | return node; 144 | } 145 | 146 | 147 | /** 148 | * 1. 左子树变成新的根节点 149 | * 2. 旧的根节点变成右子树 150 | * 3. 左子树的右子树变成原本根节点的左子树 151 | * 152 | * @param node 153 | */ 154 | AVL rotationLL(AVL node) { 155 | System.out.println("LL run"); 156 | AVL root = node.left; 157 | node.left = root.right; 158 | root.right = node; 159 | node.height = (getHeight(node.left) > getHeight(node.right) ? getHeight(node.left) : getHeight(node.right)) + 1; 160 | root.height = (getHeight(root.left) > getHeight(root.right) ? getHeight(root.left) : getHeight(root.right)) + 1; 161 | return root; 162 | } 163 | 164 | //LR旋转: 165 | //1. 根节点的左子树进行右旋转 166 | //2. 根节点进行左旋转 167 | AVL rotationLR(AVL node) { 168 | System.out.println("LR run"); 169 | node.left = rotationRR(node.left); 170 | return rotationLL(node); 171 | } 172 | 173 | AVL rotationRR(AVL node) { 174 | System.out.println("RR run"); 175 | AVL root = node.right; 176 | node.right = root.left; 177 | root.left = node; 178 | node.height = (getHeight(node.left) > getHeight(node.right) ? getHeight(node.left) : getHeight(node.right)) + 1; 179 | root.height = (getHeight(root.left) > getHeight(root.right) ? getHeight(root.left) : getHeight(root.right)) + 1; 180 | return root; 181 | } 182 | 183 | //RL旋转: 184 | //1. 根节点的右子树进行左旋转 185 | //2. 根节点进行右旋转 186 | AVL rotationRL(AVL node) { 187 | System.out.println("RL run"); 188 | node.right = rotationLL(node.right); 189 | return rotationRR(node); 190 | } 191 | 192 | 193 | void preOrderTraversal(AVL node) { 194 | if (node == null || node.data == DELETED_NODE_DATA) { 195 | return; 196 | } 197 | System.out.print(node.data + " "); 198 | node.preOrderTraversal(node.left); 199 | node.preOrderTraversal(node.right); 200 | } 201 | 202 | void inOrderTraversal(AVL node) { 203 | if (node == null || node.data == DELETED_NODE_DATA) { 204 | return; 205 | } 206 | node.inOrderTraversal(node.left); 207 | System.out.print(node.data + " "); 208 | node.inOrderTraversal(node.right); 209 | } 210 | 211 | void postOrderTraversal(AVL node) { 212 | if (node == null || node.data == DELETED_NODE_DATA) { 213 | return; 214 | } 215 | node.postOrderTraversal(node.left); 216 | node.postOrderTraversal(node.right); 217 | System.out.print(node.data + " "); 218 | } 219 | 220 | //层序遍历 221 | void layerOrder(AVL node) { 222 | Queue queue = new LinkedList<>(); 223 | queue.offer(node); 224 | while (!queue.isEmpty()) { 225 | AVL iterator = queue.poll(); 226 | if (iterator != null && iterator.data != DELETED_NODE_DATA) { 227 | System.out.print(iterator.data + "\t"); 228 | } 229 | if (iterator.left != null) { 230 | queue.offer(iterator.left); 231 | } 232 | if (iterator.right != null) { 233 | queue.offer(iterator.right); 234 | } 235 | } 236 | } 237 | 238 | AVL create(int[] data) { 239 | AVL node = null; 240 | for (int i = 0; i < data.length; i++) { 241 | node = insert(node, data[i]); 242 | System.out.println("insert returns node data " + node.data); 243 | } 244 | return node; 245 | } 246 | 247 | /** 248 | * 计算免息期数在预期收益下的折扣率。如预期收益年化10%,12期免息,计算折扣率 249 | * 250 | * @param originIncomeRate 预期年化收益 251 | * @param count 免息期数 252 | * @return 折扣率 253 | */ 254 | private float discount(float originIncomeRate, int count) { 255 | float monthIncomeRate = originIncomeRate / 12f; 256 | float expectIncome = 0f; 257 | int originPrice = 1000; 258 | for (int i = 0; i < count; i++) { 259 | expectIncome += (originPrice - i * originPrice / count) * monthIncomeRate; 260 | } 261 | return expectIncome / originPrice; 262 | } 263 | 264 | public static void main(String[] args) { 265 | int data[] = {10, 20, 30, 40, 50, 60, 70}; 266 | AVL node = new AVL().create(data); 267 | new AVL().delete(node, 40); 268 | new AVL().layerOrder(node); 269 | System.out.println(new AVL().discount(0.1f, 24)); 270 | } 271 | } 272 | -------------------------------------------------------------------------------- /algorithm/AVLTree.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | using namespace std; 4 | 5 | class AVL{ 6 | private: 7 | int data; //结点的键值 8 | int height; //结点的高度 9 | AVL* lchild; //左孩子 10 | AVL* rchild; //右孩子 11 | public: 12 | //查找最小值 13 | AVL* FindMin(AVL* avl){ 14 | AVL* cur = avl; 15 | //搜索树为空时,返回NULL 16 | if(cur == NULL){ 17 | return NULL; 18 | } 19 | while(cur){ 20 | //左子树为空时,返回该节点 21 | if(cur->lchild == NULL){ 22 | return cur; 23 | }else{//否则在左子树里找最小值 24 | cur = cur->lchild; 25 | } 26 | } 27 | } 28 | 29 | //查找最大值 30 | AVL* FindMax(AVL* avl){ 31 | AVL* cur = avl; 32 | //搜索树为空时,返回NULL 33 | if(cur == NULL){ 34 | return NULL; 35 | } 36 | while(cur){ 37 | //右子树为空时,返回该节点 38 | if(cur->rchild == NULL){ 39 | return cur; 40 | }else{//否则在左子树里找最小值 41 | cur = cur->rchild; 42 | } 43 | } 44 | } 45 | 46 | //插入函数 47 | AVL* Insert(AVL* avl,int data){ 48 | //平衡二叉树为空,则构建根节点 49 | if(!avl){ 50 | avl = new AVL; 51 | avl->data = data; 52 | avl->height = 0; 53 | avl->lchild = avl->rchild = NULL; 54 | }else if(data < avl->data){//若data小于根节点的值,则插入到左子树 55 | avl->lchild = avl->Insert(avl->lchild,data); 56 | int rheight = this->getHeight(avl->rchild); //右子树高度 57 | int lheight = this->getHeight(avl->lchild); //左子树高度 58 | //如果插入导致左子树失衡,即左子树比右子树高2 59 | if(lheight - rheight == 2){ 60 | if(data lchild->data){ 61 | //插入的结点比左孩子的键值小 62 | //那么一定是插入到左孩子的左子树上,故进行LL旋转 63 | avl = this->SingleLeftRotation(avl); 64 | }else{//否则是插入到左孩子的右子树上,故要进行LR旋转 65 | avl = this->DoubleLeftRightRotation(avl); 66 | } 67 | } 68 | }else if(data > avl->data){//若data小于根节点的值,则插入到左子树 69 | avl->rchild = avl->Insert(avl->rchild,data); 70 | int rheight = this->getHeight(avl->rchild); //右子树高度 71 | int lheight = this->getHeight(avl->lchild); //左子树高度 72 | //如果插入导致右子树失衡,即右子树比左子树高2 73 | if(rheight - lheight == 2){ 74 | if(data > avl->rchild->data){ 75 | //插入的结点比右孩子的键值大 76 | //那么一定是插入到右孩子的右子树上,故进行RR旋转 77 | avl = this->SingleRightRotation(avl); 78 | }else{//否则是插入到右孩子的左子树上,故要进行RL旋转 79 | avl = this->DoubleRightLeftRotation(avl); 80 | } 81 | } 82 | } 83 | //更新结点的高度 84 | avl->height = this->Max(this->getHeight(avl->lchild),this->getHeight(avl->rchild))+1; 85 | return avl; 86 | } 87 | 88 | //二叉搜索树的构造,利用data数组构造二叉搜索树 89 | AVL* Create(int* data,int size){ 90 | AVL* avl = NULL; 91 | for(int i = 0 ; i < size ; i++){ 92 | avl = this->Insert(avl,data[i]); 93 | } 94 | return avl; 95 | } 96 | 97 | //删除操作 98 | AVL* Delete(AVL* avl,int data){ 99 | if(!avl){//树空时,直接返回NULL 100 | return avl; 101 | }else if(data < avl->data){ 102 | //data小于根节点时,到左子树去删除data,则有可能使右子树比左子树高2 103 | avl->lchild = this->Delete(avl->lchild,data); 104 | int rheight = this->getHeight(avl->rchild); //右子树高度 105 | int lheight = this->getHeight(avl->lchild); //左子树高度 106 | if(rheight - lheight == 2){//右子树比左子树高2时 107 | if(data > avl->rchild->data){ 108 | //如果是data比右子树的键值大,在右子树的右子树上,则进行RR旋转 109 | avl = this->SingleRightRotation(avl); 110 | }else{//否则是data比右子树的键值小,在右子树的左子树上,则进行RL旋转 111 | avl = this->DoubleRightLeftRotation(avl); 112 | } 113 | } 114 | }else if(data > avl->data){ 115 | //data大于根节点时,到右子树去删除data 116 | avl->rchild = this->Delete(avl->rchild,data); 117 | int rheight = this->getHeight(avl->rchild); //右子树高度 118 | int lheight = this->getHeight(avl->lchild); //左子树高度 119 | if(lheight - rheight == 2){//左子树比右子树高2时 120 | if(data < avl->lchild->data){ 121 | //如果是data比左子树的键值小,在左子树的左子树上,则进行LL旋转 122 | avl = this->SingleLeftRotation(avl); 123 | }else{//否则是data比左子树的键值大,在左子树的右子树上,则进行LR旋转 124 | avl = this->DoubleLeftRightRotation(avl); 125 | } 126 | } 127 | }else{//data等于根节点时 128 | if(avl->lchild && avl->rchild){ 129 | //左右子树都不空时,用右子树的最小来代替根节点 130 | AVL* tmp = this->FindMin(avl->rchild); 131 | avl->data = tmp->data; 132 | //删除右子树的最小结点 133 | avl->rchild = this->Delete(avl->rchild,tmp->data); 134 | }else{//当左右子树都为空或者有一个空时 135 | AVL* tmp = avl; 136 | if(!avl->lchild){//左子树为空时 137 | avl = avl->rchild; 138 | }else if(!avl->rchild){//右子树为空时 139 | avl = avl->lchild; 140 | } 141 | delete tmp; 142 | } 143 | } 144 | return avl; 145 | } 146 | 147 | //单左旋:左左旋函数 148 | //左子树的左子树导致的失衡,把左子树与根结点进行调整 149 | //根结点的左孩子做根结点,之前的根结点做现在根结点的右孩子 150 | //这是因为平衡二叉树一定是二叉搜索树的缘故导致的 151 | AVL* SingleLeftRotation(AVL* avl){ 152 | //注意:avl必须有一个左子结点tmp 153 | //将avl与tmp做左单旋,更新avl与tmp的高度,返回新的根结点tmp 154 | AVL* tmp = avl->lchild; 155 | avl->lchild = tmp->rchild; 156 | tmp->rchild = avl; 157 | avl->height = this->Max(this->getHeight(avl->lchild),this->getHeight(avl->rchild))+1; 158 | tmp->height = this->Max(this->getHeight(tmp->lchild),this->getHeight(avl))+1; 159 | return tmp; 160 | } 161 | 162 | //单右旋:右右旋函数 163 | //右子树的右子树导致的失衡,把右子树与根结点进行调整 164 | //根结点的右孩子做根结点,之前的根结点做现在根结点的左孩子 165 | //这是因为平衡二叉树一定是二叉搜索树的缘故导致的 166 | AVL* SingleRightRotation(AVL* avl){ 167 | //注意:avl必须有一个右子结点tmp 168 | //将avl与tmp做右单旋,更新avl与tmp的高度,返回新的根结点tmp 169 | AVL* tmp = avl->rchild; 170 | avl->rchild = tmp->lchild; 171 | tmp->lchild = avl; 172 | avl->height = this->Max(this->getHeight(avl->lchild),this->getHeight(avl->rchild))+1; 173 | tmp->height = this->Max(this->getHeight(tmp->rchild),this->getHeight(avl))+1; 174 | return tmp; 175 | } 176 | 177 | //左右旋转:LR旋转,左子树的右子树插入导致对的失衡 178 | AVL* DoubleLeftRightRotation(AVL* avl){ 179 | //注意:avl必须有一个左子结点B,且B必须有一个右子结点C 180 | //将avl、B与C做两次单旋,返回新的根结点C 181 | //首先对avl的左子树进行单右旋即RR旋转 182 | avl->lchild = this->SingleRightRotation(avl->lchild); 183 | //然后对avl进行单左旋即LL旋转 184 | return this->SingleLeftRotation(avl); 185 | } 186 | 187 | //右左旋转:RL旋转,右子树的左子树插入导致对的失衡 188 | AVL* DoubleRightLeftRotation(AVL* avl){ 189 | //注意:avl必须有一个左子结点B,且B必须有一个右子结点C 190 | //将avl、B与C做两次单旋,返回新的根结点C 191 | //首先对avl的右子树进行单左旋即LL旋转 192 | avl->rchild = this->SingleLeftRotation(avl->rchild); 193 | //然后对avl进行单右旋即RR旋转 194 | return this->SingleRightRotation(avl); 195 | } 196 | 197 | //获得树的高度 198 | int getHeight(AVL* avl){ 199 | if(!avl){ 200 | return 0; 201 | } 202 | return avl->height; 203 | } 204 | 205 | //求两个数的最大值 206 | int Max(int a,int b){ 207 | return (a>b)?a:b; 208 | } 209 | 210 | //递归前序遍历 211 | void PreorderTraversal(AVL* T){ 212 | if(T == NULL){ 213 | return; 214 | } 215 | cout<data<<" "; //访问根节点并输出 216 | T->PreorderTraversal(T->lchild); //递归前序遍历左子树 217 | T->PreorderTraversal(T->rchild); //递归前序遍历右子树 218 | } 219 | 220 | //递归中序遍历 221 | void InorderTraversal(AVL* T){ 222 | if(T == NULL){ 223 | return; 224 | } 225 | T->InorderTraversal(T->lchild); //递归中序遍历左子树 226 | cout<data<<" "; //访问根节点并输出 227 | T->InorderTraversal(T->rchild); //递归中序遍历左子树 228 | } 229 | 230 | //递归后序遍历 231 | void PostorderTraversal(AVL* T){ 232 | if(T == NULL){ 233 | return; 234 | } 235 | T->PostorderTraversal(T->lchild); //递归后序遍历左子树 236 | T->PostorderTraversal(T->rchild); //递归后序遍历右子树 237 | cout<data<<" "; //访问并打印根节点 238 | } 239 | 240 | int getdata(AVL* avl){ 241 | return avl->data; 242 | } 243 | }; 244 | 245 | int main() 246 | { 247 | int size; 248 | cout<<"请输入结点个数:"<>size; 250 | int* data; 251 | data = new int[size]; 252 | cout<<"请输入每个结点的值:"<>data[i]; 255 | } 256 | AVL* avl; 257 | avl = new AVL; 258 | avl = avl->Create(data,size); 259 | 260 | cout<<"前序遍历(递归):"<PreorderTraversal(avl); 262 | cout<InorderTraversal(avl); 266 | cout<PostorderTraversal(avl); 270 | cout<FindMax(avl); 274 | cout<<"二叉搜索树的最大值为:"<getdata(avl_max); 276 | cout<FindMin(avl); 281 | cout<getdata(avl_min); 282 | cout<>num; 287 | avl = avl->Delete(avl,num); 288 | cout<<"删除之后:"<PreorderTraversal(avl); 291 | cout<InorderTraversal(avl); 295 | cout<PostorderTraversal(avl); 299 | cout<>num; 303 | avl = avl->Delete(avl,num); 304 | cout<<"删除之后:"<PreorderTraversal(avl); 307 | cout<InorderTraversal(avl); 311 | cout<PostorderTraversal(avl); 315 | cout<>num; 319 | avl = avl->Delete(avl,num); 320 | cout<<"删除之后:"<PreorderTraversal(avl); 323 | cout<InorderTraversal(avl); 327 | cout<PostorderTraversal(avl); 331 | cout< 35 | 接下来我们在activity的dispatchTouchEvent方法内打日志做记录,并且记录目标view的touch事件与click事件。 36 | 37 | ```kotlin 38 | package com.example.review 39 | 40 | import android.os.Bundle 41 | import android.os.PersistableBundle 42 | import android.util.Log 43 | import android.view.MotionEvent 44 | import android.view.View 45 | import androidx.appcompat.app.AppCompatActivity 46 | import com.bumptech.glide.Glide 47 | import kotlinx.android.synthetic.main.activity_main.* 48 | import java.util.* 49 | 50 | 51 | class MainActivity : AppCompatActivity() { 52 | private val TAG = "MainActivity" 53 | override fun onCreate(savedInstanceState: Bundle?) { 54 | super.onCreate(savedInstanceState) 55 | setContentView(R.layout.activity_main) 56 | btn_child1.setOnClickListener { 57 | Log.d(TAG, "btn child1 click") 58 | } 59 | btn_child2.setOnClickListener { Log.d(TAG, "btn child2 click") } 60 | btn_child1.setOnTouchListener { v, event -> 61 | if (event?.action != MotionEvent.ACTION_MOVE) { 62 | Log.d(TAG, "btn1 on touch listener action ${event?.action}") 63 | } 64 | false 65 | } 66 | btn_child2.setOnTouchListener { v, event -> 67 | if (event?.action != MotionEvent.ACTION_MOVE) { 68 | Log.d(TAG, "btn2 on touch listener action ${event?.action}") 69 | } 70 | false 71 | } 72 | } 73 | 74 | override fun dispatchTouchEvent(ev: MotionEvent?): Boolean { 75 | if (ev?.action != MotionEvent.ACTION_MOVE) { 76 | Log.i(TAG, "MainActivity dispatchTouchEvent action ${ev?.action}") 77 | } 78 | return super.dispatchTouchEvent(ev) 79 | } 80 | 81 | } 82 | ``` 83 | 84 | 最后我们看一下xml布局文件: 85 | 86 | ```xml 87 | 88 | 95 | 96 |