diff --git "a/Flutter/Dart-\345\237\272\347\241\200.md" "b/Flutter/Dart-\345\237\272\347\241\200.md" index de61a65..7fb971e 100644 --- "a/Flutter/Dart-\345\237\272\347\241\200.md" +++ "b/Flutter/Dart-\345\237\272\347\241\200.md" @@ -22,7 +22,7 @@ ### 二、Dart 常量 -* final:可以开始不赋值,只能赋值一次,是惰性初始化,即在运行时第一次使用前才真正初始化,可以通过运行时赋值 +* final:只能赋值一次,是惰性初始化,即在运行时第一次使用前才真正初始化,可以通过运行时赋值 * const:需要在解释运行前就要赋值,且赋值后不变,如果修饰类中的变量,则必须添加static关键字且`static const` ### 三、Dart数据类型 diff --git a/Git/git-14-revert.md b/Git/git-14-revert.md index 6530b70..93ad5d9 100644 --- a/Git/git-14-revert.md +++ b/Git/git-14-revert.md @@ -1,4 +1,15 @@ -## revert(反向提交) +## revert 撤销 > 在不改变这个提交的前提下撤销对齐的修改 +分为两种 + +1、单一的commit的撤销 + +2、两个分支merge后的commit的撤销 + + + +[git撤销merge,彻底学会git revert的用法](https://www.cnblogs.com/bescheiden/articles/10563651.html) + +[参考文章2](https://www.cnblogs.com/bescheiden/articles/10563651.html) diff --git "a/Mac/mac-\344\277\256\345\244\215python\346\217\220\347\244\272.md" "b/Mac/mac-\344\277\256\345\244\215python\346\217\220\347\244\272.md" index d64491c..4b561fd 100644 --- "a/Mac/mac-\344\277\256\345\244\215python\346\217\220\347\244\272.md" +++ "b/Mac/mac-\344\277\256\345\244\215python\346\217\220\347\244\272.md" @@ -4,7 +4,7 @@ 1、现象 -![image-20221114003952161](/Users/guojie/Notes/Mac/images/终端提示env.png) +![](https://cdn.jsdelivr.net/gh/GJBlog/Notes/Mac/images/%E7%BB%88%E7%AB%AF%E6%8F%90%E7%A4%BAenv.png) 2、解决方案 diff --git "a/Mac/xattr\345\221\275\344\273\244.md" "b/Mac/xattr\345\221\275\344\273\244.md" new file mode 100644 index 0000000..81bd75a --- /dev/null +++ "b/Mac/xattr\345\221\275\344\273\244.md" @@ -0,0 +1,19 @@ +## xattr + +#### 定义 + +xattr命令可用于显示、修改或删除一个或多个文件的扩展属性,包括目录和符号链接。 + +```shell +sudo xattr -d com.apple.quarantine /Applications/xxxx.app +``` + +-c:清除所有属性 + +-d:删除给定属性 + +-r:指定文件夹,递归文件夹下的所有文件 + + + +[参考](https://blog.niekun.net/archives/1680.html) \ No newline at end of file diff --git "a/Mac/\351\205\215\347\275\256\350\207\252\345\256\232\344\271\211Ruby.md" "b/Mac/\351\205\215\347\275\256\350\207\252\345\256\232\344\271\211Ruby.md" new file mode 100644 index 0000000..c968b06 --- /dev/null +++ "b/Mac/\351\205\215\347\275\256\350\207\252\345\256\232\344\271\211Ruby.md" @@ -0,0 +1,80 @@ +## 配置可访问权限的Ruby + +* 思想是:基于 brew,通过 brew 安装 Ruby,然后在环境变量中指定当前系统依赖的Ruby指向新安装的Ruby可执行文件 +* 适用于 Mac M系列、Inter系列 + +##### 操作步骤 + +1、安装brew + +```shell +/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" +``` + +配置环境变量 + +```shell +//打开 .zshrc 或 .bash_profile 文件 +export PATH="/opt/homebrew/bin:$PATH" +``` + +2、基于 brew 安装 Ruby + +```shell +brew install ruby +``` + +安装后的提示信息 + +```shell +==> ruby +ruby is keg-only, which means it was not symlinked into /opt/homebrew, +because macOS already provides this software and installing another version in +parallel can cause all kinds of trouble. + +If you need to have ruby first in your PATH, run: + echo 'export PATH="/opt/homebrew/opt/ruby/bin:$PATH"' >> ~/.zshrc + +For compilers to find ruby you may need to set: + export LDFLAGS="-L/opt/homebrew/opt/ruby/lib" + export CPPFLAGS="-I/opt/homebrew/opt/ruby/include" + +For pkg-config to find ruby you may need to set: + export PKG_CONFIG_PATH="/opt/homebrew/opt/ruby/lib/pkgconfig" +==> qt +You can add Homebrew's Qt to QtCreator's "Qt Versions" in: + Preferences > Qt Versions > Link with Qt... +pressing "Choose..." and selecting as the Qt installation path: + /opt/homebrew +``` + +配置环境变量 + +```shell +//打开 .zshrc 或 .bash_profile 文件 +export PATH="/opt/homebrew/Cellar/ruby/3.2.1/bin:$PATH" +``` + +##### 其他命令安装 + +1、Cocoapods + +```shell +sudo gem install cocoapods +``` + +配置环境变量 + +```shell +//打开 .zshrc 或 .bash_profile 文件 +export PATH="/opt/homebrew/lib/ruby/gems/3.2.0/bin:$PATH" +``` + + + +#### 参数来源 + +1、[苹果M1/M2芯片安装CocoaPods](https://www.jianshu.com/p/270ecd9a9a25) + +2、[猫哥-m1 silicon macos 安装 cocoapods](https://wiki.ducafecat.tech/blog/flutter-tips/3-m1-macos-install-cocoapods.html#_3-%E9%85%8D%E7%BD%AE%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F) + diff --git "a/OC/OC\345\244\215\344\271\240-02.md" "b/OC/OC\345\244\215\344\271\240-02.md" index 766c7fb..cecebc8 100644 --- "a/OC/OC\345\244\215\344\271\240-02.md" +++ "b/OC/OC\345\244\215\344\271\240-02.md" @@ -19,7 +19,29 @@ * 类方法 * ……………… +![image-20230305114208234](/Users/guo/Notes/OC/images/image-20230305114208234.png) + +* instance的isa指向class + * 当调用对象方法时,通过instance的isa找到class,最后找到对象方法的实现进行调用 +* class的isa指向meta-class + * 当调用类方法时,通过class的isa找到meta-class,最后找到类方法的实现进行调用 + + + + + + + + + + + + + + + #### 总结 + * isa * instance对象的isa指针指向class对象 * class对象的isa指针指向meta-class对象 diff --git "a/OC/OC\345\244\215\344\271\240-OC\347\261\273.md" "b/OC/OC\345\244\215\344\271\240-OC\347\261\273.md" index 20bd791..105f608 100644 --- "a/OC/OC\345\244\215\344\271\240-OC\347\261\273.md" +++ "b/OC/OC\345\244\215\344\271\240-OC\347\261\273.md" @@ -34,41 +34,100 @@ class_isMetaClass(objMetaClass) ### 相关知识点 * 1个16进制数 = 4个二进制数 + * 2个16进制数 = 8个二进制数 = 1个字节 + * 1个字节 = 8个二进制数 * b: 1字节 + * h: 2字节 + * w: 4字节 + * g: 8字节 * 内存对齐:结构体的大小必须是最大成员大小的倍数 * 内存大小端: - + * 大端模式:1、数据的高字节保存在内存的低地址中,2、数据的低字节保存在内存的高地址中 * 小端模式:1、数据的高字节保存在内存的高地址中,2、数据的低字节保存在内存的低地址中 * 在X86和一般的OS中(windows,FreeBSD,Linux)使用小端模式 * Mac OSX 是大端模式, iOS 是小端模式 - + * OC 三种对象 - + * instanced对象(实例对象) * isa指针 * 成员变量 - - * class对象(类对象),一个类的类对象内存中只有一份 + * class对象(类对象),一个类的类对象在内存中只有一份 * isa指针 * superclass指针 * 类的属性信息(property) * 类的对象方法信息(instanceMethod) * 类的协议信息(protocol) - * 类的成员信息(ivar) - + * 类的成员信息(描述信息)(ivar) * meta-class对象(元类对象)一个类的元类对象内存中只有一份 * isa指针 * superclass指针 * 类的类方法信息 + + 查看Class是否为元类对象meta-class + + ```objective-c + BOOL isMetaClass = class_isMetaClass(NSObject class) + ``` + + ```objective-c + Class objc_getClass(const char *aClassName) + // 1、传入的字符串类名 + // 2、返回对应的类对象 + + Class _Nullable object_getClass(id _Nullable obj) + /* + 1、传入的obj可能是instance对象、class对象、metaclass对象 + 2、返回值 + a) 如果是instance对象,返回class对象 + b) 如果是class对象,返回meta-class对象 + c) 如果是meta-class对象,返回NSObject(基类)的 meta-class对象 + */ + - (Class)class、+ (Class)class + /* + 返回的就是类对象 + */ + - (Class)class { + return object_getClass(self); + } + + Class object_getClass(id obj) + { + if (obj) return obj->getIsa(); + else return Nil; + } + + + (Class)class { + return self; + } + ``` + + +不借助第三方变量如何交换两个变量的值 + +```objective-c +int a = 10; +int b = 11; +// 借助加减法运算 +a = b - a; +b = b - a; +a = b + a; +// 借助位运算符 +a = a ^ b; +b = a ^ b; +a = a ^ b; +``` + + ### 面试题 @@ -79,4 +138,3 @@ class_isMetaClass(objMetaClass) - diff --git "a/OC/OC\350\277\220\350\241\214\350\277\207\347\250\213.md" "b/OC/OC\350\277\220\350\241\214\350\277\207\347\250\213.md" new file mode 100644 index 0000000..737e091 --- /dev/null +++ "b/OC/OC\350\277\220\350\241\214\350\277\207\347\250\213.md" @@ -0,0 +1,9 @@ +## OC 运行过程 + +1、编写OC源文件:.m、.c + +2、编译:cc -c xxx.m xxx.c + +3、链接:cc xxx.o xxx.o -framework XX(Foundation),只有用到才需要加上 + +4、运行:./a.out \ No newline at end of file diff --git a/OC/images/image-20230305114208234.png b/OC/images/image-20230305114208234.png new file mode 100644 index 0000000..e7fe86d Binary files /dev/null and b/OC/images/image-20230305114208234.png differ diff --git a/Python/Module.md b/Python/Module.md new file mode 100644 index 0000000..154e1da --- /dev/null +++ b/Python/Module.md @@ -0,0 +1,84 @@ +## Module(模块) + +通过 import 文件名来使用该文件中的内容 + +通常,1个文件就是1个模块,文件名就是模块名(建议全小写) + +#### import + +* Import 模块 as 别名 + +* Import 后面可以跟上多个模块名 + +```python +import 模块1, 模块2, ... +``` + +建议 import 后面只导入1个模块 + +* from 模块 import 名称 as 别名 +* from 模块 import 名称1, 名称2, .... +* from 模块 import * + +如果从不同模块导入了相同的名称,那么后导入的会覆盖掉前导入的 + +* 可以通过```__all__ = [名称1,名称2, ...]``` 控制 import * 的内容 + +#### 导入模块 + +##### 在1个python程序中 + +* 有且只有1个模块作为程序入口被直接运行,我们称为主模块(main module) +* 剩下的其他模块,只能作为辅助模块,被主模块直接或间接导入 + +##### 不管模块被 import 多少次 + +* 模块中的代码只会被执行1次 +* 模块只会被初始化1次 + +##### 要避免循环导入 + +* 比如A导入B,B导入A + +#### 模块的内置变量 + +* ```__file__```:模块的完整文件路径 +* ```__name__```: + * 当直接执行该模块时,值为:```__main__``` + * 当被其他模块导入时:值为:模块名 + +#### `__name__` 使用 + +用于:在自定义模块文件中,编写**测试**代码,当该模块被其他模块引用时,如果没有**测试**代码不在`if __name__ == '__main__':`中,那么被引入时会被自动执行,但是当放置到`if __name__ == '__main__':`中则只会在当前模块中执行时才会运行 + +```python +if __name__ == '__main__': + test1(20, 10) +``` + +#### `__all__`使用 + +用于在自定义模块中,被`__all__`指定的函数名,在其他模块中通过`import *`导入该模块时,只会导入在`__all__`列表中指定的函数,未指定的则无法使用 + +```python +# my_module1.py 文件 +def test1(a, b): + print(a + b) + +def test2(a, b): + print(a * b) + +__all__ = ["test1", "test2"] +``` + +#### 注意事项 + +不同模块都通过 import XX方式导入相同的xx名称,那么最后通过import XX 导入的部分会覆盖掉之前导入的部分 + +```python +from my_module1 import test1 +from my_module2 import test1 + +test1(10, 20) # test1实际执行的是来自my_module2中的test1函数实现 +``` + diff --git "a/Python/if\350\257\255\345\217\245.md" "b/Python/if\350\257\255\345\217\245.md" new file mode 100644 index 0000000..94fd9f4 --- /dev/null +++ "b/Python/if\350\257\255\345\217\245.md" @@ -0,0 +1,53 @@ +### if 语句 + +语法: + +if 条件: + +​ 要执行的语句 + +最终要之执行的语句 + +```python +age = 10 +if age > 10: + print("大于10") +print("结束了") +``` + +### If else 语句 + +语法: + +If 条件: + +​ 要执行的语句 + +else: + +​ 要执行的语句 + +```python +age = int(input("请输入你的年龄:")) +if age > 18: + print("您已成年, 游玩需要补票10元") +else: + print("您不需要补票") +print("祝您游玩愉快") +``` + +### if elif else 语句 + +elif 语句可以有多个 + +```python +age = int(input("请输入你的年龄:")) +if age > 18: + print("您已成年, 游玩需要补票10元") +elif age > 10: + print("小于18且大于10") +else: + print("您不需要补票") +print("祝您游玩愉快") +``` + diff --git a/Python/images/image-20230321003604268.png b/Python/images/image-20230321003604268.png new file mode 100644 index 0000000..9411aef Binary files /dev/null and b/Python/images/image-20230321003604268.png differ diff --git "a/Python/images/\344\275\234\347\224\250\345\237\237.png" "b/Python/images/\344\275\234\347\224\250\345\237\237.png" new file mode 100644 index 0000000..29e3a46 Binary files /dev/null and "b/Python/images/\344\275\234\347\224\250\345\237\237.png" differ diff --git "a/Python/images/\350\256\277\351\227\256\345\257\271\350\261\241\345\261\236\346\200\247.png" "b/Python/images/\350\256\277\351\227\256\345\257\271\350\261\241\345\261\236\346\200\247.png" new file mode 100644 index 0000000..332b8b7 Binary files /dev/null and "b/Python/images/\350\256\277\351\227\256\345\257\271\350\261\241\345\261\236\346\200\247.png" differ diff --git "a/Python/\344\275\234\347\224\250\345\237\237.md" "b/Python/\344\275\234\347\224\250\345\237\237.md" new file mode 100644 index 0000000..6e5e89a --- /dev/null +++ "b/Python/\344\275\234\347\224\250\345\237\237.md" @@ -0,0 +1,40 @@ +## 作用域(scope) + +* 作用域:根据定义位置的不同,标识符的作用范围会有所不同 +* 标识符:编码过程中用到的一些名称(函数名、变量名、模块名等) + +![image-20230212113713450](/Users/guojie/Notes/Python/images/作用域.png) + +* 局部的标识符:可以用在局部作用域 +* 全局的标识符:可以用在全局、局部作用域 +* 内置的标识符:可以用在内置、全局、局部作用域 +* 标识符的搜索顺序(就近原则) + * 局部作用域 -> 全局作用域 -> 内置作用域 -> is not defined + +#### 将函数内定义的变量声明为全局变量,使用global关键字 + +```python +num = 200 + +def test_b(): + num = 500 + print(f"test_b:{num}") + +test_b() +print(num) # 输出 200 +``` + +如果想实现num的打印为500,则需要在函数内部使用global为num做声明,将其变为全局变量 + +```python +num = 200 + +def test_b(): + global num + num = 500 + print(f"test_b:{num}") + +test_b() +print(num) # 输出 500 +``` + diff --git "a/Python/\345\205\203\347\245\226.md" "b/Python/\345\205\203\347\245\226.md" index fb60a22..974e68c 100644 --- "a/Python/\345\205\203\347\245\226.md" +++ "b/Python/\345\205\203\347\245\226.md" @@ -1,4 +1,10 @@ -## 元祖(tuple) +# 元祖(tuple) + +元组:Python 将不能修改的值称为不可变的,而不可变的列表称为元组 + +### 定义元组 + +语法:**变量名称 = (元素1, XXXX)**,()可以省略,只是为了更整洁、清晰 * 跟list非常相似,支持切片、下标访问,是一个可迭代对象 * 空元祖 @@ -8,7 +14,7 @@ t = () t = tuple() ``` -* 创建只有1个元素的元祖 +* 创建只有1个元素的元祖,而**,**不可以省略 ```python t1 = (55,) @@ -31,10 +37,30 @@ print(name) => MJ print(male) => True ``` -* 是不可变的类型 +* **是不可变的类型** + +```python +dimensions = (200, 50) +dimensions[0] = 300 +# 输出 + dimensions[0] = 300 + ~~~~~~~~~~^^^ +TypeError: 'tuple' object does not support item assignment +``` + * 对比 list - * tuple 属于不可变类型,数据相对更安全,资源消耗会更低 + * tuple 属于不可变类型,数据相对更安全,**资源消耗**会更低 * 优先使用tuple,实在不行再使用list, list属于可变类型 * 对比str * 由于str、tuple 是不可变类型,所以它们的 += 、*= 无法实现原地操作 + +### 遍历 + +* 使用 for 循环 + +```python +dimensions = 200, 100, 10, 5 +for di in dimensions: + print(di) +``` diff --git "a/Python/\345\207\275\346\225\260.md" "b/Python/\345\207\275\346\225\260.md" new file mode 100644 index 0000000..955b790 --- /dev/null +++ "b/Python/\345\207\275\346\225\260.md" @@ -0,0 +1,403 @@ +# 函数 + +### 定义 + +定义一个新的函数,将这段代码写到函数中(def 是 definition 的缩写,意为:定义) + +```python +def greet_user(): + """显示简单的问候语""" + print("Hello!") +# greet_user:表示函数名,后面()是放置函数参数 +# """显示简单的问候语""":表示对函数的注释,描述函数的功能,在函数调用时,可以看到注释信息 +``` + +### 调用 + +```python +greet_user() +``` + +函数的定义,一定要在函数的**调用之前** + +Python中的函数分类: + +1、内置函数: type、max、len等 + +2、自定义函数:XXX + +```python +def 函数名(): + 函数体 +``` + +* 函数调用 + +```pyth +函数名() +``` + +#### 参数 (parameter) + +* 作用:将外面的数据传递到函数内部进行使用,让函数的功能更加灵活 + +* 定义函数时,用来接收数据的side变量叫做:形式参数(parameter),简称:形参 +* 调用函数时,传递的数据叫做:实际参数(argument),简称:实参 + +#### 参数的默认值 + +* 如果在很多时候参数都是一个固定值,建议给参数设置一个**默认值**,这样可以省略实参 +* 有1个限制:必须从最右往左是连续的 + +```python +正确✅ +def tes1(a=1, b=2, c=4): + pass + +def tes2(a, b=2, c=4): + pass + +def test3(a, b, c=3): + pass +``` + +```python +错误❌ +def test4(a, b=4, c): + pass + +def test4(a=1, b=4, c): + pass +``` + +#### 关键字参数 + +* 默认情况下,我们是从左往右按顺序传递参数(位置参数,positional argument) +* 也可以按照参数名传递参数(关键字参数, keyword argument) + +```python +def move_circle(x, y, radius): + pass + +move_circle(10, 20, 30) +move_circle(x=10, y=20, radius=30) +move_circle(radius=30, x=10, y=20) +``` + +* 关键字参数的好处:参数可读性高,不必非得按照从左往右的顺序 + +#### 可变参数(arbitrary argument) + +位置不定长参数类型 + +```python +def test1(*args): + print("xxx") +``` + + + +* *参数名:是一个可变参数,他可以将任意数量的值打包成1个元组对象 +* 不能设置默认值 +* 不能使用关键字参数的形式 + +```python +// names:元组类型 +def hello(*names): + for n in names: + print(f'{n}') +=> hello('MJ', 'Jack') +``` + +#### 非可变参数、可变参数混用 + +* 可变参数的右边,必须使用关键字参数 + +```python +def hello(*names, title): + for n in names: + print(f'{n}, 我是title:{title}') +hello('GK', 'MJ', title='KK') +``` + +#### 用*解包可迭代实参 + +```python +def move_circle(x, y, radius): + t.penup() + t.goto(x, y) + t.pendown() + + t.circle(radius) + +move_circle(50, 60, 70) +等价于 move_circle(*[50, 60, 70]) +等价于 move_circle(*(50, 60, 70)) +等价于 move_circle(*range(50, 60, 70)) +``` +如果实参是字典,只会将字典的key解包传递给可变参数 +```python +def hello(*names): + for n in names: + print(f'你好,{n}') + +hello(*{'name': 'GJ', 'age': 19}) +=> +你好,name +你好,age +``` + +#### 关键字参数字典化 + +```python +def show_info(name=None, age=None, city=None): + if name: + print(f'name = {name}') + if age: + print(f'age = {age}') + if city: + print(f'city = {city}') + +show_info(age=19, city='BJ') +``` + +```python +def show_info(name=None, age=None, city=None): + name and print(f'name = {name}') + age and print(f'name = {age}') + city and print(f'name = {city}') + +show_info(age=19, city='BJ') +``` +关键字不定长参数类型 + +```python +def test1(**kwargs): + print("xxx") +``` + + + +**info:表示info是一个字典 + +* 关键字参数的名字作为key +* 关键字参数的值作为value + +```python +def show_info(**info): + if "name" in info: + print('name =', info['name']) + if "age" in info: + print('age =', info['age']) + if "city" in info: + print('city =', info['city']) + +show_info(name='GJ', age=19, city='BJ') +``` + +#### *形参和**形参混用 + +* 两个可以混用,但是:*形参必须放在**形参的左边 + +```python +def test(*s1, name, **s2): + print(s1) + print(name) + print(s2) + +test(10, 20, 30, name='GJ', age=18, city='广州') +=> +(10, 20, 30) +GJ +{'age': 18, 'city': '广州'} +``` + +#### 强制使用关键字参数 + +* *右边的形参都必须强制使用关键字参数 + +```python +def move_circle(*, x=0, y=0, radius=50): + t.penup() + t.goto(x, y) + t.pendown() + t.circle(radius) +move_circle(x=10, y=20, radius=30) +``` + +```python +def test(a, b, *, c, d): + pass +test(10, 20, c=30, d=40) +``` + +#### 返回值 (return value) + +* 根据有无返回值,函数可以分为2类: + * 有返回值的函数 + * 无返回值的函数 + +* 如果函数没有明确return具体的数据,等价于 return None,也可以显式写上返回值None + +```python +def test1(n: int) -> None: + pass +``` + +#### Pass + +* 相当于空代码,啥也不干 +* 如果函数体尚未确定,一般先用pass代替,表示函数体待定 + +#### 引用传递(pass-by-reference) + +* 在python中,将实参传递给形参时,使用的是:引用传递 +* 实参、形参:指向的是同一个对象 + +#### 参数类型 + +* python 的形参可以接收任意类型的实参 + +* 参数类型可以指定多个 + +```python +def test1(a: int | list, b: int) -> tuple | int : + pass +``` + +#### 标注(annotation) + +* 标注的本质是注释,因此标注对程序的执行没有影响 + +```python +float:被称为标注 +def avg(a: float, b: float) -> float: + return (a + b) / 2 +``` + +* 打印标注 + +```python +print(test1.__annotations__) +=> {'a': int | list, 'b': , 'return': None} +``` + +#### 文档字符串(doc string),说明文档 + +* 作用:类似于说明书、用户手册 +* 本质是一种注释,一次一般也叫做文档注释 +* 通常使用1对3双引号 + +```python +def hello1(): + """打印3次hello""" + print('hello') + print('hello') + print('hello') +``` + +```python +def avg(a: float, b: float) -> float: + """ + 求a和b的平均值 + :param a: 第1个数值 + :param b: 第2个数值 + :return: 平均值 + """ + return (a + b) / 2 +``` + +* 打印文档 + +```python +print(avg.__doc__) +help(avg) => 打印更详细 +``` + +#### 内部函数( inner function) + +```python +def four_square(x, y, side): + def move(x, y): + t.penup() + t.goto(x, y) + t.pendown() +``` + +#### global语句 + +* 在函数中使用全局变量 + * 如果是只读,直接使用该变量即可 + * 如果是要进行赋值操作,就要配合使用global语句 +* global语句:将指定的标识符强制解释为全局变量 +* 可以实现:在函数中修改全局变量的值 + +```python +k = 10 + +def test(): + # k是全局变量 + global k + k = 20 + print('test') + + +print(f'k = {k}') +test() +print(f'k = {k}') + +=> +k = 10 +test +k = 20 +``` + +#### nonlocal语句 + +* 在内部函数中使用外部函数的局部变量 + * 如果是只读,直接使用该变量即可 + * 如果是要进行赋值操作,就要配合使用nonlocal语句 + +```python +k = 10 +def test3(): + def test4(): + def test5(): + nonlocal k + k = 40 + test5() + + print(f'k = {k}') + test4() + print(f'k = {k}') + +test3() +=> +SyntaxError: no binding for nonlocal 'k' found +``` + +#### 定义lambda匿名函数 + +语法: + +Lambda 传入参数:函数体(一行代码) + +* lambda:是关键字,表示定义匿名函数 +* 函数体:只能写一行,不能写多行代码 + +```python +def test_func(testFunc): + result = testFunc(2, 3) + print(result) +# 定义匿名函数 +test_func(lambda x, y: x + y) +# 输出 +5 +``` + + + +#### 注意 + +函数调用时,如果有位置参数时,**位置参数必须在关键字参数的前面**,但关键字参数之间不存在先后顺序 + diff --git "a/Python/\345\210\227\350\241\250.md" "b/Python/\345\210\227\350\241\250.md" index f1ba390..22b87a5 100644 --- "a/Python/\345\210\227\350\241\250.md" +++ "b/Python/\345\210\227\350\241\250.md" @@ -1,6 +1,6 @@ # 列表(list) - +使用**[]**来定义列表,使用**,**来分隔其中的元素 * 列表中的元素可以是任意类型 @@ -25,8 +25,8 @@ print(10 not in [11, 22]) #### 索引(index) -* 每个元素都有与之对应的索引,索引从0开始,可以使用索引访问对应位置的元素 -* 可以使用负数索引,比如-1表示倒数第1个 +* 每个元素都有与之对应的索引,索引从**0**开始,可以使用索引访问对应位置的元素 +* 可以使用负数索引,比如**-1表示倒数第1个** ```python s = [11, 22, 33, 44] @@ -111,7 +111,9 @@ s = [10, 11, 12, 13, 14, 15, 16] print(s[-4:]) => [13, 14, 15, 16] ``` -* s[ : ]:所有元素(相当于复制列表) +* s[ : ]:所有元素(相当于**复制**列表) + +要复制列表,可以创建一个包含整个列表的切片,同时省略起始索引和终止索引,让Python创建一个起始于第一个元素,终止与最后一个元素的切片,即复制整个列表 ```python s = [10, 11, 12, 13, 14, 15, 16] @@ -121,6 +123,7 @@ print(s[:]) => [10, 11, 12, 13, 14, 15, 16] #### s[i:j:k] * 参考range(i, j, k) +* 表示每隔k个元素 #### s[:: -k] @@ -207,6 +210,8 @@ print(s) => [66, 55, 88, 33, 22, 11] > 又叫做列表解析式,可以更简洁地生成列表元素 +语法:**新列表名称 = [表达式 for 元素 in 列表]** + ```python s = [i for i in range(12, 18)] print(s) => [12, 13, 14, 15, 16, 17] @@ -234,8 +239,8 @@ print(s) => [0, 0, 0, 0, 0] #### 求列表的最值 -* 使用max(列表) 函数获取列表中的最大元素 -* 使用min(列表) 函数获取列表中的最小元素 +* 使用**max**(列表) 函数获取列表中的最大元素 +* 使用**min**(列表) 函数获取列表中的最小元素 #### 对比字符串(Str) @@ -257,16 +262,19 @@ print(s) => [0, 0, 0, 0, 0] * 在[i, len(s)) 范围内搜索 * count * s.count(x):统计s中有多少个元素x -* append +* **append**:追加元素到末尾 + * s.append(x):添加元素x到s的尾部 * s.append(x) 等价于 s[len(x):] = [x] -* insert +* **insert** + * s.insert(i, x):将元素x插入到索引为i的位置 * i的正常合理范围是:[-len(s), len(s) - 1] * 如果i < -len(s),代表往头部插入 * 如果i > len(s)-1,代表往尾部插入,跟s.append(x)的效果一样 * 等价于s[i:i] = [x] -* s.extend(t):将可迭代对象t中的所有元素添加到尾部 +* **extend**(t):将可迭代对象t中的所有元素添加到尾部 + * 等价于:s + t、s[len(s):] = t * 删除-pop * s.pop():删除并返回尾部元素,调用空列表的pop方法会报错,IndexError: pop from empty list @@ -277,13 +285,54 @@ print(s) => [0, 0, 0, 0, 0] * 删除-remove * s.remove(x):只会删除1个元素x(按照从左往右搜索) * 如果元素不在s中,会报错,ValueError: list.remove(x): x not in list -* del 删除 +* del 语句删除 * 同样实现删除功能,del s[1] * del s[100:],使用切片,越界不会报错 * 如果越界,报错。IndexError: list assignment index out of range * del s[i:j] 等价于 s[i:k] = [] * clear 删除所有元素 * 等价于 del s[:] + +* sort方法排序(**会直接改变列表中的顺序**) + + * 列表.sort,默认按照字母全小写时,顺序升序 + * 列表.sort(reverse=True),表示:按照降序排列 + + ```python + cars = ['bmw', 'audi', 'toyota', 'subaru'] + cars.sort() + # ['audi', 'bmw', 'subaru', 'toyota'] + cars.sort(reverse=True) + print(cars) + # ['toyota', 'subaru', 'bmw', 'audi'] + ``` + +* sorted函数排序(临时改变,不会影响列表本身的顺序) + +```python +cars = ['bmw', 'audi', 'toyota', 'subaru'] +# 临时排序 +newCars = sorted(cars, reverse=True) +# ['toyota', 'subaru', 'bmw', 'audi'] +``` + +* 反转列表元素 + +```python +cars = ['bmw', 'audi', 'toyota', 'subaru'] +cars.reverse() +print(cars) +# ['subaru', 'toyota', 'audi', 'bmw'] +``` + +* len函数,用于获取列表长度 + +```python +cars = ['bmw', 'audi', 'toyota', 'subaru'] +length = len(cars) +print(length) +# 4 +``` #### del s[:] vs del s @@ -337,3 +386,86 @@ print(s1) => [56, 44, 33, [22, 11]] * list += 的本质 * s += t 的本质是执行了s.extend(t) ,t是可迭代对象 + +#### 遍历列表 + +* **for 循环** + +```python +magicians = ['alice', 'david', 'carolina'] +for magician in magicians: + print(f"{magician.title()}, that was a great trick!") +# 输出 +Alice, that was a great trick! +David, that was a great trick! +Carolina, that was a great trick! +``` + +完整版for循环 + +``` +for 变量 in 集合: + 循环体代码 +else: + 没有通过break退出循环,循环结束后,会执行的代码 +``` + + + +#### range函数 + +生成一系列**数**,range(1, 5):**左闭右开**,生成数是1<=x<5 + +```python +# 指定两个参数 +for value in range(1, 5): + print(value, end=' ') +# 输出 +1 2 3 4 +# 指定1个参数 +for value in range(6): + print(value, end=' ') +# 输出 +0 1 2 3 4 5 +``` + +使用range创建数值列表 + +```python +numbers = list(range(1, 6)) +print(numbers) +# 输出 +[1, 2, 3, 4, 5] +``` + +支持设置step(步长) + +```python +numbers = list(range(1, 5, 2)) +print(numbers) +# 输出 +[1, 3] +``` + +求和函数 + +```python +print(sum([1, 2, 3, 4])) +``` + + + +#### 注意 + +* 在 python 中,是根据代码缩进来判断代码行与程序其他部分的关系,如果需要缩进而未缩进,会在运行时报错 + +```python +# 打印1的前面有缩进,所以属于for循环的一部分 +# 打印2的前面没有缩进,所以不属于for循环的一部分 +magicians = ['alice', 'david', 'carolina'] +for magician in magicians: + print(f"{magician.title()}, that was a great trick!") + print("打印1") +print("打印2") +``` + diff --git "a/Python/\345\214\205.md" "b/Python/\345\214\205.md" new file mode 100644 index 0000000..2a590d7 --- /dev/null +++ "b/Python/\345\214\205.md" @@ -0,0 +1,59 @@ +## 包(package) + +### 定义: + +就是一个文件夹,里面可以存放很多python的模块文件,通过包,在逻辑上将一批模块归为一类,方便使用 + +### 创建 + +创建一个package,默认会自动创建`__init__.py`文件,通过这个文件来表示一个文件夹是python的包,而非普通的文件夹 + +### 使用 + +使用时跟模块类似,也是通过from 或者import来导入,只是导入时读了包名 + +```python +import my_package.my_module1 +import my_package.my_module2 + +my_package.my_module1.info_print1() +my_package.my_module2.info_print2() +``` + +除此之外,如果包中想要配置`__all__`时可以在`__init__.py`中实现,作用:同模块中一样,控制`import *`能够导入的内容 + +```python +__all__ = ["模块名称1", "模块名称2"] +``` + +### 第三方包 + +一个包,就是一堆同类型功能的集合体 + +非常出名的三方包有: + +1、科学计算中常用的:numpy包 + +2、数据分析中常用的:pandas包 + +3、大数据计算常用的:pyspark、apache-flink包 + +4、图形可视化常用的:matplotlib、pyecharts + +5、人工智能中常用的:tensorflow + +等等 + +#### 安装第三方包-pip + +使用python内置的pip程序即可 + +1、通过终端命令: + +```shell +pip install 包名称 +# 如果安装速度很慢,可以指定清华的下载源 +pip install -i https://pypi.tuna.tsinghua.edu.cn/simple 包名称 +``` + +2、通过pyCharm来安装 diff --git "a/Python/\345\217\230\351\207\217.md" "b/Python/\345\217\230\351\207\217.md" index 9eea83b..9a615b6 100644 --- "a/Python/\345\217\230\351\207\217.md" +++ "b/Python/\345\217\230\351\207\217.md" @@ -1,4 +1,8 @@ -## 变量 +# 变量 + +### 定义 + +变量名 = 变量值 ### 细节 @@ -36,8 +40,8 @@ NameError: name 'name222' is not defined a,b = b, a ``` -* 命名 - * 可以由单词字符(英文字幕、中文等)、数字、下划线组成 +* 命名**规则** + * 可以由单词字符(英文、中文)、数字、下划线组成,不推荐使用中文 比如:name、abc_678 * Python 是区分大小写的 @@ -66,6 +70,14 @@ a,b = b, a * 大驼峰:所有单词的首字母大写 * 下划线连接(**推荐**):比如:my_name_and_age +* 命名规范: + + * 见名知意 + + * 下划线命名法,当有多个单词组合名称时,使用下划线做分隔 + + * 英文字母全小写 + * 关键字 > 也叫保留字(reserved word) @@ -85,3 +97,11 @@ help('keywords') > 直接写出来的一个固定值 比如:age = 18、height = 20.1 + + + +### 注意点 + +在 python 中变量是没有类型的,变量中存储的数据有类型 + +在 python 中任何类型都可以转为字符串类型 diff --git "a/Python/\345\217\257\350\247\201\346\200\247.md" "b/Python/\345\217\257\350\247\201\346\200\247.md" new file mode 100644 index 0000000..21e28b9 --- /dev/null +++ "b/Python/\345\217\257\350\247\201\346\200\247.md" @@ -0,0 +1,62 @@ +## 可见性 + +* 如果属性名/方法名是以双下划线开头,且不以双下划线结尾 + + * 那么这个属性/方法将会对外不可见 + * 比如: + + ```python + __name、__name_、__name_a_ 对外是不可见的 + 但 __name__ 对外是可见的 + ``` + + +#### 不可见的原因 + +* 属性原名称被改为了:_类名 + 原名称 + * 比如 __name 被改成了:`_类名__name` + * 通过`_类名__name`还是可以访问"不可见的属性/方法",因此,在Python中,不存在真正的"不可见" + +```python +__name => _Student__name +``` + +* 方法和属性一样,同样可以对外不可见 + + +#### 属性的存取 + +* 通常 + * get*方法被称为getter(访问器) + * set*方法被称为setter(修改器) + * 它们被统称为accessor(存取器) + +```python +class Student: + def __init__(self): + self.__name = None + self.__age = None + + def __str__(self): + return f'{self.__age}岁{self.__name}' + + def get_name(self): + return self.__name + + def set_name(self, name): + self.__name = name + + def get_age(self): + return self.__age + + def set_age(self, age): + self.__age = age +``` + +```python +s = Student() +s.set_age(19) +s.set_name('GJ') +print(s.get_age()) +print(s.get_name()) +``` \ No newline at end of file diff --git "a/Python/\345\255\227\345\205\270.md" "b/Python/\345\255\227\345\205\270.md" index 39e0c43..96043d0 100644 --- "a/Python/\345\255\227\345\205\270.md" +++ "b/Python/\345\255\227\345\205\270.md" @@ -11,6 +11,10 @@ } ``` +#### 保留定义时的元素排列顺序 + +如果将字典打印出来或者遍历其元素,则元素的排列顺序与其添加顺序相同 + #### 根据key获取对应的value * d[key] @@ -104,3 +108,171 @@ d1 = dict(name='GJ', age=20) print(d1) => {'name': 'GJ', 'age': 20} ``` +#### 遍历 + +* 字典的遍历顺序,和key的添加顺序一致(该特性是从Python3.7开始的),默认情况下,会遍历字典所有的键 + +```python +d = {'name': 'GJ'} +d['age'] = 18 +d['name'] = 168 +d['height'] = 2.0 +for key in d: + print(key, d[key]) +=> +name 168 +age 18 +height 1.9 +``` + +```python +user_0 = { + 'username': 'efermi', + 'first': 'enrico', + 'last': 'fermi' + } + +for key in user_0.keys(): + print(key) +等价于 +for key in user_0: + print(key) +``` + + + +* 使用字典的items(),返回可迭代对象 + +```python +for key, value in d.items(): + print(key, value) +=> +name 168 +age 18 +height 2.0 +``` + +```python +for i in d.items(): + print(i) +=> +('name', 168) +('age', 18) +('height', 2.0) +``` + +```python +for k in d.keys(): + print(k, d[k]) +=> +name 168 +age 18 +height 2.0 +``` + +```python +for v in d.values(): + print(v) +=> +168 +18 +2.0 +``` + +#### 删除 + +* Key-value -pop 方法 + +如果d中不存在这个key,删除key对应的键值对,并返回d[key] + +如果d中不存在这个key,删除key时会报错(key Error) + +```python +print(d.pop('age')) # 18 +``` + +* key-value- del 方法 + +如果d中不存在这个key,删除key对应的键值对,并返回d[key] + +如果d中不存在这个key,删除key时会报错(key Error) + +```python +del d['height'] +``` + +* key-value-popitem 方法 + +d.popitem():删除1个键值对,并返回1个元祖(key, d[key]) + +```python +删除的顺序和遍历顺序相反 +print (d.popitem()) # height, 1.9 +print (d.popitem()) # age, 18 +print (d.popitem()) # name, gj +print(d, len(d)) # {}, 0 +``` + +* key-value-clear 方法 + +d.clear():删除d中的所有键值对 + +#### key + +* dict 的 key 必须是可哈希的 + +```python +d = { + [5, 6]: 20, + 'age': 19 +} +=> TypeError: unhashable type: 'list' +``` + +#### format_map 方法 + +```python +d = { + 'name': 'GJ', + 'age': 18, + 'key1': 20 +} +s1 = '{name}名字 = {age}, {key1}'.format_map(d) +=> GJ名字 = 18, 20 +``` + +#### 推导式 + +```python +d = {} +for i in range(5): + d[i] = i ** 2 + +for k in d: + print(f'd[{k} = {d[k]}') + +=> +d[0 = 0 +d[1 = 1 +d[2 = 4 +d[3 = 9 +d[4 = 16 +``` + +等价于 + +```python +列表推导式 +s = [i ** 2 for in range(5)] +=> +[0, 1, 4, 9, 16] + +推导式 +d = {i: i ** 2 for i in range(5)} +print(d) +=> +{0: 0, 1: 1, 2: 4, 3: 9, 4: 16} +``` + + + diff --git "a/Python/\345\255\227\347\254\246\344\270\262.md" "b/Python/\345\255\227\347\254\246\344\270\262.md" index ef8adf0..894eeb6 100644 --- "a/Python/\345\255\227\347\254\246\344\270\262.md" +++ "b/Python/\345\255\227\347\254\246\344\270\262.md" @@ -2,10 +2,93 @@ #### 子串 -> 字符串中任意个连续的字符组成的序列,称为改字符串的子串(subString),包括空串 +> 字符串中任意个连续的字符组成的序列,称为该字符串的子串(subString),包括空串 比如字符串'KMJ', 共7个子串:'','K','M','J','KM','MJ','KMJ' +也属于数据容器的一员,字符串是字符的容器,一个字符串可以存放任意数量的字符,并且每一个字符都有下标,也是从0开始 + +#### 定义 + +支持双引号、单引号、三引号 + +```python +# 第一种 +str1 = "我是字符串" +# 第二种 +str2 = '我是字符串' +# 第三种 +str3 = """我是字符串""" # 与多行注释写法一样,同样支持换行操作 +``` + +#### 拼接方式 + +1、**+** **直接拼接**,**缺点**:只能拼接字符串内容 + +```py +str1 = "GJ" +str2 = "Hello" +str3 = str2 + str1 +``` + +2、**%s** 占位型的拼接方式,可以拼接任何数据类型 + +```python +num1 = 100 +num2 = 200 +# %:表示占位 +# s:表示将变量变为字符串放入占位的地方 +str2 = "Hello %s" % num1 +# 注意:如果% 后面有多个,则需要使用()包裹,并且每一个之间使用,分隔 +str3 = "Hello 第一个数 %s 第二个数 %s" % (num1, num2) +``` + +除了 %s 占位类型外,还有其他的数据类型占位,最常用的如下 + +| 格式符号 | 转化 | +| -------- | -------------------------------- | +| %s | 将内容转换为字符串,放入占位位置 | +| %d | 将内容转换为整数,放入占位位置 | +| %f | 将内容转换为浮点型,放入占位位置 | + +```python +name = "GJ" +set_up_year = 2017 +stock_price = 19.99 +message = "我是:%s, 我成立于:%d, 我的价格是:%.2f" % (name, set_up_year, stock_price) +print(message) +# 我是:GJ, 我成立于:2017, 我的价格是:19.99 +``` + +占位符中的**精度控制** + +```python +使用:m.n 来表示,m和.n均可省略 +m:控制宽度,要求是数字(很少使用),设置的宽度小于数字自身,不生效 +.n:控制小数点精度,要求是数字,会进行小数的四舍五入 +%5d:表示将证书的宽度控制在5位,如数字11,被设置为5d,输出为:空格空格空格11,空格来补足宽度 +%5.2f:表示将宽度控制在5位,将小数点精度设置为2,小数点和小数点精度也包含在宽度内,如11.345设置了%7.2f,输出为:空格空格11.35,空格用来补足宽度,小数部分限制2位精度,四舍五入为.35 +%.2f:表示不限制宽度,只设置小数点精度为2位,如11.345设置了%.2f,输出为:11.35 +``` + + + +3、**快速格式化字符串:**format 格式的拼接方式,可以拼接任何数据类型 + +**语法**:f"内容{变量}",不会关心变量类型,不会做精度控制,按照变量的原样输出 + +```python +num1 = 100 +str1 = f"Hello {num1}" +num2 = 11.345 +print(f"Hello {num2}") +# 输出:Hello 11.345 +``` + +4、格式化表达式 + +语法:f"{表达式}"、"%s\%d\%f" % {表达式1,表达式2,表达式3} + #### 常用方法 ##### 查询 - index diff --git "a/Python/\345\256\271\345\231\250.md" "b/Python/\345\256\271\345\231\250.md" new file mode 100644 index 0000000..42b7d64 --- /dev/null +++ "b/Python/\345\256\271\345\231\250.md" @@ -0,0 +1,19 @@ +## 容器 + +通用转换功能 + +1、list(容器) + +将给定容器转换为列表 + +2、tuple(容器) + +将给定容器转为元组 + +py3、str(容器) + +将给定容器转为字符串 + +4、set(容器) + +将给定容器转为集合 \ No newline at end of file diff --git "a/Python/\345\257\271\350\261\241.md" "b/Python/\345\257\271\350\261\241.md" index 2d07cd2..5699e1a 100644 --- "a/Python/\345\257\271\350\261\241.md" +++ "b/Python/\345\257\271\350\261\241.md" @@ -6,4 +6,172 @@ * 可以通过id函数获取对象的id * Id 函数获取的并不是变量的id,而是变量所指向的对象id * 变量是没有id的,对象才有id -* 如果两个对象的id相同,说明他们其实是同一个对象 \ No newline at end of file +* 如果两个对象的id相同,说明他们其实是同一个对象 + + #### 初始化方法 + +```python +__init__(self,XXX) +``` + +* 是一个特殊的方法,每当类**创建**实例时会**自动**调用 +* **init**前后__是固定写法,否则不会被调用到 +* 第一个参数self:必须包含,python在每次调用该方法创建实例时,会自动传入实参self,每个实例调用方法时,都会自动传递self,该self是一个指向实例本身的引用,让实例可以访问类中的属性和方法,实际调用时会自动传递 +* 后面参数:不是必须的,用于在`__init__`内部给定义的属性赋值 + +```python +class Car: + """一次模拟汽车的简单尝试""" + + def __init__(self, make, model, year): + """初始化描述汽车的属性""" + # 定义4个变量(属性) + self.make = make + self.model = model + self.year = year + # 里程表 + self.odometer_reading = 0 + + def get_descriptive_name(self): + """返回格式规范的描述性信息""" + long_name = f"{self.year} {self.make} {self.model}" + return long_name.title() + +# 实例化对象 +my_car = Car('audi', 'a4', 2024) +my_car.get_descriptive_name() +``` + +#### 定义方法 + +* 第一个形参必须是:self,调用方法时会自动传入 + +```python +class GJDog: + """一次模拟小狗的简单尝试""" + + def __init__(self, name, age): + """初始化属性 name 和 age""" + self.name = name + self.age = age + print("执行了初始化方法--") + + def sit(self): + """模拟小狗收到命令时做下""" + print(f"{self.name} is now sitting.") + + def roll_over(self): + """模拟小狗收到命令时打滚""" + print(f"{self.name} rolled over!") + +my_dog = GJDog('ss', 20) +my_dog.sit() +``` + +#### 访问属性 + +* 使用实例名称`.`方法名称(参数) + +```python +my_dog = GJDog('ss', 20) +my_dog.name +``` + +#### 给属性指定默认值 + +* 在初始化方法中可以直接设置默认值,例如:odometer_reading + +```python + def __init__(self, make, model, year): + """初始化描述汽车的属性""" + # 定义4个变量(属性) + self.make = make + self.model = model + self.year = year + # 里程表 + self.odometer_reading = 0 +``` + +## 继承 + +#### 子类的初始化方法 + +* 需要调用父类初始化`__init__()`方法,会初始化父类中定义的所有属性,让子类也可以使用 +* 语法 + +先定义父类 + +```python +class MyCar: + def __init__(self, make, model, year): + self.make = make + self.model = model + self.year = year + self.odometer_reading = 0 + + def get_descriptive_name(self): + long_name = f"{self.year} {self.make} {self.model}" + return long_name.title() + + def read_odometer(self): + print(f"This car has {self.odometer_reading} miles on it.") + + def update_odometer(self, mileage): + if mileage >= self.odometer_reading: + self.odometer_reading = mileage + else: + print("You can't roll back an odometer!") + + def increment_odometer(self, miles): + self.odometer_reading += miles +``` + +定义子类 + +* 创建子类时,父类必须在当前文件中,且位于子类前面 +* 括号中指定**父类**名称,例如:MyCar +* super():是一个特殊函数,用于调用父类的方法 + +```python +class ElectricCar(MyCar): + def __init__(self, make, model, year): + super().__init__(make, model, year) + self.battery_size = 40 + + def describe_battery(self): + print(f"This car has a {self.battery_size}-Kwh battery.") +``` + +#### 重写父类方法 + +* 直接在子类中重写即可 + +get_descriptive_name方法:就是重写的父类方法 + +```python +class ElectricCar(Car): + """模拟电动汽车的独特之处""" + def __init__(self, make, model, year): + super().__init__(make, model, year) + self.battery = Battery() + + def get_descriptive_name(self): + print("子类实现") +``` + +#### 编程风格 + +1、类名使用**驼峰命名法**,即:将类名中每个单词的首字母都大写 + +2、实例名和模块名都采用全小写格式,单词之间使用下划线 + +3、每个类定义后面都应该紧跟一个文档字符串,来简要的描述类的功能,每个模块也都应该包含一个文档字符串,对其中类的作用进行描述 + +4、类中可以使用一个空行来分隔方法,而在模块中,可以使用两个空行来分隔类 + +5、当需要同时导入标准库中的模块和你编写的模块时,先导入标准库模块的import语句,再添加一个空行,编写导入自己编写的模块import语句 + + + + + diff --git "a/Python/\345\270\270\347\224\250\345\207\275\346\225\260.md" "b/Python/\345\270\270\347\224\250\345\207\275\346\225\260.md" index 88e1ff5..8d4f967 100644 --- "a/Python/\345\270\270\347\224\250\345\207\275\346\225\260.md" +++ "b/Python/\345\270\270\347\224\250\345\207\275\346\225\260.md" @@ -161,10 +161,23 @@ side = t.numinput("请输入", "正方形的边长") > 使用该函数可以得知具体的数据类型 +两种使用方式 + +(1)、type(字面量) + ```python print(type('100')) # 打印 - + #str:是string 类型的缩写 +``` + +(2)、type(变量名称) + +```python +mony = 200 +print(type(money)) +# 打印 + ``` #### 随机数 @@ -227,6 +240,67 @@ t = divmod(13, 4) => (3, 1) ``` +#### dir 函数 + +* 所有可用的属性名、方法名 + +```python +class Dog: + def __init__(self, name): + self.__name = name + + def run(self): + print('run', self.__name) + + def __sleep(self): + print('sleep', self.__name) +``` + +```python +s = Dog('妮妮') +print(dir(s)) +=> +['_Dog__name', '_Dog__sleep', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'run'] +``` + +#### isinstance + +* 判断某个对象是否为某种类型的实例 + +```python +class Animal: + pass +class Dog(Animal): + pass +class RobotDog(Dog): + pass +d = RobotDog() + +print(isinstance(d, Animal)) => True +print(isinstance(d, Dog)) => True +print(isinstance(d, (int, str))) => False +``` + +#### issubclass + +* 判断某个类是否为另一个类的子类 + +```python +print(issubclass(RobotDog, Dog)) +print(issubclass(RobotDog, Animal)) +print(issubclass(RobotDog, RobotDog)) +print(issubclass(Dog, RobotDog)) +print(issubclass(RobotDog, (int, Dog))) +=> +True +True +True +False +True +``` + + + diff --git "a/Python/\345\274\202\345\270\270.md" "b/Python/\345\274\202\345\270\270.md" new file mode 100644 index 0000000..b7b2265 --- /dev/null +++ "b/Python/\345\274\202\345\270\270.md" @@ -0,0 +1,101 @@ +## 异常Exception + +在 Python 中,可能会遇到3种错误: + +1、语法错误(syntax error) + +2、逻辑错误 (logic error bug) + +3、异常 (exception) + +#### 捕获异常 + +* try、except、else、finally 配合使用 + +![image-20230321003604268](/Users/guojie/Notes/Python/images/image-20230321003604268.png) + +* try:包含可能会产生异常的代码,一旦产生异常,会直接跳过try中剩余未执行的代码 +* except:当出现异常时,会执行except中的代码,可以**省略** ,可通过as获取到异常对象 +* else:当没有出现异常时,会执行else中的代码,可以**省略**,只能在有except 时使用 +* finally:不管是否出现异常,最终都会执行 finally 中的代码,可以**省略** + +```python +from pathlib import Path +path = Path("alice.txt") +try: + contents = path.read_text(encoding='utf-8') +# 可以捕获所有的异常 +except Exception as e: + print(f"异常对象是:{e}") +else: + print("继续开始执行了") +print("内容是") +``` + +except 后面可以换成具体异常类型 + +#### 常见(内置)异常类型 + +* ZeroDivisionError:0作为除数 +* IndexError:索引超出正常范围 +* NameError:无法找到名称(标识符) +* KeyError:无法找到字典的Key +* TypeError:使用了不恰当类型的对象 +* ValueError:虽然类型正确,但值不正确 +* AttributeError:操作(访问、赋值等)属性失败 + +#### 异常的传播 + +* 异常会由内往外传播出去,直到被拦截捕获或传播到全局作用域为止 +* 当异常传播到全局作用域时,还没有被拦截捕获,就会导致程序终止运行,并将异常信息打印出来 + +```python +# 异常从func1中抛出到func2中,再到main中 +def func1(): + print("func1 开始执行") + num = 1 / 0 + print("func1 结束执行") + +def func2(): + print("func2 开始执行") + func1() + print("func2 结束执行") + +def main(): + try: + func2() + except Exception as e: + print(f"出现异常了,异常的信息是:{e}") + +main() +``` + +#### 抛出异常 + +* 通过 raise 主动抛出异常 + +```python +class Person: + def __init__(self): + self.__age = 1 + @property + def age(self): + return self.__age + + @age.setter + def age(self, age): + if age < 1: + raise ValueError('age不能小于1') + if age > 120: + raise ValueError('age不能大于120') + self.__age = age + +p1 = Person() +p1.age = -10 +print(p1.age) +``` + +#### 自定义异常 + +* 自定义的异常类型,最终要继承自Exception 而不是BasicException + diff --git "a/Python/\345\276\252\347\216\257\350\257\255\345\217\245.md" "b/Python/\345\276\252\347\216\257\350\257\255\345\217\245.md" index 58ce6e9..3a9d1b7 100644 --- "a/Python/\345\276\252\347\216\257\350\257\255\345\217\245.md" +++ "b/Python/\345\276\252\347\216\257\350\257\255\345\217\245.md" @@ -1,5 +1,13 @@ ## 循环语句 +语法: + +```python +while 条件: + 语句1 + 。。。。。。。 +``` + #### while、for 也可以跟else进行搭配使用 * 当循环正常结束(非break结束)后,会执行1次else语句 @@ -70,5 +78,19 @@ else: 结果:0 1 2 done +#### continue + +用法:中断本次循环,直接进入下一次循环 + +作用范围:所在的循环体 + +#### break + +用法:退出当前循环体,执行循环后面的代码 + +作用范围:所在的循环体 + + + diff --git "a/Python/\346\225\260.md" "b/Python/\346\225\260.md" new file mode 100644 index 0000000..9c823c0 --- /dev/null +++ "b/Python/\346\225\260.md" @@ -0,0 +1,50 @@ +# 数 + +分为:整数、浮点数 + +#### 下划线表示 + +```python +# 整数 +num1 = 1_000_000 +# 浮点数 +num2 = 1_000_000.924 +``` + +#### 赋值 + +除了**变量名 = 变量值**之外,可以一次赋值多个变量,要求变量名和值的**个数要相同** + +```python +x, y, z = 0, 1, 2 +``` + +#### 常量 + +在**Python**中没有内置的常量类型,**只能人为的方式,使用全大写字母来表示将某个变量视为常量** + +```python +MAX_CONNECTIONS = 5000 +``` + +#### 细节 + +* 任意两个数相除,结果总是**浮点数**,即使两个数都是整数且能被整除 +* 如果一个操作数是整数,另一个操作数是浮点数,结果总是**浮点数** + +```python +num1 = 4 / 2 +print(type(num1)) +# 打印 +2.0 => +``` + +#### 显示Python之禅 + +来自2004的Tim Peters 编写,优秀Python代码的指导原则 + +```python +import this +``` + +编写上面代码,执行python解释器,即可输出之禅的20条内容,[官方英文](https://peps.python.org/pep-0020/),[维基中文](https://zh.wikipedia.org/wiki/Python%E4%B9%8B%E7%A6%85) diff --git "a/Python/\346\226\207\344\273\266.md" "b/Python/\346\226\207\344\273\266.md" new file mode 100644 index 0000000..de025c8 --- /dev/null +++ "b/Python/\346\226\207\344\273\266.md" @@ -0,0 +1,113 @@ +## 文件 + +文件操作步骤,通常有三步:打开文件、读写文件、关闭文件 + +有两种方式来处理文件操作 + +第一种是,使用**pathlib**模块来操作 + +能够更轻松在各种操作系统中处理文件和目录 + +#### 打开文件 + +* 使用**open**函数,打开一个已经存在的文件,或者创建一个新的文件 + +```python +# 1、从pathlib模块中导入Path类 +path = Path('mySelf.txt') +# 2、从path路径中读取整个数据到contents中,读取的格式是字符串类型 +contents = path.read_text() +# 从path路径中读取整个数据,转化到每行数据,放到lines列表类型中 +lines = contents.splitlines() +``` + +#### 写入文件 + +1、python只能将字符串写入文本文件中 + +2、如果指定路径文件不存在,则会创建,如果文件已经存在,那么write_text()会删除其现有内容,并将指定的内容写入其中 + +```python +# 1、从pathlib模块中导入Path类 +from pathlib import Path +# 2、创建要写入的Path对象,并制定输出的文件路径 +path = Path('mySelf.txt') +# 3、写入数据到文件中,result表示:写入成功的字符数量 +result = path.write_text("今天") +``` + +第二种是,使用open函数来操作 + +#### 打开文件 + +mySelf.txt:文件路径 + +r:打开文件操作模式,r:表示只读,w:表示写入(如果文件不存在会**自动创建**文件,如果文件存在会**清空**里面原有的内容),a:表示在原有文件内容基础上最后拼接内容 + +encoding:表示编码格式 + +```python +# 第一种打开方式,这种方式下,必须要最后通过f.close() 来结束对文件的占用操作 +f = open("mySelf.txt", "r", encoding="UTF-8") +# 第二种打开方式,这种方式下,会自动在最后调用f.close()方法,不需要手动调用 +with open("mySelf.txt", "r", encoding="UTF-8") as f: + for line in f: + print(f"读取内容:{line}") +``` + +#### 读取文件 + +```python +# size:指定读取的长度,如果是文本内容,指的是字符数,如果是二进制数据,指的是字节数 +# 读取文件所有内容 +f.read(size) +# 读取一行 +f.readline() +# 读取所有行,得到列表 +f.readlines() +``` + +```python +# 循环读取所有行 +for line in f: + print(line) +``` + +#### 写入文件 + +w:模式 + +如果文件不存在,会创建文件,并写入文件中 + +如果文件已经存在,在会清空文件内容。写入新内容 + +```python +# 打开文件,设置为写入模式,格式是UTF-8 +f = open("mySelf2.txt", "w", encoding="UTF-8") +# 将Hello, World22222写入文件中 +f.write("Hello, World22222") +# 刷新(可省略),用于将write写到内存缓冲区中的内容写入到硬盘中 +f.flush() +# 关闭文件 +f.close() # 已经自动包含了flush功能 +``` + +a:模式 + +如果文件不存在,会创建文件,并写入文件中 + +如果文件已经存在,在会在文件内容的末尾追加内容 + +```python +f = open("mySelf2.txt", "a", encoding="UTF-8") +f.write("This is my world!!") +f.close() +``` + +#### 关闭文件 + +```python +# f:文件对象 +f.close() +``` + diff --git "a/Python/\346\263\250\351\207\212.md" "b/Python/\346\263\250\351\207\212.md" new file mode 100644 index 0000000..15d10ff --- /dev/null +++ "b/Python/\346\263\250\351\207\212.md" @@ -0,0 +1,32 @@ +# 注释 + +python 中的注释分为:单行注释、多行注释 + +### 单行注释 + +定义:以#开头,#右边的所有文字当做说明 + +建议:**#** 号与注释内容之间以一个空格隔开 + +```python +# 我是单行注释 +``` + +### 多行注释 + +定义:以一对三个双引号(**"""**)引起来来当做说明 + +场景:一般对文件、类、方法进行注释 + +```python +""" +666 +12.222 +"你好" +""" +或者 +# 666 +# 12.222 +# 你好 +``` + diff --git "a/Python/\350\277\220\347\256\227\347\254\246.md" "b/Python/\350\277\220\347\256\227\347\254\246.md" index e1ce19c..4fcf7b8 100644 --- "a/Python/\350\277\220\347\256\227\347\254\246.md" +++ "b/Python/\350\277\220\347\256\227\347\254\246.md" @@ -4,6 +4,11 @@ ![image-20221106180858552](/Users/guojie/Notes/Python/images/算术运算符.png) +```python +num1 = 9 // 2 # 4 +num2 = 9 % 2 # 4.5 +``` + #### 模(modulo) * 模运算符的作用是求余数,所以也叫求余运算符、取余运算符、余数运算符 @@ -64,4 +69,4 @@ print(-10 % -7) # -3 ### 注意 -* 在`Python`中不存在自增、自减运算符 +* 在`Python`中**不存在**自增、自减运算符 diff --git "a/Python/\351\233\206\345\220\210.md" "b/Python/\351\233\206\345\220\210.md" index fadd079..1b04124 100644 --- "a/Python/\351\233\206\345\220\210.md" +++ "b/Python/\351\233\206\345\220\210.md" @@ -1,5 +1,7 @@ ## 集合(set) +**无序、元素不重复** + * set 也可以像list、tuple 一样,用来存放一组数据 * set 是可迭代对象,但它的元素没有固定的先后顺序 @@ -45,9 +47,72 @@ print(s1) => {33, 11, 44, 22, 55} * s.add(x):添加元素x * s.discard(x):删除元素x,删除不存在的元素不会报错 * s.remove(x):删除元素x,删除不存在的元素会报错,KeyError -* s.pop(x):删除并返回1个元素,如果集合s的长度为0,会报错(KeyError) +* s.pop(x):**删除并随机返回1个元素**,如果集合s的长度为0,会报错(KeyError) * s.clear():删除集合s中的所有元素 +#### 集合差集、并集 + +* 差集 + +**语法**:集合1.diffenerce(集合2) + +**功能**:取出集合1和集合2的差集(集合1中有而集合2中没有的),**不影响**原有集合1和集合2 + +```python +set1 = {1, 2, 3} +set2 = {1, 5, 6} +set3 = set1.difference(set2) +print(set3)# 输出:{2, 3} +``` + +* 消除2个集合的差集 + +**语法**:集合1.diffenerce_update(集合2) + +**功能**:对比集合1和集合2,在集合1内,删除和集合2相同的元素,**影响**原有集合1,不影响原有集合2 + +```python +set1 = {1, 2, 3} +set2 = {1, 5, 6} +set1.difference_update(set2) +print(set1) +print(set2) +# 输出 +{2, 3} +{1, 5, 6} +``` + +* 2个集合合并 + +语法:集合1.union(集合2) + +功能:将集合1和集合2组合成新集合,不影响原有集合1和集合2 + +```python +set1 = {1, 2, 3} +set3 = set1.union(set2) +print(set3) +print(set2) +print(set1) +# 输出 +{1, 2, 3, 5, 6} +{1, 5, 6} +{1, 2, 3} +``` + +#### 遍历 + +不支持while循环**** + +可以使用for循环 + +```python +set3 = {1, 2, 3, 5, 6} +for el in set3: + print(el, end=" ") +# 输出:1 2 3 5 6 +``` + #### 可哈希、不可哈希 * set 中的元素必须都是可哈希的(hashable) diff --git "a/Python/\351\235\242\345\220\221\345\257\271\350\261\241.md" "b/Python/\351\235\242\345\220\221\345\257\271\350\261\241.md" new file mode 100644 index 0000000..1988caa --- /dev/null +++ "b/Python/\351\235\242\345\220\221\345\257\271\350\261\241.md" @@ -0,0 +1,513 @@ +## 面向对象 + +#### 类 (class) + +* 类名通常采用大驼峰的格式: 所有单词的首字母大写:MyName +* 定义一个类 + +```python +class Dog: + """狗""" + pass +``` + +#### 类的实例化 + +* 可以通过类创建出对象 + * 对象也叫做类的实例 + * 通过类创建对象的过程,也叫做:类的实例化 + +#### 方法(method) + +* 什么是方法 + * 是一种需要通过对象来调用的特殊函数(function) + +* 常见的格式:对象.方法名(参数) + +#### 方法的定义 + +* 方法的定义格式和函数是一样的 +* 方法必须定义在类(class)的内部 +* 方法的第一个参数固定是self(类方法、静态方法除外) + * self 指向的是当前正在调用方法的对象 + * self 可以改为其他名字(建议保留使用self) +* 当通过对象.方法名(参数)方式调用方法时 + * 不需要显示传递参数给self + * Python 会自动将对象赋值给self + +```python +class Dog: + def run(self): + print(f'【{self.age}, {self.name}】') + +d1 = Dog() +d1.name = "GJ" +d1.age = 10 +d1.run() +``` + +#### 构造方法(constructor) + +* 构造方法是一种特殊的方法,方法名是固定的:`__init__` + * 对象在创建完毕时,会自动调用构造方法 + * 一般在构造方法中完成一些初始化操作,比如 + * 声明一下有哪些属性(一般也叫做:成员变量、实例变量) + * 初始化属性的值 + +```python +class Dog: + def __init__(self): + # 声明并初始化属性 + self.name = None + self.age = None + self.breed = None +``` + +* 带参数的构造方法 + + * 创建对象时传递的参数,会自动传递给构造方法 + + ```python + class Dog: + def __init__(self, name=None, age=1, breed=None): + # 声明并初始化属性 + self.name = name + self.age = age + self.breed = breed + + d1 = Dog() + ``` + +* 在子类的构造方法中,调用父类的构造方法 + +```python +class Person: + def __init__(self, name, age): + self.name = name + self.age = age + + def __str__(self): + return f'{self.name}_{self.age}' + + +class Student(Person): + def __init__(self, name, age, no): + super().__init__(name, age) + self.no = no + + def __str__(self): + return f'{self.no}_{super().__str__()}' + +s = Student('GJ', 18, 1) +print(s.__dict__) +print(s) + +# => {'name': 'GJ', 'age': 18, 'no': 1} +# => 1_GJ_18 +``` + +```python +class Person: + def __init__(self, name, age): + self.__name = name + self.__age = age + + @property + def age(self): + return self.__age + + @property + def name(self): + return self.__name + +class Student(Person): + def __init__(self, name, age, no): + super().__init__(name, age) + self.__no = no + + def show(self): + print(f'no is {self.__no}') + print(f'name is {self.name}') + print(f'age is {self.age}') + +s = Student('GJ', 18, 1) +s.show() + +=> +no is 1 +name is GJ +age is 18 +``` + + + + + +#### 内置的属性、方法 + +* 以下划线开头、结尾的属性、方法,通常都是对象内置的(与生俱来的) +* 属性:`__doc__`、`__annotations__`、`__dict__`等 +* 方法:`__init__`、`__str__`、`__len__`、`__bool__`等 + +##### `__dict__` + +* 对象的`__dict__`里面存放着对象的所有自定义属性 + +##### `__str__` + +* 执行`str(对象)`时会调用对象的`__str__`方法 + +##### 删除属性 + +* 可以通过del删除对象的属性 + +#### @property + +* `@property`是一个装饰器(decorator) + * 可以让getter、setter的使用方式,像访问属性一样简单、优雅 + +* 常规使用步骤 + 1. 让getter、setter 的方法名一样 + 2. 让`@property` 装饰getter + 3. 让`@方法名.setter` 装饰setter + 4. 用`对象.方法名 = 值`调用setter + +```python +class Student: + def __init__(self): + self.__name = None + self.__age = None + + def __str__(self): + return f'{self.__age}岁{self.__name}' + + @property + def name(self): + return self.__name + + @name.setter + def name(self, name): + self.__name = name + + @name.deleter + def name(self): + del self.__name + + @property + def age(self): + return self.__age + + @age.setter + def age(self, age): + self.__age = age + + @age.deleter + def age(self): + del self.__age + +s = Student() +s.age = 19 +s.name = 'GJ' +print(s.age) +print(s.name) +print(s.__dict__) + +del s.age +print(s.__dict__) +del s.name +print(s.__dict__) +``` + +在 Python 中不支持重载 + +#### 对象属性、类属性 + +```python +class Dog: + count = 0 + + def __init__(self, name): + self._name = name + # 访问类属性 + Dog.count += 1 + print(f'创建了第{Dog.count}条狗') + +d1 = Dog('GJ1') +d2 = Dog('GJ2') +``` + +* name + * 对象属性、实例属性 + * 对象变量、实例变量、成员变量 +* count + * 类属性 + * 类变量 + * 类属性存储在类中 + +##### 对象属性 + +```python +print(对象.属性) +对象.属性 = 值 +``` + +#### 类属性 + +```python +print(类.属性) +print(对象.__class__.属性) +类.属性 = 值、对象.__class__.属性 = 值 +# 不推荐写法 +print(对象.属性) +``` + +![image-20230224104215483](/Users/guojie/Notes/Python/images/访问对象属性.png) + +#### 类方法(class method) + +* 带有`@classmethod`装饰器的方法,叫做:类方法(第1个参数是固定的cls,代表类) +* 带有`@staticmethod`装饰器的方法,叫做:静态方法 +* 其他的方法,叫做:对象方法、实例方法(第1个参数是固定的self,代表对象) + +#### 对象方法、类方法 + +* 对象方法 + * 对象.方法(参数) + * 类.方法(对象,参数) + * 对象.`__class__`.方法(对象,参数) +* 类方法 + * 类.方法(参数) + * 对象.`__class__`.方法(参数) + * 对象.方法(参数) + +```python +class Dog: + def test1(self, text): + print('对象方法', id(self), text) + + @classmethod + def test2(cls,text): + print('类方法', id(cls), text) + +d1 = Dog() +d2 = Dog() + +# 对象方法 +d1.test1('内容1') +Dog.test1(d1, 'Dog') +d1.__class__.test1(d1, 'd1.__class__') +d2.__class__.test1(d1, 'd2.__class__') + +# 类方法 +d2.test2('内容2') +Dog.test1(d2, '内容1') +d1.__class__.test1(d2, 'd1.__class__') +d2.__class__.test1(d2, 'd2.__class__') +``` + +#### 静态方法 + +* 对象方法的第个参数是固定的self,代表对象 +* 类方法的第1个参数是固定的cls,代表类 +* 静态方法没有固定的参数 + +```python +@staticmethod +def test3(text): + print('静态方法', text) + +d3.test3('内容3') +Dog.test3('内容3') +d3.__class__.test3('内容3') +``` + +##### 调用方法 + +* 对象.方法(参数) +* 类.方法(参数) + +* 对象.`__class__`.方法(参数) + +#### 方法的选择 + +什么情况发下选择对象方法 + +* 方法的执行者是实例对象 + +什么情况下使用类方法 + +* 方法的执行者不要求是实例对象,无须实例化对象 +* 需要再方法内部操作当前类的类属性 + +什么情况下使用静态方法 + +* 方法的执行者不要求是实例对象,无须实例化对象 +* 不需要再方法内部操作当前类的类属性 + +#### 继承(inheritance) + +* Animal类一般被称为是Dog类的 + * 父类(parent class) + * 超类(super class) + * 基类(base class) +* Dog类一般被称为是Animal类 + * 子类(child class、sub class) + * 派生类、衍生类(derived class) +* 通过子类访问父类|通过父类访问子类方法 + +```python +class Camera: + def take_photo(self): + print('Camera') + +class Player: + def play(self): + print('Player play') + +class Phone(Camera, Player): + pass + +# 打印父类 +print(Phone. __bases__) => (, ) +print(Phone. __base__) => +# 打印子类 +print(Camera.__subclasses__()) => [] +``` + +* 类属性 + +在类里面,访问私有属性时,Python 内部会自动转成它真实的属性名进行访问 + +```python +class Person: + __count = 10 + + @classmethod + def show(cls): + # _Person_count + print(cls.__count) + + +class Student(Person): + __count = 20 + + @classmethod + def show(cls): + # _Student_count + print(cls.__count) + + +Person.show() +Student.show() +=> 10 20 +``` + +```python +class Person: + __count = 10 + @classmethod + def show(cls): + print(cls.__count) + +class Student(Person): + __count = 20 + +Person.show() +Student.show() +=> 10 10 +``` + +```python +class Person: + __count = 10 + @classmethod + def show(cls): + print(cls.__count) + +class Student(Person): + @classmethod + def show(cls): + print(cls.__count) + +Person.show() => 10 +Student.show() => AttributeError: type object 'Student' has no attribute '_Student__count' +``` + +#### 多继承 + +* Python 支持多继承 + +```python +class Camera: + def take_photo(self): + print('Camera') + +class Player: + def play(self): + print('Player play') + +class Phone(Camera, Player): + pass +``` + +* 实际开发过程中不推荐使用 + +#### 继承连 + +* 继承连可以无限长 + +#### 重写(override) + +什么是重写? + +* 子类拥有和父类一样的方法(相同名称、相同参数) +* 优先调用自己的方法,如果自己不存在这个方法,会顺着继承链向上寻找方法,直到找到为止 +* 重写会覆盖掉父类的方法实现,有些地方也叫做:覆写 + +对象方法 + +```python +调用cls类的父类中的对象方法 +cls.__base__.obj_method(obj, 参数) +# 等价于 +super(cls, obj).obj_method(参数) +# 等价于 +super().obj_method(参数) +``` + +#### 多态(polymorphism) + +什么是多态? + +* 父类类型的变量,指向子类类型的对象 +* 根据对象的真实类型,决定调用哪个对象方法 + +```python +class Animal: + def run(self): + print('Animal run') + +class Dog(Animal): + def run(self): + print('Dog run') + +class Cat(Animal): + def run(self): + print('Cat run') + +a = Animal() +d = Dog() +c = Cat() + +def test(obj: Animal): + obj.run() + +test(a) +test(d) +test(c) +=> +Animal run +Dog run +Cat run +``` + diff --git a/Swift/21-Swift-Key-Path.md b/Swift/21-Swift-Key-Path.md deleted file mode 100644 index 9285c95..0000000 --- a/Swift/21-Swift-Key-Path.md +++ /dev/null @@ -1,3 +0,0 @@ -### Key-Path Expression - -> 该表达式引用类型的属性或者下标 \ No newline at end of file diff --git "a/Swift/38-Swift-\345\271\266\345\217\221.md" "b/Swift/38-Swift-\345\271\266\345\217\221.md" deleted file mode 100644 index 4f602fa..0000000 --- "a/Swift/38-Swift-\345\271\266\345\217\221.md" +++ /dev/null @@ -1,2 +0,0 @@ -## Swift-并发 - diff --git "a/Swift/Swift\350\277\233\351\230\266\347\254\224\350\256\260/AttributedString.md" "b/Swift/Swift\350\277\233\351\230\266\347\254\224\350\256\260/AttributedString.md" new file mode 100644 index 0000000..f39d5b0 --- /dev/null +++ "b/Swift/Swift\350\277\233\351\230\266\347\254\224\350\256\260/AttributedString.md" @@ -0,0 +1,35 @@ +## AttributeString + +从iOS 15开始可以使用 + +#### 自定义 AttributedStringKey + +```swift +//定义 +enum OutlineColorAttribute : AttributedStringKey { + typealias Value = Color // 属性类型 + static let name = "OutlineColor" // 属性名称 +} + +struct ExtendedColorAtributes: AttributeScope { + let outlineColor: OutlineColorAttribute +} + +extension AttributeDynamicLookup { + subscript(dynamicMember keyPath: KeyPath) -> T { + get { self[T.self] } + } +} +``` + +```swift +//使用 +var attributedString2 = AttributedString("Hello") +attributedString.outlineColor = .red +``` + +#### 参考资料 + +1、[比较全面](https://nilcoalescing.com/blog/AttributedStringAttributeScopes/) + +2、[还可以](https://fatbobman.com/zh/posts/attributedstring/) \ No newline at end of file diff --git "a/Swift/Swift\350\277\233\351\230\266\347\254\224\350\256\260/\345\207\275\346\225\260.md" "b/Swift/Swift\350\277\233\351\230\266\347\254\224\350\256\260/\345\207\275\346\225\260.md" new file mode 100644 index 0000000..e69de29 diff --git "a/Swift/Swift\350\277\233\351\230\266\347\254\224\350\256\260/\345\215\217\350\256\256.md" "b/Swift/Swift\350\277\233\351\230\266\347\254\224\350\256\260/\345\215\217\350\256\256.md" new file mode 100644 index 0000000..d0d439f --- /dev/null +++ "b/Swift/Swift\350\277\233\351\230\266\347\254\224\350\256\260/\345\215\217\350\256\256.md" @@ -0,0 +1,20 @@ +## 协议 + +Swift 的协议可以通过扩展的方式,来提供超过它所要求的的功能 + +只有蝶衣中被要求的方法会被动态派发,“当你调用变量上的一个要求的方法时,具体哪一个方法会被使用,是在运行时基于变量的动态类型来决定的。协议扩展中的那些**非要求**的方法,始终会基于变量的静态类型进行静态派发 + +协议可以通过条件化扩展 (conditional extensions) 添加需要额外约束的 API + +协议支持**继承**其他的协议 + +协议可以被**组合**起来形成新的协议,即:协议合成 + +```swift +public typealias Codable = Decodable & Encodable +``` + +协议的实现支持依赖其他协议的实现,即:条件化实现 + +协议支持声明一个或者多个**关联类型**,这些类型充当占位符的角色,相关类型在之后会被用来为协议定义其他的要求。实现了这个协议的类型需要为每一个关联类型指定对应的具体类型 + diff --git "a/Swift/Swift\350\277\233\351\230\266\347\254\224\350\256\260/\345\217\257\351\200\211\345\200\274.md" "b/Swift/Swift\350\277\233\351\230\266\347\254\224\350\256\260/\345\217\257\351\200\211\345\200\274.md" new file mode 100644 index 0000000..bf50b6a --- /dev/null +++ "b/Swift/Swift\350\277\233\351\230\266\347\254\224\350\256\260/\345\217\257\351\200\211\345\200\274.md" @@ -0,0 +1,119 @@ +## 可选值 + +#### map + +对于可选值,调用 **map** 时,如果转换本身也是可选值,那么最终得到的将是一个双重嵌套的可选值 + +```swift +let stringNumbers = ["1", "2", "3", "foo"] +let x = stringNumbers.first.map { Int($0) } +x 的类型是 Int?? +``` + +#### flatMap + +可以把结果展平为单个可选值 + +```swift +let stringNumbers = ["1", "2", "3", "foo"] +let x = stringNumbers.first.flatMap { Int($0) } +x 的类型是 Int? +``` + +#### compactMap + +使用模式匹配 + +```swift +for case let i? in numbers.map({ Int($0) }) { + // i 是非可选值 + print(i) +} +``` + +可以将nil过滤出去,并将非**nil**值进行解包的map + +从**非可选值** ==> **可选值** + +Swift 会**自动**完成隐式转换 + +#### 字典 + +如果想要设置某个key的value为 nil,不能直接通过语法糖设置,**会导致字典将该key移除** + +```swift +var dictWithNils: [String: Int?] = [ + "one": 1, + "two": 2, + "none": nil + ] +// 打印 +["one": Optional(1), "two": Optional(2), "none": nil] +// ❌,导致key被移除 +dictWithNils["two"] = (nil) +dictWithNils["two"] = Optional(nil) + +// ✅,正确写法 +dictWithNils["two"] = .some(nil) +dictWithNils.updateValue(nil, forKey: "two") +dictWithNils["two"]? = nil +``` + +#### 强制解包的时机 + +当你能确定你的某个值不可能是 nil 时可以使用叹号,你应当会希望如果它意外是 nil 的话,程序应当直接挂掉 + +#### 调试版本添加断言信息 + +通过添加运算符重载 + +```swift +// 整数 +infix operator !? +func !?(wrapped: T?, failureText: @autoclosure () -> String) ->T { + assert(wrapped != nil, failureText()) + return wrapped ?? 0 +} +// 数组 +func !?(wrapped: T?, failText: @autoclosure () -> String) -> T { + assert(wrapped != nil, failText()) + return wrapped ?? [] +} +// 字符串 +func !?(wrapped: T?, failText: @autoclosure () -> String) -> T { + assert(wrapped != nil, failText()) + return wrapped ?? "" +} +// 字典 +func !?(wrapped: T?, failText: @autoclosure () -> String) -> T { + assert(wrapped != nil, failText()) + return wrapped ?? [:] +} +// 显式地提供一个不同的默认值,或者是为非标准的类型提供这个操作符 +func !?(wrapped: T?, nilDefault: @autoclosure () -> (value: T, text: String)) -> T { + assert(wrapped != nil, nilDefault().text) + return wrapped ?? nilDefault().value +} +``` + +针对**挂起**操作,有**三种使用方式** + +1、使用assert:**发布版本中,会被移除** + +2、使用fatalError:**发布版本中,会被移除** + +3、使用precondition:发布版本中**不会**被移除 + +#### 隐式可选值行为 + +虽然隐式解包的可选值在行为上就好像是非可选值一样,不过你依然可以对它们使用可选链,nil 合并,if let,map 或者将它们与 nil 比较,所有的这些操作都是一样的 + +```swift +// ❌,Crash +var a: String! = nil +let b = a.isEmpty +// ✅,正常执行 +var a: String! = nil +let c = a?.isEmpty +``` + diff --git "a/Swift/Swift\350\277\233\351\230\266\347\254\224\350\256\260/\345\255\227\347\254\246\344\270\262.md" "b/Swift/Swift\350\277\233\351\230\266\347\254\224\350\256\260/\345\255\227\347\254\246\344\270\262.md" new file mode 100644 index 0000000..a3983e7 --- /dev/null +++ "b/Swift/Swift\350\277\233\351\230\266\347\254\224\350\256\260/\345\255\227\347\254\246\344\270\262.md" @@ -0,0 +1,223 @@ +## 字符串 + +#### Unicode + +是一个可变长格式 + +* 一个**Unicode**字符,也叫做扩展子位簇(exteneded grapheme cluster),由一个或多个Unicode标量(Unicode scalar)组成 +* 一个**Unicode**标量可以被编码成一个或多个编码单元(code units) + +用户在屏幕中看到的单个字符,可能是由多个Unicode标量组合起来,“对于这种用户感知到的“单个字符”,**Unicode** 中有一个术语,叫做 **(扩展) 字位簇**,对应的英文叫做 (extended) grapheme cluster。 + +字位簇是通过**Character**表示 + +#### 字符串 + +是 **value Types** + +**被复制** + +当 `String` 值被传递给函数或方法时,或者当它被赋值给常量或变量时,该 `String` 值被复制。在每种情况下,都会创建现有 `String` 值的新副本,并传递或分配新副本,而不是原始版本 + +#### 多行字符串 + +1、当源代码在多行字符串文本中包含换行符时,该换行符也会出现在字符串的值中。如果你想使用换行符让你的源代码更容易阅读,但你不希望换行符成为字符串值的一部分,在这些行末尾写一个反斜杠( `\` ): + +```swift +let softWrappedQuotation = """ +The White Rabbit put on his spectacles. "Where shall I begin, \ +The GJ is Good Boy +""" +print(softWrappedQuotation) +=> The White Rabbit put on his spectacles. "Where shall I begin, The GJ is Good Boy +``` + +```swift +let softWrappedQuotation = """ +The White Rabbit put on his spectacles. "Where shall I begin, +The GJ is Good Boy +""" +print(softWrappedQuotation) +=> The White Rabbit put on his spectacles. "Where shall I begin, +The GJ is Good Boy +``` + +#### 扩展字符串分隔符 + +作用 + +1、可以将字符串字面值放在扩展分隔符**#**中,以便在不调用其效果的情况下在字符串中包含特殊字符 + +```swift +let threeMoreDoubleQuotationMarks = #""" +Here are three more double \n quotes +"""# +print(threeMoreDoubleQuotationMarks) +// 代码中\n不会被生效 +=> Here are three more double \n quotes +``` + +2、如果需要再扩展分隔符中生效特殊字符,可以添加**#** + +```swift +let threeMoreDoubleQuotationMarks = #""" +Here are three more double \#n quotes +"""# +print(threeMoreDoubleQuotationMarks) +// 代码中\n会被生效 +=> +Here are three more double + quotes +``` + +#### Character + +1、**遍历字符串,得到每一个Character(字符)** + +```swift +for s in "GJ" { + print(s) +} +=> +"G" +"J" +``` + +2、**String 中拼接Character字符** + +调用``public mutating func append(_ other: String)``方法,来自 ``extension String : RangeReplaceableCollection`` + +```swift +var re: String = "GJ" +let excle: Character = "F" +re.append(excle) +``` + +3、**`Character` 值必须只包含一个字符** + +4、字符串插值 + +```swift +let multiplier = 3 +let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)" +print("Write an interpolated string in Swift using \(multiplier).") +print(#"Write an interpolated string in Swift using \(multiplier)."#) +=> +Write an interpolated string in Swift using 3. +Write an interpolated string in Swift using \(multiplier). +``` + +5、Swift对 `Character` 值使用扩展字形簇意味着字符串连接和修改**不一定**会影响字符串的字符数 + +```swift +var word = "cafe" +print("the number of characters in \(word) is \(word.count)") +// Prints "the number of characters in cafe is 4" +// 结尾拼接上新的字符 +word += "\u{301}" // COMBINING ACUTE ACCENT, U+0301 +// 结果中仍然是4个字符 +print("the number of characters in \(word) is \(word.count)") +// Prints "the number of characters in café is 4" +``` + +6、Swift 中 String 的 count 并**不一定**与 NSString 中 length 的值相同 + +两个内存组成不同: `NSString` 的长度基于字符串的UTF-16表示中16位代码单元的数量,而不是字符串中Unicode扩展字形簇的数量。 + +7、不能通过整数值作为索引来访问 + +具体访问方法如下 + +endIndex:表示的String中最后一个字符位置的下一个索引位置 + +```swift +let greeting = "Guten Tag!" +greeting[greeting.startIndex] +// G +greeting[greeting.index(before: greeting.endIndex)] +// ! +greeting[greeting.index(after: greeting.startIndex)] +// u +let index = greeting.index(greeting.startIndex, offsetBy: 7) +greeting[index] +// a +``` + +访问**超过字符串范围外的索引值**将触发运行时错误 + +```swift +greeting[greeting.endIndex] +greeting.index(after: greeting.endIndex) +``` + +8、在对字符串执行操作时,只在很短的时间内使用子字符串。当您准备长时间存储结果时,可以将子字符串转换为 `String` 的实例 + +```swift +let greeting = "Hello, world!" +let index = greeting.firstIndex(of: ",") ?? greeting.endIndex +let beginning = greeting[.. 是一种可以保持类型安全性的代码重用技术 + +通常认为泛型是多态的一种形式,而多态则是指一个接口或者名称可以通过多个类型进行访问的现象 + +多态范畴包括但不限于下面4种概念 + +* 多个同名但是类型不同的函数 +* 当一个函数或方法接受类 C 作为参数的时候,我们也可以给它传递 C 的派生类,这种用法叫做**子类型多态 (subtype polymorphism)** +* 当一个函数 (通过尖括号语法) 接受泛型参数的时候,我们管这个函数叫做**泛型函数** (generic function) (这和泛型类型类似)。这种用法叫做**参数化多态** (parametric polymorphism)。这些泛型化的参数,也被叫做**泛型 (generics)** +* 定义一个协议并让多个类型实现它。这是另外一种更加结构化的**专属多态** diff --git "a/Swift/Swift\350\277\233\351\230\266\347\254\224\350\256\260/\351\224\256\350\267\257\345\276\204.md" "b/Swift/Swift\350\277\233\351\230\266\347\254\224\350\256\260/\351\224\256\350\267\257\345\276\204.md" new file mode 100644 index 0000000..a4493b0 --- /dev/null +++ "b/Swift/Swift\350\277\233\351\230\266\347\254\224\350\256\260/\351\224\256\350\267\257\345\276\204.md" @@ -0,0 +1,26 @@ +## 键路径 + +> 描述了一个从根开始的类型层级路径 + +1、键路径可以由任意的存储和计算属性组合而成,编译器会自动为所有类型生成**[keyPath:]**的下标方法,通过这个方法来""调用""某个键路径 + +2、键路径不仅可以对属性做引用,也可以用它们来描述下标操作 + +#### 可写键路径 + +**作用**:用它来读取或者写入一个值 + +形式: + +* **WritableKeyPath**:适用除了**ReferenceWritableKeyPath**之外的所有类型,**要求原值是可变的** +* **ReferenceWritableKeyPath**:和具有引用语义的值配合使用,**不要求原值是可变** + +#### 键路径类型 + +* **AnyKeyPath** 与 **(Any) -> Any?** 函数相似 + +* **PartialKeyPath\** 和 **(Source) -> Any?** 函数相似 +* **KeyPath** 和 **(Source) -> Target** 函数相似 +* **WritableKeyPath** 和 **(Source) -> Target** 与 **(inout Source, Target) -> ()** 一对函数相似 + +* **ReferenceWritableKeyPath** 和 **(Source) -> Target** 与 **(Source, Target) -> ()** 这一对函数相似 \ No newline at end of file diff --git "a/Swift/01-Swift--\345\270\270\351\207\217\343\200\201\345\217\230\351\207\217.md" "b/Swift/\345\237\272\347\241\200/01-Swift--\345\270\270\351\207\217\343\200\201\345\217\230\351\207\217.md" similarity index 100% rename from "Swift/01-Swift--\345\270\270\351\207\217\343\200\201\345\217\230\351\207\217.md" rename to "Swift/\345\237\272\347\241\200/01-Swift--\345\270\270\351\207\217\343\200\201\345\217\230\351\207\217.md" diff --git "a/Swift/02-Swift--\345\237\272\346\234\254\350\277\220\347\256\227\347\254\246.md" "b/Swift/\345\237\272\347\241\200/02-Swift--\345\237\272\346\234\254\350\277\220\347\256\227\347\254\246.md" similarity index 100% rename from "Swift/02-Swift--\345\237\272\346\234\254\350\277\220\347\256\227\347\254\246.md" rename to "Swift/\345\237\272\347\241\200/02-Swift--\345\237\272\346\234\254\350\277\220\347\256\227\347\254\246.md" diff --git "a/Swift/03-Swift--\345\255\227\347\254\246\344\270\262\343\200\201\345\255\227\347\254\246.md" "b/Swift/\345\237\272\347\241\200/03-Swift--\345\255\227\347\254\246\344\270\262\343\200\201\345\255\227\347\254\246.md" similarity index 100% rename from "Swift/03-Swift--\345\255\227\347\254\246\344\270\262\343\200\201\345\255\227\347\254\246.md" rename to "Swift/\345\237\272\347\241\200/03-Swift--\345\255\227\347\254\246\344\270\262\343\200\201\345\255\227\347\254\246.md" diff --git "a/Swift/04-Swift--\351\233\206\345\220\210.md" "b/Swift/\345\237\272\347\241\200/04-Swift--\351\233\206\345\220\210.md" similarity index 100% rename from "Swift/04-Swift--\351\233\206\345\220\210.md" rename to "Swift/\345\237\272\347\241\200/04-Swift--\351\233\206\345\220\210.md" diff --git "a/Swift/05-Swift--\346\216\247\345\210\266\346\265\201.md" "b/Swift/\345\237\272\347\241\200/05-Swift--\346\216\247\345\210\266\346\265\201.md" similarity index 100% rename from "Swift/05-Swift--\346\216\247\345\210\266\346\265\201.md" rename to "Swift/\345\237\272\347\241\200/05-Swift--\346\216\247\345\210\266\346\265\201.md" diff --git "a/Swift/06-Swift--\345\207\275\346\225\260.md" "b/Swift/\345\237\272\347\241\200/06-Swift--\345\207\275\346\225\260.md" similarity index 100% rename from "Swift/06-Swift--\345\207\275\346\225\260.md" rename to "Swift/\345\237\272\347\241\200/06-Swift--\345\207\275\346\225\260.md" diff --git "a/Swift/07-Swift--\351\227\255\345\214\205.md" "b/Swift/\345\237\272\347\241\200/07-Swift--\351\227\255\345\214\205.md" similarity index 100% rename from "Swift/07-Swift--\351\227\255\345\214\205.md" rename to "Swift/\345\237\272\347\241\200/07-Swift--\351\227\255\345\214\205.md" diff --git "a/Swift/08-Swift--\346\236\232\344\270\276.md" "b/Swift/\345\237\272\347\241\200/08-Swift--\346\236\232\344\270\276.md" similarity index 98% rename from "Swift/08-Swift--\346\236\232\344\270\276.md" rename to "Swift/\345\237\272\347\241\200/08-Swift--\346\236\232\344\270\276.md" index 34b0e3d..0b02b12 100644 --- "a/Swift/08-Swift--\346\236\232\344\270\276.md" +++ "b/Swift/\345\237\272\347\241\200/08-Swift--\346\236\232\344\270\276.md" @@ -113,7 +113,7 @@ let possiblePlanet = Planet(rawValue: 7) ### 递归枚举 * 也是一种枚举类型,它有一个或多个枚举成员使用该枚举类型的实例作为关联值 -* 使用递归枚举时,编译器会插入一个间接层。你可以在枚举成员前加上 indirect 来表示该成员可递归 +* 使用递归枚举时,编译器会插入一个间接层。你可以在枚举成员前加上 **indirect** 来表示该成员可递归 ```swift func evaluate(_ expression: ArithmeticExpression) -> Int { diff --git "a/Swift/09-Swift--\347\261\273\345\222\214\347\273\223\346\236\204\344\275\223.md" "b/Swift/\345\237\272\347\241\200/09-Swift--\347\261\273\345\222\214\347\273\223\346\236\204\344\275\223.md" similarity index 100% rename from "Swift/09-Swift--\347\261\273\345\222\214\347\273\223\346\236\204\344\275\223.md" rename to "Swift/\345\237\272\347\241\200/09-Swift--\347\261\273\345\222\214\347\273\223\346\236\204\344\275\223.md" diff --git "a/Swift/10-Swift--\345\261\236\346\200\247.md" "b/Swift/\345\237\272\347\241\200/10-Swift--\345\261\236\346\200\247.md" similarity index 100% rename from "Swift/10-Swift--\345\261\236\346\200\247.md" rename to "Swift/\345\237\272\347\241\200/10-Swift--\345\261\236\346\200\247.md" diff --git "a/Swift/11-Swift--\346\226\271\346\263\225.md" "b/Swift/\345\237\272\347\241\200/11-Swift--\346\226\271\346\263\225.md" similarity index 100% rename from "Swift/11-Swift--\346\226\271\346\263\225.md" rename to "Swift/\345\237\272\347\241\200/11-Swift--\346\226\271\346\263\225.md" diff --git "a/Swift/12-Swift--\344\270\213\346\240\207.md" "b/Swift/\345\237\272\347\241\200/12-Swift--\344\270\213\346\240\207.md" similarity index 100% rename from "Swift/12-Swift--\344\270\213\346\240\207.md" rename to "Swift/\345\237\272\347\241\200/12-Swift--\344\270\213\346\240\207.md" diff --git "a/Swift/13-Swift--\347\273\247\346\211\277.md" "b/Swift/\345\237\272\347\241\200/13-Swift--\347\273\247\346\211\277.md" similarity index 100% rename from "Swift/13-Swift--\347\273\247\346\211\277.md" rename to "Swift/\345\237\272\347\241\200/13-Swift--\347\273\247\346\211\277.md" diff --git "a/Swift/14-Swift--\346\236\204\351\200\240\345\231\250.md" "b/Swift/\345\237\272\347\241\200/14-Swift--\346\236\204\351\200\240\345\231\250.md" similarity index 100% rename from "Swift/14-Swift--\346\236\204\351\200\240\345\231\250.md" rename to "Swift/\345\237\272\347\241\200/14-Swift--\346\236\204\351\200\240\345\231\250.md" diff --git "a/Swift/15-Swift--\346\236\220\346\236\204\345\231\250.md" "b/Swift/\345\237\272\347\241\200/15-Swift--\346\236\220\346\236\204\345\231\250.md" similarity index 100% rename from "Swift/15-Swift--\346\236\220\346\236\204\345\231\250.md" rename to "Swift/\345\237\272\347\241\200/15-Swift--\346\236\220\346\236\204\345\231\250.md" diff --git "a/Swift/16-Swift--\346\211\251\345\261\225.md" "b/Swift/\345\237\272\347\241\200/16-Swift--\346\211\251\345\261\225.md" similarity index 100% rename from "Swift/16-Swift--\346\211\251\345\261\225.md" rename to "Swift/\345\237\272\347\241\200/16-Swift--\346\211\251\345\261\225.md" diff --git "a/Swift/17-Swift--\346\226\255\350\250\200.md" "b/Swift/\345\237\272\347\241\200/17-Swift--\346\226\255\350\250\200.md" similarity index 100% rename from "Swift/17-Swift--\346\226\255\350\250\200.md" rename to "Swift/\345\237\272\347\241\200/17-Swift--\346\226\255\350\250\200.md" diff --git "a/Swift/18-Swift--\350\256\277\351\227\256\346\216\247\345\210\266.md" "b/Swift/\345\237\272\347\241\200/18-Swift--\350\256\277\351\227\256\346\216\247\345\210\266.md" similarity index 100% rename from "Swift/18-Swift--\350\256\277\351\227\256\346\216\247\345\210\266.md" rename to "Swift/\345\237\272\347\241\200/18-Swift--\350\256\277\351\227\256\346\216\247\345\210\266.md" diff --git "a/Swift/19-Swift--\345\215\217\350\256\256.md" "b/Swift/\345\237\272\347\241\200/19-Swift--\345\215\217\350\256\256.md" similarity index 99% rename from "Swift/19-Swift--\345\215\217\350\256\256.md" rename to "Swift/\345\237\272\347\241\200/19-Swift--\345\215\217\350\256\256.md" index 16c2bc1..756f345 100644 --- "a/Swift/19-Swift--\345\215\217\350\256\256.md" +++ "b/Swift/\345\237\272\347\241\200/19-Swift--\345\215\217\350\256\256.md" @@ -149,3 +149,7 @@ protocol Runnable: class {} @objc protocol Runnable {} ``` +#### 存在体 + +//TODO 待补充 + diff --git "a/Swift/20-Swift-\347\211\271\346\256\212\347\261\273\345\236\213.md" "b/Swift/\345\237\272\347\241\200/20-Swift-\347\211\271\346\256\212\347\261\273\345\236\213.md" similarity index 100% rename from "Swift/20-Swift-\347\211\271\346\256\212\347\261\273\345\236\213.md" rename to "Swift/\345\237\272\347\241\200/20-Swift-\347\211\271\346\256\212\347\261\273\345\236\213.md" diff --git "a/Swift/\345\237\272\347\241\200/21-Swift-Key-Path-Expression.md" "b/Swift/\345\237\272\347\241\200/21-Swift-Key-Path-Expression.md" new file mode 100644 index 0000000..c2f203b --- /dev/null +++ "b/Swift/\345\237\272\347\241\200/21-Swift-Key-Path-Expression.md" @@ -0,0 +1,16 @@ +### Key-Path键路径 + +> 描述一个从根开始的类型层级路径 + + + +我们可以为**一个函数创建一个等效的实现**,该函数`(Root) -> Value`预期的键路径为`\Root.Value`。在Swift 5.2中,我们甚至不需要自己做转换。根据这项提议,该功能被内置到Swift中,结果,一个键路径表达式`\Root.value`可以在允许使用`(Root) -> valu`e函数的地方使用。同样,**键路径表明它可以做的不仅仅是访问一个值。在这种情况下,它甚至取代了一个函数调用。** + + + +[针对\.self 写法的解释](https://www.hackingwithswift.com/books/ios-swiftui/why-does-self-work-for-foreach) + +[探索Swift中KeyPath的使用](https://juejin.cn/post/7093702462233640973) + + + diff --git "a/Swift/22-Swift-\351\224\231\350\257\257.md" "b/Swift/\345\237\272\347\241\200/22-Swift-\351\224\231\350\257\257.md" similarity index 100% rename from "Swift/22-Swift-\351\224\231\350\257\257.md" rename to "Swift/\345\237\272\347\241\200/22-Swift-\351\224\231\350\257\257.md" diff --git "a/Swift/23-Swift-\346\263\233\345\236\213.md" "b/Swift/\345\237\272\347\241\200/23-Swift-\346\263\233\345\236\213.md" similarity index 75% rename from "Swift/23-Swift-\346\263\233\345\236\213.md" rename to "Swift/\345\237\272\347\241\200/23-Swift-\346\263\233\345\236\213.md" index df88add..7e01a5f 100644 --- "a/Swift/23-Swift-\346\263\233\345\236\213.md" +++ "b/Swift/\345\237\272\347\241\200/23-Swift-\346\263\233\345\236\213.md" @@ -73,7 +73,13 @@ class Person { } ``` +#### 泛型特化 +在许多情况下 Swift 编译器可以使用一种叫做**泛型特化 (generic specialization)** 或者称作**单态 (monomorphization)** 的方式 + +**特化**是指:编译器用 Int 这样的具体类型作为泛型参数类型,去把泛型类型或者函数复制一份,然后特化后的函数可以专门为Int进行优化,并去掉所有的间接层 + +特化不仅仅节省了虚拟派发的开销,也开启的更多优化的可能 diff --git "a/Swift/24-Swift-\346\272\242\345\207\272\350\277\220\347\256\227\347\254\246.md" "b/Swift/\345\237\272\347\241\200/24-Swift-\346\272\242\345\207\272\350\277\220\347\256\227\347\254\246.md" similarity index 100% rename from "Swift/24-Swift-\346\272\242\345\207\272\350\277\220\347\256\227\347\254\246.md" rename to "Swift/\345\237\272\347\241\200/24-Swift-\346\272\242\345\207\272\350\277\220\347\256\227\347\254\246.md" diff --git a/Swift/25-Swift-Equatable.md "b/Swift/\345\237\272\347\241\200/25-Swift-Equatable.md" similarity index 100% rename from Swift/25-Swift-Equatable.md rename to "Swift/\345\237\272\347\241\200/25-Swift-Equatable.md" diff --git "a/Swift/26-Swift-\345\206\205\345\255\230\347\256\241\347\220\206.md" "b/Swift/\345\237\272\347\241\200/26-Swift-\345\206\205\345\255\230\347\256\241\347\220\206.md" similarity index 100% rename from "Swift/26-Swift-\345\206\205\345\255\230\347\256\241\347\220\206.md" rename to "Swift/\345\237\272\347\241\200/26-Swift-\345\206\205\345\255\230\347\256\241\347\220\206.md" diff --git "a/Swift/27-Swift-\346\250\241\345\274\217\345\214\271\351\205\215.md" "b/Swift/\345\237\272\347\241\200/27-Swift-\346\250\241\345\274\217\345\214\271\351\205\215.md" similarity index 100% rename from "Swift/27-Swift-\346\250\241\345\274\217\345\214\271\351\205\215.md" rename to "Swift/\345\237\272\347\241\200/27-Swift-\346\250\241\345\274\217\345\214\271\351\205\215.md" diff --git "a/Swift/28-Swift-\344\273\243\347\240\201\346\240\207\350\256\260.md" "b/Swift/\345\237\272\347\241\200/28-Swift-\344\273\243\347\240\201\346\240\207\350\256\260.md" similarity index 100% rename from "Swift/28-Swift-\344\273\243\347\240\201\346\240\207\350\256\260.md" rename to "Swift/\345\237\272\347\241\200/28-Swift-\344\273\243\347\240\201\346\240\207\350\256\260.md" diff --git "a/Swift/29-Swift-\346\235\241\344\273\266\347\274\226\350\257\221.md" "b/Swift/\345\237\272\347\241\200/29-Swift-\346\235\241\344\273\266\347\274\226\350\257\221.md" similarity index 100% rename from "Swift/29-Swift-\346\235\241\344\273\266\347\274\226\350\257\221.md" rename to "Swift/\345\237\272\347\241\200/29-Swift-\346\235\241\344\273\266\347\274\226\350\257\221.md" diff --git "a/Swift/30-Swift-\350\207\252\345\256\232\344\271\211\347\250\213\345\272\217\345\205\245\345\217\243.md" "b/Swift/\345\237\272\347\241\200/30-Swift-\350\207\252\345\256\232\344\271\211\347\250\213\345\272\217\345\205\245\345\217\243.md" similarity index 100% rename from "Swift/30-Swift-\350\207\252\345\256\232\344\271\211\347\250\213\345\272\217\345\205\245\345\217\243.md" rename to "Swift/\345\237\272\347\241\200/30-Swift-\350\207\252\345\256\232\344\271\211\347\250\213\345\272\217\345\205\245\345\217\243.md" diff --git "a/Swift/31-Swift-OC\346\241\245\346\216\245.md" "b/Swift/\345\237\272\347\241\200/31-Swift-OC\346\241\245\346\216\245.md" similarity index 100% rename from "Swift/31-Swift-OC\346\241\245\346\216\245.md" rename to "Swift/\345\237\272\347\241\200/31-Swift-OC\346\241\245\346\216\245.md" diff --git "a/Swift/32-Swift-\345\207\275\346\225\260\345\274\217\347\274\226\347\250\213.md" "b/Swift/\345\237\272\347\241\200/32-Swift-\345\207\275\346\225\260\345\274\217\347\274\226\347\250\213.md" similarity index 100% rename from "Swift/32-Swift-\345\207\275\346\225\260\345\274\217\347\274\226\347\250\213.md" rename to "Swift/\345\237\272\347\241\200/32-Swift-\345\207\275\346\225\260\345\274\217\347\274\226\347\250\213.md" diff --git "a/Swift/33-Swift-\351\235\242\345\220\221\345\215\217\350\256\256\347\274\226\347\250\213.md" "b/Swift/\345\237\272\347\241\200/33-Swift-\351\235\242\345\220\221\345\215\217\350\256\256\347\274\226\347\250\213.md" similarity index 100% rename from "Swift/33-Swift-\351\235\242\345\220\221\345\215\217\350\256\256\347\274\226\347\250\213.md" rename to "Swift/\345\237\272\347\241\200/33-Swift-\351\235\242\345\220\221\345\215\217\350\256\256\347\274\226\347\250\213.md" diff --git "a/Swift/34-Swift-\345\223\215\345\272\224\345\274\217\347\274\226\347\250\213.md" "b/Swift/\345\237\272\347\241\200/34-Swift-\345\223\215\345\272\224\345\274\217\347\274\226\347\250\213.md" similarity index 100% rename from "Swift/34-Swift-\345\223\215\345\272\224\345\274\217\347\274\226\347\250\213.md" rename to "Swift/\345\237\272\347\241\200/34-Swift-\345\223\215\345\272\224\345\274\217\347\274\226\347\250\213.md" diff --git "a/Swift/35-Swfit-\345\217\215\345\260\204.md" "b/Swift/\345\237\272\347\241\200/35-Swfit-\345\217\215\345\260\204.md" similarity index 100% rename from "Swift/35-Swfit-\345\217\215\345\260\204.md" rename to "Swift/\345\237\272\347\241\200/35-Swfit-\345\217\215\345\260\204.md" diff --git "a/Swift/36-\345\206\205\345\255\230\350\256\277\351\227\256\345\206\262\347\252\201.md" "b/Swift/\345\237\272\347\241\200/36-\345\206\205\345\255\230\350\256\277\351\227\256\345\206\262\347\252\201.md" similarity index 100% rename from "Swift/36-\345\206\205\345\255\230\350\256\277\351\227\256\345\206\262\347\252\201.md" rename to "Swift/\345\237\272\347\241\200/36-\345\206\205\345\255\230\350\256\277\351\227\256\345\206\262\347\252\201.md" diff --git "a/Swift/37-\346\214\207\351\222\210.md" "b/Swift/\345\237\272\347\241\200/37-\346\214\207\351\222\210.md" similarity index 100% rename from "Swift/37-\346\214\207\351\222\210.md" rename to "Swift/\345\237\272\347\241\200/37-\346\214\207\351\222\210.md" diff --git "a/Swift/\345\237\272\347\241\200/38-Swift-\345\271\266\345\217\221.md" "b/Swift/\345\237\272\347\241\200/38-Swift-\345\271\266\345\217\221.md" new file mode 100644 index 0000000..7e99b05 --- /dev/null +++ "b/Swift/\345\237\272\347\241\200/38-Swift-\345\271\266\345\217\221.md" @@ -0,0 +1,263 @@ +## Swift-并发 + +#### 定义异步方法 + +为了表明函数或方法是异步的,可以在其参数后面的声明中写入 `async` 关键字,类似于使用 `throws` 标记抛出函数。如果函数或方法返回一个值,在返回箭头( `->` )之前写 `async` + +对于既异步又抛出的函数或方法,在 `throws` 之前写 `async` + +```swift +func listPhotos(inGallery name: String) async throws -> [String] { + let result = // ... some asynchronous networking code ... + return result +} +``` + +#### 调用异步方法 + +只有如下地方可以调用异步函数或方法 + +* Code in the body of an asynchronous function, method, or property. + +异步函数、方法或属性体中的代码 + +* Code in the static `main()` method of a structure, class, or enumeration that’s marked with `@main`. + +标记为 `@main` 的结构体、类或枚举的静态 `main()` 方法中的代码。 + +* Code in an unstructured child task, as shown in [Unstructured Concurrency](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/concurrency#Unstructured-Concurrency) below + +非结构化子任务中的代码,如下面的非结构化并发中所示。 + +#### 执行流程 + +调用异步方法时,执行将暂停,直到该方法返回。在调用前面写 `await` 来标记可能的暂停点。这就像在调用抛出函数时写 `try` ,以标记在出现错误时可能对程序流进行的更改。在异步方法内部,只有在调用另一个异步方法时才挂起执行流程——挂起从来不是隐式的或抢占式的——这意味着每个可能的挂起点都用 `await` 标记。标记代码中所有可能的挂起点有助于使并发代码更容易阅读和理解 + +#### 模拟并发工作时间 + + `Task.sleep(for:tolerance:clock:)` 此方法将当前任务挂起至少给定的时间。用来模拟等待网络耗时情况 + +```swift +// 定义 +func listPhotos(inGallery name: String) async throws -> [String] { + try await Task.sleep(for: .seconds(2)) + return ["IMG001", "IMG99", "IMG0404"] +} +// 调用 +let photos = try await listPhotos(inGallery: "A Rainy Weekend") +``` + +#### Asynchronous Sequences(异步序列) + +遍历时,一次等待集合的一个元素,对应的协议是:AsyncSequence + +```swift +let handle = FileHandle.standardInput +for try await line in handle.bytes.lines { + print(line) +} +``` + +#### 并行调用异步函数 + +1、一次只运行一段代码,逐个调用,调用方等待该代码完成后,再继续运行下一行代码 + +```swift +let firstPhoto = await downloadPhoto(named: photoNames[0]) +let secondPhoto = await downloadPhoto(named: photoNames[1]) +let thirdPhoto = await downloadPhoto(named: photoNames[2]) + +let photos = [firstPhoto, secondPhoto, thirdPhoto] +show(photos) +``` + +**最大问题:**虽然是异步方式,并且允许在下载过程中进行其他工作,但是一次只运行一个对downloadPhoto的调用 + +**改进**:调用异步代码并让它与周围代码并行运行,**在定义常量时在 `let` 前面写 `async` ,然后在每次使用常量时写 `await`** + +```swift +async let firstPhoto = downloadPhoto(named: photoNames[0]) +async let secondPhoto = downloadPhoto(named: photoNames[1]) +async let thirdPhoto = downloadPhoto(named: photoNames[2]) + +let photos = await [firstPhoto, secondPhoto, thirdPhoto] +show(photos) +``` + +让同时多个异步代码可以同时执行 + +#### Task and Task Groups (任务和任务组) + +任务是作为程序的一部分异步运行的工作单元,所有异步代码都是作为某个任务的一部分运行,创建多个任务时,Swift可以让它们同时运行 + +**Async - let** :语法会隐式创建子任务,用于明确知道需要运行哪些任务场景 + +**TaskGroup**:创建任务组,显式添加子任务,更好控制优先级和任务取消,允许创建动态数量的任务 + +同一个任务组中,每个任务都有相同的父任务,每个任务可以拥有子任务,由于任务和任务组之间存在显式关系,因此这种方法称为结构化并发。**具有如下特点:** + +* 在**父任务**中,不能忘记等待它的**子任务**完成 +* 当在**子任务**上设置更高的优先级时,**父任务**的优先级将自动升级 +* 当**父任务**被取消时,它的每个**子任务**也会自动取消 +* 任务本地值有效且自动地传播到**子任务** + +使用任务组,有两个方法:``withTaskGroup``、``withThrowingTaskGroup(支持抛出异常)`` + +```swift +await withTaskGroup(of: Data.self) { group in + let photoNames = await listPhotos(inGallery: "Summer Vacation") + for name in photoNames { + group.addTask { + return await downloadPhoto(named: name) + } + } + for await photo in group { + show(photo) + } +} +``` +如果需要再任务组有返回结果,则可以这样子 +```swift +let photos = await withTaskGroup(of: Data.self) { group in + let photoNames = await listPhotos(inGallery: "Summer Vacation") + for name in photoNames { + group.addTask { + return await downloadPhoto(named: name) + } + } + var results: [Data] = [] + // 循环等待下一个子任务完成,将该任务的结果附加到结果数组中,然后继续等待,直到所有子任务都完成 + for await photo in group { + results.append(photo) + } + return results +} +``` + +#### Task Cancellation(任务取消) + +遇到如下场景,则会任务取消 + +* 抛出类似CancellationError的错误 +* 返回nil或者空集合 +* 返回部分完成的工作 + +当需要检查**任务是否被取消**时,可以通过如下两种方法 + +```swift +// 第一种(会抛出错误) +Task.checkCancellation() +// 第二种(属性) +Task.isCancelled +``` + +```swift +let photos = await withTaskGroup(of: Optional.self) { group in + let photoNames = await listPhotos(inGallery: "Summer Vacation") + for name in photoNames { + // addTaskUnlessCancelled:避免在取消后开始新的工作 + group.addTaskUnlessCancelled { + guard isCancelled == false else { return nil } + return await downloadPhoto(named: name) + } + } + var results: [Data] = [] + for await photo in group { + if let photo { results.append(photo) } + } + return results +} +``` + +使用```Task.withTaskCancellationHandler(operation:onCancel:)` ``处理需要立即通知取消的工作 + +```swift +let task = await Task.withTaskCancellationHandler { + // ... +} onCancel: { + print("Canceled!") +} + + +// ... some time later... +task.cancel() // Prints "Canceled!" +``` + +#### Unstructured Concurrency(非结构化并发) + +比对上面的结构化并发,非结构化任务不存在父任务 + +创建**在当前Actor上运行的**非结构化任务 + +```swift +Task.init(priority:operation:) +``` + +创建**不在当前Actor上运行**的非结构化任务(分离任务) + +```swift +Task.detached(priority:operation:) +``` + +#### Actor(演员) + +引用类型 + +用于安全的在并并发代码之间共享信息,类中引用类型和值类型的比较同样适用于actor,定义 actor + +```swift +actor TemperatureLogger { + let label: String + var measurements: [Int] + private(set) var max: Int + + + init(label: String, measurement: Int) { + self.label = label + self.measurements = [measurement] + self.max = measurement + } +} +``` + +特点:具有外部可以访问属性,但是只有内部可以修改属性 + +#### 可发送协议 + +声明符合**Sendable**协议,将类型标记为可发送的,该协议没有任何代码要求,一般来说,一个类型有三种可发送的方式 + +* 值类型,其可变状态由其他可发送数据组成,例如,具有可发送的存储属性的结构体或者具有可发送的关联值的枚举 +* 类型没有任何可变状态,例如只有只读属性的结构体或者类 +* 类型具有确保其可变状态安全的代码,例如标记**@MainActor**,或者在特定线程或队列上序列化对其属性的访问的类 + +总是可发送的类型,例如结构体只有可发送的属性,枚举只具有可发送的关联值 + +```swift +struct TemperatureReading: Sendable { + var measurement: Int +} + +extension TemperatureLogger { + func addReading(from reading: TemperatureReading) { + measurements.append(reading.measurement) + } +} +``` + +如果需要显式将类型标记为**不可发送**,覆盖对Sendable协议的隐式一致性,使用扩展 + +```swift +struct FileDescriptor { + let rawValue: CInt +} + +@available(*, unavailable) +extension FileDescriptor: Sendable {} +``` + + + +#### 参考资料 + +[官方文档](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/concurrency/#Calling-Asynchronous-Functions-in-Parallel) + diff --git a/SwiftUI/01-SwiftUI.md b/SwiftUI/01-SwiftUI.md index dd9e4ec..d91fdea 100644 --- a/SwiftUI/01-SwiftUI.md +++ b/SwiftUI/01-SwiftUI.md @@ -1,5 +1,71 @@ ### SWiftUI +@State:用于View中的私有状态值,一般来说它修饰的都是struct类型,不应该被 + + + +### Layout + +布局步骤: + +1、父视图给子视图一个提议建议size + +2、子视图选择自己的size + +3、父视图放置子视图在自己的坐标空间中 + +### Data + +在设计一个数据模型时,通常需要考虑以下三个问题 + +1、这个视图需要什么数据来完成它的工作(What data does this view need to do its job?) + +2、视图将如何操作这些数据(How will this view manipulate that data?) + +3、数据从何而来(Where will the data come from?) + +三种工具用于创建对**ObservableObject**的依赖关系 + +1、**@ObservedObject**:修饰持有符合ObservableObject类型的视图的属性,使用它可以通知SwiftUI开始跟踪视图的依赖属性,需要自己维护生命周期 + +2、**@StateObject**:将ObservableObject的生命周期绑定到view中,被创建其的View所持有的 + +3、**@EnvironmentObject**:在父视图中传入model,则所有的子视图中都可以直接使用,并且不需要一层一层传递,模型必须接遵守 ObservableObject 协议 + + + +```swift +// 父视图 +@main +struct SwiftUIDemoApp: App { + var body: some Scene { + WindowGroup { + BackgroundAndOverlay().environmentObject(Model(name: "GJ")) + } + } +} +// 子视图 +struct SubView: View { + @EnvironmentObject var data: Model + var body: some View { + Text("name = \(data.name)") + } +} +// 定义model +class Model: ObservableObject { + var name: String + init(name: String) { + self.name = name + } +} +``` + + + + + + + #### 相关资料 [地址](https://my.oschina.net/u/4662964/blog/4649446) diff --git a/SwiftUI/02-Combine.md b/SwiftUI/02-Combine.md index da5e306..18bc1b5 100644 --- a/SwiftUI/02-Combine.md +++ b/SwiftUI/02-Combine.md @@ -4,6 +4,20 @@ > 非常适合用来配合声明式的SwiftUI,创建出稳定和单向的数据流动 +异步编程的本质 + +* 响应未来发生的事件流 + +响应式异步编程的抽象和特点 + +* 异步操作在合适的时机发布事件(事件带有数据) +* 使用一个或者多个操作来处理这些事件以及内部的数据 +* 在末端,会有一个订阅者来消化处理后的事件和数据,并进一步驱动程序的其他部分(UI界面)的运行 + +过程 + +* 事件(及其对应的数据)被发布(Publisher) ---> 操作(事件和数据)变形(IOperator) --> 被订阅者使用(Subscriber) + 两种编程方式:1、指令式;2、声明式 @@ -22,3 +36,226 @@ Subscriber Operator +#### Publisher + +> 事件发布 + + + +##### SubScripber + +> 事件接收 + +系统提供的有 + +1、sink + +使用 + +```swift +let buttonClicked: AnyPublisher +buttonClicked +.scan(0) { value, _ in value + 1 } +.map { String($0) } +.sink { print("Button pressed count: \($0)") } +``` + +定义 + +```swift +public func sink(receiveValue: @escaping ((Self.Output) -> Void)) -> AnyCancellable +``` + +```swift +public func sink(receiveCompletion: @escaping ((Subscribers.Completion) -> Void), receiveValue: @escaping ((Self.Output) -> Void)) -> AnyCancellable +``` + +2、assign + +要求 + +只有class类型的实例的属性才能被绑定,ObservableObject 接口正好满足 + +使用 + +```swift +class Foo { + var bar: String = "" +} +let foo = Foo() +let buttonClicked: AnyPublisher +buttonClicked + .scan(0) { value, _ in value + 1 } + .map { String($0) } + .assign(to: \.bar, on: foo) +``` + +定义 + +```swift +public func assign(to keyPath: ReferenceWritableKeyPath, on object: Root) -> AnyCancellable +``` + +#### Subject + +本身也是一个Publisher,外部调用这可以通过send方法来主动地发布Ouput值、failure事件或者finish事件,它可以将传统的指令式异步API里的事件和信号转化到响应式的世界中去 + +##### 两种常见的 Subject 类 + +* PassthroughSubject + +不会对接受的值进行保留,订阅开始后,它将监听并响应接下来的事件 + +```swift +let publisher = PassthroughSubject() +print("开始订阅") +let call = publisher.sink { complete in + print(complete) +} receiveValue: { value in + print(value) +} +publisher.send(1) +publisher.send(2) +publisher.send(completion: .finished) + +// 打印 +开始订阅 +1 +2 +finished +``` + +```swift +let publisher = PassthroughSubject() +print("开始订阅") +publisher.send(1) +let call = publisher.sink { complete in + print(complete) +} receiveValue: { value in + print(value) +} +publisher.send(2) +publisher.send(completion: .finished) + +// 打印 +开始订阅 +2 +finished +``` + +注意点:使用时,一定要添加sink的返回值,否则订阅会自动取消,不会执行 + +* CurrentValueSubject + +与上面PassthroughSubject不同,它会包装和持有1个值,并在设置该值时发送事件并保留新的值。在订阅发生的瞬间,CurrentValueSubject 会把当前保存的值发送给订阅者 + +```swift +let publisher = CurrentValueSubject(0) +print("开始订阅") +let call = publisher.sink { complete in + print(complete) +} receiveValue: { value in + print(value) +} +publisher.value = 1 +publisher.value = 2 +publisher.send(completion: .finished) + +// 打印 +开始订阅 +0 +1 +2 +finished +``` + +开始订阅后,publisher 里当前存储的 0 被立即发送给了 receiveValue,接下来对 publisher.value 的每次设置也都触发了订阅者的响应。 + +#### Scheduler + +> 解决的问题:什么地方、什么时候来发布事件和执行代码 + +Combine 里提供了 receive(on:options:) 来让下游在指定的线程中接收事件。比如,对于后台线程的网络请求返回,可以通过这样的方式在 main runloop 中进行处理 + +RunLoop 就是一个实现了 Scheduler 协议的类型,它知道要如何执行后续的订阅任务 + +```swift +URLSession.shared.dataTaskPublisher(for: URL(string: "https://www.baidu.com")!) + .compactMap { String(data: $0.data, encoding: .utf8) } + .receive(on: RunLoop.main) + .sink { _ in + + } receiveValue: { + print($0) + } +``` + +Scheduler 的另一个重要工作是为事件的发布指定和规划时间,改变事件链的传递时间,比如加入延迟或者等待空闲时再进行传递,这些延时也是由 Scheduler 负责调度的 + +常见的两种操作是delay、debounce + +**delay**:简单将所有事件按照一定事件延后 + +**debounce**:设置一个计时器,在事件第一次到来时,计时器启动。在计时器有效期间,每次接收到新值,则将计时器时间重置。当且仅当计时窗口中没有新的值到来时,最后一次事件的值才会被当作新的事件发送出去。 + +**Empty**:是一个简单的发布者,只在被订阅时候发布一个完成事件,不会输出任何的ouput值 +只能用于表示某个事件已经发生 + +**Just**:表示单一的值,在被订阅后,值会被发送出去,紧接着是finished +**Sequence**:接收一个数组,也可以是一个Range,,被订阅时,元素被逐个发送出来 + +**Scan**:一边进行重复操作,一边将每一步中间状态发送出去的场景十分普遍 +**flapMap**:的变形闭包中需要返回一个Publisher + +**removeDuplicates**:移除重复的事件值,经常用来减少非常消耗资源的操作 + +**Fail**:在订阅时发送一个错误事件 + +如果 Publisher 在出错时发送的是 SampleError,但订阅方声明只接受 MyError 时,就算实际上 Publisher 只发出 Output 值而从不会发出 Failure 值,我们也无法使用这个 Subscriber 去接收一个类型不符的 Publisher 的事件 + +**mapError**:将publisher的Failure转换其他Failure类型 +**tryMap**:将处理数据时发生的错误转变为标志事件流失败的结束事件 + +除了 tryMap 以外,Combine 中还有很多类似的以 try 开头的 Operator,比如 tryScan,tryFilter,tryReduce 等等。当你有需求在数据转换或者处理时,将事件流以错误进行终止,都可以使用对应操作的 try 版本来进行抛出,并在订阅者一侧接收到对应的错误事件 + +**replaceError**:会把错误替换成一个给定的值,并且立即发送 finish事件 + +**catch**:接受一个新的publisher, 当上游 Publisher 发生错误时,catch 操作会使用新的 Publisher 来把原来的 Publisher 替换掉 + +#### 操作符熔合: +将操作符的作用时机提前到创建publisher时的方式,被称为操作符熔合 + +**zip**压缩: +它会把两个 (或多个) Publisher 事件序列中在同一 index 位置上的值进行合并,也就是说,Publisher1 中的第一个事件和 Publisher2 中的第一个事件结对合并,Publisher1 中的第二个事件和 Publisher2 中的第二个事件合并,以此类推 +在时序语义上更接近于:当...且... + +**combineLatest** +与zip相反,语义接近于"当...或..." + +当Publisher1 发布值,或者 Publisher2 发布值时,将两个值合并,作为新的事件发布出去。 +不论是哪个输入 Publisher,只要发生了新的事件,combineLatest 就把新发生的事件值和另一个 Publisher 中当前的最新值合并 + +**Future**:用于订阅操作和值的发布是异步行为,不在同一时间发生,提供一个方式可以让我们创建一个接受未来事件的publisher +注意点:只能提供一次性的Publisher, +对于Promise,只有两个选择,要么发送一个值并让Publisher正常结束,或者发送一个错误,适用于必然产生事件结果,且至多只会产生一个结果的场景 + +**subject**: +如果你的异步 API 有可能不发送任何一个值,而是可能发布两个或更多的值的话,你会需要一个更加一般性的 Publisher 类型来把指令式程序转换为响应式程序,这个类型就是 Subject + +**Timer Publishe**r:使用时,注意需要手动调用connect() 方法,它才会开始发送事件 + +Subject +1、sink +2、assign:将 Publisher 的输出值通过 key path 绑定到一个对象的属性上去 + +#### Cancellable、AnyCancellable + +1、**Cancelable**:是一个抽象协议,需要再何时的时候主动调用cancel() 方法来完结,如果我们在没有调用cancel()的情况下就将connect 的返回值忽略或者释放掉,那么就会永远无法取消掉,会一直存在,并造成内存泄漏 + +2、**AnyCancellable**:是一个class,它会在自己的deinit 中帮我们调用cancel(),自动释放资源 + +可以将Cancellable作为参数传递给AnyCancelable的初始化方法,将Cancellable 包装成一个可以自动取消的对象 + +#### 注意 + +@publisher:需要内部生成并持有存储,只能针对定义在class 里的变量添加@published diff --git "a/VisionPro/usdz\350\265\204\346\272\220.md" "b/VisionPro/usdz\350\265\204\346\272\220.md" new file mode 100644 index 0000000..e69de29 diff --git "a/ZSHShell/\345\237\272\347\241\200\350\257\255\346\263\225.md" "b/ZSHShell/\345\237\272\347\241\200\350\257\255\346\263\225.md" new file mode 100644 index 0000000..3744828 --- /dev/null +++ "b/ZSHShell/\345\237\272\347\241\200\350\257\255\346\263\225.md" @@ -0,0 +1,11 @@ +1、变量 + +* 定义 + +=左右两端不能有空格 + +```shell +num1=10 + +``` + diff --git "a/iOS/Apple Connection\345\220\216\345\217\260\351\227\256\351\242\230.md" "b/iOS/Apple Connection\345\220\216\345\217\260\351\227\256\351\242\230.md" new file mode 100644 index 0000000..2eee6c6 --- /dev/null +++ "b/iOS/Apple Connection\345\220\216\345\217\260\351\227\256\351\242\230.md" @@ -0,0 +1,21 @@ +## Apple Connection 后台问题 + +一、TF的问题 + +1、TF外链提示:此beta版本目前不接受任何新测试员 + +问题原因: + +1、没有设置测试人数 + +2、 + +解决方案 + +参考来源 + +[https://blog.csdn.net/shaobo8910/article/details/106384176]() + +[https://stackoverflow.com/questions/53758738/testflight-public-link-doesnt-accept-new-beta-testers]() + +[https://blog.csdn.net/shaobo8910/article/details/106384176]() \ No newline at end of file diff --git "a/iOS/App\347\232\204\351\207\215\347\255\276\345\220\215.md" "b/iOS/App\347\232\204\351\207\215\347\255\276\345\220\215.md" index 5c029a9..cf4cf05 100644 --- "a/iOS/App\347\232\204\351\207\215\347\255\276\345\220\215.md" +++ "b/iOS/App\347\232\204\351\207\215\347\255\276\345\220\215.md" @@ -11,7 +11,7 @@ * Provisioning Profile:选择对应的描述文件 * 其他选项都是可选 -![ios-app-signer](/Users/guo/Notes/iOS/images/ios-app-signer.png) +![ios-app-signer](https://cdn.jsdelivr.net/gh/GJBlog/Notes/iOS/images/ios-app-signer.png) ##### 2、sigh脚本 @@ -33,8 +33,8 @@ sudo gem install sigh ```bash [WARNING] You are calling sigh directly. Usage of the tool name without the `fastlane` prefix is deprecated in fastlane 2.0 -Please update your scripts to use `fastlane sigh resign` instead. -[21:27:40]: Path to ipa file: + Please update your scripts to use `fastlane sigh resign` instead. + [21:27:40]: Path to ipa file: ``` * 继续输入相关.ipa文件所在path路径,或者直接将文件拖入该行中,回车 diff --git a/iOS/AsyncAndAwait.md b/iOS/AsyncAndAwait.md new file mode 100644 index 0000000..2c76bb8 --- /dev/null +++ b/iOS/AsyncAndAwait.md @@ -0,0 +1,505 @@ +## Async-await + +#### Async Property + +* 仅仅只读属性可以被标记为 async +* 必须显式标记出来 get 关键字 + +```swift +extension UIImage { + var thunmbnail: UIImage? { + get async { + let size = CGSize(width: 40, height: 40) + return await self.byPreparingThumbnail(ofSize: size) + } + } +} +``` + +* 从swift 5.5 开始, 属性get 也可以抛出异常 + +#### 使用 await 的场景 + +* 函数、属性、初始化器、for循环 + +```swift +``` + +使用 async-let 可以并行处理异步工作 + +#### 任务和任务组 + +#### Task modifier(修饰符) + +* task modifier 的任务上下文将和它所修饰的View的声明周期绑定;当被修饰的 View identifier 改变 (比如被其他 View 取代) 或者被从屏幕上移除时时,task 所关联的任务也将被取消;而 onAppear 和 Task.init 所创建的任务,则和 View 的生命周期无关 + + + +#### OC =>Swift + +1、如果是包含completion关键字,则会自动将其转为async的形式以及原本的swift形式 + +```objective-c +// OC ++ (void)checkPerform:(NSString *)name completion:(void(^)(NSString *))completion; + +// Swift +class func checkPerform(_ name: String) async -> String +``` + +2、如果不包含completion的关键字,则需要在OC方法声明时指定NS_SWIFT_ASYNC(XX),才可以 + +```objective-c +// OC,NS_SWIFT_ASYNC(XX) +// XX:表示第一个参数(从1开始) ++ (void)handleResult:(NSString *)name success:(void(^)(NSString *))success failure:(void(^)(NSError *error))failure NS_SWIFT_ASYNC(3); + +// Swift +class func handleResult(_ name: String, success: @escaping (String) -> Void) async -> Error +``` + +#### 结构化并发 + +非结构化并发带来的问题 + +1、并不能保证函数中任务的执行一定会在函数调用的结束而结束 + +2、派发回调破坏了并发的黑盒 + +**定义** + +1、即使使用并发操作,也要保证控制流丼的单一入口和单一出口 + +2、程序可以产生多个控制流来实现并发,但是所有的并发路径在出口时都应该处于完成(或取消)状态,并合并到一起 + +**条件** + +1、需要依赖异步函数,异步函数又必须运行在某个任务的上下文中 + +2、以任务为基本要素组织的 + +**目的** + +1、主要是将子任务的生命周期控制在任务组的作用域内 + +##### 当前任务状态 + +1、使用 withUnsafeCurrentTask:获取和检查当前任务,前提:在任意的异步函数中 + +##### 任务层级-在任务树上创建叶子节点 + +有两个方法 + +**1、任务组(task group)** + +在某个异步函数中,通过withTaskGroup为当前任务添加一组结构化的并发子任务 + +如果使用group时,没有明确await任务组,编译器在检测到结构化并发作用域结束时,会为我们自动添加上await并在等待所有任务结束后再继续控制流 + +```swift +print("Start") + +await withTaskGroup(of: Int.self) { group in + for i in 0..<3{ + group.addTask { + await work(i) + } + } + print("Task added") + for await result in group { + print("Get result:\(result)") + break + } + print("Task ended") +} +print("End") + +private func work(_ value: Int) async -> Int { + print("Start work\(value)") + try? await Task.sleep(nanoseconds: UInt64(value) * NSEC_PER_SEC) + print("Work\(value)done") + return value +} +``` + +打印结果 + +```swift +Start +Task added +Start work1 +Start work0 +Start work2 +Work0done +Get result:0 +Task ended +Work1done +Work2done +End +``` + +* 值捕获 + +任务组中的每个子任务都拥有返回值 + +下面做法会导致编译错误 + +错误信息:Mutation of captured var ‘value’ in concurrently-executing code + +```swift +let v: Int = await withTaskGroup(of: Int.self) { group in + var value = 0 + for i in 0 ..< 3 { + group.addTask { + let result = await work(i) + value += result + return result + } + } + // 等待所有子任务完成 + await group.waitForAll() + return value +} +``` + +将代码通过addTask 添加到任务组时,必须认识到:这些代码有可能以并发方式同时运行。编译器可以检测到这里我们在一个明显的并发上下文中改变了某个共享状态。不加限制地从并发环境中访问某个值是危险操作,可能造成崩溃。得益于结构化并发,现在编译器可以理解任务上下文的区别,在静态检查时就发现这一点,从而从根本上避免了这里的内存风险 + +即使只读取var value的值,也是不被允许的 + +* 任务组逃逸 + +虽然Swift 编译器没有阻止将 withTaskGroup 闭包中的group被外部持有并再作用范围之外使用,但是在闭包外使用的话,将完全破坏结构化并发的假设 + +**不足**: + +a、每次想要使用withTaskGroup时,都需要遵守同样的模板,创建任务组,定义和添加子任务,使用await等待完成等,都是模板代码 + +b、对于所有子任务,它们的返回值也必须是同样的类型,灵活性下降 + +使用 + +**2、异步绑定 (async let)** + +除了任务组以外,这是另一种创建结构化并发子任务的方式。为了简化上面结构化并发的使用而诞生 + +上面 withTaskGroup 的等价写法 + +```swift +func useAsyncLet() async { + print("Start") + async let v0 = work(0) + async let v1 = work(1) + async let v2 = work(2) + print("Task added") + + let result = await v0 + v1 + v2 + print("Task ended") + print("End.Result:\(result)") +} +``` + +* 隐式取消 + +如果没有await,swift 并发会在被绑定的常量离开作用域时,隐式地将绑定的子任务取消掉,然后进行await + +#### 结构化并发的组合 + +通过嵌套使用 withTaskGroup 或者 async let,可以在一般人能够轻易理解的范围内,灵活地构建出这种多层级的并发任务 + +```swift +// 第一层任务组 +await withTaskGroup(of: Int.self) { group in + group.addTask { + // 第二层任务组 + await withTaskGroup(of: Int.self) { innerGroup in + innerGroup.addTask { + await work(0) + } + innerGroup.addTask { + await work(2) + } + return await innerGroup.reduce(0) { + result, value in + result + value + } + } + } + group.addTask { + await work(1) + } +} +print("End") +``` + +#### 非结构化任务 + +创建任务的方式 + +* Task.init - 创建非结构化的任务根节点,从当前任务中继承运行环境:比如 actor 隔离域,优先级、本地值(是指:仅存在于当前任务上下文中的,有外界注入的值) + +* Task.detached - 创建非结构化的任务根节点,不从当前任务中继承优先级和本地值等运行环境,完全新的游离任务环境 + +创建任务时,可以得到一个具体的Task值,充当了任务的标识。从Task.init 或者 Task.detached 的闭包中返回的值,将作为整个Task 运行结束后的值 + +使用Task.value 这个异步只读属性,可以获取到整个Task的返回值 + +#### 任务取消 + +在遇到任务取消时,如果想要进行处理并提前结束任务,大致有两类选择: + +**1、提前返回空置或者部分值** + + + +**2、通过抛出错误并汇报给父层级任务,让当前任务异常结束** + +约定错误和自定义错误 + +```swift +// 标准库内的一个特殊错误类型 +CancellationError +// 在需要插件取消状态并抛出错误时可以直接调用如何方法 +Task.checkCancellation() +``` + +设计并发系统时应该遵守的规范 + +1、尽可能块地对任务取消作出响应,避免额外的非必要工作 + +2、并迅速通过抛出来完成任务,将结构化并发的控制权交回给调用者 + +**3、取消的清理工作** + +在结构化并发中,**defer**会等到子任务await全部完成后再调用 + +在使用defer时,只有在异步操作返回或者抛出时,才会被触发,如果我们使用 checkCancellation 在每次 await 时检查取消的话,实际上抛出错误的时机会比任务被取消的时机要晚一些:在异步函数执行暂停期间的取消,并不会立即导致抛出,只有在下一次调用 checkCancellation 进行检查时,才进行抛出并触发 defer 进行资源清理。 + +如果遇到如下情况 + +* 需要在取消发生的时刻,**立即**作出响应 +* 在某些情况下,无法通过checkCancellation抛出错误时 + +可以考虑使用**withTaskCancellationHandler** + +#### Actor + +对比 Class 类型 + +| 类型 | 不同点 | 相同点 | +| ----- | ------------------------------------------------------------ | ------------------------------------------------------------ | +| Class | 不支持保护内部状态 | 拥有初始化方法、普通方法、属性、下标、被扩展并满足协议、支持泛型 | +| Actor | 1、保护其中的内部状态(或者说存储系统)让自身免受数据竞争的困扰,包括对属性的直接访问能允许发生在self里 | 拥有初始化方法、普通方法、属性、下标、被扩展并满足协议、支持泛型 | + +从 actor 外部持有对这个actor的引用,并对某个具有 actor 隔离特性的声明的访问,叫做跨actor调用,且这个调用只能在异步方法中可以使用 + +```swift +actor Room { + let roomNumber = "101" + var visitorCount: Int = 0 + + init() {} + + func visit() -> Int { + visitorCount += 1 + return visitorCount + } +} +``` + +虽然 Room.visit 并没有被标记为 async 函数,但是编译期间 Swift 会对 actor Room 进行隔离检查,它会决定哪些调用是跨 actor 隔离域的调用。因为 actor 要保证隔离状态不被意外改变,因此对于这些调用,必须等待到合适的时间才能处理。编译器会应用上面的规则,要求调用方引入潜在暂停点 **await**。 + +```swift +func bar() async { + let room = Room() + let visitCount = await room.visit() + print(visitCount) + print(await room.visitorCount) +} +``` + + + +隔离域 + +* 某个隔离局中的声明,可以无缝访问相同隔离域中的其他成员 + +* 某个隔离域外的声明,不论它位于传统的非隔离中,还是位于其他 actor 的隔离域中,都无法直接访问这个隔离域的成员。只有通过异步消息的方法,才能跨越隔离域进行访问 + +#### Actor 协议 + +所有的actor类型都隐式地遵守Actor协议 + +当需要让actor去遵守非actor协议时,默认会报错 + +```swift +protocol Popular { + var popular: Bool { get } +} +``` + +```swift +extension Room: Popular { + var popular: Bool { + return visitorCount > 0 + } +} +``` + +**Error:**Actor-isolated property 'popular' cannot be used to satisfy nonisolated protocol requirement + +Room.pipular 和 Popular.popular 产生了隔离域上的冲突,解决方案有两种: + +**1、**让Popular 在某个隔离域中,通过让 PopularActor 作为Actor 协议的细分存在,例如 + +```swift +protocol PopularActor: Actor { + var popular: Bool { get } +} +``` + +```swift +extension Room: PopularActor { + var popular: Bool { + return visitorCount > 0 + } +} +``` + +当Room实现PopularActor时,其中的popularActor也将作为隔离域中的一部分存在,于是 Room 将可以在同一个隔离域中访问到 + +**2**、定义异步协议方法 + +将涉及到的成员设计为异步方法或者属性 + +```swift +protocol PopularAsync { + var popular: Bool { get async } +} +``` +让 Room 实现 PopularAsync +```swift +extension Room: PopularAsync { + var popular: Bool { + get async { + visitorCount > 0 + } + } +} +``` + +使用时 + +```swift +let room = Room() +await print("is popular?\(room.popular)") +// 或者 +print("is popular?\(await room.popular)") +``` + +如果需要一个既能被class 或者 struct 这样的"传统"类型满足,“又能以安全的方式工作在 actor 里的协议,可以考虑将协议的成员声明为异步成员(例如 PopularAsync 中的popular ) + +```swift + +class RoomClass: PopularAsync { + var popular: Bool { return false } +} +``` + +即便在 protocol 中被声明为了 get async,普通类型还是可以用同步函数来实现协议的异步定义 + +#### nonisolated + +想要对 Actor 类型满足一个同步协议,需要明确将协议的要求声明放到隔离域外,才可以,可以使用 **nonisloated**关键字 + +```swift +extension Room: CustomStringConvertible { + nonisolated var description: String { + return "\(roomNumber)" + } +} +``` + +当然了,这样子在隔离域外的成员description 是不能同步访问隔离域内的内容的,有一个例外,在同一个模块内,用let声明的存储变量(roomNumber)可以,在不同的模块中,如果想要访问let的变量时,需要加上 await 关键字 + +#### isolated + +* 在 actor 中的声明,默认处于 actor 的隔离域中 +* 在 actor 中的声明,如果加上 nonisolated,那么它将被置于隔离域外 +* 在 actor 外的声明,默认处于 actor 隔离域外 + + +除此之外,对于actor之外的声明,如果想让它处于某个隔离域中,可以使用**isolated**关键字来修饰 + +```swift +func reportRoom(room: isolated Room) { + print("Room:\(room.visitorCount)") +} +``` + +**切换隔离域** + +如果我们在某个 actor 中声明了接受 isolated 参数的方法,即使它只接受一个这种参数,其隔离域依然存在冲突:方法本身在 actor 中,“原则上”应该是按照 self 进行 actor 隔离的,但同时它又被声明了参数隔离,被明确表示需要被隔离在参数的域中。此时,Swift 将选择尊重更明确的表述,也就是使用参数定义的隔离域来运行代码 + +```swift +extension Room { + func baz1(_ another: Room) async { + print(self.visitorCount) + print(await another.visitorCount) + } +} +``` + +```swift +extension Room { + func baz2(_ another: isolated Room) async { + print(await visitorCount) + print(another.visitorCount) + } +} +``` + +#### 全局actor + +针对需要保护的状态存在于actor外部,或者代码不可能汇集到单一的actor实例中时,需要一种作用域更加宽广的隔离手段 + +为此,我们可以声明全局actor,通常被作为属性包装使用,可以被任意地添加到某个属性或者方法前,对属性或者方法进行标注,把它限定在该全局actor的隔离域中 + +**MainActor**就是一个全局actor + +#### 自定义全局actor + +需要自定义全局的几种情况 + +* 若干个若干个可以成组的状态:它们散落在各个类型里,但是需要以串行的方式避免写入时的数据竞争 + +* 存在需要被某个 actor 隔离的全局变量,此时单纯的 actor 类型无法做到将其纳入隔离域 +* 需要隔离的状态是跨越模块的:提供隔离域的人希望某些由其他开发者生成的状态被纳入该隔离域以保证执行时的安全。开发者在编译自己的模块时,可以向外部提供一个全局 actor,这样别人就能使用定义在模块内部的隔离域了 + +#### Sendable + +是一个协议,用于表示该类型可以安全地在不同并发域之间传递 + +**Swift 并发在设计针对跨越并发域的数据安全时,需要处理三件事** + +1、对于那些跨越并发域时可能不受保护的可变状态,编译器则应该给出错误,以保证数据安全 + +2、Swift 的并发设计,是鼓励使用值类型的。但是有些情况下引用类型确实可以带来更优秀的性能。对于 1 中的限制,应该为资深程序员留有余地,让他们可以可以自由设计 API,同时保证数据安全和性能 + +3、Swift 5.5 之前已经存在大量的代码,如果强制开始 1 的话,可能会造成大量的编译错误。我们需要平滑和渐进式的迁移过程 + +##### 值类型 + +* 所有的基本类型都是默认满足sendable +* 使用所有值类型构造的struct也是自动满足 sendable + +##### class 类型 + +* 必须是 final,不允许继承 +* 所有成员必须都是 sendable 的 +* 所有的成员都必须使用let声明为不变量 +* Class 类型就算满足sendable协议,也**需要显式**为它添加上 sendable + +##### actor 类型 + +* 所有的actor类型都满足sendable的要求 +* 编译器会自动为其添加 sendable diff --git "a/iOS/CocoaPods-\345\270\270\347\224\250\345\221\275\344\273\244.md" "b/iOS/CocoaPods-\345\270\270\347\224\250\345\221\275\344\273\244.md" index 590241b..5c8c665 100644 --- "a/iOS/CocoaPods-\345\270\270\347\224\250\345\221\275\344\273\244.md" +++ "b/iOS/CocoaPods-\345\270\270\347\224\250\345\221\275\344\273\244.md" @@ -13,4 +13,12 @@ gem sources -l ```bash**** sudo gem install cocoapods -``` \ No newline at end of file +``` + +#### 更新指定版本的Pod + +``` +sudo gem install -n /usr/local/bin cocoapods -v 1.5.3 +``` + +[来源](https://kukumalucn.github.io/blog/2018/09/20/Cocoapods%E7%9A%84%E7%89%88%E6%9C%AC%E5%8D%87%E7%BA%A7%E5%92%8C%E9%99%8D%E7%BA%A7/) \ No newline at end of file diff --git a/iOS/StoreKit-SwiftUI.md b/iOS/StoreKit-SwiftUI.md new file mode 100644 index 0000000..f69e1c6 --- /dev/null +++ b/iOS/StoreKit-SwiftUI.md @@ -0,0 +1,9 @@ +## StoreKit-SwiftUI + +涉及的UI有 + +StoreView + +ProdictView + +SubscriptionStoreView \ No newline at end of file diff --git "a/iOS/iOS-\347\254\246\345\217\267\345\214\226ips.md" "b/iOS/iOS-\347\254\246\345\217\267\345\214\226ips.md" index aad83fb..897e336 100644 --- "a/iOS/iOS-\347\254\246\345\217\267\345\214\226ips.md" +++ "b/iOS/iOS-\347\254\246\345\217\267\345\214\226ips.md" @@ -2,16 +2,39 @@ ### 具体操作步骤 -##### 1、找到symbolicatecrash工具 +##### 在 iOS 15以前 + +##### 1、查找 symbolicatecrash工具 ``` find /Applications/Xcode.app -name symbolicatecrash ``` -### +##### 2、使用方式 + +```shell +./symbolicatecrash crashFilePath dsymPath > crashSymbolFilePath +``` + +##### 在 iOS 15以后 + +##### 1、查找 CrashSymbolicator 工具 + +```shell +find /Applications/Xcode.app -name CrashSymbolicator -type f +``` + +##### 2、使用方式 + +```shell +python3 CrashSymbolicator.py -d /dSYMs -o /xxxSymbo.crash -p /xxxCrash.ips +``` ##### 参考来源 * https://www.jianshu.com/p/921366b3390d +* [CrashSymbolicator](https://juejin.cn/post/7030619552211795982#heading-3) +* [通过ips分析crash](https://www.jianshu.com/p/3e8723fff641) +* [官方Crash文件分析](https://developer.apple.com/documentation/xcode/examining-the-fields-in-a-crash-report) diff --git "a/iOS/iOS-\350\247\246\350\247\211\345\217\215\351\246\210.md" "b/iOS/iOS-\350\247\246\350\247\211\345\217\215\351\246\210.md" new file mode 100644 index 0000000..76a0758 --- /dev/null +++ "b/iOS/iOS-\350\247\246\350\247\211\345\217\215\351\246\210.md" @@ -0,0 +1,15 @@ +## 触觉反馈 + +#### 类型 + +* [`UIImpactFeedbackGenerator`](https://developer.apple.com/documentation/uikit/uiimpactfeedbackgenerator):撞击、冲击反馈 + +* [`UINotificationFeedbackGenerator`](https://developer.apple.com/documentation/uikit/uinotificationfeedbackgenerator):通知反馈 + +* [`UISelectionFeedbackGenerator`](https://developer.apple.com/documentation/uikit/uiselectionfeedbackgenerator):选中文本反馈 + +#### 参考资料 + +1、[官方文档](https://developer.apple.com/documentation/uikit/uifeedbackgenerator#2555399) + +2、[三方资料](https://yeziahehe.com/2017/07/07/Haptic_feedback_with_uifeedbackgenerator/) \ No newline at end of file diff --git "a/iOS/xcodo\351\205\215\347\275\256\351\241\271.md" "b/iOS/xcodo\351\205\215\347\275\256\351\241\271.md" new file mode 100644 index 0000000..c1b1bfd --- /dev/null +++ "b/iOS/xcodo\351\205\215\347\275\256\351\241\271.md" @@ -0,0 +1,12 @@ +## Xcode 配置 + + + +[Build settings reference](https://developer.apple.com/documentation/xcode/build-settings-reference#Privacy-Location-When-In-Use-Usage-Description) + +[Xcode Build System Guide](https://developer.apple.com/library/archive/documentation/DeveloperTools/Reference/XcodeBuildSettingRef/1-Build_Setting_Reference/build_setting_ref.html) + +[Information Property List Key Reference](https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html#//apple_ref/doc/uid/20001431-102088) + + + diff --git "a/iOS/\346\211\213\345\212\250\344\270\213\350\275\275SDK.md" "b/iOS/\346\211\213\345\212\250\344\270\213\350\275\275SDK.md" new file mode 100644 index 0000000..12798f6 --- /dev/null +++ "b/iOS/\346\211\213\345\212\250\344\270\213\350\275\275SDK.md" @@ -0,0 +1,25 @@ +## 手动下载Xcode SDK + +1、先安装显示xcode SDK list 的组件 + +```shell +brew install xcodesorg/made/xcodes +``` + +2、执行该组件 + +```shell +xcodes runtimes --include-betas +``` + +3、使用Apple官方安装命令 + +```shell +xcodes runtimes install "iOS 16.4" +``` + +#### 参考来源 + +1、[组件地址](https://github.com/actions/runner-images/issues/8402) + +2、[Apple工具文档](https://github.com/XcodesOrg/xcodes/tree/1.4.1#install-runtimes-) diff --git "a/iOS/\346\227\245\346\234\237\346\225\264\347\220\206.md" "b/iOS/\346\227\245\346\234\237\346\225\264\347\220\206.md" new file mode 100644 index 0000000..b1f814a --- /dev/null +++ "b/iOS/\346\227\245\346\234\237\346\225\264\347\220\206.md" @@ -0,0 +1,14 @@ +## 日期整理 + +1、YYYY 与 yyyy + +参考资料 + +1、[iOS 中令人头疼的时间日期处理](https://sunsetwan.github.io/2020/04/20/iOS-%E4%B8%AD%E4%BB%A4%E4%BA%BA%E5%A4%B4%E7%96%BC%E7%9A%84%E6%97%B6%E9%97%B4%E6%97%A5%E6%9C%9F%E5%A4%84%E7%90%86/) + +2、[Apple官方文档讲解](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/DataFormatting/Articles/dfDateFormatting10_4.html#//apple_ref/doc/uid/TP40002369-SW1) + +3、[Date Formatting中"YYYY"与"yyyy"的区别](https://www.jianshu.com/p/a4a307477c63) + + + diff --git "a/iOS/\346\234\272\345\231\250\345\255\246\344\271\24001.md" "b/iOS/\346\234\272\345\231\250\345\255\246\344\271\24001.md" new file mode 100644 index 0000000..2f9163b --- /dev/null +++ "b/iOS/\346\234\272\345\231\250\345\255\246\344\271\24001.md" @@ -0,0 +1,14 @@ +# Core ML + +#### 框架 + +![框架图](https://docs-assets.developer.apple.com/published/8905e2c376/rendered2x-1636573848.png) + +支持种类 + + + +#### 转化工具 + +* 将其他模型转为Core ML,python package:Core ML Tools +* \ No newline at end of file diff --git "a/iOS/\346\267\273\345\212\240FaceID.md" "b/iOS/\346\267\273\345\212\240FaceID.md" new file mode 100644 index 0000000..2105e17 --- /dev/null +++ "b/iOS/\346\267\273\345\212\240FaceID.md" @@ -0,0 +1,4 @@ +## 添加FaceID功能 + +[参考资源](https://juejin.cn/post/7411799494416498722) + diff --git "a/iOS/\346\270\205\351\231\244Xcode\344\270\255\351\242\204\350\247\210\346\225\260\346\215\256.md" "b/iOS/\346\270\205\351\231\244Xcode\344\270\255\351\242\204\350\247\210\346\225\260\346\215\256.md" new file mode 100644 index 0000000..e59271e --- /dev/null +++ "b/iOS/\346\270\205\351\231\244Xcode\344\270\255\351\242\204\350\247\210\346\225\260\346\215\256.md" @@ -0,0 +1,9 @@ +## Xcode清除缓存 + +* 清除预览数据 + +``` +运行此命令:xcrun simctl --set previews delete all +``` + + \ No newline at end of file diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/02-\345\212\250\346\200\201\346\225\260\347\273\204.md" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/02-\345\212\250\346\200\201\346\225\260\347\273\204.md" index 530e300..cecfe25 100644 --- "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/02-\345\212\250\346\200\201\346\225\260\347\273\204.md" +++ "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/02-\345\212\250\346\200\201\346\225\260\347\273\204.md" @@ -1,8 +1,14 @@ ## 动态数组 +#### 数组(Array) + +* 数组是一种顺序存储的线性表,所有元素的内存地址是连续的 + + + #### 接口设计 -![image-20220410110844316](/Users/guo/Notes/学习算法与数据结构笔记/02-动态数组-接口设计.png) +![](https://cdn.jsdelivr.net/gh/GJBlog/Notes@feature/2023/%E5%AD%A6%E4%B9%A0%E7%AE%97%E6%B3%95%E4%B8%8E%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E7%AC%94%E8%AE%B0/images/%E5%8A%A8%E6%80%81%E6%95%B0%E7%BB%84/02-%E5%8A%A8%E6%80%81%E6%95%B0%E7%BB%84-%E6%8E%A5%E5%8F%A3%E8%AE%BE%E8%AE%A1.png) #### 缩容 diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/03-\351\223\276\350\241\250.md" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/03-\351\223\276\350\241\250.md" index 1ef4517..59eefbb 100644 --- "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/03-\351\223\276\350\241\250.md" +++ "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/03-\351\223\276\350\241\250.md" @@ -8,7 +8,201 @@ > 是一种链式存储的线性表,所有元素的内存地址不一定是连续的 -![image-20220410200004440](/Users/guo/Notes/学习算法与数据结构笔记/03-链表_节点.png) +![image-20220410200004440](/Users/guo/Notes/学习算法与数据结构笔记/images/链表/03-链表_节点.png) + +#### 操作 + +* 定义Node结点 + +```swift +private static class Node { + E element; + Node next; + + public Node(E element, Node next) { + this.element = element; + this.next = next; + } +} +``` + + + +* 清空元素-clear + +![image-20231126174817086](/Users/guo/Notes/学习算法与数据结构笔记/images/链表/清空元素.png) + + + +```swift +size = 0 +first = null +``` + +* 添加结点 + +```swift +public void add(int index, E element) { + rangeCheckForAdd(index); + // 先获取到index对应的Node + Node prevNode = index == 0 ? first : node(index - 1); + prevNode.next = new Node<>(element, prevNode.next); + size++; +} +``` + +* 寻找index对应的Node结点 + +```swift +Node node = first; +for (int i = 0; i < index; i++) { + node = node.next; +} +return node; +``` + +* 删除结点 + +```swift +``` + + + + + +#### Leetcode + +[地址](https://leetcode.cn/problems/delete-node-in-a-linked-list/) + +**题目** + +237-删除链表中的节点 + +```swift +public void deleteNode(ListNode node) { + +} +``` +示例 1: + +![示例](https://assets.leetcode.com/uploads/2020/09/01/node1.jpg) + +``` +输入:head = [4,5,1,9], node = 5 +输出:[4,1,9] +解释:指定链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9 +``` + +**解题** + +* 问题:无法通过常规的先拿到链表要删除结点的前一个结点,然后来直接指向要删除结点的下一个结点, +* 思路 +* 1、拿到要删除结点的下一个结点 +* 2、用下一个节点来覆盖掉要要删除的结点 +* 3、让要删除的结点的next指向下一个结点的下一个结点 + + + +**题目** + +[地址](https://leetcode.cn/problems/reverse-linked-list/) + +206-反转链表 + +给你单链表的头节点 `head` ,请你反转链表,并返回反转后的链表。 + +**示例 1:** + +![示例1](https://assets.leetcode.com/uploads/2021/02/19/rev1ex1.jpg) + +``` +输入:head = [1,2,3,4,5] +输出:[5,4,3,2,1] +``` + +**解题** + +第一种方案:递归 + +```swift +public ListNode reverseList(ListNode head) { + if (head == null || head.next == null) { + return head; + } + ListNode newHead = reverseList(head.next); + head.next.next = head; + head.next = null; + + return newHead; +} +``` + +第二种方案:非递归 + +思路 + +1、先让head指向的结点指向newHead,新的头节点newHead指向head指向的结点,然后让head指向head.next的结点, + +2、重复此操作 + +![image-20231126232216986](/Users/guo/Notes/学习算法与数据结构笔记/images/链表/反转链表-非递归.png) + + + +```swift +public ListNode reverseList2(ListNode head) { + ListNode newHead = null; + + while (head != null) { + ListNode tmp = head.next; + head.next = newHead; + newHead = head; + head = tmp; + } + + return newHead; +} +``` + +**题目** + +[地址](https://leetcode.cn/problems/linked-list-cycle/) + +141-环形链表 + +给你一个链表的头节点 `head` ,判断链表中是否有环 + +*如果链表中存在环* ,则返回 `true` 。 否则,返回 `false` 。 + +**示例 1:** + +![图片](https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2018/12/07/circularlinkedlist.png) + +``` +输入:head = [3,2,0,-4], pos = 1 +输出:true +解释:链表中有一个环,其尾部连接到第二个节点。 +``` + +**解题** + +思路:使用快慢指针 + +![图片](/Users/guo/Notes/学习算法与数据结构笔记/images/链表/环形链表.png) + +```swift +public boolean hasCycle(ListNode head) { + if (head == null || head.next == null) return false; + ListNode slow = head; + ListNode fast = head.next; + while (fast != null && fast.next != null) { + slow = slow.next; + fast = fast.next.next; + if (slow == fast) return true; + } + return false; +} +``` @@ -16,6 +210,10 @@ > 有时候为了让代码更贱精简,统一所有结点的处理逻辑,可以在最前面增加一个虚拟的头结点(结点中不存储数据) +![图片](/Users/guo/Notes/学习算法与数据结构笔记/images/链表/虚拟头节点.png) + + + #### 单向链表 > 每一个结点中只包含元素内容和next指针 @@ -52,6 +250,10 @@ ![image-20220418002724307](/Users/guo/Notes/学习算法与数据结构笔记/images/单向循环链表_01.png) +在添加时,需要考虑到,添加第1个节点的情况 + +![image-20231129002310531](/Users/guo/Notes/学习算法与数据结构笔记/images/链表/单项循环链表.png) + #### 双向循环链表 ![image-20220418015525547](/Users/guo/Notes/学习算法与数据结构笔记/images/双向循环链表_01.png) @@ -73,3 +275,7 @@ * 解决判断是否为环 ![image-20220412022201431](/Users/guo/Notes/学习算法与数据结构笔记/03-链表-判断链表是否为环.png) + +#### 参考资料 + +* [动画形式看算法每一步](https://visualgo.net/zh) diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/05-\351\230\237\345\210\227.md" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/05-\351\230\237\345\210\227.md" index 4282bde..019beff 100644 --- "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/05-\351\230\237\345\210\227.md" +++ "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/05-\351\230\237\345\210\227.md" @@ -2,8 +2,8 @@ > 是一种特殊的线性表,只能在头尾两端进行操作 -* 队列:只能从队尾添加元素,一般叫做enQueue,入队 -* 队头:只能从队头移除元素,一般叫做deQueue,出队 +* 队列:只能从**队尾添加**元素,一般叫做enQueue,入队 +* 队头:只能从**队头移除**元素,一般叫做deQueue,出队 * 先进先出的原则:First in First Out,FIFO ![image-20220419014240909](/Users/guo/Notes/学习算法与数据结构笔记/images/队列_01.png) @@ -20,6 +20,10 @@ > > 英文 deque 是 double ended queue 的简称 +概念:能在**头尾**两端**添加**、**删除**的队列 + +英文deque:是 double ended queue 的简称 + ![image-20220419224623298](/Users/guo/Notes/学习算法与数据结构笔记/images/双端队列_01.png) ```java @@ -46,3 +50,63 @@ E rear(); > 底层使用数组来实现 ![image-20220419230424338](/Users/guo/Notes/学习算法与数据结构笔记/images/循环队列_01.png) + +### 优先级队列(Priority Queue) + +普通队列是**FIFO**原则,先进先出 + +**优先级队列**则是按照**优先级高低**进行出队,**优先级高**的元素作为**队头**优先出队 + +#### 接口 + +```java +int size(); +boolean isEmpty(); +void enQueue(E element); +E dequeue(); +E front(); +void clear(); +``` + +#### 实现 + +这里采取二叉堆作为优先级队列的底层实现 + +```java +public class PriorityQueue { + private BinaryHeap heap; + + public PriorityQueue() { + this(null); + } + + public PriorityQueue(Comparator comparator) { + heap = new BinaryHeap<>(comparator); + } + + public int size() { + return heap.size(); + } + + public boolean isEmpty() { + return heap.size() == 0; + } + + public void enQueue(E element) { + heap.add(element); + } + + public E dequeue() { + return heap.remove(); + } + + public E front() { + return heap.get(); + } + + public void clear() { + heap.clear(); + } +} +``` + diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/06-\344\272\214\345\217\211\346\240\221.md" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/06-\344\272\214\345\217\211\346\240\221.md" index 12087bd..e994db8 100644 --- "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/06-\344\272\214\345\217\211\346\240\221.md" +++ "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/06-\344\272\214\345\217\211\346\240\221.md" @@ -6,13 +6,14 @@ * 空树:一棵树可以没有任何节点 * 根节点:一颗树可以只有1个节点 * 子树、左子树、右子树 -* 节点的度(degree):子树的个数 -* 树的度:所有节点度中的最大值 -* 叶子节点(leaf):度为0的节点 +* 节点的度(degree):**子树的个数** +* 树的度:**所有节点度中的最大值** +* 叶子节点(leaf):**度为0的节点** * 非叶子节点:度不是0的节点 * 层数(level):根节点在第1层,根节点的子节点在第2层,依次类推 * 节点的深度(depth):从根节点到当前节点的唯一路径上的节点总数 * 节点的高度(height):从当前节点到最远叶子节点的路径上的节点总数 +* 节点的祖先:是从根到该节点所经分支上的所有节点 * 树的深度:所有节点深度中的最大值 * 树的高度:所有结点高度中的最大值 * 树的深度等于树的高度 @@ -52,6 +53,7 @@ * 第i层的节点数量:2^(i -1) * 叶子节点的数量:2^(h-1) * 总节点数量n,n = 2^h - 1,h = log2(n + 1) +* 满二叉树一定是真二叉树,真二叉树不一定是满二叉树 #### 完全二叉树 (Complet Binary Tree) @@ -64,14 +66,14 @@ * 度为1的节点只有左子树 * 度为1的节点要么是1个,要么是0个 -* 同样节点数量的二叉树,完全二叉树的高度最小 +* 同样节点数量的二叉树,完全二叉树的高度**最小** * 假设完全二叉树的高度为h(h >= 1),那么 * 至少有2^(h - 1)个节点 * 最多有2^h - 1个节点(满二叉树) * 总节点数量为 n, * 2^(h - 1) <= n < 2^h * h - 1 <= log2n < h - * h = floor(log2n) + 1 + * **h = floor(log2n) + 1** * floor是向下取整,ceil是向上取整 * 一颗有n个节点的完全二叉树(n > 0),从上到下,从左到右对节点从1开始进行编号,对任何第i个节点 * 如果i = 1,它是根节点 @@ -86,7 +88,10 @@ #### 二叉搜索树(Binary Search Tree) -> 二叉搜索树是二叉树的一种,是应用非常广泛的一种二叉树,英文简称BST,又称:二叉查找树、二叉排序树 +> 二叉搜索树是二叉树的一种,是应用非常广泛的一种二叉树,英文简称BST +> + +又称:二叉查找树、二叉排序树 ![image-20220423181045991](/Users/guo/Notes/学习算法与数据结构笔记/images/二叉搜索树_01.png) @@ -96,37 +101,54 @@ #### 特性 -* 任意一个节点的值都大于其左子树所有节点的值 +* 任意一个节点的值都**大于其左子树**所有节点的值 -* 任意一个节点的值都小于其右子树所有节点的值 +* 任意一个节点的值都**小于其右子树**所有节点的值 * 它的左右子树也是一颗二叉搜索树 +* 它存储的元素必须具备**可比较性**、且元素不允许为**null** + * 没有索引的概念(对比动态数组、链表) * 在n个动态的整数中搜索某个整数?(查看其是否存在) * 假设使用动态数组来存放元素,从第0个位置开始遍历搜索,平均时间复杂度为O(n) * 如果维护一个有序的动态数组,使用二分搜索,最坏时间复杂度为O(logn),但是添加、删除的平均时间复杂度为O(n) * 使用二叉搜索树,添加、删除、搜索的最坏时间复杂度均为O(logn) - -* 添加节点 - + +#### 接口设计 + +```java +int size() // 元素的数量 +boolean isEmpty() // 是否为空 +void clear() // 清空所有元素 +void add(E element) // 添加元素 +void remove(E element) // 删除元素 +boolean contains(E element) // 是否包含某元素 +``` + +#### 添加节点 + * 添加步骤: - + 1、找到父节点parent - + 2、创建新节点node - + 3、将parent.left = node或者parent.right = node - + +#### 学习网站 + +* http://btv.melezinek.cz/binary-search-tree.html +* https://www.cs.usfca.edu/~galles/visualization/Algorithms.html #### 线性数据结构的遍历 -之前线性数据结构的遍历较为简单,分为 +之前**线性数据结构**的遍历较为简单,分为 -##### 正序遍历 +* 正序遍历 -##### 逆序遍历 +* 逆序遍历 #### 二叉树遍历 @@ -134,15 +156,23 @@ ##### 前序遍历(Preorder Traversal) -* 访问顺序:**根节点**、前序遍历左子树、前序遍历右子树 +* 访问顺序 + +**根节点**、前序遍历左子树、前序遍历右子树 ##### 中序遍历(Inorder Traversal) -* 访问顺序:中序遍历左子树、**根节点**、中序遍历右子树(二叉搜索树的中序遍历是升序或者降序的) +* 访问顺序 + +中序遍历左子树、**根节点**、中序遍历右子树 + +**注意**:**二叉搜索树的中序遍历是升序或者降序的** ##### 后序遍历(Postorder Traversal) -* 访问顺序:后序遍历左子树、后序遍历右子树、**根节点** +* 访问顺序 + +后序遍历左子树、后序遍历右子树、**根节点** ##### 层序遍历(Level Order Traversal) @@ -169,14 +199,15 @@ * * 计算二叉树的高度,可以使用迭代、递归两种思路 -* 判断一棵树是否为完全二叉树,思如如下 + + + +* 判断一棵树**是否为完全二叉树**,思如如下 * 如果树为空,直接返回false * 如果树不为空,开始层序遍历二叉树(使用队列数据结构) - * 如果当前node.left != null,将node - * 如果当前node.left == null, - * 如果当前node.right != null, - * 如果当前node.right == null, - + * 如果当前node.left != null && node.right != null,将node.left、node.right 按顺序入队 + * 如果当前node.left == null && node.right != null,返回 false + * 如果当前node.left != null && node.right == null 或者 node.left == null && node.right == null,那么后面遍历的节点应该都为叶子节点,才是完全二叉树,否则,返回false * 根据以下结果一定可以重构出唯一的二叉树 * 前序遍历 + 中序遍历 * 后续遍历 + 中序遍历 @@ -186,7 +217,7 @@ #### 前驱节点(predecessor) -* 前驱节点:中序遍历时的前一个节点 +* 前驱节点:**中序遍历时的前一个节点** * 如果是二叉搜索树,前驱节点就是前一个比它小的节点 * 思路 * 如果node.left != null,则前驱节点 predecessor = node.left.right.right....,终止条件:right 为 null @@ -195,7 +226,7 @@ #### 后继节点(successor) -* 后继节点:中序遍历时的后一个节点 +* 后继节点:**中序遍历时的后一个节点** * 如果是二叉搜索树,后继节点就是后一个比它大的节点 @@ -223,6 +254,8 @@ ![image-20220428002018136](/Users/guo/Notes/学习算法与数据结构笔记/images/二叉搜索树删除叶子节点.png) +分为以下几种情况: + ##### 删除叶子节点 ```java @@ -256,12 +289,10 @@ root = child child .root = null ``` - - ##### 删除度为2的节点 * 先用前驱或者后继节点的值覆盖原节点的值,然后删除相应的前驱或者后继节点 -* 如果一个节点的度为2,那么它的前驱·后继节点的度只可能是1或者0 +* 如果一个节点的度为2,那么**它的前驱·后继节点的度只可能是1或者0** #### 二叉搜索树的复杂度 @@ -281,7 +312,7 @@ child .root = null > 一颗达到适度平衡的二叉搜索树,可以称之为平衡二叉搜索树 -* 英文简称为:BBST +* 英文简称为:**BBST** * 经典常见的平衡二叉搜索树有:(一般也称为:自平衡的二叉搜索树(Self-balancing Binary Search Tree)) * AVL树 * windows NT 内核中广泛使用 @@ -295,7 +326,7 @@ child .root = null > 是最早发明的自平衡二叉搜索树之一 -* 平衡因子(Balance Factor):某结点的左右子树的高度差 +* 平衡因子(**Balance Factor**):某结点的左右子树的高度差 * 特点 ``` @@ -400,12 +431,12 @@ T1、p、g的parent属性 ##### 添加 -* 可能会导致所有祖先节点都失衡 +* 可能会导致**所有祖先节点**都失衡 * 只要让高度最低的失衡节点恢复平衡,整棵树就恢复平衡[仅仅需要O(1)次调整] ##### 删除 -* 可能会导致父节点或祖先节点失衡(只有1个节点会失衡) +* 可能会导致**父节点**或**祖先节点**失衡(只有1个节点会失衡) * 让父节点恢复平衡后,可能会导致更高层的祖先节点失衡[最多需要O(logn)次调整] ##### 平均时间复杂度 diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/07-\347\272\242\351\273\221\346\240\221.md" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/07-\347\272\242\351\273\221\346\240\221.md" index c7bf57b..b7bfa13 100644 --- "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/07-\347\272\242\351\273\221\346\240\221.md" +++ "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/07-\347\272\242\351\273\221\346\240\221.md" @@ -14,7 +14,10 @@ * RED节点的Parent都是BLACK * 从根节点到叶子节点的所有路径上不能有2个连续的RED节点 -* 从任一节点到叶子节点的所有路径都包含相同数目的BLACK节点 + +5、从任一节点到叶子节点的所有路径都包含相同数目的BLACK节点 + +是一颗真二叉树(度为0或者2) ![image-20220507003453626](/Users/guo/Notes/学习算法与数据结构笔记/images/红黑树_01.png) @@ -24,7 +27,44 @@ ![image-20220809000914613](/Users/guo/Notes/学习算法与数据结构笔记/images/红黑树等价_02.png) -* 红黑树和4阶B树(2-3-4树)具有等价性 -* BLACK节点和它的RED子节点融合在一起,形成一个B树节点 -* 红黑树的BLACK节点子树与4阶B树的节点总个数相等 -* +* **红黑树和4阶B树(2-3-4树)具有等价性** +* **BLACK节点和它的RED子节点融合在一起,形成一个B树节点** +* **红黑树的BLACK节点个数与4阶B树的节点总个数相等** + +#### 红黑树 vs 2-3-4树 + +#### 添加的所有情况 + +* 有4种情况情况满足红黑树的性质4 + +parent为black + +* 有8种情况不满足红黑树的性质4 + +parent为red + +第一种:**LL**(左旋)\**RR**(右旋) + +判断条件:uncle不是RED + +1、parent染成BLACK,grand染成RED + +2、grand进行单旋操作 + +第二种:**LR** \ **RL** + +判断条件:uncle不是RED + +1、自己染成BLACK,grand 染成RED + +2、进行双旋操作 + +LR:parent进行左旋,grand进行右旋 + +RL:parent进行右旋,grand进行左旋 + +第三种:上溢 LL + +判定条件:uncle是RED + +1、parent diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/08-B-\346\240\221.md" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/08-B-\346\240\221.md" index 6ea3695..20e1345 100644 --- "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/08-B-\346\240\221.md" +++ "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/08-B-\346\240\221.md" @@ -11,6 +11,8 @@ ### M阶B树的性质(m >= 2) +M阶:一个节点最多拥有的子节点个数 + ##### 假设一个节点存储的元素个数为x * 根节点:1 <= x <= m - 1 @@ -38,7 +40,7 @@ * 3代合并的超级节点,最多拥有8个子节点(至少是8阶B树) * 4代合并的超级节点,最多拥有2的n次方个子节点(至少是2的n阶B树) -##### m阶B树,最多需要Log2m代合并 +##### m阶B树,最多需要log2m代合并 #### 搜索 @@ -56,7 +58,17 @@ 如果插入元素造成叶子节点的元素个数超过当前阶限制,这种现象称为 **上溢( overflow)** -上溢的解决方案 +##### 上溢的解决方案 + +> 是唯一一种可以让B树变高的情况 + +上溢节点的元素个数必然等于m + +* 假设上溢节点最中间元素的位置是k + * **将k位置的元素向上与父节点合并** + * 将[0, k-1]和[k + 1, m - 1]位置的元素分裂成2个子节点,这2个子节点的元素个数,必然都不会低于最低限制(⌜ m/2⌝ - 1) +* 一次分裂完毕后,有可能导致父节点上溢,依然按照上述方法解决 + * 最极端的情况,有可能一直分裂到根结点 #### 删除-叶子节点 @@ -70,12 +82,14 @@ ##### 非叶子节点的前驱或者后继元素,必定在叶子节点中 * 所以这里的删除前驱或者后续元素,就是最开始提到的情况:删除的元素在叶子节点中 -* 真正的删除元素都是发生在叶子节点中 +* **真正的删除元素都是发生在叶子节点中** 如果删除叶子节点中的一个元素后,元素个数可能会低于最低限制(>=⌜ m/2⌝ - 1),这种情况被称为**下溢**(underflow) ##### 删除-下溢的解决 +> 是唯一一种可以让B树变矮的情况 + 下溢节点的元素数量必然等于⌜ m/2⌝ - 2 如果下溢节点临近的兄弟节点,有至少⌜ m/2⌝个元素,可以向其借一个元素 @@ -90,5 +104,11 @@ * 将父节点的元素b挪下来跟左右子节点进行合并 * 合并后的节点元素个数等于⌜ m/2⌝ + ⌜ m/2⌝ - 2,不超过m - 1 +* 这个操作可能会导致父节点下溢,依然按照上述方法解决,下溢现象可能会一直往上传播 ![image-20220508204826194](/Users/guo/Notes/学习算法与数据结构笔记/images/下溢解决_02.png) + +#### 4阶B树的性质 + +* 所有节点能存储的元素个数x:1 <= x <= 3 +* 所有非叶子结点的子节点个数y:2 <= y <= 4 diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/10\345\244\247\346\216\222\345\272\217\347\256\227\346\263\225.md" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/10\345\244\247\346\216\222\345\272\217\347\256\227\346\263\225.md" index 6a9880d..541a2cc 100644 --- "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/10\345\244\247\346\216\222\345\272\217\347\256\227\346\263\225.md" +++ "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/10\345\244\247\346\216\222\345\272\217\347\256\227\346\263\225.md" @@ -22,7 +22,9 @@ 冒泡、选择、插入、归并、快速、希尔、堆排序属于比较排序(Comparison Sorting) -### 冒泡排序 +### 基于比较的排序 + +#### 冒泡排序 执行流程(这里以升序为例) @@ -45,6 +47,7 @@ * 最坏、平均时间复杂度:O(n的2次方) * 最好时间复杂度:O(n) * 空间复杂度:O(1) +* 属于稳定排序 ##### 原地算法(In-place Algorithm) @@ -84,6 +87,8 @@ * 堆的元素数量减1 * 对0位置进行1次sift Down 操作 +属于不稳定排序 + ##### 插入排序(Insertion Sort) > 类似于扑克牌的排序 @@ -98,8 +103,41 @@ * 每当扫描到一个元素,就将它插入到头部合适的位置,使得头部数据依然保持有序 +##### 插入排序优化 + +###### 二分搜索(Binary Search) + +* 如果是无序数组,从第1个位置开始遍历搜索,平均时间复杂度:O(n) +* 如果是有序数组,可以使用二分搜索,最坏时间复杂度:O(logn) + +二分搜索-思路 + +* 假设在[begin,end) 范围内搜搜某个元素v,mid = (begin + end) /2 + * 如果v < m,去[begin, mid) 范围内二分搜索 + * 如果 v > m,去[mid + 1, end) 范围内二分搜索 + * 如果 v == m,直接返回 mid + + + ##### 归并排序(Mege Sort) +##### 执行流程 + +* 不断地将当前序列平均分割成2个子序列 + * 直到不能再分割(序列中只剩1个元素) +* 不断地将2个子序列合并成一个序列 + * 直到最终只剩下1个有序序列 + +##### 细节 + +* 在合并的时候,考虑将前一个数组备份一份,再开始合并操作 + +##### 复杂度 + +* 由于归并排序总是平均分割子序列,所以最好、最坏、平均时间复杂度都是O(nlogn) +* 空间复杂度是O(n) +* 属于稳定排序 + ##### 快速排序(Quick Sort) * 执行流程 @@ -120,6 +158,11 @@ 直到不能再分割(子序列中只剩下1个元素) +* 本质 + * 逐渐将每一个元素都转换成轴点元素 + + + ##### 希尔排序(Shell Sort) * 希尔排序把序列看做是一个矩阵,分成m列,逐列进行排序 @@ -127,15 +170,44 @@ * 当m为1时,整个序列将完全有序 * 希尔排序被称为递增减量排序(Diminishing Increment Sort) * 矩阵的列数取决于步长序列(step sequence) - * 比如, +* 希尔排序底层一般使用插入排序对每一列进行排序,也有很多资料认为希尔排序是插入排序的改进版 + +### 非基于比较的排序 + +##### 1、计数排序 (Counting Sort) + +> 适合对一定范围内的整数排序 + +**核心思想** + +* 统计每个整数在序列中出现的次数,进而推导出每个整数在有序序列中的索引 + +**复杂度** + +* 最好、最坏、平均的时间复杂度:O(n + k),空间复杂度:O(n + k) +* k是整数的取值范围 +* 属于稳定排序 + +如果自定义对象可以提供用以排序的整数类型,依然可以使用计数排序 + -##### 计数排序 ##### 基数排序(Radix Sort) +> 基数排序非常适合用于整数排序(尤其是非负整数) + +执行流程:依次对个位数、十位数、百位数、千位数、万位数...进行排序(从低位到高位) + +个位数、十位数、百位数的取值范围都是固定的0~9,可以使用计数排序对它们进行排序 + +**复杂度** + +* 最好、最坏、平均时间复杂度:O(d * (n + k)),d是最大值的位数,k是进制,属于稳定排序 +* 空间复杂度:O(n + k),k是进制 + ##### 桶排序(Bucket Sort) -执行流程 +**执行流程** * 创建一定数量的桶(比如用数组、链表作为桶) * 按照一定的规则(不同类型的数据,规则不同),将序列中的元素均匀分配到对应的桶 diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/11-\351\233\206\345\220\210.md" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/11-\351\233\206\345\220\210.md" new file mode 100644 index 0000000..28ef009 --- /dev/null +++ "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/11-\351\233\206\345\220\210.md" @@ -0,0 +1,34 @@ +## 集合 + +#### 特点 + +* 不存放重复的元素 +* 常用于去重 + +#### 接口 + +```java +public interface Set { + int size(); + boolean isEmpty(); + void clear(); + boolean contains(E element); + void add(E element); + void remove(E element); + void traversal(Visitor visitor); + // 遍历 + public static abstract class Visitor { + boolean stop; + public abstract boolean visit(E element); + } +} +``` + + + +#### 实现 + +* 动态数组 +* 链表 +* 二叉树(AVL、红黑树) + diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/13-\345\223\210\345\270\214\350\241\250.md" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/13-\345\223\210\345\270\214\350\241\250.md" new file mode 100644 index 0000000..ffaf595 --- /dev/null +++ "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/13-\345\223\210\345\270\214\350\241\250.md" @@ -0,0 +1,58 @@ +## 哈希表(Hash Table) + +* 哈希表也叫散列表 + +* 哈希表是空间换时间的应用 + +* 哈希函数,也叫做散列函数 + +* 哈希表内部的数组元素,也叫bucket(桶),整个数组叫buckets 或者bucket Array + +#### 添加、搜索、删除的流程 + +1、利用哈希函数生成key对应的index【O(1)】 + +2、根据index操作定位数组元素【O(1)】 + +#### 哈希冲突(Hash Collision) + +也叫**哈希碰撞** + +* 2个不同的key,经过哈希函数计算出相同的结果 +* Key1 != key2,hash(key1) = hash(key2) + +#### 解决哈希冲突的常见方法 + +1、开放定址法(Open Addressing) + +* 按照一定的规则向其他地址探测,直到遇到空桶 + +2、再哈希法(Re-hashing) + +* 设计多个哈希函数 + +3、链地址法(Separate Chainning) + +* 比如通过链表将同一index的元素串起来 + +#### 哈希函数 + +哈希表中哈希函数的实现步骤如下: + +1、先生成**key**的哈希值(必须是**整数**) + +2、再让**key的哈希值**跟**数组的大小**进行相关运算 + + + + + +#### 自定义对象作为Key + +自定义对象作为key,最好同时重写hashCode、equals 方法 + +* equals:用以判断2个key是否为同一个key + * 自反性:对于任何非null 的 x,,x.equals(x)必须返回true + * 对称性:对于任何非null 的 x,y,如果y.equals(x) 返回 true,x.equals(x)必须返回true + * 传递性:对于任何非null 的 + * 一致性: diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/14-\345\271\266\346\237\245\351\233\206.md" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/14-\345\271\266\346\237\245\351\233\206.md" new file mode 100644 index 0000000..e6a169c --- /dev/null +++ "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/14-\345\271\266\346\237\245\351\233\206.md" @@ -0,0 +1,198 @@ +## 并查集(Union Find) + +#### 适用特点 + +1、非常适合解决这类"连接"相关的问题 + +2、能够办到查询、连接的**均摊时间复杂度**都是O(α(n)), α(n) < 5 + +并查集也叫做不相交集合(**Disjoint** **Set**) + +#### 核心操作 + +* 查找(Find):查找元素所在的集合(这里的集合不是指Set这种数据结构,而是指广义的数据集合) +* 合并(Union):将两个元素所在的集合合并为一个集合 + +#### 常见两种实现思路 + +1、Quick Find + +* 查找:时间复杂度:O(1) + +代码实现 + +```java +public UnionFind(int capacity) { + if (capacity < 0) { + throw new IllegalArgumentException("capacity must be >= 1"); + } + parents = new int[capacity]; + for (int i = 0; i < parents.length; i++) { + parents[i] = i; + } +} + +protected void rangeCheck(int v) { + if (v < 0 || v >= parents.length) { + throw new IllegalArgumentException("v is out of bounds"); + } +} + +public int find(int v) { + rangeCheck(v); + return parents[v]; +} +``` + +* 合并:时间复杂度:O(n) + * union(v1, v2):让v1所在集合的所有元素都指向v2的根节点 + +代码实现 + +```java +public void union(int v1, int v2) { + int p1 = find(v1); + int p2 = find(v2); + if (p1 == p2) return; + for (int i = 0; i < parents.length; i++) { + if (parents[i] == p1) { + parents[i] = p2; + } + } +} +``` + +2、Quick Union + +* 查找:时间复杂度:O(logn),可以优化至O(α(n)), α(n) < 5 + +代码实现 + +```java +public int find(int v) { + rangeCheck(v); + while (v != parents[v]) { + v = parents[v]; + } + return v; +} +``` + +* 合并:时间复杂度:O(logn),可以优化至O(α(n)), α(n) < 5 + * union(v1, v2):让 v1的根节点指向v2的根节点 + +代码实现 + +```java +public void union(int v1, int v2) { + int p1 = find(v1); + int p2 = find(v2); + if (p1 == p2) return; + parents[p1] = p2; +} +``` + + +#### Quick Union - 优化 + +> 在Union的过程中,可能会出现树不平衡的情况,甚至退化成链表 + +**有两种常见的优化方案** + +1、基于**size**的优化:元素少的树嫁接到元素多的树 + +代码 + +```java +private int[] sizes; +public UnionFind_QU_S(int capacity) { + super(capacity); + sizes = new int[capacity]; + for (int i = 0; i < sizes.length; i++) { + sizes[i] = 1; + } +} + +public void union(int v1, int v2) { + int p1 = find(v1); + int p2 = find(v2); + if (p1 == p2) return; + if (sizes[p1] < sizes[p2]) { + parents[p1] = p2; + sizes[p2] += sizes[p1]; + } else { + parents[p2] = p1; + sizes[p1] += sizes[p2]; + } +} +``` + +2、基于**rank**的优化:矮的树嫁接到高的树 + +```java +private int[] ranks; +public UnionFind_QU_R(int capacity) { + super(capacity); + ranks = new int[capacity]; + for (int i = 0; i < ranks.length; i++) { + ranks[i] = 1; + } +} + +public void union(int v1, int v2) { + int p1 = find(v1); + int p2 = find(v2); + if (p1 == p2) return; + + if (ranks[p1] < ranks[p2]) { + parents[p1] = p2; + } else if (ranks[p2] < ranks[p1]) { + parents[p2] = p1; + } else { + parents[p1] = p2; + ranks[p2]++; + } +} +``` + +#### Quick Union- 基于rank的优化 + +1、**路径压缩(Path Compression)** + +```java +public int find(int v) { + rangeCheck(v); + if (parents[v] != v) { + parents[v] = find(parents[v]); + } + return parents[v]; +} +``` + +2、**路径分裂(Path Spliting)** + +```java +public int find(int v) { + rangeCheck(v); + while (v != parents[v]) { + int p = parents[v]; + parents[v] = parents[p]; + v = p; + } + return v; +} +``` + +3、**路径减半(Path Halving)** + +```java +public int find(int v) { + rangeCheck(v); + while (v != parents[v]) { + parents[v] = parents[parents[v]]; + v = parents[v]; + } + return v; +} +``` + diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/15-\345\233\276.md" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/15-\345\233\276.md" new file mode 100644 index 0000000..d363841 --- /dev/null +++ "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/15-\345\233\276.md" @@ -0,0 +1,200 @@ +# 图(Graph) + +## 一、基本概念 + +**1、顶点、边** + +图是由顶点(**vertex**)和边(**edge**)组成,通常表示为G = (V, E),G表示一个图,V是顶点集,E是边集 + +顶点集V有穷且非空 + +任意两个定点之间都可以用边来表示它们之间的关系,边集E可以是空 + +## 二、类型 + +#### **1、有向图(Directed Graph)** + +* 有向图的边是有明确方向的 +* 有向无环图(Direted Acyclic Graph,简称 **DAG**) +如果一个有向图,从任意顶点出发经过若干条变回到该顶点,那么它就是一个有向无环图 + +
+ + +
+#### **出度、入度** + +> 只适用于有向图 + +* 出度(**Out-degree**) + +一个顶点的出度为x,是指有x条边以该顶点为起点 + +* 入度(**In-degree**) + +一个顶点的入度为x,是指有x条边以该顶点为终点 + +#### **2、无向图(Undirected Graph)** + +* 无向图的边是无方向的 + +#### **3、混合图(Mixed Graph)** + +* 混合图的边可能是无向的,也可能是有向的 + +#### **4、简单图、多重图** + +* 平行边 + +1、在无向图中,关联一对顶点的无向边如果多于1条,则称这些边为平行边 + +2、在有向图中,关联一对顶点的有向边如果多于1条,且它们的方向相同,则称这些边为平行边 + +* 多重图(Multigraph) + +有平行边或者有自环的图 + +* 简单图(Simple Graph) + +既没有平行边也没有自环的图 + +#### **5、无向完全图(Undirected Complete Graph)** + +完全图:任意两个顶点之间都存在边 + +* 无向完全图的任意两个定点之间都存在边 +* n个顶点的无向完全图有n*(n - 1) /2 条边 + +#### **6、有向完全图** (Directed Complete Graph) + + 有向完全图的任意两个顶点之间都存在方向相反的两条边 + +* n个顶点的有向图完全图有n(n - 1)条边 + +稠密图(**Dense Graph**):边树接近于或等于完全图 + +稀疏图(**Sparse Graph**):边树远远少于完全图 + +#### **7、有权图**(Weighted Graph) + +有权图的边可以拥有权值(Weight) + +#### **8、连通图(Connected Graph)** + +* 如果顶点x 和 y 之间存在可相互抵达的路径(直接或间接的路径),则称x和y是连通的 +* 如果无向图G中任意2个顶点都是**连通的**,则称G为**连通图** + +#### **9、连通分量(connected Component)** + +* 连通分量:无向图的极大连通子图 +* 连通图只有一个连通分量,即其自身,非连通图的无向图有多个连通分量 + +#### **10、强连通图(Strongly Connected Graph)** + +* 如果有向图G中任意2个顶点都是连通的,则称G为强连通图 + +#### **11、强连通分量(Strongly Connected Component)** + +* 强连通分量:有向图的极大强连通子图 +* 强连通图只有一个强连通分量,即其自身;非强连通图的有向图有多个强连通分量 + +## 三、实现 + +图有两种实现方案 + +1、邻接矩阵(Adjacency Matrix) + +2、邻接表(Adjacency List) + +#### 遍历 + +* 从图中某一顶点出发访问图中其余顶点,。且每一个顶点仅被访问一次 +* 图有两种遍历方式(有向图、无向图都适用) + * 广度优先搜索(Breadth First Search,BFS),又称为宽度优先搜索,横向优先搜索 + + 二叉树的层序遍历就是一种广度优先搜索,使用队列来实现 + + ```java + public void bfs(V begin, VertexVisitor visitor) { + if (visitor == null) return; + Vertex beginVertex = vertices.get(begin); + if (beginVertex == null) return; + + Set> visitedVertices = new HashSet<>(); + Queue> queue = new LinkedList<>(); + queue.offer(beginVertex); + visitedVertices.add(beginVertex); + + while (!queue.isEmpty()) { + Vertex vertex = queue.poll(); + if (visitor.visit(vertex.value)) return; + + for (Edge edge : vertex.outEdges) { + if (visitedVertices.contains(edge.to)) { + continue; + } + queue.offer(edge.to); + visitedVertices.add(edge.to); + } + + } + } + ``` + + * 深度优先搜索(Depth First Search,DFS) + + 二叉树的前序遍历就是一种深度优先搜索 + + 顺着一条路一直走,直到不能走了,开始回退到上一个路径 + + **非递归** + + ```java + public void dfs(V begin, VertexVisitor visitor) { + if (visitor == null) return; + Vertex beginVertex = vertices.get(begin); + if (beginVertex == null) return; + Set> visitedVertices = new HashSet<>(); + Stack> stack = new Stack<>(); + // 先访问起点 + stack.push(beginVertex); + if (visitor.visit(beginVertex.value)) return; + visitedVertices.add(beginVertex); + + while (!stack.isEmpty()) { + Vertex vertex = stack.pop(); + for (Edge edge: vertex.outEdges) { + if (visitedVertices.contains(edge.to)) { + continue; + } + stack.push(edge.from); + stack.push(edge.to); + visitedVertices.add(edge.to); + if (visitor.visit(edge.to.value)) return; + break; + } + } + } + ``` + + 递归 + + ```java + public void dfs(V begin, VertexVisitor visitor) { + Vertex beginVertex = vertices.get(begin); + if (beginVertex == null) return; + dfs(beginVertex, new HashSet<>(), visitor); + } + + private void dfs(Vertex vertex, Set> visitedVertices, VertexVisitor visitor) { + visitor.visit(vertex.value); + visitedVertices.add(vertex); + + for (Edge edge : vertex.outEdges) { + if (visitedVertices.contains(edge.to)) continue; + dfs(edge.to, visitedVertices, visitor); + } + } + ``` + + diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/16-AOV\347\275\221.md" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/16-AOV\347\275\221.md" new file mode 100644 index 0000000..3492914 --- /dev/null +++ "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/16-AOV\347\275\221.md" @@ -0,0 +1,42 @@ +## AOV网(Activity On Vertex Network) + +* 一项大的工程常被分为多个小的子工程 + * 子工程之间可能存在一定先后顺序,即某些子工程必须在其他的一些工程完成后才能开始 + +* 在现代管理中,人们常用有向图来描述和分析一项工程的计划和实施过程,子工程被称为活动(Activity) + * 以顶点表示活动、有向边表示活动之间的先后关系,这样的图简称为 AOV 网 + +* 标准的AOV网必须是一个**有向无环图**(Directed Acyclic Graph,简称 **DAG**) + +### 拓扑排序(Topological Sort) + +概念: + +将AOV网中所有活动排成一个序列,使得每一个活动的前驱活动都排在该活动的前面 + +**前驱活动**:有向边起点的活动称为终点的前驱活动 + +* 只有当一个活动的前驱全部都完成后,这个活动才能进行 + +**后继活动**:有向边终点的活动成为起点的后继活动 + +拓扑排序的结果不一定是**唯一**的 + +**拓扑排序思路** + +基于卡恩算法实现,具体如下: + +假设L是存犯法拓扑排序结果的列表 + +1、把所有入度为0的顶点放入L中,然后把这些顶点从图中去掉 + +2、重复操作1,直到找不到入度为0的顶点 + +如果此时L中的元素个数和顶点总数相同,说明拓扑排序完成 + +如果此时L中的元素个数少于顶点总数,说明原图中存在的环,无法进行拓扑排序 + + + + + diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/17-\347\224\237\346\210\220\346\240\221.md" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/17-\347\224\237\346\210\220\346\240\221.md" new file mode 100644 index 0000000..5131638 --- /dev/null +++ "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/17-\347\224\237\346\210\220\346\240\221.md" @@ -0,0 +1,53 @@ +## 生成树(Spanning Tree) + +* 生成树(Spanning Tree),也称为**支撑树** + + 连通图的极小连通子图,它包含有图中全部的n个顶点,恰好只有 n - 1条边 + + 不是唯一的,可以有多个 + + + +## 最小生成树(Minimum Spanning Tree) + +* 最小生成树(Minimum Spanning Tree, 简称 MST) + * 也称为最小权重生成树( Minimum Weight Spanning Tree)、最小支撑树 + * 是所有生成树种,总权值最小的那颗 + * 适用于**有权**的**连通**图(无向) +* 应用 + * 在城市之间铺设光缆 +* 如果图的每一条边的权值**都互不相同**,那么最小生成树将只有一个,否则可能会**有多个最小生成树** + +* 求最小生成树的2个经典算法 + * **Prim**(普里姆算法) + * **Kruskal**(克鲁斯克尔算法) + +#### 切分定理 + +* 切分(Cut):把图中的节点分为两部分,称为一个切分 +* 下图有个切分C= (S, T),S = {A,B,D},T= {C,E} + +
+ + +
+**横切边(Crossing Edge)**:如果一个边的两个顶点,分别属于切分的两部分,这个边称为**横切边**,例如:BC、BE、DE + +**切分定理**:给定任意切分,横切边中权值最小的边必然属于最小生成树 + +#### Prim 算法 + +假设G = (V, E) 是有权的连通图,A 是 G 中最小生成树的边集 + +算法从 S = { u0 }(u0 ∈ V),A = { } 开始,重复执行下述操作,直到 S = V 为止 + +1、找到切分 C = (S,V – S) 的最小横切边 (u0,v0) 并入集合 A,同时将 v0 并入集合 S + + + +#### Kruskal 算法 - 执行过程 + +* 按照边的权重顺序(从小到大)将边加入到生成树中,直到生成树中含有V - 1条边为止(v 是顶点数量) +* 若加入该边UI与生成树形成环,则不加入该边 +* 从第三条边开始,可能会与生成树形成环 + diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/18-\346\234\200\347\237\255\350\267\257\345\276\204.md" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/18-\346\234\200\347\237\255\350\267\257\345\276\204.md" new file mode 100644 index 0000000..9ffa34d --- /dev/null +++ "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/18-\346\234\200\347\237\255\350\267\257\345\276\204.md" @@ -0,0 +1,65 @@ +## 最短路径(Shortest Path) + +* 最短路径是指两顶点之间权值之和最小的路径(有向图、无向图均适用,不能有负权环) +#### 最短路径 - 无权图 +* 无权图相当于是全部权值为1的有权图 + +#### 最短路径 - 负权边 + +* 有负权边,但没有负权环时,存在最短路径 + +#### 最短路径 - 负权环 + +* 有负权环时,**不存在**最短路径 + +#### 典型应用 + +* 路径规划问题 + +#### 求解最短路径的3个经典算法 + +##### 单源最短路径算法 + +* Dijkstra (迪杰斯特拉算法) +* Bellman-Ford (贝尔曼-福特算法) + +##### 多源最短路径算法 + +* Floyd(弗洛伊德算法) + +#### Dijkstra + +* 属于单源最短路径算法,用于计算一个顶点到其他所有顶点的最短路径 +* 使用前提:不能有**负权边** +* 时间复杂度:可优化至O(ElogV),E 是边数量,V是顶点数量 + +* **松弛操作**(Relaxation):更新两个顶点之间的最短路径,这里一般是指:更新源点到另一个点的最短路径,松弛操作的意义是尝试找出更短的最短路径 + + + +#### Bellman-ford + +* 也属于单源最短路径算法,支持负权边,还能检测出是否有负权环 +* 算法原理:对所有的边进行 V - 1次松弛操作(V 是节点数量),得到所有可能的最短路径 + +#### Floyd + +* 属于多源最短路径算法,能够求出任意两个顶点之间的最短路径,支持负权边 + +* 时间复杂度:O(V^3),效率比执行V次Dijkstra 算法要好(V 是顶点数量) + +* 算法原理 + + 从任意顶点 i 到任意顶点j的最短路径不外乎两种可能, + + 1种是:直接从i到j + + 2种是:从i经过若千个顶点到j + + * 假设dist(i, j) 为顶点i到顶点j的最短路径的距离 + + * 对于每一个顶点k,检查 dist(i, k) + dist(k, j) 0, b > 0, d>= 0 + +* d > $\log_ba$,T(n) = O($n^d$) +* d = $\log_ba$,T(n) = O($n^dlogn$​) +* d < $\log_ba$,T(n) = O($n^{log_ba}$) + + + +比如归并排序的运行时间是:T(n) = 2T($\frac n2$) + O(n),a = 2, b = 2, d = 1,所以T(n) = O(n$logn$) + diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/23-\345\212\250\346\200\201\350\247\204\345\210\222.md" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/23-\345\212\250\346\200\201\350\247\204\345\210\222.md" new file mode 100644 index 0000000..cb68366 --- /dev/null +++ "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/23-\345\212\250\346\200\201\350\247\204\345\210\222.md" @@ -0,0 +1,91 @@ +## 动态规划(Dynamic Progamming) + +#### 动态规划,简称DP + +* 是求解最优化问题的一种常见策略 + +#### 通常的使用套路 + +1、暴力递归(自顶向下,出现了重叠子问题) + +2、记忆力搜索(自顶向下) + +3、递推(自底向上) + +#### 常规步骤 + +* 定义状态(状态是原问题、子问题的解) + * 比如定义dp(i) 的含义 +* 设置初始状态 + * 比如设置dp(0)的值 +* 确定状态转移方程 + * 比如确定dp(i) 和 dp(i - 1)的关系 + +#### 概念 + +* 将复杂的原问题拆解成若干个简单的子问题 +* 每个子问题仅仅解决1次,并保存它们的解 +* 最后推倒出原问题的解 + +#### 可以用动态规划解决的问题 + +* 最优子结构(最优化原理):通过求解子问题的最优解,可以获得原问题的最优解 +* 无后效性 + * 在阶段的状态一旦确定,则此后过程的演变不再受此各状态及决策的影响(未来与过去无关) + * 在推倒后面阶段的状态时,只关心前面阶段的具体状态值,不关心这个状态是怎么一步步推导出来的 + +#### 第3题-最长上升子序列(LIS) + +* 最长上升子序列 + + + +#### 第5题-最长公共子串(Longest Common Substring) + +* 子串是连续的子序列 +* 解题思路 + +```java +// 假设2个字符串分别是 str1, str2 +i ∈ [1, str1.length] +j ∈ [1, str2.length] +假设dp[i, j]是以str1[i - 1]、str2[j - 1]结尾的最长公共子串长度 +dp(i, 0)、dp(0, j) 初始值为0 +如果str1[i -1] == str2[j - 1],那么 dp(i, j) = dp(i - 1, j - 1) + 1 +如果str1[i - 1] != str2[j - 1],那么dp(i, j) = 0 + +最长公共子串的长度是所有do(i, j) 中的最大值max {dp(i, j)} +``` + +#### 第6题-0-1背包 + +* 题目: + +有n件物品和一个最大承重为 W 的背包,每件物品的重量是 Wi、价值是Vi,在保证总重量不超过 W 的前提下,选择某些物品装入背包,背包的最大总价值是多少?,注意:每个物品只有 1件,也就是每个物品只能选择0 件或者 1件 + +* 解题思路 + +```java +假设 values 是价值数组,weights 是重量数组 +编号为k的物品,价值是 values[k],重量是 weights[k], k∈ [0, n) + +假设 dp(i, j) 是最大承重为 j、有前 i 件物品可选时的最大总价值,i ∈ [0,n), j ∈ [0, W] +dp(i, 0)、dp(0, j) 初始值均为 0 +如果 j < weights[i - 1],那么 dp(i, j) = dp(i- 1, j) +如果 j >= weights[i - 1], 那么dp(i, j) = max { dp(i - 1, j), dp(i - 1, j - weights[i - 1]) + values[i - 1]} +``` + +#### 第7题-0-1背包 + +* 题目: + +有n件物品和一个最大承重为 W 的背包,每件物品的重量是 Wi、价值是Vi,在保证总重量恰好等于 W 的前提下,选择某些物品装入背包,背包的最大总价值是多少?,注意:每个物品只有 1件,也就是每个物品只能选择0 件或者 1件 + +* 解题思路 + +```java +dp(i, j) 初始状态 +dp(i, 0) = 0, 总重量恰好为0,最大总价值必然也为0 +dp(0, j) = -∞(负无穷), j >= 1,负数在这里代表无法恰好装满 +``` + diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/24-\345\270\203\351\232\206\350\277\207\346\273\244\345\231\250.md" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/24-\345\270\203\351\232\206\350\277\207\346\273\244\345\231\250.md" new file mode 100644 index 0000000..03eb406 --- /dev/null +++ "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/24-\345\270\203\351\232\206\350\277\207\346\273\244\345\231\250.md" @@ -0,0 +1,26 @@ +# 布隆过滤器 (Bloom Filter) + +* 由布隆 1970年提出 +* 它是一个空间效率高的概率型数据结构,可以用来告诉你,一个元素一定不存在或者**可能**存在 +* 优点 + * 空间效率和查询时间都远远超过一般的算法 +* 缺点 + * 有一定的误判率,删除困难 + +* 本质 + * 是一个很长的二进制向量和一系列随机映射函数(Hash函数) + +* 常见应用 + * 网页黑名单系统、垃圾邮件过滤系统、爬虫的网址判重系统、解决缓存穿透问题 + +### 原理 + +* 添加元素:将每一个哈希函数生成的索引位置都设为1 +* 查询元素: + * 如果有一个哈希函数生成索引位置不为1,就代表不存在 + * 如果有一个哈希函数生成的索引位置都为1,就代表存在(存在一定的误判率) + +### 复杂度 + +* 添加、查询的时间复杂度是:O(k),k是哈希函数的个数 +* 添加、查询的空间复杂度是:O(m),m是二进制位的个数 diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/25-\350\267\263\350\241\250.md" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/25-\350\267\263\350\241\250.md" new file mode 100644 index 0000000..0efce03 --- /dev/null +++ "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/25-\350\267\263\350\241\250.md" @@ -0,0 +1,21 @@ +# 跳表(SkipList) + +## 概念 + +* 跳表,又叫跳跃表、跳跃列表,在**有序链表**的基础上增加了"跳跃"的功能 + +* 设计的初中是为了取代平衡树 + +## 对比平衡树 + +* 跳表的实现和维护更加简单 +* 跳表的搜索、删除、添加的平均时间复杂度是O(logn) + +## 跳表的搜索 + +1、从顶层链表的首元素开始,从做往右搜索,直到好到一个大于或等于目标的元素,或者到达当前层链表的尾部 + +2、如果该元素等于目标元素,则表明该元素已被找到 + + + diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/26-B+\346\240\221.md" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/26-B+\346\240\221.md" new file mode 100644 index 0000000..ea3c2d3 --- /dev/null +++ "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/26-B+\346\240\221.md" @@ -0,0 +1,15 @@ +## B+树 + +#### 概念 + +* B+树是B树的变体,常用于数据库和操作系统的文件系统中 +* MySQL数据库的索引就是基于B+树实现的 + +#### 特点 + +* 分为内部节点(叶子节点),叶子节点2种节点 + * 内部节点只存储key,不存储具体数据 + * 叶子节点存储key和具体数据 + * 所有的叶子节点形成一条有序链表 + * m 阶B+树非根节点的元素数量x,⌜m/2⌝ <= x <= m + diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/27-\344\270\262.md" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/27-\344\270\262.md" new file mode 100644 index 0000000..0425f34 --- /dev/null +++ "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/27-\344\270\262.md" @@ -0,0 +1,21 @@ +# 串(Sequence) + +概念:是由若干个字符组成的有限序列 + +前缀(prefix)、真前缀(proper prefix)、后缀(suffix)、真后缀(proper suffix) + +区别:真后缀|真前缀不能包含字符串自己 + +### 串匹配算法 + +经典的算法 + +1、蛮力(Brute Force) + +2、KMP + +3、Boyer-Moore + +4、Rabin-Karp + +5、Sunday diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/Trie\346\240\221.md" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/Trie\346\240\221.md" new file mode 100644 index 0000000..fa29f9b --- /dev/null +++ "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/Trie\346\240\221.md" @@ -0,0 +1,11 @@ +# Trie + +也叫字典树,前缀树(Prefix Tree)、单词查找树 + +搜搜字符串的效率主要跟字符串的长度有关 + +### 总结 + +优点:搜索前缀的效率主要跟前缀的长度有关 + +缺点:需要耗费大量的内存,有待改进 diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/02-\345\212\250\346\200\201\346\225\260\347\273\204-\346\216\245\345\217\243\350\256\276\350\256\241.png" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\345\212\250\346\200\201\346\225\260\347\273\204/02-\345\212\250\346\200\201\346\225\260\347\273\204-\346\216\245\345\217\243\350\256\276\350\256\241.png" similarity index 100% rename from "\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/02-\345\212\250\346\200\201\346\225\260\347\273\204-\346\216\245\345\217\243\350\256\276\350\256\241.png" rename to "\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\345\212\250\346\200\201\346\225\260\347\273\204/02-\345\212\250\346\200\201\346\225\260\347\273\204-\346\216\245\345\217\243\350\256\276\350\256\241.png" diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\345\233\276/\345\210\207\345\210\206\345\256\232\347\220\206_1.png" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\345\233\276/\345\210\207\345\210\206\345\256\232\347\220\206_1.png" new file mode 100644 index 0000000..92680ee Binary files /dev/null and "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\345\233\276/\345\210\207\345\210\206\345\256\232\347\220\206_1.png" differ diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\345\233\276/\345\210\207\345\210\206\345\256\232\347\220\206_2.png" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\345\233\276/\345\210\207\345\210\206\345\256\232\347\220\206_2.png" new file mode 100644 index 0000000..e68993a Binary files /dev/null and "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\345\233\276/\345\210\207\345\210\206\345\256\232\347\220\206_2.png" differ diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\345\233\276/\346\234\211\345\220\221\346\227\240\347\216\257\345\233\276.png" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\345\233\276/\346\234\211\345\220\221\346\227\240\347\216\257\345\233\276.png" new file mode 100644 index 0000000..c986ffb Binary files /dev/null and "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\345\233\276/\346\234\211\345\220\221\346\227\240\347\216\257\345\233\276.png" differ diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\345\233\276/\346\234\211\345\220\221\346\234\211\347\216\257\345\233\276.png" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\345\233\276/\346\234\211\345\220\221\346\234\211\347\216\257\345\233\276.png" new file mode 100644 index 0000000..61f824c Binary files /dev/null and "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\345\233\276/\346\234\211\345\220\221\346\234\211\347\216\257\345\233\276.png" differ diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\346\216\222\345\272\217/\345\237\272\346\225\260\346\216\222\345\272\217\350\277\207\347\250\213.png" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\346\216\222\345\272\217/\345\237\272\346\225\260\346\216\222\345\272\217\350\277\207\347\250\213.png" new file mode 100644 index 0000000..2423b18 Binary files /dev/null and "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\346\216\222\345\272\217/\345\237\272\346\225\260\346\216\222\345\272\217\350\277\207\347\250\213.png" differ diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\346\216\222\345\272\217/\345\277\253\351\200\237\346\216\222\345\272\21701.png" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\346\216\222\345\272\217/\345\277\253\351\200\237\346\216\222\345\272\21701.png" new file mode 100644 index 0000000..e3d5d5f Binary files /dev/null and "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\346\216\222\345\272\217/\345\277\253\351\200\237\346\216\222\345\272\21701.png" differ diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\346\216\222\345\272\217/\350\256\241\346\225\260\346\216\222\345\272\217_\345\210\235\345\247\213\347\211\210.png" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\346\216\222\345\272\217/\350\256\241\346\225\260\346\216\222\345\272\217_\345\210\235\345\247\213\347\211\210.png" new file mode 100644 index 0000000..8f55b7f Binary files /dev/null and "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\346\216\222\345\272\217/\350\256\241\346\225\260\346\216\222\345\272\217_\345\210\235\345\247\213\347\211\210.png" differ diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\346\216\222\345\272\217/\350\256\241\346\225\260\346\216\222\345\272\217_\346\224\271\350\277\233.png" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\346\216\222\345\272\217/\350\256\241\346\225\260\346\216\222\345\272\217_\346\224\271\350\277\233.png" new file mode 100644 index 0000000..666b648 Binary files /dev/null and "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\346\216\222\345\272\217/\350\256\241\346\225\260\346\216\222\345\272\217_\346\224\271\350\277\233.png" differ diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\346\216\222\345\272\217/\350\256\241\346\225\260\346\216\222\345\272\217_\346\224\271\350\277\233\344\273\243\347\240\201.png" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\346\216\222\345\272\217/\350\256\241\346\225\260\346\216\222\345\272\217_\346\224\271\350\277\233\344\273\243\347\240\201.png" new file mode 100644 index 0000000..b12fca6 Binary files /dev/null and "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\346\216\222\345\272\217/\350\256\241\346\225\260\346\216\222\345\272\217_\346\224\271\350\277\233\344\273\243\347\240\201.png" differ diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/03-\351\223\276\350\241\250_\350\212\202\347\202\271.png" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\351\223\276\350\241\250/03-\351\223\276\350\241\250_\350\212\202\347\202\271.png" similarity index 100% rename from "\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/03-\351\223\276\350\241\250_\350\212\202\347\202\271.png" rename to "\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\351\223\276\350\241\250/03-\351\223\276\350\241\250_\350\212\202\347\202\271.png" diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\351\223\276\350\241\250/\345\215\225\351\241\271\345\276\252\347\216\257\351\223\276\350\241\250.png" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\351\223\276\350\241\250/\345\215\225\351\241\271\345\276\252\347\216\257\351\223\276\350\241\250.png" new file mode 100644 index 0000000..a7b4403 Binary files /dev/null and "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\351\223\276\350\241\250/\345\215\225\351\241\271\345\276\252\347\216\257\351\223\276\350\241\250.png" differ diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\351\223\276\350\241\250/\345\217\215\350\275\254\351\223\276\350\241\250-\351\235\236\351\200\222\345\275\222.png" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\351\223\276\350\241\250/\345\217\215\350\275\254\351\223\276\350\241\250-\351\235\236\351\200\222\345\275\222.png" new file mode 100644 index 0000000..a46db04 Binary files /dev/null and "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\351\223\276\350\241\250/\345\217\215\350\275\254\351\223\276\350\241\250-\351\235\236\351\200\222\345\275\222.png" differ diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\351\223\276\350\241\250/\346\270\205\347\251\272\345\205\203\347\264\240.png" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\351\223\276\350\241\250/\346\270\205\347\251\272\345\205\203\347\264\240.png" new file mode 100644 index 0000000..85c5587 Binary files /dev/null and "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\351\223\276\350\241\250/\346\270\205\347\251\272\345\205\203\347\264\240.png" differ diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\351\223\276\350\241\250/\347\216\257\345\275\242\351\223\276\350\241\250.png" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\351\223\276\350\241\250/\347\216\257\345\275\242\351\223\276\350\241\250.png" new file mode 100644 index 0000000..008b54c Binary files /dev/null and "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\351\223\276\350\241\250/\347\216\257\345\275\242\351\223\276\350\241\250.png" differ diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\351\223\276\350\241\250/\350\231\232\346\213\237\345\244\264\350\212\202\347\202\271.png" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\351\223\276\350\241\250/\350\231\232\346\213\237\345\244\264\350\212\202\347\202\271.png" new file mode 100644 index 0000000..67c3f1a Binary files /dev/null and "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/images/\351\223\276\350\241\250/\350\231\232\346\213\237\345\244\264\350\212\202\347\202\271.png" differ diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/\345\223\210\345\244\253\346\233\274\346\240\221.md" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/\345\223\210\345\244\253\346\233\274\346\240\221.md" new file mode 100644 index 0000000..b79fde4 --- /dev/null +++ "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/\345\223\210\345\244\253\346\233\274\346\240\221.md" @@ -0,0 +1,24 @@ +## 哈夫曼树 + +#### 哈夫曼编码 (Huffman Coding) + +* 哈夫曼编码,又称为霍夫曼编码,它是现代压缩算法的基础 + + + +计算哈夫曼编码 + +一、先根据频率得到哈夫曼树 + +步骤 +1、按频率从低到高排列 + +2、合并,从左到右合并,构建二叉树 + +二、在计算得到编码 + +1、如果是左子节点,标记为0 + +2、如果是右子节点,标记为1 + +[参考资料](https://blog.csdn.net/FX677588/article/details/70767446) \ No newline at end of file diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/\345\240\206.md" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/\345\240\206.md" index 8dcb761..dfa0701 100644 --- "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/\345\240\206.md" +++ "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/\345\240\206.md" @@ -12,9 +12,158 @@ #### 性质 -* 任意节点的值总是>=(<=)子节点的值 +* 任意**节点**的值总是**>=(<=)子节点**的值 * 如果任意节点的值总是>=子节点的值,称为:最大堆、大根堆、大顶堆 * 如果任意节点的值总是<=子节点的值,称为:最小堆、小根堆、小顶堆 +* 堆中的元素必须具备可比较性 +* 二叉堆的逻辑结构就是一颗完成二叉树,所以也叫完全二叉堆 +#### 索引i规律 +* 如果 i= 0, 它是根节点 +* 如果i > 0, 它的父节点编号为**floor((i - 1) /2)** + +* 如果2i + 1 <= n - 1, 它的左子节点编号为2i + 1 +* 如果2i + 1 < n - 1, 它无左子节点 +* 如果2i + 2 <= n - 1, 它的右子节点编号为2i + 2 +* 如果2i + 2 > n - 1, 它无右子节点 +* **第一个叶子节点的索引就是非叶子节点的数量** + +#### 接口设计 + +```java +int size(); // 元素的数量 +boolean isEmpty(); // 是否为空 +void clear(); // 清空 +void add(E element); // 添加元素 +E get(); // 获得堆顶元素 +E remove(); //删除堆顶元素 +E replace(E element); // 删除堆顶元素的同时插入一个新元素 +``` + +### 实现 + +鉴于完全二叉树的一些特性,二叉堆的底层一般用**数组**实现即可 + +#### 添加操作 + +这里以最大堆举例 + +[补充图] + +**添加步骤** + +循环执行以下代码,node为新添加节点 + +```java +如果 node > 父节点,那么与父节点交换位置 + +如果 node <= 父节点,或者 node 没有父节点,那么退出循环 +``` + +这个过程叫做:**上滤(Sift Up)** + +时间复杂度:O(logn) + +```java +private void siftUp(int index) { + E e = elements[index]; + while (index > 0) { + int pIndex = (index - 1) >> 1; + E p = elements[pIndex]; + if (compare(e, p) <= 0) { + break; + } + // 交换E、P + elements[index] = p; + index = pIndex; + } + elements[index] = e; +} +``` + +#### 删除操作 + +这里以最大堆举例 + +[补充图] + +**删除步骤** + +1、用最后一个节点覆盖根节点 + +2、删除最后一个节点 + +3、循环执行以下操作,node为待删除节点 + +```java +如果 node < 子节点,与最大的子节点交换位置 +如果 node >= 子节点,或者 node 没有子节点,退出循环 +``` + +这个过程叫做:**下滤(Sift Down)** + +时间复杂度:O(logn) + +```java +private void siftDown(int index) { + int half = size >> 1; + E element = elements[index]; + // 第一个叶子节点的索引 == 非叶子节点的数量 + // index < 第一个叶子节点的索引 + while (index < half) { + // index的节点有2种情况 + // 1、只有左子节点 + // 2、同时有左右子节点 + + // 默认为左子节点跟它进行比较 + int childIndex = (index << 1) + 1; + E child = elements[childIndex]; + // 右子节点 + int rightIndex = childIndex + 1; + // 选出左右子节点最大的那个 + if (rightIndex < size && compare(elements[rightIndex], child) > 0) { + child = elements[childIndex = rightIndex]; + } + if (compare(element, child) >= 0) { + break; + } + // 将子节点存放在index位置 + elements[index] = child; + // 重新设置index + index = childIndex; + } + elements[index] = element; +} +``` + +#### 批量建堆heapify + +有两种实现逻辑, + +1、自下而上的下滤 + +```java +for (int i = (size >> 1) - 1; i >= 0; i--) { + siftDown(i); +} +``` + +时间复杂度:O(n) + +2、自上而下的上滤 + +```java +for (int i = 1; i < size; i++) { + siftUp(i); +} +``` + +时间复杂度:O(nlogn) + +#### Top K问题 + +* 从n个整数中,找出最大的前k个数(k远远小于n) +* 如果使用排序算法进行全排序,需要O(nlogn)的时间复杂度 +* 如果使用二叉堆来解决,可以使用O(nlongk)的时间复杂度 diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/\346\216\222\345\272\217\347\256\227\346\263\225.md" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/\346\216\222\345\272\217\347\256\227\346\263\225.md" index ef385c8..b24b37f 100644 --- "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/\346\216\222\345\272\217\347\256\227\346\263\225.md" +++ "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/\346\216\222\345\272\217\347\256\227\346\263\225.md" @@ -1,46 +1,538 @@ -### 排序算法 +# 排序 -#### 冒泡排序 +## 冒泡排序(Bubble Sort) > 时间复杂度:O(n^2) -* 执行流程 - * 1、从头开始比较每一对相邻元素,如果第1个比第2个大,就交换它们的位置 +### 执行流程(以升序为例) + +1、从头开始比较每一对相邻元素,如果第1个比第2个大,就交换它们的位置 + +* 执行完一轮后,最末尾那个元素就是最大的元素 + +2、忽略1中曾经找到的最大元素,重复执行步骤1,直到所有元素有序 + +```java +for (int end = array.length - 1; end > 0; end--) { + for (int begin = 1; begin <= end; begin++) { + if (array[begin - 1] > array[begin]) { + // 交换 + int temp = array[begin - 1]; + array[begin - 1] = array[begin]; + array[begin] = temp; + } + } +} +``` 冒泡排序优化1 -* 如果序列已经完全有序,可以提前终止冒泡排序 +* 如果序列已经完全有序,可以提前终止冒泡排序,添加标志位**sorted** + +```java +for (int end = array.length - 1; end > 0; end--) { + Boolean sorted = true; + for (int begin = 1; begin <= end; begin++) { + if (array[begin - 1] > array[begin]) { + // 交换 + int temp = array[begin - 1]; + array[begin - 1] = array[begin]; + array[begin] = temp; + sorted = false; + } + } + if (sorted) break; +} +``` 冒泡排序优化2 * 如果序列尾部已经局部排序,可以记录最后一次交换的位置,减少比较次数 +```java +for (int end = array.length - 1; end > 0; end--) { + // sortedIndex的初始值在数组完全有序时使用 + int sortedIndex = 1; + for (int begin = 1; begin <= end; begin++) { + if (array[begin - 1] > array[begin]) { + // 交换 + int temp = array[begin - 1]; + array[begin - 1] = array[begin]; + array[begin] = temp; + sortedIndex = begin; + } + } + end = sortedIndex; + } + } +``` + #### 排序算法的稳定性(Stability) * 如果相等的2个元素,在排序前后的相对位置保持不变,那么这是稳定的排序算法 -* 冒泡排序属于稳定的排序算法 +* 冒泡排序属于**稳定的排序算法** -### 选择排序 +## 选择排序 > 选择排序的交换次数要远远小于冒泡排序,平均性能优于冒泡排序 > -> 最好、最坏、平均时间复杂度:O(n^2),空间复杂度:O(1),属于不稳定排序 -* 1、从序列中找出最大的那个元素,然后与最末尾的元素交换位置 -* 2、执行完一轮后,最末尾的那个元素就是最大的元素 -* 3、忽略1中曾经找到的最大元素,重复执行步骤1 +执行流程 -### 堆排序(Heap Sort) +1、从序列中找出最大的那个元素,然后与最末尾的元素交换位置 + +* 执行完一轮后,最末尾的那个元素就是最大的元素 + +2、忽略1中曾经找到的最大元素,重复执行步骤1 + +```java +for (int end = array.length - 1; end > 0; end--) { + int maxIndex = 0; + for (int begin = 1; begin <= end; begin++) { + // 为了稳定性,需要添加上=的情况 + if (array[begin] >= array[maxIndex]) { + maxIndex = begin; + } + } + int temp = array[end]; + array[end] = array[maxIndex]; + array[maxIndex] = temp; + } +``` + +最好、最坏、平均时间复杂度:**O(n^2)**,空间复杂度:O(1),属于**不稳定**排序 + +## 堆排序(Heap Sort) -> 可以认为是对选择排序的一种优化, -> > 时间复杂度:nlogn + n 简化为:nlogn -* 1、对序列进行原地建堆(heapify) -* 2、重复执行以下流程,直到堆的元素数量为1 - * A、交换堆顶元素与尾元素 - * B、堆的元素数量减1 - * C、对0位置进行1次siftDown操作 +可以认为是对选择排序的一种优化 + +执行流程 + +1、对序列进行原地建堆(**heapify**) + +2、重复执行以下流程,直到堆的元素数量为1 + +* 交换堆顶元素与尾元素 +* 堆的元素数量减1 +* 对0位置进行1次siftDown操作 + +```java +public class HeapSort> extends Sort { + private int heapSize; + @Override + protected void sort() { + heapSize = array.length; + // 原地建堆 + for (int i = (heapSize >> 1) - 1; i >= 0; i--) { + siftDown(i); + } + + while (heapSize > 1) { + // 交换堆顶元素与尾元素 + // 堆的元素数量减1 + swap(0, --heapSize); + // 对0位置做siftDown + siftDown(0); + } + } + + private void siftDown(int index) { + int half = heapSize >> 1; + E element = array[index]; + // 第一个叶子节点的索引 == 非叶子节点的数量 + // index < 第一个叶子节点的索引 + while (index < half) { + // index的节点有2种情况 + // 1、只有左子节点 + // 2、同时有左右子节点 + + // 默认为左子节点跟它进行比较 + int childIndex = (index << 1) + 1; + E child = array[childIndex]; + // 右子节点 + int rightIndex = childIndex + 1; + // 选出左右子节点最大的那个 + if (rightIndex < heapSize && cmp(array[rightIndex], child) > 0) { + child = array[childIndex = rightIndex]; + } + if (cmp(element, child) >= 0) { + break; + } + // 将子节点存放在index位置 + array[index] = child; + // 重新设置index + index = childIndex; + } + array[index] = element; + } +} +``` + +**时间复杂度** + +O(nlogn) + +**空间复杂度** + +O(1) + +属于**不稳定**排序 + +## 插入排序(Insertion Sort) + +> 非常类似于扑克牌的排序 + +##### 执行流程 + +1、在执行的过程中,插入排序会将排序分为2部分 + +* 头部是已经**排好序**的,尾部是**待排序**的 + +2、从头部开始扫描每一个元素 + +* 每当扫描到一个元素,就将它插入到头部合适的位置,使得头部数据依然保持有序 + +```java +for (int begin = 1; begin < array.length; begin++) { + int cur = begin; + while (cur > 0 && cmp(array[cur], array[cur - 1]) < 0) { + swap(cur, cur - 1); + cur--; + } +} +``` + +逆序对 + +插入排序的时间复杂度与逆序对的数量成正比关系 + +逆序对的数量越多,插入排序的时间复杂度越高 + +逆序对的数量极少时,插入排序的效率特别高 + +时间复杂度 + +* 最坏、平均时间复杂度:O(n^2) +* 最好时间复杂度:O(n) +* 空间复杂度:O(1) +* 属于**稳定**排序 + +#### 优化 + +思路:将【交换】转为【挪动】 + +1、先将待插入的元素备份 + +2、头部有序数据中比待插入元素大的,都朝尾部方向挪动1个位置 + +3、将待插入元素放到最终的合适位置 + +```java +for (int begin = 1; begin < array.length; begin++) { + int cur = begin; + E v = array[cur]; + while (cur > 0 && cmp(v, array[cur - 1]) < 0) { + array[cur] = array[cur - 1]; + cur--; + } + array[cur] = v; +} +``` + +#### 二分搜索(Binary Search) + +如果是无序数组,从第0个位置开始遍历搜索,平均时间复杂度:O(n) + +如果是**有序数组**,可以使用二分搜索,最坏时间复杂度:O(logn) + +**思路** + +假设在[begin,end)范围内搜索某个元素v,mid = (begin + end) / 2 + +如果 v < m,去 [begin,mid) 范围内二分搜索 + +如果 v > m,去 [mid+1,,end) 范围内二分搜索 + +如果 v == m,直接返回 mid + +#### 插入排序-二分搜索优化 + +**思路** + +假设在[begin, end) 范围内搜索某个元素v,mid ==(begin + end) / 2 + +如果 v< m,去[begin, mid) 范围内二分搜索 + +如果 v>= m,去 [mid +1 , end)范围内二分搜索 + +#### 注意 + +使用二分搜索后,只是减少了比较次数,但是插入排序的平均时间复杂度依然是**O(n^2)** + +## 归并排序(Merge Sort) + +执行流程 + +1、不断地将当前序列平均分隔成2个子序列 + +直到不能再分隔(序列中只剩下1个元素) + +2、不断地将2个子序列合并成一个有序序列 + +直到最终只剩下1个有序序列 + +**divide 实现** + +```java +leftArray = (E[]) new Comparable[array.length >> 1]; +sort(0, array.length); + +private void sort(int begin, int end) { + if (end - begin < 2) return; + int mid = (begin + end) >> 1; + sort(begin, mid); + sort(mid, end); + merge(begin, mid, end); +} +``` + +**merge 实现** + +设置li、le、ri、re、ai标记 + +li:复制出来的数组的起始位置,li = 0 + +le:复制出来的数组的结束位置下一个位置,le = mid - begin + +ri:待排序数组中从mid开始的起始位置,ri = mid + +re:待排序数组中结束位置下一个位置,re = end + +ai:待排序数组中要放置的位置 + +```java +private void merge(int begin, int mid, int end) { + int li = 0, le = mid - begin; + int ri = mid, re = end; + int ai = begin; + + // 备份左边数组 + for (int i = li; i < le; i++) { + leftArray[i] = array[begin + i]; + } + + // 如果左边还没有结束 + while(li < le) { + if (ri < re && cmp(array[ri], leftArray[li]) < 0) { + array[ai++] = array[ri++]; + } else { + array[ai++] = leftArray[li++]; + } + } + } +``` + +**时间复杂度** + +由于归并排序总是平均分隔子序列,所以最好、最坏、平均时间复杂度都是O(nlogn),属于**稳定**排序 + +**空间复杂度** + +O(n/2 + logn) + +## 快速排序(Quick Sort) + +执行流程 + +1、从序列中选择一个轴点元素(**pivot**) + +假设每次选择0位置的元素为轴点元素 + +2、利用**pivot**将序列分割成2个子序列 + +将小于**pivot**的元素放在pivot的左侧 + +将大于pivot的元素放在pivot的右侧 + +等于pivot的元素放在左右侧都可以 + +3、对子序列进行1、2操作,直到**不能**再分隔(子序列中只剩下1个元素) + +![image-20240616183830123](/Users/guojie/Notes/学习算法与数据结构笔记/images/排序/快速排序01.png) + +#### 本质 + +逐渐将每一个元素都转换成轴点元素 + +### 希尔排序(Shell Sort) + +思路 + +将序列看做是一个**矩阵**,分成m列,逐列进行排序 + +* m 从某个整数逐渐减为1 +* 当m 是 1时,整个序列将完全有序 + +希尔排序也被称为递减增量排序(Diminishing Increment Sort) + +矩阵的列数取决于步长序列(step sequence) + +✓ 比如,如果步长序列为{1,5,19,41,109,...},就代表依次分成109列、41列、19列、5列、1列进行排序 + +✓ 不同的步长序列,执行效率也不同 + +希尔排序底层一般使用插入排序对每一列进行排序,很多资料认为希尔排序是插入排序的改版版 + +最好的情况是步长序列只有1,且序列几乎有序,时间复杂度为:O(n) + +空间复杂度:**O(1)**,属于**不稳定排序** + +希尔本人给出的步长序列计算方式,最坏时间复杂度是**O(n^2)** + +```java +List stepSequeue = new ArrayList<>(); +int step = array.length; +while ((step >>= 1) > 0) { + stepSequeue.add(step); +} +return stepSequeue; +``` + +目前已知的最好的步长序列计算方式,最坏时间复杂度是O(n^4/3) + +```java +List stepSequence = new LinkedList<>(); +int k = 0, step = 0; +while (true) { + if (k % 2 == 0) { + int pow = (int)Math.pow(2, k >> 1); + step = 1 + 9 * (pow * pow - pow); + } else { + int pow1 = (int)Math.pow(2, (k - 1) >> 1); + int pow2 = (int)Math.pow(2, (k + 1) >> 1); + step = 1 + 8 * pow1 * pow2 - 6 * pow2; + } + if (step >= array.length) break; + stepSequence.add(0, step); + k++; +} +return stepSequence; +``` + +### 计数排序(Counting Sort) + +**不是基于比较的排序** + +属于用空间换时间,某些时间平均时间复杂度可以比O(nlogn)更新 + +使用范围:对**一定范围**内的**整数**进行排序 + +思想: + +统计每个整数在序列中出现的次数,进而推到出每个整数在有序序列中的索引 + +![image-20240622182753556](/Users/guojie/Notes/学习算法与数据结构笔记/images/排序/计数排序_初始版.png) + +**计数排序-改进思路** + +![image-20240622182643696](/Users/guojie/Notes/学习算法与数据结构笔记/images/排序/计数排序_改进.png) + +**改进版代码实现** + +![image-20240622182904969](/Users/guojie/Notes/学习算法与数据结构笔记/images/排序/计数排序_改进代码.png) + +如果自定义对象中可以提供**用以排序的整数类型**,依然可以使用计数排序 + + + +### 基数排序(Radix Sort) + +**不是基于比较的排序** + +属于用空间换时间,某些时间平均时间复杂度可以比O(nlogn)更新 + +非常适合用于整数排序(尤其是非负整数) + +执行流程: + +依次对个位数、十位数、百位数、千位数、万位数..进行排序(从低到高) + +![image-20240622205338298](/Users/guojie/Notes/学习算法与数据结构笔记/images/排序/基数排序过程.png) + + + +代码实现(基于计数排序) + +```java +protected void sort() { + // 找出最值 + int max = 0; + for (int i = 0; i < array.length; i++) { + if (array[i] > max) { + max = array[i]; + } + } + /* 个位数:594 / 1 % 10 + * 十位数:594 / 10 % 10 + * 百位数:594 / 100 % 10 + * 千位数: 594 / 1000 % 10 + */ + for (int divide = 1; divide <= max; divide *= 10) { + countingSort(divide); + } + } + + private void countingSort(int divide) { + // 开辟内存空间,存储次数 + int[] counts = new int[10]; + for (int i = 0; i < array.length; i++) { + counts[array[i] / divide % 10]++; + } + // 累加次数 + for (int i = 1; i < counts.length; i++) { + counts[i] += counts[i - 1]; + } + + // 从后往前遍历元素,将它放到有序数组中的合适位置 + int[] newArray = new int[array.length]; + + for (int i = array.length - 1; i >= 0; i--) { + newArray[--counts[array[i] / divide % 10]] = array[i]; + } + // 将有序数组赋值到array + for (int i = 0; i < newArray.length; i++) { + array[i] = newArray[i]; + } + } +``` + +最好最坏平均**时间复杂度**:O(d*(n + k)),d 是最大值的位数,k是进制,属于**稳定排序** + +**空间复杂度**:O(n + k),k是进制 + + + +### 桶排序(Bucket Sort) + +**不是基于比较的排序** + +属于用空间换时间,某些时间平均时间复杂度可以比O(nlogn)更新 + +执行流程: + +①创建一定数量的桶(比如用数组、链表作为桶) + +② 按照一定的规则(不同类型的数据,规则不同),将序列中的元素均匀分配到对应的桶 + +③ 分别对每个桶进行单独排序 + +④ 将所有非空桶的元素合并成有序序列 + +**空间复杂度**:O(n + m),m 是桶的数量 +**时间复杂度**:O(n + n ∗ logn − n ∗ logm),因此为 O n + k ,k 为 n ∗ logn − n ∗ logm +属于**稳定排序** diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/\346\230\240\345\260\204.md" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/\346\230\240\345\260\204.md" new file mode 100644 index 0000000..9385ee3 --- /dev/null +++ "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/\346\230\240\345\260\204.md" @@ -0,0 +1,2 @@ +# 映射(Map) + diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/\347\256\227\346\263\225\351\242\230/\351\223\276\350\241\250/\345\210\206\345\211\262\351\223\276\350\241\250.md" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/\347\256\227\346\263\225\351\242\230/\351\223\276\350\241\250/\345\210\206\345\211\262\351\223\276\350\241\250.md" new file mode 100644 index 0000000..aa7ae46 --- /dev/null +++ "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/\347\256\227\346\263\225\351\242\230/\351\223\276\350\241\250/\345\210\206\345\211\262\351\223\276\350\241\250.md" @@ -0,0 +1,13 @@ +## 分割链表 + +[链接](https://leetcode.cn/problems/partition-list/) + +**题目** + +给你一个链表的头节点 `head` 和一个特定值 `x` ,请你对链表进行分隔,使得所有 **小于** `x` 的节点都出现在 **大于或等于** `x` 的节点之前。 + +你应当 **保留** 两个分区中每个节点的初始相对位置。 + +![图片](https://assets.leetcode.com/uploads/2021/01/04/partition.jpg) + +**解题** \ No newline at end of file diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/\347\256\227\346\263\225\351\242\230/\351\223\276\350\241\250/\345\233\236\346\226\207\351\223\276\350\241\250.md" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/\347\256\227\346\263\225\351\242\230/\351\223\276\350\241\250/\345\233\236\346\226\207\351\223\276\350\241\250.md" new file mode 100644 index 0000000..f125c84 --- /dev/null +++ "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/\347\256\227\346\263\225\351\242\230/\351\223\276\350\241\250/\345\233\236\346\226\207\351\223\276\350\241\250.md" @@ -0,0 +1,30 @@ +## 回文链表 + +[链表](https://leetcode.cn/problems/palindrome-linked-list/) + +**题目** + +给你一个单链表的头节点 `head` ,请你判断该链表是否为回文链表。如果是,返回 `true` ;否则,返回 `false` + +**示例 1:** + +![图片](https://assets.leetcode.com/uploads/2021/03/03/pal1linked-list.jpg) + +``` +输入:head = [1,2,2,1] +输出:true +``` + +**示例 2:** + +![图片](https://assets.leetcode.com/uploads/2021/03/03/pal2linked-list.jpg) + +``` +输入:head = [1,2] +输出:false +``` + + + +**解题** + diff --git "a/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/\347\256\227\346\263\225\351\242\230/\351\223\276\350\241\250/\347\233\270\344\272\244\351\223\276\350\241\250.md" "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/\347\256\227\346\263\225\351\242\230/\351\223\276\350\241\250/\347\233\270\344\272\244\351\223\276\350\241\250.md" new file mode 100644 index 0000000..6920e33 --- /dev/null +++ "b/\345\255\246\344\271\240\347\256\227\346\263\225\344\270\216\346\225\260\346\215\256\347\273\223\346\236\204\347\254\224\350\256\260/\347\256\227\346\263\225\351\242\230/\351\223\276\350\241\250/\347\233\270\344\272\244\351\223\276\350\241\250.md" @@ -0,0 +1,13 @@ +## 相交链表 + +[链接](https://leetcode.cn/problems/intersection-of-two-linked-lists/) + +**题目** + +给你两个单链表的头节点 `headA` 和 `headB` ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 `null` 。 + +图示两个链表在节点 `c1` 开始相交**:** + +![图片](https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2018/12/14/160_statement.png) + +**解题** \ No newline at end of file diff --git "a/\346\223\215\344\275\234\347\263\273\347\273\237/\350\257\273\344\271\246\347\254\224\350\256\260/01-.md" "b/\346\223\215\344\275\234\347\263\273\347\273\237/\350\257\273\344\271\246\347\254\224\350\256\260/01-.md" new file mode 100644 index 0000000..d53c409 --- /dev/null +++ "b/\346\223\215\344\275\234\347\263\273\347\273\237/\350\257\273\344\271\246\347\254\224\350\256\260/01-.md" @@ -0,0 +1,63 @@ +## 操作系统-概念 + +#### 1、定义: + +操作系统是一组控制和管理计算机硬件和软件资源,合理地对各类作业进行调 度,以及方便用户使用的程序的集合 + +#### 2、操作系统的演进 + +人工操作 => 脱机输入输出方式 => 单道批处理系统 => 多道批处理系统 => 分时系统 => 实时系统 + +#### 3、微机操作系统的发展 + +##### 1、单用户单任务操作系统 + +CP/M => MS-DOS + +##### 2、单用户多任务操作系统 + +Windows1.0 => Windows2.0 => Windows3.0 => Windows3.1 => Windows95 => ...... + +##### 3、多用户多任务操作系统 + +最具代表性:Unix,是Bell实验室在1969~1970期间开发的 + +基于Unix 变型的是 Solaris 、Linux + +#### 4、进程 + +进程是指:在系统中能独立运行并作为资源分配的基本单位,它是由一组机器指令、数据和堆 栈等组成的,是一个能独立运行的活动实体 + +为使多个程序能并发执行,系统必须分别为每个**程序**建立**进程(Process)** + +#### 5、线程 + +为了解决进程有用自己的资源导致调度付出的开销较大问题,引入线程(Threads) + +一个进程可以包含若干个线程,线程可以利用进程所拥有的资源,线程作为独立运行和独立调度的基本单位 + +**临界资源|独占资源**:指在一段时间内只允许一个进程访问的资源 + +#### 虚拟技术 + +1、时分复用技术(分时使用方式) + +2、空分复用技术:用于提高存储空间的利用率 + +#### 操作系统的主要功能 + +##### 处理机管理功能 + +1、进程控制 + +2、进程同步 + +3、进程通信 + +##### 设备管理功能 + +1、缓冲管理:在 I/O 设备和CPU之间引入缓冲,有效缓和CPU和I/O设备速度不匹配的矛盾,提高CPU利用率,提高系统吞吐量 + +2、设备分配 + +3、设备处理 \ No newline at end of file diff --git "a/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/Vim.md" "b/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/Vim.md" new file mode 100644 index 0000000..be2992e --- /dev/null +++ "b/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/Vim.md" @@ -0,0 +1,49 @@ +## Vim + +支持三种模式 + +#### 命令模式 + +> 输入的内容当做命令看待 + +![image-20230409103154126](./image-20230409103154126-1007515.png) + +移动光标 + +![image-20230409103706065](./image-20230409103706065.png) + +![image-20230409104006763](./image-20230409104006763.png) + +文本操作 + +![image-20230409104646007](./image-20230409104646007-1008409.png) + +![image-20230409105446168](./image-20230409105446168.png) + +#### 输入模式 + +> 输入的内容当文本内容看待 + + + +#### 底线命令模式 + +> 输入的内容当命令看待,在底部显示 + +![image-20230409103117797](./image-20230409103117797-1007481.png) + +* :w 保存文件 +* :w! 强制保存 +* :q 退出文件 +* :q! 强制退出,不保存 +* :wq 保存退出文件 +* :w filename 另存为其他文件 +* :set nu 显示行号 +* :set nonu 取消显示行号 + +#### 参考资料 + +* [视频](https://space.bilibili.com/522319853/channel/seriesdetail?sid=666503&ctype=0) +* [命令网站](https://ss64.com/osx/setfile.html) +* [命令全称](https://cloud.tencent.com/developer/article/1608604?from=15425&areaSource=102001.2&traceId=2VaO9mk2Fwz4dW-lxXCCd) + diff --git "a/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/image-20230408232443975-0967488.png" "b/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/image-20230408232443975-0967488.png" new file mode 100644 index 0000000..8ca2266 Binary files /dev/null and "b/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/image-20230408232443975-0967488.png" differ diff --git "a/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/image-20230408232813978-0967697-0967700.png" "b/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/image-20230408232813978-0967697-0967700.png" new file mode 100644 index 0000000..2bcd802 Binary files /dev/null and "b/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/image-20230408232813978-0967697-0967700.png" differ diff --git "a/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/image-20230408234258057-0968579.png" "b/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/image-20230408234258057-0968579.png" new file mode 100644 index 0000000..ae01eed Binary files /dev/null and "b/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/image-20230408234258057-0968579.png" differ diff --git "a/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/image-20230409014825756-0976107.png" "b/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/image-20230409014825756-0976107.png" new file mode 100644 index 0000000..6ee9547 Binary files /dev/null and "b/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/image-20230409014825756-0976107.png" differ diff --git "a/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/image-20230409103117797-1007481.png" "b/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/image-20230409103117797-1007481.png" new file mode 100644 index 0000000..88f3d7a Binary files /dev/null and "b/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/image-20230409103117797-1007481.png" differ diff --git "a/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/image-20230409103154126-1007515.png" "b/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/image-20230409103154126-1007515.png" new file mode 100644 index 0000000..edaa4ba Binary files /dev/null and "b/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/image-20230409103154126-1007515.png" differ diff --git "a/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/image-20230409103706065.png" "b/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/image-20230409103706065.png" new file mode 100644 index 0000000..b32b00a Binary files /dev/null and "b/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/image-20230409103706065.png" differ diff --git "a/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/image-20230409104006763.png" "b/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/image-20230409104006763.png" new file mode 100644 index 0000000..ec06152 Binary files /dev/null and "b/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/image-20230409104006763.png" differ diff --git "a/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/image-20230409104646007-1008409.png" "b/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/image-20230409104646007-1008409.png" new file mode 100644 index 0000000..b3a8c03 Binary files /dev/null and "b/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/image-20230409104646007-1008409.png" differ diff --git "a/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/image-20230409105446168.png" "b/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/image-20230409105446168.png" new file mode 100644 index 0000000..7c5c21d Binary files /dev/null and "b/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/image-20230409105446168.png" differ diff --git "a/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/images/Xnip2023-04-08_18-46-35.jpg" "b/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/images/Xnip2023-04-08_18-46-35.jpg" new file mode 100644 index 0000000..bfd8ff3 Binary files /dev/null and "b/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/images/Xnip2023-04-08_18-46-35.jpg" differ diff --git "a/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/images/Xnip2023-04-08_18-53-43.jpg" "b/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/images/Xnip2023-04-08_18-53-43.jpg" new file mode 100644 index 0000000..fbbd547 Binary files /dev/null and "b/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/images/Xnip2023-04-08_18-53-43.jpg" differ diff --git "a/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/images/Xnip2023-04-08_18-58-44.jpg" "b/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/images/Xnip2023-04-08_18-58-44.jpg" new file mode 100644 index 0000000..3d04daf Binary files /dev/null and "b/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/images/Xnip2023-04-08_18-58-44.jpg" differ diff --git "a/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/images/icon_256x256.png" "b/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/images/icon_256x256.png" new file mode 100644 index 0000000..6d03cf6 Binary files /dev/null and "b/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/images/icon_256x256.png" differ diff --git "a/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/images/icon_512x512.png" "b/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/images/icon_512x512.png" new file mode 100644 index 0000000..dec6916 Binary files /dev/null and "b/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/images/icon_512x512.png" differ diff --git "a/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/images/ifconfig.png" "b/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/images/ifconfig.png" new file mode 100644 index 0000000..10869dc Binary files /dev/null and "b/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/images/ifconfig.png" differ diff --git "a/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/shell\350\204\232\346\234\254.md" "b/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/shell\350\204\232\346\234\254.md" new file mode 100644 index 0000000..68e6e71 --- /dev/null +++ "b/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/shell\350\204\232\346\234\254.md" @@ -0,0 +1,20 @@ +## Shell脚本 + +sh脚本可以通过sh、bash、source 命令名来执行sh脚本文件 + +```shell +# test.sh中 +cd ~/Desktop +ls -l +``` + +#### sh bash + +* 当前shell 环境会启动一个紫禁城来执行脚本文件,执行后返回到父进程的shell环境 +* 执行cd时,在子进程中会进入到cd的目录,但是在父进程中环境并没有改变,也就是书记目录没有改变 + +#### source + +* 在当前的shell环境喜爱执行脚本文件 +* 执行cd后会跳转到cd的目录 +* source可以用一个点"."来替代,比如:". test.sh",经过验证,在Mac中需要 ./test.sh 才可以 \ No newline at end of file diff --git "a/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/\347\254\224\350\256\260.md" "b/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/\347\254\224\350\256\260.md" new file mode 100644 index 0000000..e5ab572 --- /dev/null +++ "b/\346\227\245\345\270\270\345\221\275\344\273\244\351\233\206\345\220\210/\347\254\224\350\256\260.md" @@ -0,0 +1,278 @@ +## 命令集合 + +#### 网络部分 + +##### ping + +> 检查网络连通性 + +* ping 域名 或者 ping ip + +```shell +ping www.baidu.com +ping 192.168.0.1 +``` + +##### ifconfig + +> 查看|配置网络接口(网卡)信息 + +```shell +ifconfig +``` + +![img](https://cdn.jsdelivr.net/gh/GJBlog/Notes@feature/2023/日常命令集合/images/ifconfig.png) + +* 查看指定网卡信息 + +ifconfig interface-name + +```shell +ifconfig en0 +``` + +##### networksetup + +> 查看网络接口简写信息 + +```shell +networksetup -listallhardwareports +``` + +##### ipconfig + +> 查看|配置网络接口(网卡)信息 + +* 获取IP地址 + +ipconfig getifaddr interface-name + +```shell +ipconfig getifaddr en0 +``` + +* 获取网关地址 + +ipconfig getoption interface-name(option-name | option-code) + +```shell +ipconfig getoption en0 router +``` + +* 获取DNS + +ipconfig getoption interface-name(option-name | option-code) domain_name_server + +```shell +ipconfig getoption en0 domain_name_server +``` + +##### 基于ifconfig、ipconfig配置IP信息 + +ifconfig interface-name inet ip-addr netmask subnet-mask + +ipconfig set interface-name(MANUAL|INFORM)ip-address subnet-mask + +##### netstat + +> 查看网络连接、端口、协议等 + +![image-20230408232443975](./image-20230408232443975-0967488.png) + +![image-20230408232813978](./image-20230408232813978-0967697-0967700.png) + +查看pid 进程ID对应的程序名称 + +```shell +ps -p pid +``` + +-r 显示网络路由表信息 + +> 查看网络数据包是如何一步一步路由出去的 + +-L 显示出监听队列的信息 + +> 查看监听队列的大小信息,需要与-a 一起使用,-aL + +-I 显示出完整的IPv6的地址信息 + +> 注意该参数在windows 和 linux上的使用区别,Mac 下不建议使用 + +常用命令如下: + +```shell +netstat -a +netstat -an +netstat -anv +netstat -anvp tcp +netstat -anvp udp +netstat -r +netstat -aL +netstat -anL +netstat -al +netstat -anl +``` + +##### ISof + +> 查看系统打开文件信息,比 netstat 更加友好 + +![image-20230408234258057](./image-20230408234258057-0968579.png) + +常用命令如下: + +```shell +lsof -i +lsof -iTCP +lsof -iTCP:8080 +lsof -iTCP:8080 -nP + +lsof -iTCP -sTCP:LISTEN +lsof -iTCP -sTCP:LISTEN -nP +lsof -iTCP:3306 -sTCP:LISTEN -nP + +配合sudo使用可以查看所有用户打开的网络连接,比如:sudo lsof -i +不加sudo,默认只能查看当前用户打开的网络连接 +``` + +##### 查看监听状态的端口 + +方法一: + +```shell +netstat -an|grep LISTEN +netstat -anv|grep -i listen +``` + +方法二: + +```shell +lsof -iTCP -sTCP:LISTEN -nP +sudo lsof -iTCP -sTCP:LISTEN -nP +``` + +##### 查看指定端口占用情况 + +方法一: + +```shell +netstat -an|grep 3306 +netstat -anv|grep 3306 +``` + +方法二: + +```shell +lsof -i:3306 -nP 可以配合sudo查看所有用户打开的连接 +lsof -iTCP:3306 -sTCP:LISTEN -nP +``` + +##### traceroute + +> 查看路由追踪信息 + +traceroute 域名 或者 traceroute IP地址 + +例如: + +```shell +traceroute www.baidu.com +traceroute 192.168.0.1 +``` + +#### 进程相关 + +##### PS + +> 查看系统进程信息(瞬时状态) + +```shell +ps -A 显示所有进程信息 +ps -e | less 显示所有进程信息,并设置less:分屏显示 +ps -ef | less 显示所有进程信息,以及更多列信息,并设置less:分屏显示 +ps -a 显示在终端中正在运行的进程信息 +ps -ax 显示所有进程信息 +ps -p 进程ID 显示当前指定进程信息 +ps -u username 显示指定用户的进程信息(username = root...) +ps -U userID 显示指定用户的进程信息(userID = 0...) +``` + +```shell +ps -o keyword 指定输出列项 +ps -A -o user -o pid -o comm +ps -L 显示所有支持的keyword +``` + +##### id + +> 查看用户信息 + +id -nu userID +显示userID对应的用户昵称 + +```shell +id -nu 501 +``` + +##### kill + +> 结束掉一个进程 + +kill -9 pid + +结束指定的pid进程,如果杀掉的是其他用户的进程,需要添加sudo来提高权限 + +![image-20230409014825756](./image-20230409014825756-0976107.png) + +Killall name + +结束掉一个名称name的进程,支持批量操作 + +```shell +Killall -9 name +``` + +pkill -9 进程名(部分名称),支持批量操作 + +结束掉一个进程 + +##### top + +> 查看动态进程信息 + +##### powermetrics + +> 获取电脑运行温度、风扇转速、硬盘读写速度等各种传感器信息 + +sudo powermetrics + +```shell +sudo powermetrics -s 传感器(smc) +指定获取某个传感器的信息 +``` + +```shell +powermetrics -h +显示支持的所有传感器 +``` + +```shell +sudo powermetrics -n 1 +命令只执行一次,默认会不断采样输出显示 +``` + +#### shutdown + +shutdown [-h(halt)|-s(sleep)|-r(reboot)] time [提示信息] + +time 支持4种形式 + +* now +* 分钟数 +* hh:mm 今天的几时几分 +* yymmddhhmm 指定年份、月份、日期、小时、分钟 + +shutdown -r now 等价于 reboot + +shutdown -h now 等价于 halt diff --git "a/\346\235\202\346\226\207/C\350\257\255\350\250\200.md" "b/\346\235\202\346\226\207/C\350\257\255\350\250\200.md" new file mode 100644 index 0000000..3963976 --- /dev/null +++ "b/\346\235\202\346\226\207/C\350\257\255\350\250\200.md" @@ -0,0 +1,422 @@ +# C 语言 + +### 基础点 + +1、原码 + +* 最高位:作为符号位,用0表示"正",用1表示"负" +* 其余位:作为数值位,表示绝对值的大小(所以原码又称为带符号的绝对值) + +2、反码 + +* 正数的反码:和原码一样 +* 负数的反码:原码保持符号位不变,数值位按位取反(0变1,1变0),得到反码 + +3、补码 + +* 正数的补码:和原码一样 +* 负数的补码:反码的末位加1,得到补码 + +4、大小端模式 + +* 决定了**多字节数据的字节存储顺序** +* 大端模式(Big-endian):高低低高,**高字节**放在低地址,**低字节**放在高地址 +* 小端模式(little-endian):高高低低,低字节放在低地址,高字节放在高地址 +* X86架构是**小端**模式 + +### 语法注意点 + +```c +if (10 > 6) + int a = 5; +// 编译报错:因为作用域不明确 +``` + +```c +int a = 5; +switch (a) +{ + case 10: + printf("A\n"); + case 5: + printf("B\n"); + break; + default: + printf("B\n"); + break; +} +// 如果case后面没有break,就会执行后面所有case中的语句,直到遇到break为止 +``` + +```c +int a = 5; +int b = 10; +switch (a) +{ + case 10: + { + printf("A\n"); + int sum = a + b; + } + case 5: + printf("B\n"); + break; + default: + printf("B\n"); + break; +} +// 编译报错,sun定义的作用域不明确 +// 解决方案:如果要在case后面定义新的变量,必须用大括号{}包住 +``` +**关于return的注意点** + +```c +// 如果不明确声明返回值类型,默认就是int类型 +test2() +{ + return 0; +} +``` + +```c +// 就算明确声明了返回值类型,也可以不返回任何值 +int test() +{ + printf("XXXX"); +} +``` + +#### 函数 + +* 默认情况下,不允许有函数的名称一样 +* 函数不能嵌套定义 +* 函数不能重复定义,但是可以重复声明 + +#### include 作用 + +* 拷贝右边文件的所有内容到#include所在的位置(位置可以是相对路径或者绝对路径) +* 自定义的文件使用""引入,系统自带的文件使用<>引入 + +```c +#include +int main() +{ + printf("哈哈哈\n"); + #include "相对路径" + #include "绝对路径" + return 0; +} +``` + +long:扩充int类型的取值范围,属于类型说明符,用于修饰 int + +long long int 等价于 long long,8个字节 + +long int 等价于 long,8个字节 + +short int 等价于 short 2个字节 + +signed == signed int,最高位要当做符号位,取值范围:-2的31次方 ~ 2的31次方 - 1 + +unsigned == unsigned int,最高位不要当做符号位,取值范围:0 ~ 2的32次方 - 1 + +#### 按位异或 ^ + +1、相同数值进行异或,结果肯定是0,比如 9 ^ 9 + +2、可以交换 9 ^ 5 ^ 6 = 9 ^ 6 ^ 5 + +3、任何数值跟0进行异或,结果还是原来的数值 + +4、a ^ b ^ a = a ^ a ^ b = 0 ^ b = b + +5、应用 + +```c +a = 10, b = 11; +a = a ^ b; +b = a ^ b; +a = a ^ b; +a = 11, b = 10; +``` + +#### 左移 + +**a << n**:将a的**所有二进制位**向左移动1位,等价于 a * 2的n次方 + +#### 右移 + +a >> n:将a的所有二进制位向右移动1为,等价于a / 2 的n次方 + +最高位符号位不动,中间空缺的位置使用符号位的值来补齐 + + #### 数组 + +* 如果想在定义数组的同时进行初始化,数组元素个数必须是常量,或者不写 + +```c +int count = 5; +❌ +int ages[count] = {10, 11, 12}; +✅ +int ages[count]; +``` + +* 数组作为函数参数,可以省略元素个数 + +```c +void change(int args[]) +{ + ...... +} +``` + +* 数组作为函数参数,传递是整个数组的地址,修改函数形参数组元素的值,会影响到外面的实参数组 + +#### 字符串 + +初始化形式 + +```c +✅ +char name1[8] = "it"; +char name2[8] = {'i', 't', '\0'}; +char name3[8] = {'i', 't', 0}; +char name4[8] = {'i', 't'}; +// 不算是一个字符串(只能说是一个字符数组) +❌ +char name5[] = {'i', 't'}; +``` + +#### strlen 函数 + +* 计算字符串的长度 +* 计算的是字符数,并不是字数 +* 计算的字符不包括\0 +* 从某个地址开始数字符的个数,直到遇到\0为止 + +```c +#include +char name[] = "itcast"; +char name2[] = {'0', '6'}; +int size = strlen(name2); +printf("%d\n", size); +// 输出:8,因为一直输出到name最后的\0为止 +``` + +#### 指针 + +// 指向函数的指针 + +```c +void test() {} +// 左侧void:指针p指向的函数没有返回值 +// 右侧():指针p指向的函数没有形参 +// 定义指向函数的指针 +void (*p)() = test; +// 直接调用 +test(); +// 指针间接调用1 +p(); +// 指针间接调用2 +(*p)(); +``` + +#### 结构体 + +* 这种赋值操作只能在结构体初始化时进行 + +```c +// 定义结构体类型 +struct Person +{ // 3个变量称为结构体的成员或者属性 + int age; + double height; + char *name; +}; +// 定义Person结构体变量p,并赋值 +// ✅ +struct Person p = {20, 1.55, "rose"}; +struct Person p2 = {.height = 1.88, .name = "jim", .age = 30}; +struct Person p3; +// ❌ +p3 = {30, 1.55, "jake"}; +``` + +* 分配存储空间时,是按顺序一次分配内部的所有成员 +* 补齐算法(对齐算法) + +结构体所占用的存储空间必须是最大成员字节数的倍数 + +```c +Struct Student +{ + int age; // 4个字节 + char *names; // 8个字节 +}; +struct Student stu; +sizeof(stu); // 16个字节 +``` + +* 定义结构体变量的三种方式 + +1、先定义类型,再定义变量(分开定义) + +```c +struct Student +{ + int age; +}; +struct Studrnt stu; +``` + +2、定义类型的同时定义变量 + +```c +struct Studrnt +{ + int age; +} stu; +struct Studrnt stu2; +``` + +3、定义类型的同时定义变量(省略了类型名称) + +```c +struct +{ + int age +} stu; +``` + +* 指向结构体的指针 + +```c +struct Person +{ + int no; + int age; +}; +// 结构体变量 +struct Student stu = {1, 20}; +struct Student *p; +p = &Stu; + +// 访问结构体成员的三种方法 +// 第一种 +stu.age +// 第二种 +(*p).age +// 第三种 +p->age +``` + +#### 预处理指令 + +* 宏定义 + +```c +// 定义形式 +#define 宏名称 值 +#define COUNT 4 +// 中间部分是COUNT的有效作用域 +// 表示宏定义的作用域截止 +#undef COUNT +``` + +```c +#define COUNT 10 +int a = COUNT; +#undef COUNT +// 此时COUNT已经无法在访问,因为作用域已经截止 +int b = COUNT; +``` + +#### static和extern 区别 + +对函数的作用: + +extern:声明和定义一个外部函数,外部函数能被本文件和其他文件访问 + +1> 默认情况下所有的函数都是外部函数 + +2> 不允许有同名的外部函数 + +static:声明和定义一个内部函数,内部函数只能被本文件访问,其他文件不能访问 + +1> 允许不同文件中有同名的内部函数 + +```c +// 完整地声明一个外部函数 +extern void test(); +// 默认情况下,所有的函数都是外部函数,所以可以省略extern +void test(); +// 完整地定义一个外部函数 +// 默认情况下,所有的函数都是外部函数,所以可以省略extern +extern void test() +{ + ...code... +} +``` + +```c +// 声明一个内部函数 +static void test2(); +// 定义一个内部函数 +static void test2() +{ + ....code.... +} +``` + +对变量的作用 + +* static:定义一个内部变量 +* extern:声明一个外部变量 + +全局变量分为2种 + +* 外部变量:定义的变量能被本文件和其他文件访问 + +1> 默认情况下,所有的全局变量**都是**外部变量 + +2> 不同文件中的同名外部变量,都代表着同一个变量 + +* 内部变量:定义的变量**只能**被本文件访问,不能被其他文件访问 + +1> 不同文件中的同名内部变量,互不影响 + +```c +// 声明一个外部变量 +extern int a; +int main() +{ + // 声明一个外部变量 + extern int a; + a = 20; +} +// 定义一个外部变量 +int a; +``` + +**static** 对局部变量作用 + +1> 延长**局部变量**的生命周期:程序结束的时候,局部变量才会被销毁 + +2> 并没有改变**局部变量**的作用域 + +3> 所有的test函数都共享着一个变量b + +4> 使用场合:如果某个函数的调用频率特别高、这个函数内部的变量值是固定不变的 + +```c +void test() +{ + int a = 0; + a++; + + static int b = 0; + b++ +} +``` + diff --git "a/\346\235\202\346\226\207/PlistBuddy.md" "b/\346\235\202\346\226\207/PlistBuddy.md" new file mode 100644 index 0000000..567c13f --- /dev/null +++ "b/\346\235\202\346\226\207/PlistBuddy.md" @@ -0,0 +1,76 @@ +使用 + +1、打印某个plist文件的内容 + +```shell +# 打印所有 +/usr/libexec/PlistBuddy -c 'Print' Info.plist +# 打印某一个key:CFBundleIdentifier +/usr/libexec/PlistBuddy -c 'Print :CFBundleIdentifier' Info.plist +``` + +2、打印keychain中安装的所有证书 + +```shell +security find-identity -v -p codesigning +``` + + + +总结流程 + +1、获取新的BundleID对应的描述文件,修改文件名称为embedded.mobileprovision + +```shell +# mv 旧的描述文件 新的描述文件 +mv 127c5eed-5319-48af-8d21-0886a95d78d3.mobileprovision embedded.mobileprovision +``` + +2、从 mobileprovision 中提取出完整权限文件 + +```shell +security cms -D -i embedded.mobileprovision > entitlements_full.plist +``` + +3、从完整权限文件中提取签名需要的权限文件 + +```shell +/usr/libexec/PlistBuddy -x -c 'Print:Entitlements' entitlements_full.plist > entitlements.plist +``` + +4、修改App包中info.plist的BundleID值为描述文件对应的值 + +```shell +/usr/libexec/PlistBuddy -c 'set :CFBundleIdentifier 新的BundleID值' Payload/TestDemo1.app/Info.plist +``` + +5、替换embedded.mobileprovision 文件 + +```shell +cp -i embedded.mobileprovision Payload/TestDemo1.app/embedded.mobileprovision +``` + +6、针对App中的Framework、App的二进制文件重新签名(这里可能存在其他action要签名的情况) + +```shell +codesign --continue -f -s "Apple Development: 641102478@qq.com (R7A9V9A39N)" --entitlements entitlements.plist Payload/TestDemo1.app +``` + +7、验证签名是否正确 + +```shell +codesign --verify Payload/TestDemo1.app +``` + +8、打包ipa + +```shell +zip -ry newTest.ipa Payload/TestDemo1.app +``` + +9、安装ipa到当前连接的设备 + +```shell +ideviceinstaller -i newTest.ipa +``` + diff --git "a/\346\235\202\346\226\207/WebRTC.md" "b/\346\235\202\346\226\207/WebRTC.md" new file mode 100644 index 0000000..620b0c3 --- /dev/null +++ "b/\346\235\202\346\226\207/WebRTC.md" @@ -0,0 +1,26 @@ +## WebRTC + +全称:Web Real-Time Communication + +包含3个重要API + +#### Network Steam API + +- MediaStream:MediaStream用来表示一个媒体数据流。 +- MediaStreamTrack在浏览器中表示一个媒体源。 + +#### RTCPeerConnection + +- RTCPeerConnection:一个RTCPeerConnection对象允许用户在两个浏览器之间直接通讯。 +- RTCIceCandidate:表示一个ICE协议的候选者。 +- RTCIceServer:表示一个ICE Server。 + +#### Peer-to-Peer Data API + +- DataChannel:数据通道(DataChannel)接口表示一个在两个节点之间的双向的数据通道。 + + + +ICE 协议 + +**Interactive Connectivity Establishment** \ No newline at end of file diff --git "a/\346\235\202\346\226\207/\344\270\252\344\272\272GitHub.md" "b/\346\235\202\346\226\207/\344\270\252\344\272\272GitHub.md" new file mode 100644 index 0000000..293e1dc --- /dev/null +++ "b/\346\235\202\346\226\207/\344\270\252\344\272\272GitHub.md" @@ -0,0 +1,10 @@ +## GitHub相关信息 + +#### Token + +Personal access tokens (classic) + +```swift +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 +``` + diff --git "a/\346\235\202\346\226\207/\346\220\234\347\264\242\346\212\200\345\267\247\344\270\216\350\257\255\346\263\225.md" "b/\346\235\202\346\226\207/\346\220\234\347\264\242\346\212\200\345\267\247\344\270\216\350\257\255\346\263\225.md" new file mode 100644 index 0000000..80951f8 --- /dev/null +++ "b/\346\235\202\346\226\207/\346\220\234\347\264\242\346\212\200\345\267\247\344\270\216\350\257\255\346\263\225.md" @@ -0,0 +1,12 @@ +## 搜索技巧与语法 + +1、限定关键词,"XXX",搜索的结果页中必须包含XXX标题 +2、限定标题,intitle:XXX +3、1和2组合使用,intitle:"XXX" +4、限定标题多个关键字,allintitle:XXX XXX +5、限定内容关键词:intext:浙江大学 +6、限定网址关键字:inurl:CCTV +7、site:限定网址来源:site:zhihu.com +8、限定图片尺寸:imagesize:2560*1440 +9、限定文件格式:XXX filetype:ppt + diff --git "a/\346\235\202\346\226\207/\351\205\215\347\275\256\345\233\276\345\272\212.md" "b/\346\235\202\346\226\207/\351\205\215\347\275\256\345\233\276\345\272\212.md" new file mode 100644 index 0000000..8074270 --- /dev/null +++ "b/\346\235\202\346\226\207/\351\205\215\347\275\256\345\233\276\345\272\212.md" @@ -0,0 +1,22 @@ +## 配置图床 + +1、推荐使用GitHub的方式 + +* 使用CDN加速访问速度 +* 使用PicGo来上传图床 + +访问的图片路径: + +路径 = 前缀(https://cdn.jsdelivr.net/gh/) + 仓库名称 + file的文件夹路径 + fileName + +``` +https://cdn.jsdelivr.net/gh/GJBlog/Notes/科学方式/images/science_00.jpg +``` + +2、自己服务器自建图床 + + + +#### 参考资料 + +1、[PicGo的使用过程](https://www.bilibili.com/video/BV1Fc411d7Ks/?p=1&spm_id_from=pageDriver) \ No newline at end of file diff --git "a/\346\235\202\346\226\207/\351\227\264\346\216\245\350\256\277\351\227\256\347\237\245\347\275\221\347\232\204\346\226\271\345\274\217.md" "b/\346\235\202\346\226\207/\351\227\264\346\216\245\350\256\277\351\227\256\347\237\245\347\275\221\347\232\204\346\226\271\345\274\217.md" new file mode 100644 index 0000000..5999445 --- /dev/null +++ "b/\346\235\202\346\226\207/\351\227\264\346\216\245\350\256\277\351\227\256\347\237\245\347\275\221\347\232\204\346\226\271\345\274\217.md" @@ -0,0 +1,159 @@ +![](https://pic1.zhimg.com/70/v2-b560a6a408a103d016be0aac3df6e5e5_1440w.avis?source=172ae18b&biz_tag=Post) + + + +科研过程中,往往需要查阅大量的中外文献。如果学校或科研机构购买了相关数据库的使用权,小伙伴们倒可以通过内网免费下载文献。但是很多时候学校和科研机构购买的权限不够,或是根本没有买,那么我们如何下载文献呢? + +英文文献我们知道可以通过SCI-HUB下载,中文文献大多收录在知网(Cnki),今天我们就来讲讲如何免费下载知网文献。 + +首先,我们可以利用好公共图书馆资源,小编在这里推荐四个。第一个是浙江图书馆(也就是小伙伴们听说的通过支付宝下载文献的方法),图书馆的网址是[http://www.zjlib.cn/](http://www.zjlib.cn/) + +![](https://pic3.zhimg.com/v2-1887b4e2c35e4eed99ea40fa0209235e_b.jpg) + +要想使用图书馆资源,当然得需要办理一个读者证。怎么办理呢?这就需要用到支付宝了,打开支付宝,在搜索框中搜索浙江省图书馆(浙江图书馆),如下图 + +![](https://pic1.zhimg.com/v2-5c89473f97da58ec8548e33b98075358_b.jpg) + +点击浙江图书馆并关注,进入如下界面 + +![](https://pic1.zhimg.com/v2-862cb80291640ab0b3fdddd99e095938_b.jpg) + +在下面菜单栏选中服务,会有二级列表弹出,如下图 + +![](https://pic2.zhimg.com/v2-a6e4618efb343ba8ecad87cf08955861_b.jpg) + +选择我的读者证,然后选择办理读者证,如下图 + +![](https://pic2.zhimg.com/v2-1e03042a863daaedbb75327e653293f9_b.jpg) + +需要我们进行授权,如下图 + +![](https://pic1.zhimg.com/v2-4e965bf29be75400527a65e284cc9cc4_b.jpg) + +授权后就差不多办好了,当然中间有设置密码的过程,小伙伴请牢记密码和读者证证号 + +![](https://pic3.zhimg.com/v2-c02b202d614b4976dc16c4194aa4e6f6_b.jpg) + +这里我们可以领取一个电子读者证,当然只要我们记住证号和密码就可以使用图书馆的网络资源了。我们回到浙江省图书馆网站 + +![](https://pic1.zhimg.com/v2-c681594c2b32199bc2e794ec8b3b60e0_b.jpg) + +在右上角有登陆按钮,点击后我们进入登陆界面 + +![](https://pic4.zhimg.com/v2-87a7e07c450aab290573f2ecc43e5e4b_b.jpg) + +填好证号和设置的密码,登陆成功后,我们就可以下载文献了,把网页拉到底部,可以看见知网数据库,如下图 + +![](https://pic3.zhimg.com/v2-fb5a5761d51512070c1fe49f5dac891a_b.jpg) + +点击中国知网数据库总站,进入如下界面,就可以搜索文献并下载了 + +![](https://pic2.zhimg.com/v2-c43dfe38aee445e5695ae50fb48f9025_b.jpg) + +当然,不仅仅知网可以下载,其他数据库也可以下载,就请感兴趣的小伙伴自行探索了。 + +第二个图书馆资源是中国国家数字图书馆,网址[http://www.nlc.cn/](http://www.nlc.cn/) + +![](https://pic2.zhimg.com/v2-ebb94154c65e837146a2db2736110475_b.jpg) + +我们注册一下就可以使用了,注册也很简单,点击上图读者门户登录注册,进入如下界面,点击“注册新用户” + +![](https://pic3.zhimg.com/v2-6d3e94fa7361171f137e82e704771d22_b.jpg) + +进入注册页面,输入手机号、密码、验证码就能完成注册 + +![](https://pic2.zhimg.com/v2-63e324fe85cfdf644dc490e243fa54e1_b.jpg) + +注册成功后,我们登陆,进入如下界面 + +![](https://pic1.zhimg.com/v2-07b6f9c1bef93f3ccdbd9a9f4c14832c_b.jpg) + +直接点击搜索,可以进入高级搜索界面 + +![](https://pic4.zhimg.com/v2-d0d00e44b635312a51d61cf992e19767_b.jpg) + +我们可以限定期刊报纸进行检索如图所示 + +![](https://pic3.zhimg.com/v2-1fe5e02e94137ca733f483717d39a342_b.jpg) + +我们可以看见第一篇就是来源于知网的文献,我们点击题目 + +![](https://pic4.zhimg.com/v2-0f0e136ffb6ae9331ee0b4b531b55b33_b.jpg) + +进入下一个页面,点击在线阅读 + +![](https://pic1.zhimg.com/v2-80023def0f00b5acdeeac740a7bebeb8_b.jpg) + +然后进入如下页面,点击左上角PDF下载就可以下载文献了。小编测试了一下,知网文献可以免费下载,但数量不多 + +![](https://pic2.zhimg.com/v2-53a13a9d3b82184dec9863bf48fb1f2d_b.jpg) + +第三个图书馆资源是国家哲学社会科学文献中心,网址[http://www.ncpssd.org/](http://www.ncpssd.org/) + +![](https://pic1.zhimg.com/v2-34db57829eaeb764813026dda62d7b08_b.jpg) + +同样是注册后可以免费获取知网文献,但关于自然科学方面的文献可能会少一些 + +第四个是全国图书馆参考咨询联盟,网址是[http://www.ucdrs.superlib.net/](http://www.ucdrs.superlib.net/) + +![](https://pic2.zhimg.com/v2-931a54b77a36ec077309d5b0dc5e6ce5_b.jpg) + +这个网站不需要注册,我们搜索文献时可以选中“期刊”,然后输入关键词,选择中文检索 + +![](https://pic4.zhimg.com/v2-588e650f9ad68465652264a2ef801143_b.jpg) + +我们可以看见检索出很多信息,如下图 + +![](https://pic1.zhimg.com/v2-03579ad797852acfbec9951e00084e64_b.jpg) + +点击感兴趣的文献题目,进入下级页面,如何获取文献呢?在页面右侧有“邮件接收全文” + +![](https://pic3.zhimg.com/v2-a9cc74551cd302fede3c03a5a5938dca_b.jpg) + +点击进去是如下界面,需要我们填写接收邮箱 + +![](https://pic2.zhimg.com/v2-52a936b78deb521acdb14338a89a101d_b.jpg) + +当然,有需要的小伙伴可以试试。 + +除了图书馆资源,小编再给大家介绍两个平台,一个是上海研发公共服务平台,网址[http://www.sgst.cn/](http://www.sgst.cn/) + +![](https://pic3.zhimg.com/v2-554ac90c234006e0cf197dee853fb1d6_b.jpg) + +![](https://pic4.zhimg.com/v2-6decf2d95e1ea6b31ca0b89d7df74d27_b.jpg) + +我们把网站向下拉,找到中西文科技文献服务平台,如上图,进去注册一个账号,注册页面如下 + +![](https://pic2.zhimg.com/v2-3dc0847b7acb5f827a6ef81a6a9289f1_b.jpg) + +按要求注册好后,我们登陆进去,可以看见有400元的万方文献余额和600元的知网下载余额,在左侧科技文献中就可以下载文献了,如下图 + +![](https://pic2.zhimg.com/v2-48d654a197f4271303a22b6182d8076d_b.jpg) + +另一个网站是iData,网址是[https://www.cn-ki.net/](https://www.cn-ki.net/) + +![](https://pic3.zhimg.com/v2-216e4a81aaf2e9561f41c71b4b9bdec6_b.jpg) + +进入网页后,我们点击上图右上角的我的iData,进行注册 + +![](https://pic2.zhimg.com/v2-e8af92d07f4b5d194fb63e4569f01985_b.jpg) + +按提示注册,注册好后,我们登陆,会进入如下界面 + +![](https://pic3.zhimg.com/v2-821f2d6a714b6f8abd922c60869ce266_b.jpg) + +每天有一定的下载额度,一般两三篇文章是没问题的,如果需要大量下载,也可以付费使用。 + +还有什么方法可以下载文献呢?有极客朋友开发出了知网下载器,当然小编没试过,感兴趣的小伙伴可以去网上搜搜看,或者去吾爱破解搜索, + +![](https://pic1.zhimg.com/v2-32f6abdc66ec420f579efe1ab1141c9c_b.jpg) + +最后就是针对人缘很广的小伙伴,如果认识在高校就读的朋友,恰好他们学校购买了知网的使用权,并且有针对学生校外使用的vpn,就可以借来下载知网文献了 + +好了,上面介绍了那么多种方法,希望能对小伙伴们有所帮助。 + +非常棒的网站: + +[浙江图书馆](https://www.zjlib.cn/#searchs_1_div) + +[最全干货—— 如何免费在Cnki(知网)下载文献方法荟萃](https://zhuanlan.zhihu.com/p/46746000) \ No newline at end of file diff --git "a/\346\261\207\347\274\226/ARM64\346\261\207\347\274\226.md" "b/\346\261\207\347\274\226/ARM64\346\261\207\347\274\226.md" new file mode 100644 index 0000000..c1a8930 --- /dev/null +++ "b/\346\261\207\347\274\226/ARM64\346\261\207\347\274\226.md" @@ -0,0 +1,39 @@ +## ARM64汇编 + +#### 寄存器 + +* 通用寄存器 + * 64bit的: x0 ~ x28 + * 32bit的:w0 ~ w28 + * x0 ~ x7:通常拿来放函数的参数,更多的参数使用堆栈来传递 + * x0:通常拿来存放函数的返回值 +* 程序计数器 + * pc (Program Counter) +* 堆栈指针 +* 链接寄存器 +* 程序状态寄存器 + +#### 指令 + +* mov +* ret + * 函数返回 + * 将lr(x30)寄存器的值复制给pc寄存器 +* add +* sub +* cmp + * 将2个寄存器相减 + * 相减的结果会影响cpsr寄存器的标志位 +* b + * 跳转指令 + * 可以带条件跳转,一般跟cmp配合使用 +* bl + * 带返回的跳转指令 + * 执行的操作 + * 将下一条指令的地址存储到lr(x30)寄存器中 + * 跳转到标记处开始执行代码 +* + +#### 参考资料 + +[iOS需要了解的ARM64汇编](https://tenloy.github.io/2021/04/16/Arm64-Introduce.html) diff --git "a/\346\261\207\347\274\226/\346\261\207\347\274\226-01.md" "b/\346\261\207\347\274\226/\346\261\207\347\274\226-01.md" index 0568789..b62cdb7 100644 --- "a/\346\261\207\347\274\226/\346\261\207\347\274\226-01.md" +++ "b/\346\261\207\347\274\226/\346\261\207\347\274\226-01.md" @@ -80,8 +80,8 @@ DX 可分为DH 和 DL > 在汇编的数据存储中,比较常用的2个单位是: -* 字节:byte,1个字节由8bit组成,可以存储在8位寄存器中 -* 字:word,1个字由2个字节组成,2个字节分别称为字的高字节和低字节 +* 字节:**byte**,1个字节由8bit组成,可以存储在8位寄存器中 +* 字:**word**,1个字由2个字节组成,2个字节分别称为字的高字节和低字节 #### CS和IP diff --git "a/\346\261\207\347\274\226/\346\261\207\347\274\226\347\254\224\350\256\260-\345\237\272\347\241\200\347\237\245\350\257\206.md" "b/\346\261\207\347\274\226/\346\261\207\347\274\226\347\254\224\350\256\260-\345\237\272\347\241\200\347\237\245\350\257\206.md" new file mode 100644 index 0000000..e8a0fa3 --- /dev/null +++ "b/\346\261\207\347\274\226/\346\261\207\347\274\226\347\254\224\350\256\260-\345\237\272\347\241\200\347\237\245\350\257\206.md" @@ -0,0 +1,89 @@ +#### CPU + +**汇编指令** + +与机器指令一一**对应**,汇编指令或者一个寄存器的名称**不区分**大小写 + +* **运算器**进行信息处理 +* 寄存器进行信息存储 + +* 控制器控制各种器件进行工作 + +* 内部总线链接各种器件,在他们之间进行数据的传送 + +具体工作过程 + +1、从**CS:IP**指向的内存单元读取指令,读取的指令进入**指令缓冲期** + +2、IP = IP + 所读取的指令的长度,从而指向下一条指令 + +3、执行指令,转到步骤1,重复这个过程 + +#### 存储器 + +1> 被划分为若干个存储单元,每个**存储单元**从0开始顺序编号 + +2> 存储器的一个存储单元可以存储 一个字节(Byte),即8 个二进制位(bit) + +3> 对于 拥有 128 个存储单元的存储器,我们可以说, 它的容量是 128 个字节(byte) + +#### 总线 + +定义:专门用于连接**CPU**和其他芯片的导线被称为总线 + +类型(按照传送信息的不同,从逻辑的上划分) + +1、地址总线 + +2、控制总线 + +3、数据总线 + +#### CPU 对存储器的读写 + +CPU 要想进行数据读写,必须进行下面信息的交互 + +* 存储单元的地址(地址信息) +* 器件的选择,读或写的命令(控制信息) +* 读或写的数据( 数据信息) + +**读取**过程 + +(1)、通过地址线将地址信息内容发出 + +(2)、通过控制线发出内存读取指令,选中存储器芯片,并通知它,将要从中读取数据 + +(3)、存储器将3号单元中的数据8通过数据线传入CPU + +**写入**过程 + +写操作与读操作的步骤相似。如向3 号单元写入数据26 +(1)、C P U 通 过 地 址 线 将 地 址 信 息 发 出 + +(2)、CPU 通过控制线发出内存写命令,选中存储器芯片,并通知它,要向其中写入 数据 + +(3)、CPU 通过数据线将数据26 送入内存的3 号单元中 + +#### 地址总线 + +* 属于CPU的外线 + +* 一个**CPU**有N根地址线,则可以说这个**CPU**的地址总线的宽度为**N**,这样的**CPU**最多可以寻找**2的N**次方个**内存单元** + +#### 数据总线 + +* 属于CPU的外线 + +* 宽度:决定了**CPU**和外界的数据传送速度 +* 1根数据总线一次可传送一个二进制数据,8根数据总线一次可以传送8位二进制数据 +* 8根数据总线一次可以传送1个字节,16根数据总线一次可以传送2个字节 + +#### 控制总线 + +* 属于CPU的外线 + +* 用于控制外部器件,控制总线是一个总称,是不同控制线的集合 +* 有多少根控制总线,意味着**CPU**提供了对外部器件的多少种控制 +* 宽度:决定了**CPU**对外部器件的控制能力 +* "读信号输出"的控制线:负责由CPU向外传送**读**信号 +* "写信号输出"的控制线:负责由CPU向外传送**写**信号 \ No newline at end of file diff --git "a/\346\261\207\347\274\226/\346\261\207\347\274\226\347\254\224\350\256\260-\345\257\204\345\255\230\345\231\250.md" "b/\346\261\207\347\274\226/\346\261\207\347\274\226\347\254\224\350\256\260-\345\257\204\345\255\230\345\231\250.md" new file mode 100644 index 0000000..bda992a --- /dev/null +++ "b/\346\261\207\347\274\226/\346\261\207\347\274\226\347\254\224\350\256\260-\345\257\204\345\255\230\345\231\250.md" @@ -0,0 +1,188 @@ +## 寄存器 + +**8086CPU** + +* 有**14个**寄存器,分别是:AX、BX、CX、DX、SI、DI、SP、BP、IP、CS、SS、DS、ES、PSW +* 所有寄存器都是16位的,可以存放2个字节 + +#### 通用寄存器 + +* AX、BX、CX、DX:用来存放**一般性**的数据,被称为通用寄存器,它们四个又可以分为两个可独立的8位寄存器来用 +* AX 可分为 AH、AL +* BX 可分为 BH、BL +* CX 可分为 CH、CL +* DX 可分为 DH、DL + +#### 寄存器中处理的数据单位 + +* **字节**: 记 为 byte , 一 个 字 节 由 8 个 b i t 组 成 , 可 以 存 在 8 位 寄 存 器 中 +* **字**:记为 word,一个字由两个字节组成,两个字节分别称为这个字的高位字节和低位字节,1个字可以存在1个16位寄存器中,字的高位字节和低位字节分别存在寄存器的高8位和低8位中 + +#### 物理地址 + +* 定义:所有的内存单元构成的 存储空间是 一个 一维的线性空间,每一个内存单元在这个空间中都有唯一的地址 +* **CPU**通过地址总线送到存储器的必须是一个内存单元的**物理地址** + +* 物理地址 = 段地址 * 16 + 偏移地址 + +#### 段地址 + +将若干连续的内存单元看作一个段,用段地址*16定位段的起始地址(基础地址),用偏移地址定位段中的内存单元 + +段地址x16 必然是16 的倍数,所以一个段的起始地址也 一定是16 的倍数 + +偏移地址 为16 位,16 位地址的寻址能力为64KB,所以一个段的长度最大为64KB + +#### 段寄存器 + +* 一共有4个段寄存器:CS、DS、SS、ES + +##### CS 和 IP + +指示**CPU**当前用读取指令的地址,**CS**:代码段寄存器、**IP**:指令指针寄存器 + +内存单元 = M(CS中的内容)*16 + N(IP中的内容) + +**jmp指令**:用于**同时修改CS、IP的内容** + +``` +jmp 段地址:偏移地址 +jmp 2AE3:3 执行后:CS=2AE3H,IP=0003H,CPU将从2AE33H处读取指令 +``` + +**仅修改IP的内容** + +``` +jmp 某一合法寄存器:用寄存器中的值修改IP +jmp ax 可以理解为:mov IP,ax +执行前:ax=1000H,CS=2000H,IP=0003H +执行后:ax=1000H,CS=2000H,IP=1000H +jump bx 可以理解为:mov IP,bx +执行前:bx=0B16H,CS=2000H,IP=0003H +执行后:bx=0B16H,CS=2000H,IP=0B16H +``` + +#### 代码段 + +* 仅仅是人为的将一段内存当做代码段看待,CPU并不会自动将我们定义的代码段中的指令当作指令 * 执行。CPU 只认被CS:IP 指向的内存单元中的内容为指令。所以,要让CPU 执行我们 放在代码段中的指令,必须要将 CS:IP 指向所定义的代码段中的第 一条指令的首地址 + +#### 字 + +使用16位寄存器来存储,高8位存放高位字节,低8位存放低位字节 + +#### 字单元 + +字单元:存放一个字型数据(16位)的内存单元,由**两个地址连续的内存单元**组成。高地址内存单元中存放字型数据的高位字节,低地址内存单元中存放字型数据的低位字节。 + +将起始地址为N的字单元简称为:N地址字单元 + +**DS寄存器**:存放访问数据的段地址 + +#### 指令 + +* mov:指令作用 + +1、将数据直接送入寄存器中,mov 寄存器名称 数据 + +2、将一个**寄存器中的内容**送入另一个寄存器中,mov 寄存器名称 寄存器名称 + +3、将一个**内存单元中的内容**送入一个寄存器中(需要明确指出:从哪一个内存单元送到哪一个寄存器中),(mov 寄存器名称 内存单元地址),当指令执行时,CPU会自动取DS中的数据为内存单元的段地址 + +有如下几种形式 + +```c +mov 寄存器, 数据 +mov 寄存器, 寄存器 +mov 寄存器, 内存单元 +mov 内存单元, 寄存器 +mov 段寄存器, 寄存器 +``` + +* add 指令 + +``` +add 寄存器, 数据 +add 寄存器, 寄存器 +add 寄存器, 内存单元 +add 内存单元, 寄存器 +``` + +* sub 指令 + +``` +sub 寄存器, 数据 +sub 寄存器, 寄存器 +sub 寄存器, 内存单元 +sub 内存单元, 寄存器 +``` + +* push 指令 + +``` +push 寄存器; (将一个寄存器中的数据入栈) +push 段寄存器; (将一个段寄存器中的数据入栈) +push 内存单元 (将一个内存单元的字入栈,栈操作都是以字为单位),这里的内存单元可以只给出偏移地址,CPU从ds中获取段地址 +``` + +* pop 指令 + +``` +pop 寄存器; (用一个寄存器接收大出栈的数据) +pop 段寄存器; (用一个段寄存求接收出栈的数据) +pop 内存单元; (用一个内存字单元接收出栈的数据),这里的内存单元可以只给出偏移地址,CPU从ds中获取段地址 +``` + + + +#### 栈 + +栈有两个基本操作:入栈、出栈,该操作被称为 LIFO(last In first Out) + +初始状态下**栈**是空的,此时,SP指向栈空间最高地址单元的下一个单元 + +入栈:将一个新的元素放入栈顶,**栈顶**是从高地址向低地址方向增长 + +**push ax** 的执行过程由两部完成: + +(1)、SP = SP - 2,SS:SP 指向当前栈顶前面的单元,以当前栈顶前面的单元为新的栈顶 + +(2)、将 ax 中的内容送入 SS:SP 指向的内存单元处,SS:SP此时指向新栈顶 + +```c +// 指令 +push ax:表示将寄存器ax中的数据送入栈中,是以字为单位进行 +pop ax:表示从栈顶取出数据送入ax,是以字为单位进行 + +``` + +**SS**:段寄存器,存放栈顶的段地址 + +**SP**:寄存器,存放偏移地址 + +任意时刻,**SS:SP**指向栈顶元素,push指令和pop指令执行时,CPU从SS和SP中得到栈顶的地址 + +出栈:从栈顶取出一个元素 + +**pop ax** 的执行过程由两部分完成: + +(1)、将 SS:SP 指向的内存单元处的数据送入ax中 + +(2)、SP = SP + 2,SS:SP指向当期那栈顶下面的单元,以当前栈顶下面的单元为新的栈顶 + +#### 总结 + +对于一个段来说,我们可以 + +* 用一个段存档数据,将它定位为"数据段",将它的段地址放在**DS**中,用 mov、add、sub 等访问内存单元的指令时,CPU就将我们定义的数据段中的内容当做数据来访问 + +* 用一个段存放代码,将它定义为"代码段",将它的段地址放在**CS**中,将段中第一条指令的偏移地址放在**IP**中,这样CPU就将执行我们定义的代码段中国你的指令 + +* 用一个段当做栈,将它定义为"栈段",将它的段地址放在**SS**中,将栈顶单元的偏移地址放在**SP**中,这样CPU在需要进行栈操作的时候,比如执行push、pop指令时,就将我们定义的栈段当做栈空间来用 + + + + + +#### 注意点 + +**8086CPU** 不支持将数据直接送入**段寄存器**的操作,所以在**8086CPU**中 mov ds, 1000H 指令是非法的!!,要想将1000H 送入ds中,只能用一个寄存器来进行中转,即:先将1000H送入一个一般寄存器中,比如bx,然后再讲bx中的内容宋送入ds中 diff --git "a/\346\261\207\347\274\226/\346\261\207\347\274\226\347\254\224\350\256\260-\347\274\226\345\206\231\344\270\200\344\270\252\347\250\213\345\272\217.md" "b/\346\261\207\347\274\226/\346\261\207\347\274\226\347\254\224\350\256\260-\347\274\226\345\206\231\344\270\200\344\270\252\347\250\213\345\272\217.md" new file mode 100644 index 0000000..a42981f --- /dev/null +++ "b/\346\261\207\347\274\226/\346\261\207\347\274\226\347\254\224\350\256\260-\347\274\226\345\206\231\344\270\200\344\270\252\347\250\213\345\272\217.md" @@ -0,0 +1,14 @@ +# 第一个程序 + +汇编语言的从写出到最终执行的过程 + +编写汇编源程序(1) => 编译链接(2) => 执行可执行文件中的程序(3) + +(3):操作 系统依照 可执行文件中的描述信息,将 可执行文件中的机器码和数据加载 入内 存,并进行相关的初始化(比如设置CS:IP 指向第一条要执行的指令),然后由CPU 执行 程序 + +### 伪指令 + +程序中包含两种指令: + +* 汇编指令:是有对应的机器码的指令,可以被编译为机器指令,最终被CPU执行 +* 伪指令:没有对应 diff --git "a/\347\247\221\345\255\246\346\226\271\345\274\217/2022-11-25-oracle.md" "b/\347\247\221\345\255\246\346\226\271\345\274\217/2022-11-25-oracle.md" index 2e5af9e..5c52abc 100644 --- "a/\347\247\221\345\255\246\346\226\271\345\274\217/2022-11-25-oracle.md" +++ "b/\347\247\221\345\255\246\346\226\271\345\274\217/2022-11-25-oracle.md" @@ -4,7 +4,7 @@ 1、域名 -目前是在2022-11-24日在[nameSilo](www.namesilo.com)购买了1年的域名,购买的域名是:guoj.xyz,有效期一年,价格:1.99$ +目前是在2022-11-24日在[nameSilo](www.namesilo.com)购买了1年的域名,购买的域名是:guoj.shop,有效期一年,价格:1.99$ 域名解析是在 cloudflare 上面,[地址](https://dash.cloudflare.com/8bc71dd98544b5c2c59731999c5b9c32) @@ -14,7 +14,7 @@ 3、当前的X-ui面版 -[访问地址](https://oracle.guoj.xyz:33445/xui/) +[访问地址](https://oracle.guoj.shop:33445/xui/) ##### 具体的一步步搭建操作步骤如下 @@ -103,7 +103,23 @@ bash <(curl -Ls https://raw.githubusercontent.com/vaxilu/x-ui/master/install.sh) [青龙面板](http://144.24.90.47:5700/) +[服务器地址](https://cloud.oracle.com/compute/instances?region=ap-chuncheon-1) +机器对应的IP地址: + +| 144.24.90.47 | | +| ------------ | ---- | +| | | + +当前的账号:gj9117@hotmail.com + +当前的密码:Gjie65251580! + + + +2023年-5-16-注册新账号 + +c 账号:gjcoder@hotmail.com [参考地址](https://github.com/bigdongdongCLUB/GoodGoodStudyDayDayUp/issues/8) diff --git "a/\347\247\221\345\255\246\346\226\271\345\274\217/\347\247\221\345\255\246\346\226\271\345\274\217-01.md" "b/\347\247\221\345\255\246\346\226\271\345\274\217/\347\247\221\345\255\246\346\226\271\345\274\217-01.md" index 70057a0..f23ff08 100644 --- "a/\347\247\221\345\255\246\346\226\271\345\274\217/\347\247\221\345\255\246\346\226\271\345\274\217-01.md" +++ "b/\347\247\221\345\255\246\346\226\271\345\274\217/\347\247\221\345\255\246\346\226\271\345\274\217-01.md" @@ -16,7 +16,7 @@ 1、获取root权限 sudo -i ``` -![science_00](/Users/guo/Notes/科学方式/images/science_00.jpg) +![](https://cdn.jsdelivr.net/gh/GJBlog/Notes/科学方式/images/science_00.jpg) ```shell 2、安装shadowsocks-sh @@ -27,14 +27,14 @@ chmod +x shadowsocks-all.sh ./shadowsocks-all.sh 2>&1 | tee shadowsocks-all.log ``` -![science_01](/Users/guo/Notes/科学方式/images/science_01.png) +![](https://cdn.jsdelivr.net/gh/GJBlog/Notes/科学方式/images/science_01.png) ```shell 5、选择ShadowsocksR ``` -![science_02](/Users/guo/Notes/科学方式/images/science_02.png) +![science_02](https://cdn.jsdelivr.net/gh/GJBlog/Notes/科学方式/images/science_02.png) ``` 6、设置对应的密码、端口号 diff --git "a/\347\275\221\347\273\234/OverWall.md" "b/\347\275\221\347\273\234/OverWall.md" index 260660f..dfa39dd 100644 --- "a/\347\275\221\347\273\234/OverWall.md" +++ "b/\347\275\221\347\273\234/OverWall.md" @@ -1,4 +1,4 @@ -## OverWall +# OverWall ## 终端配置代理 diff --git "a/\347\275\221\347\273\234/Socks5.md" "b/\347\275\221\347\273\234/Socks5.md" new file mode 100644 index 0000000..aa13977 --- /dev/null +++ "b/\347\275\221\347\273\234/Socks5.md" @@ -0,0 +1,13 @@ +## Socks5 + + + + + +[文章](https://cloud.tencent.com/developer/article/1682604) + +官方文档: + +https://www.ietf.org/rfc/rfc1928.txt + +https://www.ietf.org/rfc/rfc1929.txt \ No newline at end of file diff --git "a/\347\275\221\347\273\234/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234\347\254\254\344\272\224\347\211\210/Network-02-\347\275\221\347\273\234\344\275\223\347\263\273\347\273\223\346\236\204.md" "b/\347\275\221\347\273\234/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234\347\254\254\344\272\224\347\211\210/Network-02-\347\275\221\347\273\234\344\275\223\347\263\273\347\273\223\346\236\204.md" index 9dff209..c43dc83 100644 --- "a/\347\275\221\347\273\234/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234\347\254\254\344\272\224\347\211\210/Network-02-\347\275\221\347\273\234\344\275\223\347\263\273\347\273\223\346\236\204.md" +++ "b/\347\275\221\347\273\234/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234\347\254\254\344\272\224\347\211\210/Network-02-\347\275\221\347\273\234\344\275\223\347\263\273\347\273\223\346\236\204.md" @@ -15,8 +15,16 @@ ##### 2、表示层 +``` +把数据转换为能与接受者的系统格式箭筒并适合传输的格式 +``` + ##### 3、会话层 +``` +为会话实体建立连接,Socks、Sockets +``` + ##### 4、运输层 ``` @@ -37,9 +45,10 @@ ##### 6、数据链路层(链路层) ``` -作用:在两个相邻结点(主机和路由器或者两个路由器)之间传送数据 +作用:在两个相邻结点(主机和路由器或者两个路由器)之间传送数据,为网络实体提供数据链路的连接建立、维持、释放 协议:XXX 传输单位:帧(frame),每一帧包括数据和必要的控制信息(如:同步信息、地址信息、差错控制等) +细分:MAC(介质访问控制)、LLC(逻辑链路控制) ``` ##### 7、物理层 @@ -50,8 +59,6 @@ 传输单位:比特(bit) ``` - - ### 五层协议体系结构 * 5 应用层 diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/01-\347\256\200\345\215\225\345\267\245\345\216\202\346\250\241\345\274\217.md" "b/\350\256\276\350\256\241\346\250\241\345\274\217/01-\347\256\200\345\215\225\345\267\245\345\216\202\346\250\241\345\274\217.md" deleted file mode 100644 index 3acb3f6..0000000 --- "a/\350\256\276\350\256\241\346\250\241\345\274\217/01-\347\256\200\345\215\225\345\267\245\345\216\202\346\250\241\345\274\217.md" +++ /dev/null @@ -1,11 +0,0 @@ -### 简单工厂模式 - -> 用一个单独的类来做创造实例的过程,这就是工厂 -> -> 聚合关系:表示一种弱的'拥有'关系,体现的是A对象可以包含B对象,但是B对象不是A对象的一部分 -> -> 合成关系:表示一种强的'拥有'关系,体现的是严格的部分和整体的关系,部分和整体的声明周期一样 - -* 优点 - * 工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对于客户端来说,去除了具体产品的依赖 - diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/06-\351\207\214\346\260\217\344\273\243\346\215\242\345\216\237\345\210\231.md" "b/\350\256\276\350\256\241\346\250\241\345\274\217/06-\351\207\214\346\260\217\344\273\243\346\215\242\345\216\237\345\210\231.md" deleted file mode 100644 index 09bdc7c..0000000 --- "a/\350\256\276\350\256\241\346\250\241\345\274\217/06-\351\207\214\346\260\217\344\273\243\346\215\242\345\216\237\345\210\231.md" +++ /dev/null @@ -1,3 +0,0 @@ -### 里氏代换原则(LSP) - -> 一个软件实体如果使用的是一个父类的话,那么一定适用于其子类,而且它察觉不出父类对象和子类对象的区别,也就是说,在软件里面,把父类都替换成它的子类,程序的行为没有变化,简单说,子类型必须能够替换掉它们的父类型 \ No newline at end of file diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/09-\345\267\245\345\216\202\346\226\271\346\263\225\346\250\241\345\274\217.md" "b/\350\256\276\350\256\241\346\250\241\345\274\217/09-\345\267\245\345\216\202\346\226\271\346\263\225\346\250\241\345\274\217.md" deleted file mode 100644 index e2e06b2..0000000 --- "a/\350\256\276\350\256\241\346\250\241\345\274\217/09-\345\267\245\345\216\202\346\226\271\346\263\225\346\250\241\345\274\217.md" +++ /dev/null @@ -1,4 +0,0 @@ -### 工厂方法模式 - -> 定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类 - diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/10-\345\216\237\345\236\213\346\250\241\345\274\217.md" "b/\350\256\276\350\256\241\346\250\241\345\274\217/10-\345\216\237\345\236\213\346\250\241\345\274\217.md" deleted file mode 100644 index 8f283a6..0000000 --- "a/\350\256\276\350\256\241\346\250\241\345\274\217/10-\345\216\237\345\236\213\346\250\241\345\274\217.md" +++ /dev/null @@ -1,4 +0,0 @@ -### 原型模式(Prototype) - -> 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象 - diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/01-\347\256\200\345\215\225\345\267\245\345\216\202\346\250\241\345\274\217.md" "b/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/01-\347\256\200\345\215\225\345\267\245\345\216\202\346\250\241\345\274\217.md" new file mode 100644 index 0000000..6bb66fb --- /dev/null +++ "b/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/01-\347\256\200\345\215\225\345\267\245\345\216\202\346\250\241\345\274\217.md" @@ -0,0 +1,24 @@ +### 简单工厂模式 + +> 用一个单独的类来做创造实例的过程,这就是工厂 +> +> 聚合关系:表示一种弱的'拥有'关系,体现的是A对象可以包含B对象,但是B对象不是A对象的一部分 +> +> 合成关系:表示一种强的'拥有'关系,体现的是严格的部分和整体的关系,部分和整体的声明周期一样 + +不是一种设计模式,更像是一种编程习惯 + +#### 包含的角色 + +* 抽象产品:定义了产品的规范,描述了产品的主要特性和功能 +* 具体产品:实现或者继承抽象产品的子类 +* 具体工厂:提供了创建产品的方法,调用者通过该方法来创建产品 + +#### 优点 + +* 封装了创建对象的过程,可以通过参数直接获取对象,把对象的创建和业务路逻辑分开,这样以后就避免了修改客户代码,如果要实现新产品直接修改工厂类,而不需要在原代码中修改,这样就降低了客户修改代码的可能性,更加容易扩展 + +#### 缺点 + +* 增加新产品时还是需要修改工厂类的代码,违背了"开闭原则" + diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/02-\347\255\226\347\225\245\346\250\241\345\274\217.md" "b/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/02-\347\255\226\347\225\245\346\250\241\345\274\217.md" similarity index 100% rename from "\350\256\276\350\256\241\346\250\241\345\274\217/02-\347\255\226\347\225\245\346\250\241\345\274\217.md" rename to "\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/02-\347\255\226\347\225\245\346\250\241\345\274\217.md" diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/07-\350\243\205\351\245\260\346\250\241\345\274\217.md" "b/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/07-\350\243\205\351\245\260\346\250\241\345\274\217.md" similarity index 100% rename from "\350\256\276\350\256\241\346\250\241\345\274\217/07-\350\243\205\351\245\260\346\250\241\345\274\217.md" rename to "\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/07-\350\243\205\351\245\260\346\250\241\345\274\217.md" diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/08-\344\273\243\347\220\206\346\250\241\345\274\217.md" "b/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/08-\344\273\243\347\220\206\346\250\241\345\274\217.md" similarity index 100% rename from "\350\256\276\350\256\241\346\250\241\345\274\217/08-\344\273\243\347\220\206\346\250\241\345\274\217.md" rename to "\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/08-\344\273\243\347\220\206\346\250\241\345\274\217.md" diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/images/Xnip2023-04-01_23-29-41.jpg" "b/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/images/Xnip2023-04-01_23-29-41.jpg" new file mode 100644 index 0000000..c0191dc Binary files /dev/null and "b/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/images/Xnip2023-04-01_23-29-41.jpg" differ diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/images/image-20230312173137823.png" "b/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/images/image-20230312173137823.png" new file mode 100644 index 0000000..d8bf564 Binary files /dev/null and "b/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/images/image-20230312173137823.png" differ diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/images/image-20230312205644102.png" "b/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/images/image-20230312205644102.png" new file mode 100644 index 0000000..494603a Binary files /dev/null and "b/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/images/image-20230312205644102.png" differ diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/images/image-20230312212521366.png" "b/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/images/image-20230312212521366.png" new file mode 100644 index 0000000..1c65a94 Binary files /dev/null and "b/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/images/image-20230312212521366.png" differ diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/images/image-20230401233038796.png" "b/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/images/image-20230401233038796.png" new file mode 100644 index 0000000..cba7254 Binary files /dev/null and "b/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/images/image-20230401233038796.png" differ diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/images/image-20230402180038232.png" "b/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/images/image-20230402180038232.png" new file mode 100644 index 0000000..82673ca Binary files /dev/null and "b/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/images/image-20230402180038232.png" differ diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/\345\210\233\345\273\272\350\200\205\346\250\241\345\274\217/09-\345\267\245\345\216\202\346\226\271\346\263\225\346\250\241\345\274\217.md" "b/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/\345\210\233\345\273\272\350\200\205\346\250\241\345\274\217/09-\345\267\245\345\216\202\346\226\271\346\263\225\346\250\241\345\274\217.md" new file mode 100644 index 0000000..ead030f --- /dev/null +++ "b/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/\345\210\233\345\273\272\350\200\205\346\250\241\345\274\217/09-\345\267\245\345\216\202\346\226\271\346\263\225\346\250\241\345\274\217.md" @@ -0,0 +1,43 @@ +### 工厂方法模式 + +**对比简单工厂** + +简单工厂:工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对于客户端来说,去除了与具体产品的依赖 + +工厂:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类,是简单工厂模式的进一步抽象和推广 + +**对比简单工厂模式,完美解决了开闭原则** + +#### 概念 + +* 定义一个用于创建对象的接口,让子类决定实例化哪个产品类对象,工厂方法使一个产品类的实例化延迟到其工厂的子类中 + +#### 结构 + +工厂方法模式的主要角色 + +1、抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法来创建产品 + +2、具体工厂(Concrete Factory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建 + +3、抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能 + +4、具体产品(Concrete Product):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应 + +#### 优缺点 + +##### 优点 + +1、用户只需要知道具体工厂的名称就可得到所要的产品,无需知道产品的具体创建过程 + +2、在系统增加新的产品时,只需要添加具体产品类和对应的具体工厂类,无需对原工厂进行任何修改,满足开闭原则 + +##### 缺点 + +1、每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度 + + + + + +![image-20230312205644102](/Users/guojie/Notes/设计模式/23种设计模式/images/image-20230312205644102.png) diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/\345\210\233\345\273\272\350\200\205\346\250\241\345\274\217/10-\345\216\237\345\236\213\346\250\241\345\274\217.md" "b/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/\345\210\233\345\273\272\350\200\205\346\250\241\345\274\217/10-\345\216\237\345\236\213\346\250\241\345\274\217.md" new file mode 100644 index 0000000..4dc0d44 --- /dev/null +++ "b/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/\345\210\233\345\273\272\350\200\205\346\250\241\345\274\217/10-\345\216\237\345\236\213\346\250\241\345\274\217.md" @@ -0,0 +1,21 @@ +### 原型模式(Prototype) + +> 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象 + +#### 概述 + +用一个已经创建的对象的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象 + +#### 结构 + +原型模式包含如下角色 + +* 抽象原型类:规定了具体原型对象必须实现的clone方法 + +* 具体原型类:实现抽象原型类的clone方法,它是可被复制的对象 +* 访问类:使用具体原型类中的clone方法来复制新的对象 + +#### 使用场景 + +* 对象的创建非常复杂,可以使用原型模式快捷的创建对象 +* 性能和安全要求比较高 diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/\345\210\233\345\273\272\350\200\205\346\250\241\345\274\217/\345\210\233\345\273\272\350\200\205\346\250\241\345\274\217.md" "b/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/\345\210\233\345\273\272\350\200\205\346\250\241\345\274\217/\345\210\233\345\273\272\350\200\205\346\250\241\345\274\217.md" new file mode 100644 index 0000000..1506c14 --- /dev/null +++ "b/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/\345\210\233\345\273\272\350\200\205\346\250\241\345\274\217/\345\210\233\345\273\272\350\200\205\346\250\241\345\274\217.md" @@ -0,0 +1,11 @@ +## 建造者模式 + +> 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示的意图时,我们需要应用:建造者(Builder)模式,又叫生成器模式 + +主要关注点:怎样创建对象,主要特点:将对象的创建与使用分离,降低系统的耦合度,使用者不需要关注对象的创建细节 + +![image-20230401233038796](/Users/guojie/Notes/设计模式/23种设计模式/images/image-20230401233038796.png) + +#### 使用场景 + +* 主要是用于创建一些复杂的对象,这些对象内部构建间的建造顺序通常是稳定的,但对象内部的构建通常面临着复杂的变化 diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/\345\210\233\345\273\272\350\200\205\346\250\241\345\274\217/\345\215\225\344\276\213\346\250\241\345\274\217.md" "b/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/\345\210\233\345\273\272\350\200\205\346\250\241\345\274\217/\345\215\225\344\276\213\346\250\241\345\274\217.md" new file mode 100644 index 0000000..6b1a255 --- /dev/null +++ "b/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/\345\210\233\345\273\272\350\200\205\346\250\241\345\274\217/\345\215\225\344\276\213\346\250\241\345\274\217.md" @@ -0,0 +1,22 @@ +## 单例模式(Singleton) + +> 保证一个类仅有一个实例,并提供一个访问它的全局访问点 + +通常,我们可以让一个全局变量使得一个对象被访问,但他不能防止你实例化多个对象。一个最好的办法就是,让类自身负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法。 + +![image-20230312173137823](/Users/guojie/Notes/设计模式/23种设计模式/images/image-20230312173137823.png) + +单例设计模式分为两种: + +1、饿汉式:类加载就会导致该实例对象被创建 + +2、懒汉式:类加载不会导致该实例对象被创建,而是首次使用该对象时才会创建 + +懒汉式-静态内部类方式实现原理: + +静态内部类单例模式中实例由内部类创建,由于JVM在加载外部类的过程中,是不会加载静态内部类的,只有内部类的属性/方法被调用时才被加载,并初始化其静态属性。静态属性由于被static修饰,保证只被实例化一次,并且严格保证实例化顺序。**特点:**是非常优秀的方式,比较常用,在没有加任何锁的情况下,保证了多线程下的安全,并且没有任何的性能影响和空间的浪费。 + +单例模式主要有以下角色: + +* 单例类,只能创建一个实例的类 +* 访问类,使用单例类 \ No newline at end of file diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/\345\210\233\345\273\272\350\200\205\346\250\241\345\274\217/\346\212\275\350\261\241\345\267\245\345\216\202\346\250\241\345\274\217.md" "b/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/\345\210\233\345\273\272\350\200\205\346\250\241\345\274\217/\346\212\275\350\261\241\345\267\245\345\216\202\346\250\241\345\274\217.md" new file mode 100644 index 0000000..6c1c082 --- /dev/null +++ "b/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/\345\210\233\345\273\272\350\200\205\346\250\241\345\274\217/\346\212\275\350\261\241\345\267\245\345\216\202\346\250\241\345\274\217.md" @@ -0,0 +1,48 @@ +## 抽象工厂模式(Abstract Factory) + +> 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类 + +#### 概念 + +是一种为访问类提供一个创建一组相关或者相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构 + +**抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品** + +#### 结构 + +主要角色如下: + +* 抽象工厂(Abstract Factory):提供了创建产品的接口,它包含了多个创建产品的方法,可以创建多个不同等级的产品 +* 具体工厂(Concrete Factory):主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建 +* 抽象产品(Abstract Product ):定义了产品的规范,描述了产品的主要特征和功能,抽象工厂模式有多个抽象产品 +* 具体产品(Concrete Product):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系 + +当需要增加同一个产品簇的话,只需要再加一个对应的工厂类即可,不需要修改其他的类 + +#### 优缺点 + +##### 优点 + +1、当一个产品簇中的多个对象被设计成一起工作时,它能保证客户单始终只是使用同一个产品簇中的对象 + +##### 缺点 + +1、当产品簇中需要增加一个新的产品时,所有的工厂类都需要进行修改 + +#### 使用场景 + +* 当需要创建的对象是一系列相互关联或者 + + + + + + + +![image-20230312212521366](/Users/guojie/Notes/设计模式/23种设计模式/images/image-20230312212521366.png) + +#### 优点 + +1、易于交换产品系列,由于具体工厂类,在一个应用中只需要在初始化的时间出现一次,这就使得改变一个应用的具体工厂变的非常容易,它只需要改变具体工厂即可使用不同的产品配置 + +2、它让具体的创建实例过程与客户端分离,客户端是通过它们的抽象接口操作实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户代码中。 \ No newline at end of file diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/\345\244\226\350\247\202\346\250\241\345\274\217.md" "b/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/\345\244\226\350\247\202\346\250\241\345\274\217.md" new file mode 100644 index 0000000..9ca9803 --- /dev/null +++ "b/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/\345\244\226\350\247\202\346\250\241\345\274\217.md" @@ -0,0 +1,19 @@ +## 外观模式 + +> 又被称作门面模式 + +定义: + +为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用 + +![image-20230402155926963](/Users/guojie/Notes/设计模式/类图Images/image-20230402155926963.png) + +特点:完美体现了依赖倒转原则和迪米特法则的思想 + +用途: + +* 首页,在设计初期阶段,应该要有意识的将不同的两个层分离,在不同的层之间简历外观Facade,大大降低耦合度 +* 其次,在开发阶段,子系统往往因为不断的重构演化而变的越来越负责,增加外观Facade可以提供一个简单的接口,减少它们之间的依赖 +* 第三,在维护一个遗留的大型系统时,可能这个系统已经非常难以维护和扩展了,此时用外观模式Facade也是非常合适的,可以为新系统开发 一个外观 Facade 类,来提供设计粗糙或高度复杂的遗留代码的比较清晰 简单的接又,让新系统与Facade 对象交互,Facade 与遗留代码交互所有复杂的工作。 + +![image-20230402160510174](/Users/guojie/Notes/设计模式/类图Images/image-20230402160510174.png) \ No newline at end of file diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/\346\250\241\346\235\277\346\250\241\345\274\217.md" "b/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/\346\250\241\346\235\277\346\250\241\345\274\217.md" new file mode 100644 index 0000000..4a1b112 --- /dev/null +++ "b/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/\346\250\241\346\235\277\346\250\241\345\274\217.md" @@ -0,0 +1,3 @@ +## 模板模式 + +> \ No newline at end of file diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/\350\247\202\345\257\237\350\200\205\346\250\241\345\274\217.md" "b/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/\350\247\202\345\257\237\350\200\205\346\250\241\345\274\217.md" new file mode 100644 index 0000000..30a90e0 --- /dev/null +++ "b/\350\256\276\350\256\241\346\250\241\345\274\217/23\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217/\350\247\202\345\257\237\350\200\205\346\250\241\345\274\217.md" @@ -0,0 +1,19 @@ +## 观察者模式 + +> 又叫发布-订阅(Publish/Subscribe)模式 + +#### 定义 + +一种1对多的依赖关系,让多个观察者对象同时监听一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使他们能够自动更新自己。 + +![image-20230402180038232](/Users/guojie/Notes/设计模式/23种设计模式/images/image-20230402180038232.png) + +* Subject类,翻译为主题或抽象通知者,一般用一个抽象类或者一个接口实现。它把所有对观察者对象的引用保存在一个聚集里,每个主题都可以由任何数量的观察者。抽象主题提供一个接口,可以增加或删除观察者对象。 +* Observer类,抽象观察者,为所有的具体观察者定义一个接又,在得到主题的通知时更新自己。这 个接又叫做更新接又。抽象观察者 一般用 一个抽象类或者 一个接又实现。更新接又通常包含 一个Update0 方法, 这个方法叫做更新方法。 +* ConcreteSubject 类,叫做具体主题或具体通知者,将有关状态存入具体现察者对象;,在具体主题的 内部状态改变时,给所有登记过的观察者发出通知。具体 主题角色通常用一个具体子类实现。 +* ConcreteObserver 类,具体观察者,实现抽象观察者角色所要求的更新接又,以便使本身的状态与 主题的状态相协调。具体观察者角色可以保存一个指向具体 主题对象的引用。具体观察者角色通常用一 个具体 子类实现。 + +#### 特点 + +* 将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是需要维护相关对 象问的一致性。我们不希望为了维持一致性而使各类紧密轉合,这样会给维护、扩展和重用都带来不便 +* 观察者模式所做的工作其实就是在解除耜合。让男合的双方都依赖于抽象, 而不是依赖于具体。从而使得各自的变化都不会影响另 一边的变化 \ No newline at end of file diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/03-\345\215\225\344\270\200\350\201\214\350\264\243\345\216\237\345\210\231.md" "b/\350\256\276\350\256\241\346\250\241\345\274\217/\345\205\255\345\244\247\345\216\237\345\210\231/03-\345\215\225\344\270\200\350\201\214\350\264\243\345\216\237\345\210\231.md" similarity index 100% rename from "\350\256\276\350\256\241\346\250\241\345\274\217/03-\345\215\225\344\270\200\350\201\214\350\264\243\345\216\237\345\210\231.md" rename to "\350\256\276\350\256\241\346\250\241\345\274\217/\345\205\255\345\244\247\345\216\237\345\210\231/03-\345\215\225\344\270\200\350\201\214\350\264\243\345\216\237\345\210\231.md" diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/04-\345\274\200\346\224\276-\345\260\201\351\227\255\345\216\237\345\210\231.md" "b/\350\256\276\350\256\241\346\250\241\345\274\217/\345\205\255\345\244\247\345\216\237\345\210\231/04-\345\274\200\346\224\276-\345\260\201\351\227\255\345\216\237\345\210\231.md" similarity index 100% rename from "\350\256\276\350\256\241\346\250\241\345\274\217/04-\345\274\200\346\224\276-\345\260\201\351\227\255\345\216\237\345\210\231.md" rename to "\350\256\276\350\256\241\346\250\241\345\274\217/\345\205\255\345\244\247\345\216\237\345\210\231/04-\345\274\200\346\224\276-\345\260\201\351\227\255\345\216\237\345\210\231.md" diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/05-\344\276\235\350\265\226\345\200\222\347\275\256\345\216\237\345\210\231.md" "b/\350\256\276\350\256\241\346\250\241\345\274\217/\345\205\255\345\244\247\345\216\237\345\210\231/05-\344\276\235\350\265\226\345\200\222\347\275\256\345\216\237\345\210\231.md" similarity index 100% rename from "\350\256\276\350\256\241\346\250\241\345\274\217/05-\344\276\235\350\265\226\345\200\222\347\275\256\345\216\237\345\210\231.md" rename to "\350\256\276\350\256\241\346\250\241\345\274\217/\345\205\255\345\244\247\345\216\237\345\210\231/05-\344\276\235\350\265\226\345\200\222\347\275\256\345\216\237\345\210\231.md" diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/\345\205\255\345\244\247\345\216\237\345\210\231/06-\351\207\214\346\260\217\344\273\243\346\215\242\345\216\237\345\210\231.md" "b/\350\256\276\350\256\241\346\250\241\345\274\217/\345\205\255\345\244\247\345\216\237\345\210\231/06-\351\207\214\346\260\217\344\273\243\346\215\242\345\216\237\345\210\231.md" new file mode 100644 index 0000000..27777a0 --- /dev/null +++ "b/\350\256\276\350\256\241\346\250\241\345\274\217/\345\205\255\345\244\247\345\216\237\345\210\231/06-\351\207\214\346\260\217\344\273\243\346\215\242\345\216\237\345\210\231.md" @@ -0,0 +1,6 @@ +### 里氏代换原则(LSP) + +> 一个软件实体如果使用的是一个父类的话,那么一定适用于其子类,而且它察觉不出父类对象和子类对象的区别,也就是说,在软件里面,把父类都替换成它的子类,程序的行为没有变化,简单说,子类型必须能够替换掉它们的父类型 + +任何基类可以出现的地方,子类一定可以出现。通俗理解:子类可以扩展父类的功能,但不能改变父类原有的功能。欢聚话说,子类继承父类时,除添加新的方法完成新增功能外,尽量不要重写父类的方法 + diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/\345\205\255\345\244\247\345\216\237\345\210\231/07-\346\216\245\345\217\243\351\232\224\347\246\273\345\216\237\345\210\231.md" "b/\350\256\276\350\256\241\346\250\241\345\274\217/\345\205\255\345\244\247\345\216\237\345\210\231/07-\346\216\245\345\217\243\351\232\224\347\246\273\345\216\237\345\210\231.md" new file mode 100644 index 0000000..1ce24c1 --- /dev/null +++ "b/\350\256\276\350\256\241\346\250\241\345\274\217/\345\205\255\345\244\247\345\216\237\345\210\231/07-\346\216\245\345\217\243\351\232\224\347\246\273\345\216\237\345\210\231.md" @@ -0,0 +1,8 @@ +## 接口隔离原则 + +> 客户端不应该被迫依赖于它不使用的方法,一个类对另一个类的依赖应该建立在最小的接口上 + + + + + diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/\345\205\255\345\244\247\345\216\237\345\210\231/\345\220\210\346\210\220\345\244\215\347\224\250\345\216\237\345\210\231.md" "b/\350\256\276\350\256\241\346\250\241\345\274\217/\345\205\255\345\244\247\345\216\237\345\210\231/\345\220\210\346\210\220\345\244\215\347\224\250\345\216\237\345\210\231.md" new file mode 100644 index 0000000..4116e68 --- /dev/null +++ "b/\350\256\276\350\256\241\346\250\241\345\274\217/\345\205\255\345\244\247\345\216\237\345\210\231/\345\220\210\346\210\220\345\244\215\347\224\250\345\216\237\345\210\231.md" @@ -0,0 +1,21 @@ +## 合成复用原则 + +> 尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现 + +通常类的复用分为继承复用和合成复用两种 + +继承复用:虽然简单和易实现,但是有缺点: + +1、继承复用破坏类的封装性。因为继承会将父类的实现细节暴露给子类,父类对子类是透明的,这种复用又称为"百箱"复用 + +2、子类和父类的耦合度高。父类实现的任何改变都会导致子类的实现发生变化,者不利于类的扩展和维护 + +3、它限制了复用的灵活性:从父类继承而来的实现是静态的,在编译时已经定义,所以在运行时不可能发生变化 + +采用组合或聚合复用时,可以将已有对象纳入新对象中,使之称为新对象的一部分,新对象可以调用已有对象的功能,它有以下优点: + +1、它维持了类的封装性,因为成员对象的内部细节是新对象看不到的,所以这种复用又称为"黑箱"复用 + +2、对象间的耦合度低。可以在类的成员位置声明抽象 + +3、复用的灵活性高。这种复用可以在运行时动态进行,新对象可以动态第引用与成员对象类型相同的对象 \ No newline at end of file diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/\345\205\255\345\244\247\345\216\237\345\210\231/\350\277\252\347\261\263\347\211\271\346\263\225\345\210\231.md" "b/\350\256\276\350\256\241\346\250\241\345\274\217/\345\205\255\345\244\247\345\216\237\345\210\231/\350\277\252\347\261\263\347\211\271\346\263\225\345\210\231.md" new file mode 100644 index 0000000..59c4f01 --- /dev/null +++ "b/\350\256\276\350\256\241\346\250\241\345\274\217/\345\205\255\345\244\247\345\216\237\345\210\231/\350\277\252\347\261\263\347\211\271\346\263\225\345\210\231.md" @@ -0,0 +1,10 @@ +## 迪米特法则 + +> 又叫最少知识原则 + +只和你的直接朋友交谈,不跟陌生人说话 + +含义:如果两个软件实体无须直接通信,那么就不应该发生直接的相互调用,可以通过第三方转发改调用。其目的是降低类之间的耦合度,提高模块的相对独立性 + + + diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/\347\261\273\345\233\276Images/image-20230311230351793.png" "b/\350\256\276\350\256\241\346\250\241\345\274\217/\347\261\273\345\233\276Images/image-20230311230351793.png" new file mode 100644 index 0000000..51eaff6 Binary files /dev/null and "b/\350\256\276\350\256\241\346\250\241\345\274\217/\347\261\273\345\233\276Images/image-20230311230351793.png" differ diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/\347\261\273\345\233\276Images/image-20230311231314839.png" "b/\350\256\276\350\256\241\346\250\241\345\274\217/\347\261\273\345\233\276Images/image-20230311231314839.png" new file mode 100644 index 0000000..5037970 Binary files /dev/null and "b/\350\256\276\350\256\241\346\250\241\345\274\217/\347\261\273\345\233\276Images/image-20230311231314839.png" differ diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/\347\261\273\345\233\276Images/image-20230311234405841.png" "b/\350\256\276\350\256\241\346\250\241\345\274\217/\347\261\273\345\233\276Images/image-20230311234405841.png" new file mode 100644 index 0000000..3495ed9 Binary files /dev/null and "b/\350\256\276\350\256\241\346\250\241\345\274\217/\347\261\273\345\233\276Images/image-20230311234405841.png" differ diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/\347\261\273\345\233\276Images/image-20230311234533547.png" "b/\350\256\276\350\256\241\346\250\241\345\274\217/\347\261\273\345\233\276Images/image-20230311234533547.png" new file mode 100644 index 0000000..dc43e80 Binary files /dev/null and "b/\350\256\276\350\256\241\346\250\241\345\274\217/\347\261\273\345\233\276Images/image-20230311234533547.png" differ diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/\347\261\273\345\233\276Images/image-20230311234812599.png" "b/\350\256\276\350\256\241\346\250\241\345\274\217/\347\261\273\345\233\276Images/image-20230311234812599.png" new file mode 100644 index 0000000..7a783b7 Binary files /dev/null and "b/\350\256\276\350\256\241\346\250\241\345\274\217/\347\261\273\345\233\276Images/image-20230311234812599.png" differ diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/\347\261\273\345\233\276Images/image-20230311235115629.png" "b/\350\256\276\350\256\241\346\250\241\345\274\217/\347\261\273\345\233\276Images/image-20230311235115629.png" new file mode 100644 index 0000000..48263d1 Binary files /dev/null and "b/\350\256\276\350\256\241\346\250\241\345\274\217/\347\261\273\345\233\276Images/image-20230311235115629.png" differ diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/\347\261\273\345\233\276Images/image-20230311235303982.png" "b/\350\256\276\350\256\241\346\250\241\345\274\217/\347\261\273\345\233\276Images/image-20230311235303982.png" new file mode 100644 index 0000000..a838f56 Binary files /dev/null and "b/\350\256\276\350\256\241\346\250\241\345\274\217/\347\261\273\345\233\276Images/image-20230311235303982.png" differ diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/\347\261\273\345\233\276Images/image-20230311235429321.png" "b/\350\256\276\350\256\241\346\250\241\345\274\217/\347\261\273\345\233\276Images/image-20230311235429321.png" new file mode 100644 index 0000000..6e0aa9a Binary files /dev/null and "b/\350\256\276\350\256\241\346\250\241\345\274\217/\347\261\273\345\233\276Images/image-20230311235429321.png" differ diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/\347\261\273\345\233\276Images/image-20230311235616578.png" "b/\350\256\276\350\256\241\346\250\241\345\274\217/\347\261\273\345\233\276Images/image-20230311235616578.png" new file mode 100644 index 0000000..f324d15 Binary files /dev/null and "b/\350\256\276\350\256\241\346\250\241\345\274\217/\347\261\273\345\233\276Images/image-20230311235616578.png" differ diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/\347\261\273\345\233\276Images/image-20230402155926963.png" "b/\350\256\276\350\256\241\346\250\241\345\274\217/\347\261\273\345\233\276Images/image-20230402155926963.png" new file mode 100644 index 0000000..ba22d88 Binary files /dev/null and "b/\350\256\276\350\256\241\346\250\241\345\274\217/\347\261\273\345\233\276Images/image-20230402155926963.png" differ diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/\347\261\273\345\233\276Images/image-20230402160510174.png" "b/\350\256\276\350\256\241\346\250\241\345\274\217/\347\261\273\345\233\276Images/image-20230402160510174.png" new file mode 100644 index 0000000..1fd4c39 Binary files /dev/null and "b/\350\256\276\350\256\241\346\250\241\345\274\217/\347\261\273\345\233\276Images/image-20230402160510174.png" differ diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217/\347\261\273\345\233\276UML.md" "b/\350\256\276\350\256\241\346\250\241\345\274\217/\347\261\273\345\233\276UML.md" new file mode 100644 index 0000000..08ff732 --- /dev/null +++ "b/\350\256\276\350\256\241\346\250\241\345\274\217/\347\261\273\345\233\276UML.md" @@ -0,0 +1,72 @@ +## 类图UML表示法 + +### 1-类的表示方式 + +![image-20230311230351793](/Users/guojie/Notes/设计模式/类图Images/image-20230311230351793.png) + +属性|方法名称前加的加号和减号表示了这个属性|方法的可见性,UML类图中表示可见性的符号有三种 + +* `+`:表示public +* `-`:表示private +* `#`:表示protected + +属性的完整表示方式是: 可见性 名称:类型 [= 缺省值] + +方法的完整表示方式是: 可见性 名称(参数类型) [: 缺省值] + +### 2-类与类之间关系 + +#### 1、关联关系 + +* 是对象之间的一种引用关系,表示一类对象与另一类对象之间的联系 +* 关联关系是类与类之间最常用的一种关系,分为一般关联关系、聚合关系、组合关系 + +关联又分为:单向关联、双向关联、自关联 + +##### 1、单向关联 + +![image-20230311231314839](/Users/guojie/Notes/设计模式/类图Images/image-20230311231314839.png) + +##### 2、双向关联 + +![image-20230311234405841](/Users/guojie/Notes/设计模式/类图Images/image-20230311234405841.png) + +所谓的双向关联就是双方各自持有对象类型的成员变量 + +##### 3、自关联 + +![image-20230311234533547](/Users/guojie/Notes/设计模式/类图Images/image-20230311234533547.png) + +#### 2、聚合关系 + +是关联关系的一种,是强关联关系,是 整体和部分之间的关系 + +聚合关系也是通过成员对象来实现的,其中成员对象是整体对象的一部分,但是成员对象可以脱离对象而独立存在 + +![image-20230311234812599](/Users/guojie/Notes/设计模式/类图Images/image-20230311234812599.png) + +##### 3、组合关系 + +组合表示类之间的整合与部分的关系,但它是一种更强烈的聚合关系 + +在组合关系中,整体对象可以控制部分对象的生命周期,一旦整体对象不存在,部分对象也将不存在,部分对象不能脱离整体对象而存在 + +![image-20230311235115629](/Users/guojie/Notes/设计模式/类图Images/image-20230311235115629.png) + +##### 4、依赖关系 + +依赖关系是一种使用关系,它是对象之间耦合度最弱的一种关联方式,是临时性的关联。在代码中,某个类的方法通过局部变量、方法的参数或者静态方法的调用来访问另一个类(被依赖类)中的某些方法来完成一些职责 + +![image-20230311235303982](/Users/guojie/Notes/设计模式/类图Images/image-20230311235303982.png) + +##### 5、继承关系 + +继承关系是对象之间狗合度最大的一种关系,表示一般与特殊的关系,是父类与子类之间的关系 + +![image-20230311235429321](/Users/guojie/Notes/设计模式/类图Images/image-20230311235429321.png) + +##### 6、实现关系 + +实现关系是接口与实现类之间的关系。在这种关系中,类实现了接口,类中的操作实现了接口所声明的所有抽象操作 + +![image-20230311235616578](/Users/guojie/Notes/设计模式/类图Images/image-20230311235616578.png) \ No newline at end of file diff --git "a/\351\235\222\351\276\231\351\235\242\347\211\210.md" "b/\351\235\222\351\276\231\351\235\242\347\211\210.md" new file mode 100644 index 0000000..b653290 --- /dev/null +++ "b/\351\235\222\351\276\231\351\235\242\347\211\210.md" @@ -0,0 +1,36 @@ +## 青龙面版 + +1、安装docker + +```python +sudo apt install docker.io +``` + +2、配置docker开机启动 + +```python +sudo systemctl start docker +sudo systemctl enable docker +``` + +3、配置青龙面版 + +```python +docker run -dit \ + --name QL \ + --hostname QL \ + --restart always \ + -p 5700:5700 \ + -v $PWD/QL/config:/ql/config \ + -v $PWD/QL/log:/ql/log \ + -v $PWD/QL/db:/ql/db \ + -v $PWD/QL/scripts:/ql/scripts \ + -v $PWD/QL/jbot:/ql/jbot \ + whyour/qinglong:latest +``` + +4、等待一段时间后,通过浏览器中输入ip:5700 + +[安装青龙面版](https://blog.csdn.net/m0_64632940/article/details/124029903) + +[青龙面版](https://github.com/whyour/qinglong)