From e631e7c07420211c8f165bb77dfd6c80337741d2 Mon Sep 17 00:00:00 2001 From: thinklive1 <469631989@qq.com> Date: Tue, 5 Dec 2023 16:16:34 +0800 Subject: [PATCH] Site updated: 2023-12-05 16:16:33 --- .../index.html" | 4 +- .../28/\347\247\230\345\257\2061/index.html" | 4 +- .../61a\346\200\273\345\222\214/index.html" | 8 +- .../index.html" | 12 +- .../index.html" | 12 +- .../index.html" | 8 +- .../index.html" | 8 +- .../index.html" | 12 +- 2023/09/29/jupyter notebook/index.html | 12 +- .../index.html" | 12 +- .../index.html" | 12 +- .../index.html" | 12 +- .../index.html" | 8 +- .../index.html" | 4 +- .../index.html" | 4 +- .../index.html" | 4 +- .../index.html" | 4 +- .../index.html" | 4 +- .../index.html" | 4 +- .../30/\346\235\200\346\211\21347/index.html" | 4 +- .../index.html" | 4 +- .../index.html" | 4 +- .../index.html" | 4 +- .../index.html" | 8 +- .../index.html" | 4 +- .../index.html" | 4 +- 2023/10/09/numpy/index.html | 4 +- 2023/10/12/sysadmin/index.html | 4 +- .../index.html" | 4 +- .../index.html" | 4 +- .../14/\350\256\241\347\275\221/index.html" | 4 +- .../index.html" | 4 +- .../index.html" | 4 +- 2023/12/03/myproj3/index.html | 4 +- .../index.html" | 108 +++- about/index.html | 4 +- archives/2023/09/index.html | 12 +- archives/2023/09/page/2/index.html | 20 +- archives/2023/09/page/3/index.html | 4 +- archives/2023/10/index.html | 4 +- archives/2023/11/index.html | 4 +- archives/2023/12/index.html | 4 +- archives/2023/index.html | 4 +- archives/2023/page/2/index.html | 4 +- archives/2023/page/3/index.html | 28 +- archives/2023/page/4/index.html | 4 +- archives/index.html | 4 +- archives/page/2/index.html | 4 +- archives/page/3/index.html | 28 +- archives/page/4/index.html | 4 +- .../Pasted image 20231205144922.png" | Bin 0 -> 57310 bytes .../Pasted image 20231205151119.png" | Bin 0 -> 44183 bytes atom.xml | 206 +++---- categories/index.html | 4 +- .../index.html" | 4 +- .../black-souls/index.html" | 12 +- .../index.html" | 12 +- .../wrpg/index.html" | 4 +- .../index.html" | 4 +- .../index.html" | 4 +- .../\347\247\230\345\257\206/index.html" | 4 +- .../index.html" | 4 +- .../index.html" | 4 +- .../page/2/index.html" | 20 +- .../\345\205\266\344\273\226/index.html" | 4 +- .../index.html" | 4 +- .../index.html" | 4 +- .../index.html" | 4 +- .../index.html" | 4 +- .../\350\256\241\347\273\204/index.html" | 4 +- .../index.html" | 4 +- guestbook/index.html | 4 +- index.html | 12 +- page/2/index.html | 96 ++-- page/3/index.html | 78 +-- page/4/index.html | 44 +- photos/index.html | 4 +- search.xml | 518 ++++++++++-------- sitemap.txt | 26 +- sitemap.xml | 72 +-- tags/JAVA/index.html | 4 +- tags/black-souls/index.html | 12 +- tags/c/index.html | 4 +- tags/hexo/index.html | 4 +- tags/hitman/index.html | 4 +- tags/icarus/index.html | 4 +- tags/index.html | 4 +- tags/linux/index.html | 4 +- tags/next/index.html | 4 +- tags/not-for-broadcast/index.html | 4 +- tags/pandas/index.html | 4 +- tags/python/index.html | 4 +- tags/vim/index.html | 4 +- tags/webstack/index.html | 4 +- .../index.html" | 4 +- .../index.html" | 4 +- .../index.html" | 4 +- .../index.html" | 4 +- .../index.html" | 4 +- .../index.html" | 4 +- .../index.html" | 4 +- .../index.html" | 4 +- .../index.html" | 4 +- .../index.html" | 4 +- .../index.html" | 4 +- .../index.html" | 12 +- "tags/\347\247\230\345\257\206/index.html" | 4 +- .../index.html" | 4 +- .../index.html" | 4 +- .../index.html" | 4 +- .../index.html" | 4 +- .../index.html" | 4 +- .../index.html" | 4 +- .../index.html" | 4 +- .../page/2/index.html" | 20 +- .../index.html" | 4 +- .../index.html" | 4 +- .../index.html" | 4 +- thanks/index.html | 4 +- 119 files changed, 983 insertions(+), 821 deletions(-) create mode 100644 "assets/\350\213\217\345\244\247linux_ppt/Pasted image 20231205144922.png" create mode 100644 "assets/\350\213\217\345\244\247linux_ppt/Pasted image 20231205151119.png" diff --git "a/2023/09/17/thinklive\347\232\204\350\277\252\347\221\236\345\205\213\346\213\211\345\233\276\344\271\246\351\246\206/index.html" "b/2023/09/17/thinklive\347\232\204\350\277\252\347\221\236\345\205\213\346\213\211\345\233\276\344\271\246\351\246\206/index.html" index 7fa26cadf..690baf125 100644 --- "a/2023/09/17/thinklive\347\232\204\350\277\252\347\221\236\345\205\213\346\213\211\345\233\276\344\271\246\351\246\206/index.html" +++ "b/2023/09/17/thinklive\347\232\204\350\277\252\347\221\236\345\205\213\346\213\211\345\233\276\344\271\246\351\246\206/index.html" @@ -405,14 +405,14 @@

更新日志

站点总字数: - 191k + 194k 站点阅读时长 ≈ - 11:36 + 11:45
diff --git "a/2023/09/28/\347\247\230\345\257\2061/index.html" "b/2023/09/28/\347\247\230\345\257\2061/index.html" index e84f50c94..7917e8806 100644 --- "a/2023/09/28/\347\247\230\345\257\2061/index.html" +++ "b/2023/09/28/\347\247\230\345\257\2061/index.html" @@ -401,14 +401,14 @@

站点总字数: - 191k + 194k

diff --git "a/2023/09/29/61a\346\200\273\345\222\214/index.html" "b/2023/09/29/61a\346\200\273\345\222\214/index.html" index aabfb05ad..f4ca1ed7e 100644 --- "a/2023/09/29/61a\346\200\273\345\222\214/index.html" +++ "b/2023/09/29/61a\346\200\273\345\222\214/index.html" @@ -608,8 +608,8 @@

生成器生成树的搜索路径

-
@@ -648,14 +648,14 @@

生成器生成树的搜索路径

站点总字数: - 191k + 194k
diff --git "a/2023/09/29/black souls\344\272\272\347\211\251\350\247\243\346\236\220/index.html" "b/2023/09/29/black souls\344\272\272\347\211\251\350\247\243\346\236\220/index.html" index 971b36680..7eca47fe2 100644 --- "a/2023/09/29/black souls\344\272\272\347\211\251\350\247\243\346\236\220/index.html" +++ "b/2023/09/29/black souls\344\272\272\347\211\251\350\247\243\346\236\220/index.html" @@ -359,13 +359,13 @@

玛丽苏

-
-
@@ -399,14 +399,14 @@

玛丽苏

站点总字数: - 191k + 194k
diff --git "a/2023/09/29/black souls\345\211\247\346\203\205\350\247\243\346\236\220/index.html" "b/2023/09/29/black souls\345\211\247\346\203\205\350\247\243\346\236\220/index.html" index 26b3be747..2c08cc63a 100644 --- "a/2023/09/29/black souls\345\211\247\346\203\205\350\247\243\346\236\220/index.html" +++ "b/2023/09/29/black souls\345\211\247\346\203\205\350\247\243\346\236\220/index.html" @@ -356,13 +356,13 @@

-
-
@@ -396,14 +396,14 @@

站点总字数: - 191k + 194k

diff --git "a/2023/09/29/blacksouls\345\216\237\350\221\227\346\242\227\350\247\243\346\236\220/index.html" "b/2023/09/29/blacksouls\345\216\237\350\221\227\346\242\227\350\247\243\346\236\220/index.html" index 4a2645a10..b17dc9cbd 100644 --- "a/2023/09/29/blacksouls\345\216\237\350\221\227\346\242\227\350\247\243\346\236\220/index.html" +++ "b/2023/09/29/blacksouls\345\216\237\350\221\227\346\242\227\350\247\243\346\236\220/index.html" @@ -383,8 +383,8 @@

ex02

-
@@ -418,14 +418,14 @@

ex02

站点总字数: - 191k + 194k 站点阅读时长 ≈ - 11:36 + 11:45
diff --git "a/2023/09/29/cs106b\346\200\273\345\222\214\347\254\224\350\256\260/index.html" "b/2023/09/29/cs106b\346\200\273\345\222\214\347\254\224\350\256\260/index.html" index 1015e55fd..9e02f4c60 100644 --- "a/2023/09/29/cs106b\346\200\273\345\222\214\347\254\224\350\256\260/index.html" +++ "b/2023/09/29/cs106b\346\200\273\345\222\214\347\254\224\350\256\260/index.html" @@ -39,8 +39,8 @@ - + @@ -426,8 +426,8 @@

汉诺塔递归

- +
@@ -481,14 +481,14 @@

汉诺塔递归

站点总字数: - 191k + 194k 站点阅读时长 ≈ - 11:36 + 11:45
diff --git "a/2023/09/29/cs106l\346\200\273\345\222\214\347\254\224\350\256\260/index.html" "b/2023/09/29/cs106l\346\200\273\345\222\214\347\254\224\350\256\260/index.html" index 5e96e3526..ca66441b1 100644 --- "a/2023/09/29/cs106l\346\200\273\345\222\214\347\254\224\350\256\260/index.html" +++ "b/2023/09/29/cs106l\346\200\273\345\222\214\347\254\224\350\256\260/index.html" @@ -47,8 +47,8 @@ - + @@ -404,8 +404,8 @@

涉及的c++特性

@@ -1200,14 +1200,14 @@

外部存储器(辅助存储器

站点总字数: - 191k + 194k 站点阅读时长 ≈ - 11:36 + 11:45
diff --git "a/2023/09/29/\350\277\252\347\221\236\345\205\213\346\213\211rpg\350\256\276\345\256\232\351\233\206/index.html" "b/2023/09/29/\350\277\252\347\221\236\345\205\213\346\213\211rpg\350\256\276\345\256\232\351\233\206/index.html" index c1eafda16..1427b5b7a 100644 --- "a/2023/09/29/\350\277\252\347\221\236\345\205\213\346\213\211rpg\350\256\276\345\256\232\351\233\206/index.html" +++ "b/2023/09/29/\350\277\252\347\221\236\345\205\213\346\213\211rpg\350\256\276\345\256\232\351\233\206/index.html" @@ -462,14 +462,14 @@

七苦圣母

站点总字数: - 191k + 194k 站点阅读时长 ≈ - 11:36 + 11:45
diff --git "a/2023/09/29/\350\277\252\347\221\236\345\205\213\346\213\211\344\270\226\347\225\214\350\247\202/index.html" "b/2023/09/29/\350\277\252\347\221\236\345\205\213\346\213\211\344\270\226\347\225\214\350\247\202/index.html" index af267b91a..62bfb9bc1 100644 --- "a/2023/09/29/\350\277\252\347\221\236\345\205\213\346\213\211\344\270\226\347\225\214\350\247\202/index.html" +++ "b/2023/09/29/\350\277\252\347\221\236\345\205\213\346\213\211\344\270\226\347\225\214\350\247\202/index.html" @@ -431,14 +431,14 @@

帕斯卡王国

站点总字数: - 191k + 194k 站点阅读时长 ≈ - 11:36 + 11:45
diff --git "a/2023/09/29/\350\277\252\347\221\236\345\205\213\346\213\211\350\275\266\344\272\213\351\233\206/index.html" "b/2023/09/29/\350\277\252\347\221\236\345\205\213\346\213\211\350\275\266\344\272\213\351\233\206/index.html" index 1239e5d48..cf457ce70 100644 --- "a/2023/09/29/\350\277\252\347\221\236\345\205\213\346\213\211\350\275\266\344\272\213\351\233\206/index.html" +++ "b/2023/09/29/\350\277\252\347\221\236\345\205\213\346\213\211\350\275\266\344\272\213\351\233\206/index.html" @@ -437,14 +437,14 @@

度量

站点总字数: - 191k + 194k 站点阅读时长 ≈ - 11:36 + 11:45
diff --git "a/2023/09/30/\344\270\215\344\272\210\346\222\255\345\207\272/index.html" "b/2023/09/30/\344\270\215\344\272\210\346\222\255\345\207\272/index.html" index c235c2ded..bca00cd72 100644 --- "a/2023/09/30/\344\270\215\344\272\210\346\222\255\345\207\272/index.html" +++ "b/2023/09/30/\344\270\215\344\272\210\346\222\255\345\207\272/index.html" @@ -395,14 +395,14 @@

站点总字数: - 191k + 194k

diff --git "a/2023/09/30/\345\267\253\345\270\210\344\272\214/index.html" "b/2023/09/30/\345\267\253\345\270\210\344\272\214/index.html" index 7be04fa21..3663f3790 100644 --- "a/2023/09/30/\345\267\253\345\270\210\344\272\214/index.html" +++ "b/2023/09/30/\345\267\253\345\270\210\344\272\214/index.html" @@ -394,14 +394,14 @@

站点总字数: - 191k + 194k

diff --git "a/2023/09/30/\345\275\261\345\255\220\345\267\245\345\216\202/index.html" "b/2023/09/30/\345\275\261\345\255\220\345\267\245\345\216\202/index.html" index 246805d18..1c1c5b451 100644 --- "a/2023/09/30/\345\275\261\345\255\220\345\267\245\345\216\202/index.html" +++ "b/2023/09/30/\345\275\261\345\255\220\345\267\245\345\216\202/index.html" @@ -394,14 +394,14 @@

站点总字数: - 191k + 194k

diff --git "a/2023/09/30/\346\235\200\346\211\21347/index.html" "b/2023/09/30/\346\235\200\346\211\21347/index.html" index dd516adfd..1da709c74 100644 --- "a/2023/09/30/\346\235\200\346\211\21347/index.html" +++ "b/2023/09/30/\346\235\200\346\211\21347/index.html" @@ -394,14 +394,14 @@

站点总字数: - 191k + 194k

diff --git "a/2023/09/30/\346\255\245\350\241\214\346\250\241\346\213\237\345\231\250/index.html" "b/2023/09/30/\346\255\245\350\241\214\346\250\241\346\213\237\345\231\250/index.html" index faa94fdc6..c96c68c30 100644 --- "a/2023/09/30/\346\255\245\350\241\214\346\250\241\346\213\237\345\231\250/index.html" +++ "b/2023/09/30/\346\255\245\350\241\214\346\250\241\346\213\237\345\231\250/index.html" @@ -394,14 +394,14 @@

站点总字数: - 191k + 194k

diff --git "a/2023/09/30/\346\270\270\346\210\217\347\256\200\350\257\204/index.html" "b/2023/09/30/\346\270\270\346\210\217\347\256\200\350\257\204/index.html" index e8e70dae3..9b3104cd8 100644 --- "a/2023/09/30/\346\270\270\346\210\217\347\256\200\350\257\204/index.html" +++ "b/2023/09/30/\346\270\270\346\210\217\347\256\200\350\257\204/index.html" @@ -394,14 +394,14 @@

站点总字数: - 191k + 194k

diff --git "a/2023/09/30/\351\276\231\350\205\276\344\270\226\347\272\252/index.html" "b/2023/09/30/\351\276\231\350\205\276\344\270\226\347\272\252/index.html" index 15d48f8e7..ce9ee8dbf 100644 --- "a/2023/09/30/\351\276\231\350\205\276\344\270\226\347\272\252/index.html" +++ "b/2023/09/30/\351\276\231\350\205\276\344\270\226\347\272\252/index.html" @@ -402,14 +402,14 @@

dai

站点总字数: - 191k + 194k 站点阅读时长 ≈ - 11:36 + 11:45
diff --git "a/2023/10/05/cpp primer plus\346\200\273\345\222\214/index.html" "b/2023/10/05/cpp primer plus\346\200\273\345\222\214/index.html" index 0c3a78dec..469387b10 100644 --- "a/2023/10/05/cpp primer plus\346\200\273\345\222\214/index.html" +++ "b/2023/10/05/cpp primer plus\346\200\273\345\222\214/index.html" @@ -32,8 +32,8 @@ - + @@ -439,8 +439,8 @@

匿名函数

diff --git "a/2023/10/05/\345\273\272\347\253\231\346\214\207\345\214\227/index.html" "b/2023/10/05/\345\273\272\347\253\231\346\214\207\345\214\227/index.html" index 34c7d863b..6e23e126a 100644 --- "a/2023/10/05/\345\273\272\347\253\231\346\214\207\345\214\227/index.html" +++ "b/2023/10/05/\345\273\272\347\253\231\346\214\207\345\214\227/index.html" @@ -583,14 +583,14 @@

js动效

站点总字数: - 191k + 194k 站点阅读时长 ≈ - 11:36 + 11:45
diff --git "a/2023/10/06/61b\346\200\273\345\222\214\347\254\224\350\256\260/index.html" "b/2023/10/06/61b\346\200\273\345\222\214\347\254\224\350\256\260/index.html" index 467875698..737acf95a 100644 --- "a/2023/10/06/61b\346\200\273\345\222\214\347\254\224\350\256\260/index.html" +++ "b/2023/10/06/61b\346\200\273\345\222\214\347\254\224\350\256\260/index.html" @@ -780,14 +780,14 @@

作业中的实现(待续)

站点总字数: - 191k + 194k 站点阅读时长 ≈ - 11:36 + 11:45
diff --git a/2023/10/09/numpy/index.html b/2023/10/09/numpy/index.html index 004b79c4b..219103966 100644 --- a/2023/10/09/numpy/index.html +++ b/2023/10/09/numpy/index.html @@ -448,14 +448,14 @@

广播

站点总字数: - 191k + 194k 站点阅读时长 ≈ - 11:36 + 11:45
diff --git a/2023/10/12/sysadmin/index.html b/2023/10/12/sysadmin/index.html index 7a73477ea..979fb15aa 100644 --- a/2023/10/12/sysadmin/index.html +++ b/2023/10/12/sysadmin/index.html @@ -989,14 +989,14 @@

一些小脚本

站点总字数: - 191k + 194k 站点阅读时长 ≈ - 11:36 + 11:45
diff --git "a/2023/10/14/mit6.006\346\200\273\345\222\214\347\254\224\350\256\260/index.html" "b/2023/10/14/mit6.006\346\200\273\345\222\214\347\254\224\350\256\260/index.html" index 35082af3d..a234a0d92 100644 --- "a/2023/10/14/mit6.006\346\200\273\345\222\214\347\254\224\350\256\260/index.html" +++ "b/2023/10/14/mit6.006\346\200\273\345\222\214\347\254\224\350\256\260/index.html" @@ -1255,14 +1255,14 @@

复杂度

站点总字数: - 191k + 194k 站点阅读时长 ≈ - 11:36 + 11:45
diff --git "a/2023/10/14/\350\213\217\345\244\247linux_ppt/index.html" "b/2023/10/14/\350\213\217\345\244\247linux_ppt/index.html" index d88037975..e357fbcd9 100644 --- "a/2023/10/14/\350\213\217\345\244\247linux_ppt/index.html" +++ "b/2023/10/14/\350\213\217\345\244\247linux_ppt/index.html" @@ -1098,14 +1098,14 @@

构建简单的交叉编译环境

站点总字数: - 191k + 194k 站点阅读时长 ≈ - 11:36 + 11:45
diff --git "a/2023/10/14/\350\256\241\347\275\221/index.html" "b/2023/10/14/\350\256\241\347\275\221/index.html" index 0e2f1b22e..009c65968 100644 --- "a/2023/10/14/\350\256\241\347\275\221/index.html" +++ "b/2023/10/14/\350\256\241\347\275\221/index.html" @@ -442,14 +442,14 @@

网络核心

站点总字数: - 191k + 194k 站点阅读时长 ≈ - 11:36 + 11:45
diff --git "a/2023/11/20/mit6.006\344\275\234\344\270\232\350\247\243\346\236\220/index.html" "b/2023/11/20/mit6.006\344\275\234\344\270\232\350\247\243\346\236\220/index.html" index 7e3513032..9ee694481 100644 --- "a/2023/11/20/mit6.006\344\275\234\344\270\232\350\247\243\346\236\220/index.html" +++ "b/2023/11/20/mit6.006\344\275\234\344\270\232\350\247\243\346\236\220/index.html" @@ -552,14 +552,14 @@

电路模拟

站点总字数: - 191k + 194k 站点阅读时长 ≈ - 11:36 + 11:45
diff --git "a/2023/11/29/\350\200\203\347\240\224\346\225\260\346\215\256\347\273\223\346\236\204/index.html" "b/2023/11/29/\350\200\203\347\240\224\346\225\260\346\215\256\347\273\223\346\236\204/index.html" index 2249c4b3c..a8c826633 100644 --- "a/2023/11/29/\350\200\203\347\240\224\346\225\260\346\215\256\347\273\223\346\236\204/index.html" +++ "b/2023/11/29/\350\200\203\347\240\224\346\225\260\346\215\256\347\273\223\346\236\204/index.html" @@ -483,14 +483,14 @@

基本操作

站点总字数: - 191k + 194k 站点阅读时长 ≈ - 11:36 + 11:45
diff --git a/2023/12/03/myproj3/index.html b/2023/12/03/myproj3/index.html index a8832b184..da0fd56de 100644 --- a/2023/12/03/myproj3/index.html +++ b/2023/12/03/myproj3/index.html @@ -2357,14 +2357,14 @@

随机森林模型

站点总字数: - 191k + 194k 站点阅读时长 ≈ - 11:36 + 11:45
diff --git "a/2023/12/03/\350\200\203\347\240\224\346\223\215\344\275\234\347\263\273\347\273\237/index.html" "b/2023/12/03/\350\200\203\347\240\224\346\223\215\344\275\234\347\263\273\347\273\237/index.html" index 01bc80c3a..a45e3e47d 100644 --- "a/2023/12/03/\350\200\203\347\240\224\346\223\215\344\275\234\347\263\273\347\273\237/index.html" +++ "b/2023/12/03/\350\200\203\347\240\224\346\223\215\344\275\234\347\263\273\347\273\237/index.html" @@ -22,18 +22,20 @@ - + - + + + - + @@ -177,7 +179,7 @@ @@ -332,7 +334,7 @@

概论

操作系统:控制管理计算机的硬件,协调控制资源分配,并为应用程序和用户提供接口以供使用

基本特征

-

操作系统的基本特征包括开并发,共享,虚拟和异步

+

操作系统的基本特征包括并发,共享,虚拟和异步

  1. 并发
    并发是指两个或多个事件在同一时间间隔内发生。操作系统的并发性是指计算机系统中同时存在多个运行的程序,因此它具有处理和调度多个程序同时执行的能力。这是通过类似时间片轮转的机制实现的。
    @@ -429,16 +431,18 @@

    历史

  2. 可靠性
    1. -
    2. 其他 网络操作系统把计算机网络中的各台计算机有机地结合起来,提供一种统一、经济而有效的 使用各台计算机的方法,实现各台计算机之间数据的互相传送。网络操作系统最主要的特点是网 络中各种资源的共享及各台计算机之间的通信。
      +

    3. 其他
      +网络操作系统把计算机网络中的各台计算机有机地结合起来,提供一种统一、经济而有效的 使用各台计算机的方法,实现各台计算机之间数据的互相传送。网络操作系统最主要的特点是网 络中各种资源的共享及各台计算机之间的通信。
      分布式计算机系统是由多台计算机组成并满足下列条件的系统:系统中任意两台计算机通过 通信方式交换信息:系统中的每台计算机都具有同等的地位,即没有主机也没有从机:每台计算 机上的资源为所有用户共享:系统中的任意台计算机都可以构成一个子系统,并且还能重构;任 何工作都可以分布在几台计算机上,由它们并行工作、协同完成。用于管理分布式计算机系统的 操作系统称为分布式计算机系统。该系统的主要特点是:分布性和并行性。分布式操作系统与网 络操作系统的本质不同是,分布式操作系统中的若干计算机相互协同完成同一任务。

    4. -
    5. 个人计算机操作系统 个人计算机操作系统是目前使用最广泛的操作系统,它广泛应用于文字处理、电子表格、游戏中,常见的有Windows、Linux和Macintosh等。

    6. +
    7. 个人计算机操作系统
      +个人计算机操作系统是目前使用最广泛的操作系统,它广泛应用于文字处理、电子表格、游戏中,常见的有Windows、Linux和Macintosh等。

    运行环境

    cpu一般执行两种程序,一种是操作系统内核程序,另一种是用户程序,因此对cpu指令需要做区分

    • 特权指令,是指不允许用户直接使用的指令,如I/O指令、置中断指令,存取用于内存保护的寄存器、送程序状态字到程序状态字寄存器等的指令。
    • -
    • 2)非特权指令,是指允许用户直接使用的指令,它不能直接访问系统中的软硬件资源,仅 限子访问用户的地址空间,这也是为了防止用户程序对系统造成破坏。 在具体实现上,将CPU的运行模式划分为用户态(目态)和核心态 (又称管态,内核态)
    • +
    • 非特权指令,是指允许用户直接使用的指令,它不能直接访问系统中的软硬件资源,仅 限子访问用户的地址空间,这也是为了防止用户程序对系统造成破坏。 在具体实现上,将CPU的运行模式划分为用户态(目态)和核心态 (又称管态,内核态)

    内核机制

      @@ -495,6 +499,84 @@

      系统调用

结构

+
    +
  1. 分层法
    +最底层为硬件,最高层为用户接口,每个高层只能调用它向下单层的功能和服务
    +优点: +
      +
    1. 便于调试和验证,由于每层都相对独立,可以隔绝问题,在单层定位问题
    2. +
    3. 易于扩充维护,只要确保层间接口不便,就可以随意修改单层内的模块
    4. +
  2. +
+

问题:1,难于定义各层。2,由于有时需要跨多层调用,额外开销较大,效率较低

+
    +
  1. 模块化 将操作系统定义成各种有自己接口的模块,各模块通过接口进行组合和通信 这样的结构需要保证模块之间的独立性,即:
  2. +
+ +
    +
  1. 宏内核
    +宏内核,指将系统的主要功能模块作为整体运行在核心态,从而为用户程序提供高性能的系统服务。因为各管理模块之间共享信息,能有效利用相互之间的有效特性,所以具有无可比拟的性能优势。
    +主流操作系统都使用了宏内核,但事实上也在逐渐引进微内核技术,成为一种混合结构

  2. +
  3. 微内核
    +微内核构架,是指将内核中最基本的功能保留在内核,而将那些不需要在核心态执行的功能移到用户态执行,从而降低内核的设计复杂性。那些移出内核的操作系统代码根据分层的原则划分成若干服务程序,它们的执行相互独立,交互则都借助于微内核进行通信。 一般可以分为两个部分:

  4. +
+ +

为了实现高可靠性,只有微内核运行在内核态,其余模块都运行在用户态,一个模块的错误不会影响整个系统
+微内核的功能:

+ +

优点:

+ +

微内核结构的主要问题是性能问题,因为需要频繁地在核心态和用户态之间进行切换,操作 系统的执行开销偏大。

+
    +
  1. 外核
    +不同于虚拟机克隆真实机器,另一种策略是对机器进行分区,给每个用户整个资源的一个子集。在底层中,一种称为外核(exokernel)的程序在内核态中运行。它的任务是为虚拟机分配资源,并检查使用这些资源的企图,以确保没有机器会使用他人的资源。每个用户层的虚拟机有自己的操作系统,但资源是受限制的
    +外核机制的优点是减少了映射层。在其他的设计中,每个虚拟机都认为它有自己的磁盘,这样虚拟机监控程序就必须维护一张表格以重映像磁盘地址,有外核就不需要维护这个表格了,并且实现了各个虚拟机之间的安全划分,没有冲突
  2. +
+

引导

+

操作系统引导是指计算机利用CPU运行定程序,通过程序识别硬盘,识别硬盘分区,识别硬盘分区上的操作系统,最后通过程序启动操作系统一环扣一一环地完成上述过程。

+
    +
  1. 激活CPU。激活的CPU读取ROM中的boot程序,将指令寄存器置为BIOS(基本输入/输出系统)的第一条指令,即开始执行BIOS的指令。
  2. +
  3. 硬件自检。启动BIOS程序后,先进行硬件自检,检查硬件是否出现故障。如有故障,主板会发出不同含义的蜂鸣,启动中止:如果没有故障,屏幕会显示CPU、内存、硬盘等信息。
  4. +
  5. 加载带有操作系统的硬盘。硬件自检后,BIOS开始读取BootSequence(通过CMOS里保存的启动顺序,或者通过与用户交互的方式),把控制权交给启动顺序排在第一位的存储设备,然后CPU将该存储设备引导扇区的内容加载到内存中。
  6. +
  7. 加载主引导记录MBR。硬盘以特定的标识符区分引导硬盘和非引导硬盘。如果发现一个存储设备不是可引导盘,就检查下一个存储设备。如无其他启动设备,就会死机。主引导记录MBR的作用是告诉CPU去硬盘的哪个主分区去找操作系统。
  8. +
  9. 扫描硬盘分区表,并加载硬盘活动分区。MBR包含硬盘分区表,硬盘分区表以特定的标识符区分活动分区和非活动分区。主引导记录扫描硬盘分区表,进而识别含有操作系统的硬盘分区(活动分区)。找到硬盘活动分区后,开始加载硬盘活动分区,将控制权交给活动分区。
  10. +
  11. 加载分区引导记录PBR。读取活动分区的第一个扇区,这个扇区称为分区引导记录(PBR),其作用是寻找并激活分区根目录下用于引导操作系统的程序(启动管理器)
  12. +
  13. 加载启动管理器。分区引导记录搜索活动分区中的启动管理器,加载启动管理器
  14. +
  15. 加裁操作系统
  16. +
+

虚拟机

+

虚拟机是一台逻辑计算机,是指利用特殊的虚拟化技术,通过隐藏特定计算平台的实际物理特性,为用户提供抽象的、统一的、模拟的计算环境。有两类虚拟化方法。
+1. 唯一运行在最高特权的程序,它在裸机上运行并且具备多道程序功能。虚拟机管理程序向上层提供若干台虚拟机、这些虚拟机是裸机硬件的精确复制品。由于每台虚拟机都与裸机相同,所以在不同的虚拟机上可以运行任何不同的操作系统。

+

虚拟机作为用户态的一个进程运行,不充许执行敏感指令。然而,虚拟机上的操作系统认为自已运行在内核态(实际上不是),称为虚拟内核态。虚拟机中的用户进程认为自已运行在用户态(实际上确实是)。当虚拟机操作系统执行了一条CPU处于内核态才充许执行的指令时,会陷入虚拟机管理程序。在支持虚拟化的CPU上,虚拟机管理程序检查这条指令是由虚拟机中的操作系统执行的还是由用户程序执行的。如果是前者,虚拟机管理程序将安排这条指令功能的正确执行。否则,虚拟机管理程序将模拟真实硬件面对用户态执行敏感指令时的行为。

+
+
    +
  1. 类似一个依赖宿主机的普通进程,操作系统安装到虚拟磁盘上(其实只是宿主操作系统中的一个文件)。客户操作系统安装完成后,就能启动并运行。 此时,虚拟机管理程序伪装成一台计算机(比如vmware)
  2. +
+

有的教材将第一类虚拟化技术称为裸金属架构,将第二类虚拟化技术称为寄居架构

+
+

进程和线程

+
+
@@ -555,14 +637,14 @@

结构

站点总字数: - 191k + 194k 站点阅读时长 ≈ - 11:36 + 11:45
diff --git a/about/index.html b/about/index.html index 29d1a245c..6defe9609 100644 --- a/about/index.html +++ b/about/index.html @@ -282,14 +282,14 @@

about 站点总字数: - 191k + 194k

diff --git a/archives/2023/09/index.html b/archives/2023/09/index.html index 7a4935f9d..28a9d40ca 100644 --- a/archives/2023/09/index.html +++ b/archives/2023/09/index.html @@ -418,8 +418,8 @@

thinklive

-
@@ -438,8 +438,8 @@

thinklive

-
@@ -477,14 +477,14 @@

thinklive

站点总字数: - 191k + 194k 站点阅读时长 ≈ - 11:36 + 11:45
diff --git a/archives/2023/09/page/2/index.html b/archives/2023/09/page/2/index.html index 760916b47..958dc56a1 100644 --- a/archives/2023/09/page/2/index.html +++ b/archives/2023/09/page/2/index.html @@ -318,8 +318,8 @@

thinklive

-
@@ -338,8 +338,8 @@

thinklive

-
@@ -358,8 +358,8 @@

thinklive

-
@@ -378,8 +378,8 @@

thinklive

-
@@ -477,14 +477,14 @@

thinklive

站点总字数: - 191k + 194k 站点阅读时长 ≈ - 11:36 + 11:45
diff --git a/archives/2023/09/page/3/index.html b/archives/2023/09/page/3/index.html index 709aa0d5d..2864b2fb9 100644 --- a/archives/2023/09/page/3/index.html +++ b/archives/2023/09/page/3/index.html @@ -337,14 +337,14 @@

thinklive

站点总字数: - 191k + 194k 站点阅读时长 ≈ - 11:36 + 11:45
diff --git a/archives/2023/10/index.html b/archives/2023/10/index.html index 2680ab873..41d497c1e 100644 --- a/archives/2023/10/index.html +++ b/archives/2023/10/index.html @@ -434,14 +434,14 @@

thinklive

站点总字数: - 191k + 194k 站点阅读时长 ≈ - 11:36 + 11:45
diff --git a/archives/2023/11/index.html b/archives/2023/11/index.html index 736f6a6f0..f3825a73c 100644 --- a/archives/2023/11/index.html +++ b/archives/2023/11/index.html @@ -314,14 +314,14 @@

thinklive

站点总字数: - 191k + 194k 站点阅读时长 ≈ - 11:36 + 11:45
diff --git a/archives/2023/12/index.html b/archives/2023/12/index.html index ecf76f3d0..21c370dc3 100644 --- a/archives/2023/12/index.html +++ b/archives/2023/12/index.html @@ -314,14 +314,14 @@

thinklive

站点总字数: - 191k + 194k 站点阅读时长 ≈ - 11:36 + 11:45
diff --git a/archives/2023/index.html b/archives/2023/index.html index 9c9ed7061..bb3167b3d 100644 --- a/archives/2023/index.html +++ b/archives/2023/index.html @@ -477,14 +477,14 @@

thinklive

站点总字数: - 191k + 194k 站点阅读时长 ≈ - 11:36 + 11:45
diff --git a/archives/2023/page/2/index.html b/archives/2023/page/2/index.html index 88e43b63e..815bfa2b0 100644 --- a/archives/2023/page/2/index.html +++ b/archives/2023/page/2/index.html @@ -477,14 +477,14 @@

thinklive

站点总字数: - 191k + 194k 站点阅读时长 ≈ - 11:36 + 11:45
diff --git a/archives/2023/page/3/index.html b/archives/2023/page/3/index.html index 3808e9045..6b3a76000 100644 --- a/archives/2023/page/3/index.html +++ b/archives/2023/page/3/index.html @@ -258,8 +258,8 @@

thinklive

-
@@ -278,8 +278,8 @@

thinklive

-
@@ -358,8 +358,8 @@

thinklive

-
@@ -378,8 +378,8 @@

thinklive

-
@@ -398,8 +398,8 @@

thinklive

-
@@ -418,8 +418,8 @@

thinklive

-
@@ -477,14 +477,14 @@

thinklive

站点总字数: - 191k + 194k 站点阅读时长 ≈ - 11:36 + 11:45
diff --git a/archives/2023/page/4/index.html b/archives/2023/page/4/index.html index 187e4e4c6..32f619254 100644 --- a/archives/2023/page/4/index.html +++ b/archives/2023/page/4/index.html @@ -377,14 +377,14 @@

thinklive

站点总字数: - 191k + 194k 站点阅读时长 ≈ - 11:36 + 11:45
diff --git a/archives/index.html b/archives/index.html index 361e87caa..7b3b9d1eb 100644 --- a/archives/index.html +++ b/archives/index.html @@ -477,14 +477,14 @@

thinklive

站点总字数: - 191k + 194k 站点阅读时长 ≈ - 11:36 + 11:45
diff --git a/archives/page/2/index.html b/archives/page/2/index.html index 2cb37afd4..9c9fd8a2c 100644 --- a/archives/page/2/index.html +++ b/archives/page/2/index.html @@ -477,14 +477,14 @@

thinklive

站点总字数: - 191k + 194k 站点阅读时长 ≈ - 11:36 + 11:45
diff --git a/archives/page/3/index.html b/archives/page/3/index.html index 5a68cf737..352c29823 100644 --- a/archives/page/3/index.html +++ b/archives/page/3/index.html @@ -258,8 +258,8 @@

thinklive

-
@@ -278,8 +278,8 @@

thinklive

-
@@ -358,8 +358,8 @@

thinklive

-
@@ -378,8 +378,8 @@

thinklive

-
@@ -398,8 +398,8 @@

thinklive

-
@@ -418,8 +418,8 @@

thinklive

-
@@ -477,14 +477,14 @@

thinklive

站点总字数: - 191k + 194k 站点阅读时长 ≈ - 11:36 + 11:45
diff --git a/archives/page/4/index.html b/archives/page/4/index.html index ecbd71a0f..4712589a1 100644 --- a/archives/page/4/index.html +++ b/archives/page/4/index.html @@ -377,14 +377,14 @@

thinklive

站点总字数: - 191k + 194k 站点阅读时长 ≈ - 11:36 + 11:45
diff --git "a/assets/\350\213\217\345\244\247linux_ppt/Pasted image 20231205144922.png" "b/assets/\350\213\217\345\244\247linux_ppt/Pasted image 20231205144922.png" new file mode 100644 index 0000000000000000000000000000000000000000..5fc7581cc070607b3b8bf9437fa42026d8f1c00f GIT binary patch literal 57310 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 B?Wh0% literal 0 HcmV?d00001 diff --git "a/assets/\350\213\217\345\244\247linux_ppt/Pasted image 20231205151119.png" "b/assets/\350\213\217\345\244\247linux_ppt/Pasted image 20231205151119.png" new file mode 100644 index 0000000000000000000000000000000000000000..863bc5a83819c679e69d3f012165b67ca91ad9cf GIT binary patch literal 44183 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 NVmQ&@sQxUk{{vH#a?=0+ literal 0 HcmV?d00001 diff --git a/atom.xml b/atom.xml index 358e24d6f..9983d4e15 100644 --- a/atom.xml +++ b/atom.xml @@ -6,7 +6,7 @@ - 2023-12-05T06:28:39.541Z + 2023-12-05T08:15:00.391Z https://thinklive1.github.io/ @@ -21,15 +21,15 @@ https://thinklive1.github.io/2023/12/03/%E8%80%83%E7%A0%94%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/ 2023-12-03T15:35:54.425Z - 2023-12-05T06:28:39.541Z + 2023-12-05T08:15:00.391Z - 概论

操作系统:控制管理计算机的硬件,协调控制资源分配,并为应用程序和用户提供接口以供使用

基本特征

操作系统的基本特征包括开并发,共享,虚拟和异步

  1. 并发
    并发是指两个或多个事件在同一时间间隔内发生。操作系统的并发性是指计算机系统中同时存在多个运行的程序,因此它具有处理和调度多个程序同时执行的能力。这是通过类似时间片轮转的机制实现的。
    并行性是指系统具有同时进行运算或操作的特性,在同一时刻能完成两种或两种以上的动作并行性要有相关硬件的支持, 如多流水线或多处理机硬件环境

  2. 共享
    共享:系统内的某些资源可以供并发的不同进程使用,分为以下几种方式

    1. 互斥共享 规定在一段时间内只充许 一个进程访问该资源,系统分配该资源前,必须确保没有其他进程正在使用它,分配后,在进程访问并释放该资源后,其他进程对资源的申请才会被操作系统允许。
      这种一段时间内只能被一个进程占有的资源被称为临界资源
      大部分硬件,某些软件的栈,变量等都属于临界资源
    2. 同时访问 某些系统资源可以在同一时间段内被多个进程同时访问,例如文件系统,这种同时访问可能是交替进行。
      互斥共享要求一种资源在一段时间内(哪怕是一段很小的时间)只能满足一个请求,同时访问通常要求一个请求可以分时间片间隔地完成,效果和连续完成相同

并发和共享是操作系统两个最基本的特征,两者之间互为存在的条件:

  • 资源共享是以程序的并发为条件的:若系统不充许程序并发执行,则自然不存在资源共享问题
  • 若系统不能对资源共享实施有效的管理,则必将影响到程序的并发执行,其至根本无法并发执行。
  1. 虚拟
    虚拟是指把一个物理上的实体变为若干逻辑上的对应物。
    虚拟处理器技术是通过多道程序设计技术,采用让多道程序并发执行的方法,来分时使用一 个处理器的。此时,虽然只有一个处理器,但它能同时为多个用户服务
    把一个物理cpu虚拟成多个虚拟cpu,称为虚拟处理器
    虚拟技术可以在时间或者空间上进行相应的现实虚拟转换

  2. 异步
    虽然进程可以并发进行,但推进速度,时间等是不确定的,操作系统必须确保,相同环境下相同操作的进程得到相同的结果,不论时间多久

功能

  1. 管理系统资源
    1. 处理机(进程)的管理,包括创建,调度,死锁检测和恢复等
    2. 存储器管理,即内存的分配和管理
    3. 文件管理,即操作系统的文件系统空间,目录,格式等
    4. 设备管理,处理用户的I/O请求
  2. 提供用户接口操作硬件和程序
    1. 命令接口
      1. 联机命令接口(交互式命令接口,适用于实时或分时系统):用户通过终端实时输入命令与操作系统交换,输入一条,操作系统解释并执行一条,然后才可以输入下一条(shell)
      2. 脱机命令接口(批处理命令接口,适用于批处理系统):用作业控制命令写成一本作业说明书,操作系统读取说明书,逐条解释执行 (脚本)
    2. 程序接口:有一系列系统调用组成,,用户在程序中使用这些系统调用命令来让操作系统提供相应服务,例如GUI界面(严格的说gui界面只是使用了操作系统提供的图形相关的系统调用)
  3. 实现了对计算机资源的扩充

历史

  1. 手工操作阶段
    缺点:1,cpu利用不充分。2,计算机资源利用率低下
  2. 批处理阶段
    1. 单道批处理系统:操作系统一次只执行一个程序,依次处理,特征:
      1. 自动性,磁带上的作业可以自动依次进行
      2. 顺序性,作业有明确顺序依次进入内存
      3. 单道性,内存中只有一个程序运行,任务完成或异常后才调入下一个 问题:任务间隔等待下一个调入时,I/O效率低下
    2. 多道批处理程序,内存中可以有多个程序共享系统资源,交替运行,避免I/O期间的算力浪费,特点是:
      1. 多道,内存存放多道程序
      2. 宏观上并行,内存中的程序都处于运行状态
      3. 微观上串行,程序交替使用cpu

问题:处理器资源,内存资源和I/O的分配,以及如何组织处理大量的程序和数据 在批处理系统中采用多道程序设计技术就形成了多道批处理操作系统。该系统把用户提交的 作业成批地送入计算机内存,然后由作业调度程序自动地选择作业运行。

  • 优点:资源利用率高,多道程序共享计算机资源,从而使各种资源得到充分利用:系统吞吐量大,CPU和其他资源保持“忙碌”状态。
  • 缺点:用户响应的时间较长:不提供人机交互能力, 用户既不能了解自已的程序的运行情况,又不能控制计算机。
  1. 分时操作系统 所谓分时技术,是指把处理器的运行时间分成很短的时间片,按时间片轮流把处理器分配给各联机作业使用。若某个作业在分配给它的时间片内不能完成其计算,则该作业暂时停止运行, 把处理器让给其他作业使用,等待下一轮再继续运行。由于计算机速度很快,作业运行轮转得也很快,因此给每个用户的感觉就像是自己已独占一台计算机。
    分时操作系统是指多个用户通过终端同时共享一台主机,这些终端连接在主机上,用户可以同时与主机进行交互操作而互不干扰,同时有较快的交互速度
    特性:

    1. 同时性,允许多个用户同时使用一台计算机(多终端)
    2. 交互性
    3. 独立性,各个用户相对独立,不会互相影响
    4. 及时性,对用户请求用较快的速度回应
  2. 实时操作系统 一些特殊场合(比如飞行器系统),对操作的时限有硬性要求(或者软性要求),这样的操作系统叫做实时操作系统
    其中绝对无法违反时限的是硬实时系统,偶尔可以违反的是软实时系统
    特点:

  • 及时性
  • 可靠性
  1. 其他 网络操作系统把计算机网络中的各台计算机有机地结合起来,提供一种统一、经济而有效的 使用各台计算机的方法,实现各台计算机之间数据的互相传送。网络操作系统最主要的特点是网 络中各种资源的共享及各台计算机之间的通信。
    分布式计算机系统是由多台计算机组成并满足下列条件的系统:系统中任意两台计算机通过 通信方式交换信息:系统中的每台计算机都具有同等的地位,即没有主机也没有从机:每台计算 机上的资源为所有用户共享:系统中的任意台计算机都可以构成一个子系统,并且还能重构;任 何工作都可以分布在几台计算机上,由它们并行工作、协同完成。用于管理分布式计算机系统的 操作系统称为分布式计算机系统。该系统的主要特点是:分布性和并行性。分布式操作系统与网 络操作系统的本质不同是,分布式操作系统中的若干计算机相互协同完成同一任务。

  2. 个人计算机操作系统 个人计算机操作系统是目前使用最广泛的操作系统,它广泛应用于文字处理、电子表格、游戏中,常见的有Windows、Linux和Macintosh等。

运行环境

cpu一般执行两种程序,一种是操作系统内核程序,另一种是用户程序,因此对cpu指令需要做区分

  • 特权指令,是指不允许用户直接使用的指令,如I/O指令、置中断指令,存取用于内存保护的寄存器、送程序状态字到程序状态字寄存器等的指令。
  • 2)非特权指令,是指允许用户直接使用的指令,它不能直接访问系统中的软硬件资源,仅 限子访问用户的地址空间,这也是为了防止用户程序对系统造成破坏。 在具体实现上,将CPU的运行模式划分为用户态(目态)和核心态 (又称管态,内核态)

内核机制

  1. 时钟管理,提供计时功能,是时间片轮转,实时系统的截止时间等功能的基础
  2. 中断机制,操作系统的大部分功能都依赖中断,可以说现代操作系统是中断驱动的,中断机制只有一小部分属于内核,负责保护和恢复现场等
  3. 原语,操作系统的底层小程序,有以下特点
    1. 最底层,最接/近硬件
    2. 操作有原子性,不可分割
    3. 运行时间短调用频繁
  4. 系统控制的数据结构和处理,常见操作有
    1. 进程管理
    2. 存储器管理
    3. 设备管理

中断和异常

由于用户态的某些操作需要核心态的一些功能,需要中断和异常机制,来让cpu从用户态进入核心态(这通过硬件实现,比如一个特殊寄存器)
中断(Interruption)也称外中断,是指来自CPU执行指令外部的事件,通常用于信息输入/ 输出,如设备发出的I/O结束中断,表示设备输入/输出处理已经完成。时钟中断,表示一个固定 的时间片已到,让处理机处理计时、启动定时运行的任务等
异常(Exception)也称内中断,是指来自CPU执行指令内部的事件,如程序的非法操作码、地址越界、运算溢出、虚存系统的缺负及专门的陷入指令等引起的事件。异常不能被屏蔽,一出现,就应立即处理。
二者的分类如图,其中故障(Fault)通常是由指令执行引起的异常,如非法操作码, 缺页故障、除数为0、运算溢出等。自陷(Trap)是一种事先安排的“异常”事件,用于在用户态下调用操作系统内核程序。终止(Abort)是指出现了使得CPU无法继续执行的硬件故障,如控制器出错、存储器校验错等。故障异常和自陷异常属于软件中断(程序性异常,终止异常和外部中断属于硬件中断。

中断处理流程:操作系统发现中断请求或者异常后,打断当前程序,调转到中断或者异常的处理程序,如果程序能解决问题,就再次回到现场继续执行,如果是致命错误,则终止程序

系统调用

一般涉及对系统资源的请求,都需要系统调用,系统调用可以视为一种特殊的公共子程序 常见类型:

  • 设备管理。完成设备的请求或释放,以及设备启动等功能。
  • 文件管理。完成文件的读、写、创建及删除等功能。
  • 进程控制。完成进程的创建、撤销、阻塞及唤醒等功能。
  • 进程通信。完成进程之间的消息传递或信号传递等功能。
  • 内存管理。完成内存的分配、回收以及获取作业占用内存区大小及始址等功能

用户程序可以执行陷入指令(又称访管指令或trap指令)来发起系统调用,此时相当于cpu使用权被交给内核,来让cpu进入核心态执行特权指令,最后结果和cpu返还给程序 当需要管理程序服务时,系统则通过硬件中断机制进入核心态,运行管理程序:也可能是程序运行出现异常情况,被动地需要管理程序的服务,这时就通过异常处理来进入核心态。管理程序运行结束时,用户程序需要继续运行,此时通过相应的保存的程序现场退出中断处理程序或异常处理程序,返回断点处继续执行

执行系统调用的过程如下:正在运行的进程先传递系统调用参数,然后由陷入(trap)指令负责将用户态转换为内核态,并将返回地址压入堆栈以备后用,接下来CPU执行相应的内核态服务程序,最后返回用户态。

注意:

  • 由用户态进入核心态,不仅状态需要切换,而且所用的堆栈也可能需要由用户堆栈切换为系统堆栈,但这个系统堆栈也是属于该进程的,此外,这个转变是硬件完成的,核心态到用户态则是操作系统完成
  • (访管指令在用户态使用,因此不是特权指令)
  • 输入输出这种涉及到中断机制的指令,必须在核心态执行
  • 命令解释这种与用户交互的程序在用户态执行,而进程调度则需要核心态(单个用户不应能影响进程这样的全局状态,否则就可以只让自己的进程优先执行)
  • 一般来说,中断处理除了保留现场,还需要用一个寄存器存储程序的状态字
  • 外部中断时,通用寄存器由操作系统保存,PC(程序计数器)则由中断指令自动保存
  • 时钟中断后,服务程序应当更新内核中时钟变量的值,当前进程占用CPU的时间,当前进程在时间片内的剩余执行时间等全部时钟相关的数据
  • 操作系统通过提供系统调用避免用户程序直接访问外设
  • 当CPU检测到中断信号后,由硬件自动保存被中断程序的断点(即程序计数器PC),之后,硬件找到该中断信号对应的中断向量,中断向量指明中断服务程序入口地址(各中断向量保存PSW、保存中断屏蔽字、保存各通用寄存器的值,并提供与中断信号对应的中断服务,中断服务程序属于操作系统内核
  • 能在内核态下执行。常见的特权指令有:
    • 有关对IO设备操作的指令
    • 有关访问程序状态的指令
    • 存取特殊寄存器的指令
  • 通道技术和中断技术结合起来就可实现CPU与I/O设备并行工作,即CPU启动通道传输数据后便进行其他程序的计算工作,而通道则进行输入输出操作;通道工作结束后,通过中断让cpu进行处理,处理完再各自进行对应的工作

结构

]]>
+ 概论

操作系统:控制管理计算机的硬件,协调控制资源分配,并为应用程序和用户提供接口以供使用

基本特征

操作系统的基本特征包括并发,共享,虚拟和异步

  1. 并发
    并发是指两个或多个事件在同一时间间隔内发生。操作系统的并发性是指计算机系统中同时存在多个运行的程序,因此它具有处理和调度多个程序同时执行的能力。这是通过类似时间片轮转的机制实现的。
    并行性是指系统具有同时进行运算或操作的特性,在同一时刻能完成两种或两种以上的动作并行性要有相关硬件的支持, 如多流水线或多处理机硬件环境

  2. 共享
    共享:系统内的某些资源可以供并发的不同进程使用,分为以下几种方式

    1. 互斥共享 规定在一段时间内只充许 一个进程访问该资源,系统分配该资源前,必须确保没有其他进程正在使用它,分配后,在进程访问并释放该资源后,其他进程对资源的申请才会被操作系统允许。
      这种一段时间内只能被一个进程占有的资源被称为临界资源
      大部分硬件,某些软件的栈,变量等都属于临界资源
    2. 同时访问 某些系统资源可以在同一时间段内被多个进程同时访问,例如文件系统,这种同时访问可能是交替进行。
      互斥共享要求一种资源在一段时间内(哪怕是一段很小的时间)只能满足一个请求,同时访问通常要求一个请求可以分时间片间隔地完成,效果和连续完成相同

并发和共享是操作系统两个最基本的特征,两者之间互为存在的条件:

  • 资源共享是以程序的并发为条件的:若系统不充许程序并发执行,则自然不存在资源共享问题
  • 若系统不能对资源共享实施有效的管理,则必将影响到程序的并发执行,其至根本无法并发执行。
  1. 虚拟
    虚拟是指把一个物理上的实体变为若干逻辑上的对应物。
    虚拟处理器技术是通过多道程序设计技术,采用让多道程序并发执行的方法,来分时使用一 个处理器的。此时,虽然只有一个处理器,但它能同时为多个用户服务
    把一个物理cpu虚拟成多个虚拟cpu,称为虚拟处理器
    虚拟技术可以在时间或者空间上进行相应的现实虚拟转换

  2. 异步
    虽然进程可以并发进行,但推进速度,时间等是不确定的,操作系统必须确保,相同环境下相同操作的进程得到相同的结果,不论时间多久

功能

  1. 管理系统资源
    1. 处理机(进程)的管理,包括创建,调度,死锁检测和恢复等
    2. 存储器管理,即内存的分配和管理
    3. 文件管理,即操作系统的文件系统空间,目录,格式等
    4. 设备管理,处理用户的I/O请求
  2. 提供用户接口操作硬件和程序
    1. 命令接口
      1. 联机命令接口(交互式命令接口,适用于实时或分时系统):用户通过终端实时输入命令与操作系统交换,输入一条,操作系统解释并执行一条,然后才可以输入下一条(shell)
      2. 脱机命令接口(批处理命令接口,适用于批处理系统):用作业控制命令写成一本作业说明书,操作系统读取说明书,逐条解释执行 (脚本)
    2. 程序接口:有一系列系统调用组成,,用户在程序中使用这些系统调用命令来让操作系统提供相应服务,例如GUI界面(严格的说gui界面只是使用了操作系统提供的图形相关的系统调用)
  3. 实现了对计算机资源的扩充

历史

  1. 手工操作阶段
    缺点:1,cpu利用不充分。2,计算机资源利用率低下
  2. 批处理阶段
    1. 单道批处理系统:操作系统一次只执行一个程序,依次处理,特征:
      1. 自动性,磁带上的作业可以自动依次进行
      2. 顺序性,作业有明确顺序依次进入内存
      3. 单道性,内存中只有一个程序运行,任务完成或异常后才调入下一个 问题:任务间隔等待下一个调入时,I/O效率低下
    2. 多道批处理程序,内存中可以有多个程序共享系统资源,交替运行,避免I/O期间的算力浪费,特点是:
      1. 多道,内存存放多道程序
      2. 宏观上并行,内存中的程序都处于运行状态
      3. 微观上串行,程序交替使用cpu

问题:处理器资源,内存资源和I/O的分配,以及如何组织处理大量的程序和数据 在批处理系统中采用多道程序设计技术就形成了多道批处理操作系统。该系统把用户提交的 作业成批地送入计算机内存,然后由作业调度程序自动地选择作业运行。

  • 优点:资源利用率高,多道程序共享计算机资源,从而使各种资源得到充分利用:系统吞吐量大,CPU和其他资源保持“忙碌”状态。
  • 缺点:用户响应的时间较长:不提供人机交互能力, 用户既不能了解自已的程序的运行情况,又不能控制计算机。
  1. 分时操作系统 所谓分时技术,是指把处理器的运行时间分成很短的时间片,按时间片轮流把处理器分配给各联机作业使用。若某个作业在分配给它的时间片内不能完成其计算,则该作业暂时停止运行, 把处理器让给其他作业使用,等待下一轮再继续运行。由于计算机速度很快,作业运行轮转得也很快,因此给每个用户的感觉就像是自己已独占一台计算机。
    分时操作系统是指多个用户通过终端同时共享一台主机,这些终端连接在主机上,用户可以同时与主机进行交互操作而互不干扰,同时有较快的交互速度
    特性:

    1. 同时性,允许多个用户同时使用一台计算机(多终端)
    2. 交互性
    3. 独立性,各个用户相对独立,不会互相影响
    4. 及时性,对用户请求用较快的速度回应
  2. 实时操作系统 一些特殊场合(比如飞行器系统),对操作的时限有硬性要求(或者软性要求),这样的操作系统叫做实时操作系统
    其中绝对无法违反时限的是硬实时系统,偶尔可以违反的是软实时系统
    特点:

  • 及时性
  • 可靠性
  1. 其他
    网络操作系统把计算机网络中的各台计算机有机地结合起来,提供一种统一、经济而有效的 使用各台计算机的方法,实现各台计算机之间数据的互相传送。网络操作系统最主要的特点是网 络中各种资源的共享及各台计算机之间的通信。
    分布式计算机系统是由多台计算机组成并满足下列条件的系统:系统中任意两台计算机通过 通信方式交换信息:系统中的每台计算机都具有同等的地位,即没有主机也没有从机:每台计算 机上的资源为所有用户共享:系统中的任意台计算机都可以构成一个子系统,并且还能重构;任 何工作都可以分布在几台计算机上,由它们并行工作、协同完成。用于管理分布式计算机系统的 操作系统称为分布式计算机系统。该系统的主要特点是:分布性和并行性。分布式操作系统与网 络操作系统的本质不同是,分布式操作系统中的若干计算机相互协同完成同一任务。

  2. 个人计算机操作系统
    个人计算机操作系统是目前使用最广泛的操作系统,它广泛应用于文字处理、电子表格、游戏中,常见的有Windows、Linux和Macintosh等。

运行环境

cpu一般执行两种程序,一种是操作系统内核程序,另一种是用户程序,因此对cpu指令需要做区分

  • 特权指令,是指不允许用户直接使用的指令,如I/O指令、置中断指令,存取用于内存保护的寄存器、送程序状态字到程序状态字寄存器等的指令。
  • 非特权指令,是指允许用户直接使用的指令,它不能直接访问系统中的软硬件资源,仅 限子访问用户的地址空间,这也是为了防止用户程序对系统造成破坏。 在具体实现上,将CPU的运行模式划分为用户态(目态)和核心态 (又称管态,内核态)

内核机制

  1. 时钟管理,提供计时功能,是时间片轮转,实时系统的截止时间等功能的基础
  2. 中断机制,操作系统的大部分功能都依赖中断,可以说现代操作系统是中断驱动的,中断机制只有一小部分属于内核,负责保护和恢复现场等
  3. 原语,操作系统的底层小程序,有以下特点
    1. 最底层,最接/近硬件
    2. 操作有原子性,不可分割
    3. 运行时间短调用频繁
  4. 系统控制的数据结构和处理,常见操作有
    1. 进程管理
    2. 存储器管理
    3. 设备管理

中断和异常

由于用户态的某些操作需要核心态的一些功能,需要中断和异常机制,来让cpu从用户态进入核心态(这通过硬件实现,比如一个特殊寄存器)
中断(Interruption)也称外中断,是指来自CPU执行指令外部的事件,通常用于信息输入/ 输出,如设备发出的I/O结束中断,表示设备输入/输出处理已经完成。时钟中断,表示一个固定 的时间片已到,让处理机处理计时、启动定时运行的任务等
异常(Exception)也称内中断,是指来自CPU执行指令内部的事件,如程序的非法操作码、地址越界、运算溢出、虚存系统的缺负及专门的陷入指令等引起的事件。异常不能被屏蔽,一出现,就应立即处理。
二者的分类如图,其中故障(Fault)通常是由指令执行引起的异常,如非法操作码, 缺页故障、除数为0、运算溢出等。自陷(Trap)是一种事先安排的“异常”事件,用于在用户态下调用操作系统内核程序。终止(Abort)是指出现了使得CPU无法继续执行的硬件故障,如控制器出错、存储器校验错等。故障异常和自陷异常属于软件中断(程序性异常,终止异常和外部中断属于硬件中断。

中断处理流程:操作系统发现中断请求或者异常后,打断当前程序,调转到中断或者异常的处理程序,如果程序能解决问题,就再次回到现场继续执行,如果是致命错误,则终止程序

系统调用

一般涉及对系统资源的请求,都需要系统调用,系统调用可以视为一种特殊的公共子程序 常见类型:

  • 设备管理。完成设备的请求或释放,以及设备启动等功能。
  • 文件管理。完成文件的读、写、创建及删除等功能。
  • 进程控制。完成进程的创建、撤销、阻塞及唤醒等功能。
  • 进程通信。完成进程之间的消息传递或信号传递等功能。
  • 内存管理。完成内存的分配、回收以及获取作业占用内存区大小及始址等功能

用户程序可以执行陷入指令(又称访管指令或trap指令)来发起系统调用,此时相当于cpu使用权被交给内核,来让cpu进入核心态执行特权指令,最后结果和cpu返还给程序 当需要管理程序服务时,系统则通过硬件中断机制进入核心态,运行管理程序:也可能是程序运行出现异常情况,被动地需要管理程序的服务,这时就通过异常处理来进入核心态。管理程序运行结束时,用户程序需要继续运行,此时通过相应的保存的程序现场退出中断处理程序或异常处理程序,返回断点处继续执行

执行系统调用的过程如下:正在运行的进程先传递系统调用参数,然后由陷入(trap)指令负责将用户态转换为内核态,并将返回地址压入堆栈以备后用,接下来CPU执行相应的内核态服务程序,最后返回用户态。

注意:

  • 由用户态进入核心态,不仅状态需要切换,而且所用的堆栈也可能需要由用户堆栈切换为系统堆栈,但这个系统堆栈也是属于该进程的,此外,这个转变是硬件完成的,核心态到用户态则是操作系统完成
  • (访管指令在用户态使用,因此不是特权指令)
  • 输入输出这种涉及到中断机制的指令,必须在核心态执行
  • 命令解释这种与用户交互的程序在用户态执行,而进程调度则需要核心态(单个用户不应能影响进程这样的全局状态,否则就可以只让自己的进程优先执行)
  • 一般来说,中断处理除了保留现场,还需要用一个寄存器存储程序的状态字
  • 外部中断时,通用寄存器由操作系统保存,PC(程序计数器)则由中断指令自动保存
  • 时钟中断后,服务程序应当更新内核中时钟变量的值,当前进程占用CPU的时间,当前进程在时间片内的剩余执行时间等全部时钟相关的数据
  • 操作系统通过提供系统调用避免用户程序直接访问外设
  • 当CPU检测到中断信号后,由硬件自动保存被中断程序的断点(即程序计数器PC),之后,硬件找到该中断信号对应的中断向量,中断向量指明中断服务程序入口地址(各中断向量保存PSW、保存中断屏蔽字、保存各通用寄存器的值,并提供与中断信号对应的中断服务,中断服务程序属于操作系统内核
  • 能在内核态下执行。常见的特权指令有:
    • 有关对IO设备操作的指令
    • 有关访问程序状态的指令
    • 存取特殊寄存器的指令
  • 通道技术和中断技术结合起来就可实现CPU与I/O设备并行工作,即CPU启动通道传输数据后便进行其他程序的计算工作,而通道则进行输入输出操作;通道工作结束后,通过中断让cpu进行处理,处理完再各自进行对应的工作

结构

  1. 分层法
    最底层为硬件,最高层为用户接口,每个高层只能调用它向下单层的功能和服务
    优点:
    1. 便于调试和验证,由于每层都相对独立,可以隔绝问题,在单层定位问题
    2. 易于扩充维护,只要确保层间接口不便,就可以随意修改单层内的模块

问题:1,难于定义各层。2,由于有时需要跨多层调用,额外开销较大,效率较低

  1. 模块化 将操作系统定义成各种有自己接口的模块,各模块通过接口进行组合和通信 这样的结构需要保证模块之间的独立性,即:
  • 内聚性,模块内部各部分间联系的紧密程度。内聚性越高,模块独立性越好。
  • 耦合度,模块间相互联系和相互影响的程度。耦合度越低,模块独立性越好。 模块化的优点:①提高了操作系统设计的正确性、可理解性和可维护性:②增强了操作系统 的可适应性:③加速了操作系统的开发过程。 模块化的缺点:①模块间的接口规定很难满足对接口的实际需求。②各模块设计者齐头并进 每个决定无法建立在上一个已验证的正确决定的基础上,因此无法找到一个可靠的决定顺序。
  1. 宏内核
    宏内核,指将系统的主要功能模块作为整体运行在核心态,从而为用户程序提供高性能的系统服务。因为各管理模块之间共享信息,能有效利用相互之间的有效特性,所以具有无可比拟的性能优势。
    主流操作系统都使用了宏内核,但事实上也在逐渐引进微内核技术,成为一种混合结构

  2. 微内核
    微内核构架,是指将内核中最基本的功能保留在内核,而将那些不需要在核心态执行的功能移到用户态执行,从而降低内核的设计复杂性。那些移出内核的操作系统代码根据分层的原则划分成若干服务程序,它们的执行相互独立,交互则都借助于微内核进行通信。 一般可以分为两个部分:

  • 微内核,实现操作系统最基本核心功能的小型内核
    • 与硬件紧密相关的功能
    • 基本功能
    • 客户和服务器的通信
  • 多个服务器

为了实现高可靠性,只有微内核运行在内核态,其余模块都运行在用户态,一个模块的错误不会影响整个系统
微内核的功能:

  • 进程(线程)管理:进程的通信,切换,调度,多处理器的同步等都应该放入微内核,但进程分类,优先级确定等不涉及机制的功能可以放入进程管理服务器
  • 低级存储器管理:比如页表机制和地址变换机制,而虚拟存储器的管理,页面置换算法等则有存储器管理服务器管理
  • 中断和陷入处理,捕获相关事件,进行中断响应处理,然后发送给相关服务器来处理

优点:

  • 拓展性和灵活性
  • 可靠性和安全性
  • 可移植性(和硬件有关的都在微内核中,其他服务器和硬件无关)
  • 分布式计算,通信采用消息传递机制,很好的支持分布式系统和网络系统

微内核结构的主要问题是性能问题,因为需要频繁地在核心态和用户态之间进行切换,操作 系统的执行开销偏大。

  1. 外核
    不同于虚拟机克隆真实机器,另一种策略是对机器进行分区,给每个用户整个资源的一个子集。在底层中,一种称为外核(exokernel)的程序在内核态中运行。它的任务是为虚拟机分配资源,并检查使用这些资源的企图,以确保没有机器会使用他人的资源。每个用户层的虚拟机有自己的操作系统,但资源是受限制的
    外核机制的优点是减少了映射层。在其他的设计中,每个虚拟机都认为它有自己的磁盘,这样虚拟机监控程序就必须维护一张表格以重映像磁盘地址,有外核就不需要维护这个表格了,并且实现了各个虚拟机之间的安全划分,没有冲突

引导

操作系统引导是指计算机利用CPU运行定程序,通过程序识别硬盘,识别硬盘分区,识别硬盘分区上的操作系统,最后通过程序启动操作系统一环扣一一环地完成上述过程。

  1. 激活CPU。激活的CPU读取ROM中的boot程序,将指令寄存器置为BIOS(基本输入/输出系统)的第一条指令,即开始执行BIOS的指令。
  2. 硬件自检。启动BIOS程序后,先进行硬件自检,检查硬件是否出现故障。如有故障,主板会发出不同含义的蜂鸣,启动中止:如果没有故障,屏幕会显示CPU、内存、硬盘等信息。
  3. 加载带有操作系统的硬盘。硬件自检后,BIOS开始读取BootSequence(通过CMOS里保存的启动顺序,或者通过与用户交互的方式),把控制权交给启动顺序排在第一位的存储设备,然后CPU将该存储设备引导扇区的内容加载到内存中。
  4. 加载主引导记录MBR。硬盘以特定的标识符区分引导硬盘和非引导硬盘。如果发现一个存储设备不是可引导盘,就检查下一个存储设备。如无其他启动设备,就会死机。主引导记录MBR的作用是告诉CPU去硬盘的哪个主分区去找操作系统。
  5. 扫描硬盘分区表,并加载硬盘活动分区。MBR包含硬盘分区表,硬盘分区表以特定的标识符区分活动分区和非活动分区。主引导记录扫描硬盘分区表,进而识别含有操作系统的硬盘分区(活动分区)。找到硬盘活动分区后,开始加载硬盘活动分区,将控制权交给活动分区。
  6. 加载分区引导记录PBR。读取活动分区的第一个扇区,这个扇区称为分区引导记录(PBR),其作用是寻找并激活分区根目录下用于引导操作系统的程序(启动管理器)
  7. 加载启动管理器。分区引导记录搜索活动分区中的启动管理器,加载启动管理器
  8. 加裁操作系统

虚拟机

虚拟机是一台逻辑计算机,是指利用特殊的虚拟化技术,通过隐藏特定计算平台的实际物理特性,为用户提供抽象的、统一的、模拟的计算环境。有两类虚拟化方法。
1. 唯一运行在最高特权的程序,它在裸机上运行并且具备多道程序功能。虚拟机管理程序向上层提供若干台虚拟机、这些虚拟机是裸机硬件的精确复制品。由于每台虚拟机都与裸机相同,所以在不同的虚拟机上可以运行任何不同的操作系统。

虚拟机作为用户态的一个进程运行,不充许执行敏感指令。然而,虚拟机上的操作系统认为自已运行在内核态(实际上不是),称为虚拟内核态。虚拟机中的用户进程认为自已运行在用户态(实际上确实是)。当虚拟机操作系统执行了一条CPU处于内核态才充许执行的指令时,会陷入虚拟机管理程序。在支持虚拟化的CPU上,虚拟机管理程序检查这条指令是由虚拟机中的操作系统执行的还是由用户程序执行的。如果是前者,虚拟机管理程序将安排这条指令功能的正确执行。否则,虚拟机管理程序将模拟真实硬件面对用户态执行敏感指令时的行为。

  1. 类似一个依赖宿主机的普通进程,操作系统安装到虚拟磁盘上(其实只是宿主操作系统中的一个文件)。客户操作系统安装完成后,就能启动并运行。 此时,虚拟机管理程序伪装成一台计算机(比如vmware)

有的教材将第一类虚拟化技术称为裸金属架构,将第二类虚拟化技术称为寄居架构


进程和线程

]]>
<h1 id="概论">概论</h1> <p><code>操作系统</code>:控制管理计算机的硬件,协调控制资源分配,并为应用程序和用户提供接口以供使用</p> <h2 id="基本特征">基本特征</h2> -<p><code>操作系统</code>的基本特征包括开并发,共享,虚拟和异步</p> +<p><code>操作系统</code>的基本特征包括并发,共享,虚拟和异步</p> <ol type="1"> <li><p>并发<br /> <code>并发</code>是指两个或多个事件在同一时间间隔内发生。操作系统的并发性是指计算机系统中同时存在多个运行的程序,因此它具有处理和调度多个程序同时执行的能力。这是通过类似时间片轮转的机制实现的。<br /> @@ -401,66 +401,66 @@ - 基于伯克利ds100和cs231n的numpy笔记 - - https://thinklive1.github.io/2023/10/09/numpy/ - 2023-10-09T12:02:04.679Z + 基于伯克利Sysadmin decal的linux笔记 + + https://thinklive1.github.io/2023/10/12/sysadmin/ + 2023-10-12T12:54:12.472Z 2023-11-27T12:50:13.887Z - Numpy 是 Python 中科学计算的核心库。 它提供了高性能的多维数组对象以及使用这些对象的工具 数组。

数组

numpy 数组是一个值网格,所有值都具有相同的类型,并由非负整数组成的元组索引。 它的维度就是数组的秩 ;它的shape就是每个维度的大小组成的元组

1
2
3
b = np.array([[1,2,3],[4,5,6]])    # Create a rank 2 array
print(b.shape) # Prints "(2, 3)"
print(b[0, 0], b[0, 1], b[1, 0]) # Prints "1 2 4"

官方数组创建教程 ds100的numpy教程 cs231n的python numpy教程

创建数组的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
>>>np.array([[1.,2.], [3.,4.]])

array([[ 1., 2.],
[ 3., 4.]])

>>>np.array([x for x in range(5)])

array([0, 1, 2, 3, 4])

>>>np.array([["A", "matrix"], ["of", "words."]])

array([['A', 'matrix'],
['of', 'words.']],
dtype='<U6')

>>>np.ones([3,2])

array([[ 1., 1.],
[ 1., 1.],
[ 1., 1.]])

>>>np.random.randn(3,2)

array([[ 0.3601399 , 1.31206686],
[-0.95112397, 0.62475726],
[-1.24179768, 1.63392069]])

1
2
3
4
5
6
7
>>>c = np.full((2,2), 7)  # Create a constant array
print(c) # Prints "[[ 7. 7.]
# [ 7. 7.]]"

>>>d = np.eye(2) # Create a 2x2 identity matrix
print(d) # Prints "[[ 1. 0.]
# [ 0. 1.]]"

数组属性

  • dtype
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
>>>np.arange(1,5).dtype

dtype('int64')

>>>np.array(["Hello", "Worlddddd!"]).dtype

dtype('<U10')
/*
What does `<U6` mean?
- `<` Little Endian
- `U` Unicode
- `6` length of longest string
*/

>>> np.array([1,2,3]).astype(float)

array([ 1., 2., 3.])

数组的类型与其包含的数据类型相对应,可以用.astype改变类型

数组编辑

重组和展开

1
2
3
4
5
6
7
8
9
>>>np.arange(1,13).reshape(4,3)

array([[ 1, 2, 3],
[ 4, 5, 6],
[ 7, 8, 9],
[10, 11, 12]])

>>>A.flatten()
array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])

切片索引和整数索引

切片时,第一个参数是行,第二个是列,切片形成的是对原来数组的引用,修改子数组也会影响原数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Create the following rank 2 array with shape (3, 4)
# [[ 1 2 3 4]
# [ 5 6 7 8]
# [ 9 10 11 12]]
a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])

# Use slicing to pull out the subarray consisting of the first 2 rows
# and columns 1 and 2; b is the following array of shape (2, 2):
# [[2 3]
# [6 7]]
b = a[:2, 1:3]

# A slice of an array is a view into the same data, so modifying it
# will modify the original array.
print(a[0, 1]) # Prints "2"
b[0, 0] = 77 # b[0, 0] is the same piece of data as a[0, 1]
print(a[0, 1]) # Prints "77"

可以混合整数索引和切片索引,这样做会产生一个比原始数组的秩更低的数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Create the following rank 2 array with shape (3, 4)
# [[ 1 2 3 4]
# [ 5 6 7 8]
# [ 9 10 11 12]]
a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])

# Two ways of accessing the data in the middle row of the array.
# Mixing integer indexing with slices yields an array of lower rank,
# while using only slices yields an array of the same rank as the
# original array:
row_r1 = a[1, :] # Rank 1 view of the second row of a
row_r2 = a[1:2, :] # Rank 2 view of the second row of a
print(row_r1, row_r1.shape) # Prints "[5 6 7 8] (4,)"
print(row_r2, row_r2.shape) # Prints "[[5 6 7 8]] (1, 4)"

# We can make the same distinction when accessing columns of an array:
col_r1 = a[:, 1]
col_r2 = a[:, 1:2]
print(col_r1, col_r1.shape) # Prints "[ 2 6 10] (3,)"
print(col_r2, col_r2.shape) # Prints "[[ 2]
# [ 6]
# [10]] (3, 1)"

整数数组 索引允许你使用另一个数组的数据构造任意数组 大批。 这是一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import numpy as np

a = np.array([[1,2], [3, 4], [5, 6]])

# An example of integer array indexing.
# The returned array will have shape (3,) and
print(a[[0, 1, 2], [0, 1, 0]]) # Prints "[1 4 5]"

# The above example of integer array indexing is equivalent to this:
print(np.array([a[0, 0], a[1, 1], a[2, 0]])) # Prints "[1 4 5]"

# When using integer array indexing, you can reuse the same
# element from the source array:
print(a[[0, 0], [1, 1]]) # Prints "[2 2]"

# Equivalent to the previous integer array indexing example
print(np.array([a[0, 1], a[0, 1]])) # Prints "[2 2]"

可以用整数数组索引修改数组部分值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import numpy as np

# Create a new array from which we will select elements
a = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])

print(a) # prints "array([[ 1, 2, 3],
# [ 4, 5, 6],
# [ 7, 8, 9],
# [10, 11, 12]])"

# Create an array of indices
b = np.array([0, 2, 0, 1])

# Select one element from each row of a using the indices in b
print(a[np.arange(4), b]) # Prints "[ 1 6 7 11]"

# Mutate one element from each row of a using the indices in b
a[np.arange(4), b] += 10

print(a) # prints "array([[11, 2, 3],
# [ 4, 5, 16],
# [17, 8, 9],
# [10, 21, 12]])

数组的数学运算

numpy 提供的数学函数的完整列表 文档 Numpy 提供了更多用于操作数组的函数; 完整的列表 文档

Numpy 提供了许多有用的函数来执行计算 数组; 最有用的之一是 sum:

1
2
3
4
5
6
7
import numpy as np

x = np.array([[1,2],[3,4]])

print(np.sum(x)) # Compute sum of all elements; prints "10"
print(np.sum(x, axis=0)) # Compute sum of each column; prints "[4 6]"
print(np.sum(x, axis=1)) # Compute sum of each row; prints "[3 7]"

转置矩阵, 只需使用 T数组对象的属性:

1
2
3
4
5
6
7
8
9
10
11
12
import numpy as np

x = np.array([[1,2], [3,4]])
print(x) # Prints "[[1 2]
# [3 4]]"
print(x.T) # Prints "[[1 3]
# [2 4]]"

# Note that taking the transpose of a rank 1 array does nothing:
v = np.array([1,2,3])
print(v) # Prints "[1 2 3]"
print(v.T) # Prints "[1 2 3]"

广播

我们有一个较小的数组和一个 较大的数组,并且我们想多次使用较小的数组来执行某些操作 在更大的阵列上。

例如,假设我们要向每个添加一个常数向量 矩阵的行。 我们可以这样做:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import numpy as np

# We will add the vector v to each row of the matrix x,
# storing the result in the matrix y
x = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
v = np.array([1, 0, 1])
y = np.empty_like(x) # Create an empty matrix with the same shape as x

# Add the vector v to each row of the matrix x with an explicit loop
for i in range(4):
y[i, :] = x[i, :] + v

# Now y is the following
# [[ 2 2 4]
# [ 5 5 7]
# [ 8 8 10]
# [11 11 13]]
print(y)

Numpy 广播允许我们执行此计算,而无需实际执行 创建多个副本 v。 考虑这个版本,使用广播:

1
2
3
4
5
6
7
8
9
10
11
import numpy as np

# We will add the vector v to each row of the matrix x,
# storing the result in the matrix y
x = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
v = np.array([1, 0, 1])
y = x + v # Add v to each row of x using broadcasting
print(y) # Prints "[[ 2 2 4]
# [ 5 5 7]
# [ 8 8 10]
# [11 11 13]]"

线路 y = x + v尽管有效 x有形状 (4, 3)v有形状 (3,)由于广播; 这条线的工作原理就像 v实际上有形状 (4, 3), 其中每一行都是一个副本 v,并且按元素求和。

一起广播两个数组遵循以下规则:

  1. 如果数组没有相同的秩,则在前面添加较低秩数组的形状 1s 直到两个形状具有相同的长度。
  2. 如果两个数组具有相同的维度,则称 兼容 它们在维度上 维度中的大小,或者如果其中一个数组在该维度中的大小为 1。
  3. 如果数组在所有维度上都兼容,则可以一起广播。
  4. 广播后,每个数组的行为就好像它的形状等于元素方向 两个输入数组的形状的最大值。
  5. 在一个数组的大小为 1 而另一个数组的大小大于 1 的任何维度中, 第一个数组的行为就好像它是沿着该维度复制的

一些应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import numpy as np

# Compute outer product of vectors
v = np.array([1,2,3]) # v has shape (3,)
w = np.array([4,5]) # w has shape (2,)
# To compute an outer product, we first reshape v to be a column
# vector of shape (3, 1); we can then broadcast it against w to yield
# an output of shape (3, 2), which is the outer product of v and w:
# [[ 4 5]
# [ 8 10]
# [12 15]]
print(np.reshape(v, (3, 1)) * w)

# Add a vector to each row of a matrix
x = np.array([[1,2,3], [4,5,6]])
# x has shape (2, 3) and v has shape (3,) so they broadcast to (2, 3),
# giving the following matrix:
# [[2 4 6]
# [5 7 9]]
print(x + v)

# Add a vector to each column of a matrix
# x has shape (2, 3) and w has shape (2,).
# If we transpose x then it has shape (3, 2) and can be broadcast
# against w to yield a result of shape (3, 2); transposing this result
# yields the final result of shape (2, 3) which is the matrix x with
# the vector w added to each column. Gives the following matrix:
# [[ 5 6 7]
# [ 9 10 11]]
print((x.T + w).T)
# Another solution is to reshape w to be a column vector of shape (2, 1);
# we can then broadcast it directly against x to produce the same
# output.
print(x + np.reshape(w, (2, 1)))

# Multiply a matrix by a constant:
# x has shape (2, 3). Numpy treats scalars as arrays of shape ();
# these can be broadcast together to shape (2, 3), producing the
# following array:
# [[ 2 4 6]
# [ 8 10 12]]
print(x * 2)
]]> + shell脚本

Shell 脚本通常以 shebang 行开头:#!path/to/interpreter。

#!是一个人类可读的 幻数表示 0x23 0x21它可以告诉 shell 将文件其余部分的执行传递给 指定翻译。 如果您的脚本作为可执行文件运行(例如 ./awesome_shell_script) 加上 shebang 行,那么 shell 将调用 可执行文件(通常是解释器)位于 path/to/interpreter运行你的 脚本。 如果您的脚本作为参数传递给解释器,例如 bash awesome_shell_script,那么 shebang 没有效果并且 bash会处理 脚本的执行。 为什么这很重要? shebang 可以被认为是一个有用的部分 执行脚本的关注 如何 元数据传递了用户 给程序的作者。 awesome_shell_script可能是一个 bash脚本,一个 python脚本,一个 ruby脚本等。这个想法是只有脚本的 对于调用的用户来说,行为而不是其实现细节应该重要。

您可能已经看到过一些变体 #!/bin/sh。 虽然最初参考的是 现代系统上的 Bourne shell sh已经提到了 Shell Command Language ,这是一个具有多种实现的 POSIX 规范。 sh通常符号链接到这些符合 POSIX 标准的 shell 之一 实现 Shell 命令语言。 以 Debian 为例, sh是 符号链接到 shell dash。 重要的是要注意 bash不 **_** 遵守这个标准,虽然运行 bash作为 bash --posix做到了 更合规。

管道

我们可以使用 |字符将多个命令链接在一行中。 例如: command1 | command2 将传递的输出 command1作为输入 command2。 我们可以根据需要多次重复此操作。

循环使用 for

Bash 可以使用 for 循环对多个对象重复操作。 语法如下:

1
2
3
4
5
for VARIABLE in LIST; do

CONSEQUENT-COMMANDS

done

缩进不是必需的,但使代码更易于阅读。 这 LIST可以是包含多个文件的目录,也可以是包含多行 init 的文件、文件列表( file1 file2 file3),甚至是一系列数字( {start..end}).

有用的命令

一些对于完成实验可能有用的命令。 当然,解决问题的方法有很多,并不需要使用这些命令。

cat

cat 打印 将文件 到标准输出 。 对于打印一些内容以通过管道输入其他命令非常有用!

cut

cut [options] [filename]提取文件的某些部分(或管道输入) 参数 根据使用的 。 一些可能有用的:

-d允许我们更改分隔符,或更改字符 cut寻找将字符串分成块。 如果省略该选项, tab用来。

-f允许我们指定与要返回的字段对应的数字,例如 cut -f1 -d" "将返回句子中的第一个单词。 数字后跟一个 -也返回指定字段之后的所有字段,因此 cut -f1- -d" "将返回整个字符串。

--complement告诉 cut返回除 之外的所有内容。 指定字段

grep

grep [pattern] [filename] 过滤 并返回文件(或管道输入)中包含指定模式的行。

sed

sed可以做 很多事情 ,比如编辑字符串和匹配正则表达式。 我们可以用 sed将一种模式替换为另一种模式,如下所示:

sed 's/<PATTERN-TO-REPLACE>/<NEW-PATTERN>/g <INPUT>'

sed` 还可以从其他东西获取管道输入,而不是显式输入。

g最后告诉 sed替换所有出现的模式; 如果我们只想替换模式的第一次出现,则可以省略它,或者用数字替换以仅替换一定次数的出现。

xargs

xargs让我们将命令应用于从管道重定向的输出。 例如, output | xargs command会适用 commandoutput。 一些有用的 选项

-n1告诉 xargs将命令应用到中的每个项目 output如果输出中有多个项目(例如多个字符串的列表),则一次

-0告诉 xargs用空字符(表示字符串的结尾)分割输出中的项目,而不是使用空格。 搭配 -n1, 这意味着 xargs会将命令应用于每个字符串,而不是将字符串分解为单个单词并将命令应用于每个单词。

与往常一样,有更多方法可以使用这些命令,因此请使用 Google 或 手册页 来了解更多信息

语法

Shell 变量和类型

与大多数其他编程语言一样, bash促进有状态分配 名称到值作为变量。

变量可以被赋值 bash语法如下: NAME=value。 请注意 赋值运算符之间缺少空格 =及其操作数。 任务 对空格敏感。

您可以通过在前面添加一个来检索变量的值 $以它的名字。 获取值 NAME必须完成 $NAME。 这就是所谓的变量 插值。

1
2
3
4
5
6
7
8
$ NAME = "Tux" # Incorrect
-bash: NAME: command not found
$ NAME="Tux" # Correct
$ echo NAME # Incorrect. We want the value we assigned to NAME, not the text
# NAME itself.
NAME
$ echo $NAME # Correct
Tux

$?保存最近执行的命令的退出代码。 在这个 上下文、退出代码 0一般表示程序已经执行 成功地。 其他 退出代码 指的是错误的性质 导致程序失败。

特殊 位置参数 允许将参数传递到脚本中。 $0是脚本的名称, $1是传递给的第一个参数 脚本, $2是传递给脚本的第二个参数, $3是第三个 论证等 $#给出传递给脚本的参数数量。

所以 ./awesome_shell_script foo bar可以访问 foo$1bar$2.

Bash 变量是 无类型的 。 它们通常被视为文本(字符串),但是 如果变量包含数字和算术运算,则可以将其视为数字 对其应用操作。 请注意,这与大多数编程不同 语言。 变量 本身没有类型,但 运算符 会处理 在不同的环境下他们的价值观也不同。 换句话说, bash变量是文本,没有任何固有的行为或属性 可以操作的文本,但操作员会解释该文本 根据其内容(数字或无数字?)和上下文 表达。

算术

Bash 支持整数算术 let内置。

1
2
3
4
5
6
$ x=1+1
$ echo $x # Incorrect. We wanted 2, not the text 1+1.
1+1
$ let x=1+1
$ echo $x # Correct
2

注意 let对空格敏感。 操作数和运算符不得 用空格分隔。

bash本身不支持浮点运算,所以我们必须依赖 如果我们想处理十进制数字,请使用外部实用程序。 一个常见的选择 这是 bc。 有趣的事实: bc实际上是它自己的完整语言!

我们经常访问 bc通过 管道 (表示为 |),这允许 将一个命令的输出用作另一命令的输入。 我们包括 -l 选项 bc为了启用浮点运算。

1
2
$ echo 1/2 | bc -l
.50000000000000000000

test

Bash 脚本经常使用 [(同义词为 test) shell 内置的 表达式的条件评估。 test计算一个表达式并 以任一状态代码退出 0(true) 或状态代码 1(错误的)。

test支持常见的字符串和数字运算符,以及许多 额外的二元和一元运算符在大多数情况下没有直接类似物 其他编程语言。 您可以看到这些运算符的列表,以及 其他有用的信息,通过输入 help test在你的壳里。 的输出 如下所示。 注意 help类似于 man,除非它用于 bash 函数而不是其他程序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
$ help test
test: test [expr]
Exits with a status of 0 (true) or 1 (false) depending on
the evaluation of EXPR. Expressions may be unary or binary. Unary
expressions are often used to examine the status of a file. There
are string operators as well, and numeric comparison operators.

File operators:

-a FILE True if file exists.
-b FILE True if file is block special.
-c FILE True if file is character special.
-d FILE True if file is a directory.
-e FILE True if file exists.
-f FILE True if file exists and is a regular file.
-g FILE True if file is set-group-id.
-h FILE True if file is a symbolic link.
-L FILE True if file is a symbolic link.
-k FILE True if file has its `sticky' bit set.
-p FILE True if file is a named pipe.
-r FILE True if file is readable by you.
-s FILE True if file exists and is not empty.
-S FILE True if file is a socket.
-t FD True if FD is opened on a terminal.
-u FILE True if the file is set-user-id.
-w FILE True if the file is writable by you.
-x FILE True if the file is executable by you.
-O FILE True if the file is effectively owned by you.
-G FILE True if the file is effectively owned by your group.
-N FILE True if the file has been modified since it was last
read.

FILE1 -nt FILE2 True if file1 is newer than file2 (according to
modification date).

FILE1 -ot FILE2 True if file1 is older than file2.

FILE1 -ef FILE2 True if file1 is a hard link to file2.

String operators:

-z STRING True if string is empty.

-n STRING
STRING True if string is not empty.

STRING1 = STRING2
True if the strings are equal.
STRING1 != STRING2
True if the strings are not equal.
STRING1 < STRING2
True if STRING1 sorts before STRING2 lexicographically.
STRING1 > STRING2
True if STRING1 sorts after STRING2 lexicographically.

Other operators:

-o OPTION True if the shell option OPTION is enabled.
! EXPR True if expr is false.
EXPR1 -a EXPR2 True if both expr1 AND expr2 are true.
EXPR1 -o EXPR2 True if either expr1 OR expr2 is true.

arg1 OP arg2 Arithmetic tests. OP is one of -eq, -ne,
-lt, -le, -gt, or -ge.

Arithmetic binary operators return true if ARG1 is equal, not-equal,
less-than, less-than-or-equal, greater-than, or greater-than-or-equal
than ARG2.

我们可以测试整数相等

1
2
3
4
$ [ 0 -eq 0 ]; echo $? # exit code 0 means true
0
$ [ 0 -eq 1 ]; echo $? # exit code 1 means false
1

字符串相等

1
2
3
4
$ [ zero = zero ]; echo $? # exit code 0 means true
0
$ [ zero = one ]; echo $? # exit code 1 means false
1

以及您可以自由进行的许多其他字符串和数字运算 探索。

控制结构

bash包括大多数编程语言典型的控制结构 – if-then-elif-else, while for-in等等。您可以阅读更多有关 条件语句迭代 中的 Bash 指南 初学者 Linux 文档项目 (LDP) 的 。 我们鼓励您 请阅读这些部分,因为本指南仅提供了一些内容的简短摘要 重要特征。

if-then-elif-else

if 语句的一般形式 bash

1
2
3
4
5
6
7
8
9
10
11
12
13
if TEST-COMMANDS; then

CONSEQUENT-COMMANDS

elif MORE-TEST-COMMANDS; then

MORE-CONSEQUENT-COMMANDS

else

ALTERNATE-CONSEQUENT-COMMANDS;

fi

缩进是一种很好的做法,但不是必需的。

例如,如果我们写

1
2
3
4
5
6
7
8
#!/bin/bash
# contents of awesome_shell_script

if [ $1 -eq $2 ]; then
echo args are equal
else
echo args are not equal
fi

我们看

1
2
3
4
$ ./awesome_shell_script 0 0
args are equal
$ ./awesome_shell_script 0 1
args are not equal

尽管

while 循环的一般形式 bash

1
2
3
4
5
while TEST-COMMANDS; do

CONSEQUENT-COMMANDS

done

如果 TEST-COMMANDS退出并带有状态码 0, CONSEQUENT-COMMANDS将要 执行。 这些步骤将重复,直到 TEST-COMMANDS退出时带有一些非零值 地位。

例如,如果我们写

1
2
3
4
5
6
7
8
#!/bin/bash
# contents of awesome_shell_script

n=$1
while [ $n -gt 0 ]; do
echo $n
let n=$n-1
done

我们看

1
2
3
4
5
6
$ ./awesome_shell_script 5
5
4
3
2
1

函数

bash supports functions, albeit in a crippled form relative to many other languages. Some notable differences include:

  • 函数不 返回 任何内容,它们只是产生输出流(例如 echo到标准输出)
  • bash严格来说是按值调用。 也就是说,只有原子值(字符串)可以 被传递到函数中。
  • 变量没有词法作用域。 bash使用一个非常简单的本地系统 范围接近动态范围。
  • bash没有一流的函数(即没有将函数传递给 其他函数)、匿名函数或闭包。

功能于 bash定义为

1
2
3
4
5
name_of_function() {

FUNCTION_BODY

}

并由

1
name_of_function $arg1 $arg2 ... $argN

请注意函数签名中缺少参数。 参数在 bash 函数的处理方式与全局位置参数类似,其中 $1 含有 $arg1, $2含有 $arg2, ETC。

例如,如果我们写

1
2
3
4
5
6
7
8
#!/bin/bash
# contents of awesome_shell_script

foo() {
echo hello $1
}

foo $1

我们看

1
2
$ ./awesome_shell_script world
hello world

实例

斐波那契

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#!/bin/bash
# contents of fibonacci

if [ $# -eq 0 ]; then
echo "fibonacci needs an argument"
exit 1
fi

fib() {
N="$1"
if [ -z "${N##*[!0-9]*}" ]; then
echo "fibonacci only makes sense for nonnegative integers"
exit 1
fi

if [ "$N" -eq 0 ]; then
echo 0
elif [ "$N" -eq 1 ]; then
echo 1
else
echo $(($(fib $((N-2))) + $(fib $((N-1)))))
fi
}

fib "$1"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
read -p “send: ” FOO
# enter “hi”
echo “sent: $FOO”
sent: hi

FOO=$(expr 1 + 1)
echo “$FOO”
2

-eq ==
-ne !=
-gt >
-ge >=
-lt <
-le <=

test zero = zero; echo $?
0 # 0 means true
test zero = one; echo $?
1 # 1 means false

if [ “$1” -eq 69 ];
then
echo “nice”
elif [ “$1” -eq 42 ];
then
echo “the answer!”
else
echo “wat r numbers”
fi

read -p "are you 21?" ANSWER
case "$ANSWER" in
“yes”)
echo "i give u cookie";;
“no”)
echo "thats illegal";;
“are you?”)
echo “lets not”;;
*)
echo "please answer"
esac

NAMES="a b c d"
for NAME in $NAMES
do
echo "Hello $NAME"
done

while true
do
echo "Hello $NAME"
done

Bash 支持整数算术 let内置的。

1
2
3
4
5
6
$ x=1+1
$ echo $x # Incorrect. We wanted 2, not the text 1+1.
1+1
$ let x=1+1
$ echo $x # Correct
2

注意 let对空格敏感。 操作数和运算符不得 用空格分隔。 test计算一个表达式并 以任一状态代码退出 0(true) 或状态代码 1(错误的)

bash支持函数,尽管相对于许多其他函数而言,其形式有缺陷 语言。 一些显着的差异包括:

  • 函数不 返回 任何内容,它们只是产生输出流(例如 echo到标准输出)
  • bash严格来说是按值调用。 也就是说,只有原子值(字符串)可以 被传递到函数中。
  • 变量没有词法作用域。 bash使用一个非常简单的本地系统 范围接近动态范围。
  • bash没有一流的函数(即没有将函数传递给 其他函数)、匿名函数或闭包

请注意函数签名中缺少参数。 参数在 bash 函数的处理方式与全局位置参数类似,其中 $1 含有 $arg1, $2含有 $arg2, ETC。

例如,如果我们写

1
2
3
4
5
6
7
8
#!/bin/bash
# contents of awesome_shell_script

foo() {
echo hello $1
}

foo $1

我们看

1
2
$ ./awesome_shell_script world
hello world

shell命令

SSH(安全外壳)

SSH 允许您通过互联网登录远程计算机。 这相当于在远程计算机上打开 shell。

用法是 ssh [remote username]@[remote host].

问题

  1. 登录到 tsunami.ocf.berkeley.edu使用您的 OCF 用户名和密码。 有一个文件在 ~staff/public_html/decal。 打开它。 文件中到底隐藏着什么秘密?

管道和重定向

将命令链接在一起对于自动化 shell 操作至关重要。 这是一个快速备忘单:

>:将 标准 输出重定向到文件(将覆盖该文件)。

>>:将标准输出附加到文件(与 >除非不覆盖)。

<:从文件中读取输入。

|:将一个程序的输出发送到下一个程序的输入。

下面是一个示例:假设您正在参加一门课程,需要您提交一个包含您的 SID 的文本文件。 您的第一反应可能是打开一个文本编辑器(例如 vim)并简单地输入它,但是有一种更快的方法来创建文件! 这里是:

echo '123456789' > sid.txt

tmux

为什么是 tmux?

  • 当通过 ssh 连接到一台计算机时,您可以打开多个窗口。
  • 您可以在编辑程序的同时对其进行编译和运行。
  • 您可以注销并通过 ssh 重新登录,而无需重新打开所有文件。

入门

  • 开始会话 tmux.
  • 从会话中分离 Ctrl-b d(释放后按 d Ctrl-b)
  • 分成 2 个窗格 Ctrl-b %(垂直)或 Ctrl-b "(水平的)
  • 交换当前窗格 Ctrl-b o
  • 在线查找有关 tmux 的更多信息。 您可能会发现 此备忘单 很有帮助!

包管理

Debian:简介 aptdpkg

在本课程中,我们将重点关注 Debian 的使用。 正如本周讲座中提到的,Debian 使用 apt/dpkg 作为其包管理器。 其他发行版使用不同的包管理器。

apt

Debian 的前端包管理器是 apt。 大多数时候,当您需要与包管理器打交道时, apt通常是要走的路。 在做任何事情之前 apt,更新包列表通常是一个好习惯,以便包管理器可以找到并获取各种包的最新版本。 为此,您可以运行:

apt update

要查找要安装的包:

apt search [package|description]

要安装包:

apt install [package]

要删除包:

apt remove [package]

使用安装的软件包一段时间后,您可能会注意到它们不会自动更新,这一功能可能存在于为其他操作系统编写的程序中。 要更新已安装的软件包,请运行:

apt upgrade或有时 apt dist-upgrade

使用起来比较普遍 apt upgrade更新你的包,但有时你需要使用 apt dist-upgrade。 阅读有关两者之间差异的更多信息 您可以在此处

在某些情况下,您希望完全确定要安装的软件包的版本。 要列出可以安装的潜在版本,您可以运行:

apt policy [package]

这根据其引脚优先级列出了要安装的候选版本以及与系统兼容的其他版本。 要安装特定目标版本的 aa 版本,您可以运行:

apt -t [targetrelease] install [package]

还有其他命令可以删除不需要的依赖项并清除包,但这就是 man页面是为了。 请注意,您将必须使用 sudo对于上述命令,因为您实际上是在修改系统本身。

dpkg

后端包管理器是 dpkg。 传统上, dpkg用于安装本地软件包。 使用 dpkg,您还可以检查软件包并修复损坏的安装。 要安装本地软件包,请运行:

dpkg -i [packagefilename]

删除系统包:

dpkg --remove [package]

要检查包以获取有关该包的更多信息:

dpkg -I [packagefilename]

要修复/配置所有已解压但未完成的安装:

dpkg --configure -a

入门

创建一个简单的包

现在,我们将使用您将在接下来的步骤中创建的 hellopenguin 可执行文件创建一个简单的包。 首先,移至您在入门部分克隆的存储库中的 a2 文件夹:

cd decal-labs/a2

现在我们将创建一个文件夹来进行此练习:

mkdir ex1

现在进入该文件夹:

cd ex1

编写和编译程序

现在,我们将用 C 语言制作一个非常简单的应用程序,打印“Hello Penguin!” 名为地狱企鹅。 调用:

touch hellopenguin.c

这将创建一个名为的空文件 hellopenguin.c。 现在,使用您选择的首选文本编辑器,例如 vim, emacs, 或者 nano,将以下代码插入 hellopenguin.c

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>

int main()

{

printf("Hello Penguin!\n");

return 0;

}

我们现在将编译您刚刚编写的源文件:

gcc hellopenguin.c -o hellopenguin

其作用是获取源文件 hellopenguin.c并将其编译为名为的可执行文件 hellopenguin-o输出标志。

打包可执行文件

现在,我们将创建可执行文件所在的文件夹结构。在 Debian 中,用户级包通常驻留在该文件夹中 /usr/bin/:

mkdir -p packpenguin/usr/bin

现在移动你编译的 hellopenguin可执行到 packpenguin/usr/bin/文件夹。

mv hellopenguin packpenguin/usr/bin/

现在我们将创建一个名为 hellopenguin。 移动到父目录 packpenguin文件夹并调用以下命令:

fpm -s dir -t deb -n hellopenguin -v 1.0~ocf1 -C packpenguin

这指定您要使用目录 -s标志,并输出 .deb包使用 -t旗帜。 它接受一个名为的目录 packpenguin, 使用 -C标志,并输出 .deb文件名为 hellopenguin, 使用 -n,版本号为 1.0~ocf1, 使用 -v旗帜。

现在通过调用 apt 并安装它来测试它:

sudo dpkg -i ./hellopenguin_1.0~ocf1_amd64.deb

现在你应该能够运行 hellopenguin通过执行以下操作:

hellopenguin

计算机网络

概述

不可否认,互联网是一个重新定义了我们世界的重要系统。 开发网络和允许设备通信的能力对于现代计算机系统至关重要。 本实验将研究计算机网络的基础知识,然后从系统管理员的角度检查网络。

我们将使用网页浏览作为类比来了解网络的基础知识。 当我上网浏览猫的图片时到底会发生什么?

但首先让我们简要了解一下网络的细节。


硬件地址mac

媒体访问控制 (MAC) 地址是唯一分配给网络接口的标识符。 所有文字

由于 MAC 地址是唯一的,因此通常称为物理地址。 八位位组通常以十六进制书写并用冒号分隔。 MAC 地址示例是 00:14:22:01:23:45。 请注意,前 3 个八位位组指的是组织唯一标识符 (OUI),它可以帮助识别制造商。 有趣的事实—— 00:14:22以上是 Dell 的 OUI。

ip

IP 地址是识别根据互联网协议连接到网络的设备的方法。 互联网协议有两个版本:IPv4 和 IPv6,它们的地址大小不同。 IPv6 地址示例是 2001:0db8:85a3:0000:0000:8a2e:0370:7334它比 IPv4 地址长得多,例如 127.0.0.1。 由于时间关系,我们只讨论 IPv4,但 IPv6 确实正在取得进展,值得一试!

IPv4 地址为 32 位,即 4 个字节,每个字节由点 (.) 分隔。 IPv4 地址示例是 127.0.0.1。 巧合的是,这个地址被称为环回地址,它映射到您自己机器上的环回接口。 这允许网络应用程序在同一台计算机(在本例中是您的计算机)上运行时相互通信。 但为什么 127.0.0.1并不是 127.0.0.0或者 127.0.0.2?

答案是 127.0.0.1是简单的约定,但从技术上讲,网络块中的任何地址 127.0.0.0/8是一个有效的环回地址。 但网络块到底是什么?

在 IPv4 中,我们可以将地址块划分为子网。 这是以 CIDR 格式编写的。 我们以上面的子网为例 127.0.0.0/8。 斜杠后面的数字 ( /),在本例中为 8,是子网掩码。 这表示网络地址中有多少位,其余位标识网络内的主机。 在这种情况下,网络地址是 127.0.0.0面具是 255.0.0.0。 所以 127.0.0.1将是第一个主机 127.0.0.0/8网络等等。

该图提供了 CIDR 寻址的可视化细分 所有文字

ARP

地址解析协议 (ARP) 是用于将 IP 地址解析为 MAC 地址的协议。 为了理解ARP,我们首先讨论发送帧的两种方式,单播和广播。 在第 2 层上下文中,单播帧意味着将该帧发送到一个 MAC 地址。 另一方面,通过将帧发送到广播地址来广播帧意味着该帧应该发送到网络上的每个设备,从而有效地“淹没”本地网络。

例如,让我们想象一个发送者 A,他有 MAC 00:DE:AD:BE:EF:00,广播一条消息,本质上是询问“谁拥有 IP 地址 42.42.42.42请在 00:DE:AD:BE:EF:00 告诉 A”。

如果一台机器B,有MAC 12:34:56:78:9a:bc有IP地址 42.42.42.42他们向发件人发送单播回复,其中包含以下信息“ 12:34:56:78:9a:bc42.42.42.42”。 发送方将此信息存储在 arp 表中,因此每当它收到发往机器 B 的数据包时,即目标 IP 地址为 42.42.42.42它将数据包发送到从 B 收到的 MAC。

为了路由 IP 数据包,设备具有所谓的路由表。 路由条目存储在路由表中,它们本质上是告诉设备应如何基于 IP 转发数据包的规则。 路由条目指定子网以及与该条目对应的接口。 设备选择具有最特定于给定数据包的子网的条目,并将其转发出该条目上的接口。

路由表通常也有一个默认网关。 在没有更具体的匹配条目的情况下,这将用作数据包的默认捕获所有内容。

以此路由表为例。

1
2
3
4
default via 10.0.2.2 dev eth0
10.0.2.0/24 dev eth0 proto kernel scope link src 10.0.2.15
10.0.2.128/25 dev eth0 proto kernel scope link src 10.0.2.15
192.168.162.0/24 dev eth1 proto kernel scope link src 192.168.162.162

一个数据包的目的地是 8.8.8.8将从默认网关 eth0 转发出去。 一个数据包的目的地是 10.0.2.1将根据第二个条目从 eth0 转发。 一个数据包的目的地是 10.0.2.254将根据第三个条目从 eth0 转发。 一个数据包的目的地是 192.168.162.254将根据第四个条目从 eth1 转发。

域名

我们已经讨论了 IP 地址以及它们如何通过 IP 与主机进行通信,但是虽然 IP 地址是机器友好的(计算机喜欢数字),但它们并不完全是人类友好的。 记住电话号码已经够难了,记住 32 位 IP 地址也不会更容易。

但我们更容易记住 <www.google.com、www.facebook.com> 或 Coolmath-games.com 等名称。 因此,在这种冲突中,域名系统 (DNS) 诞生了,它是机器友好的 IP 地址和人类友好的域名之间的折衷方案。

DNS 是一个将 google.com 等域名映射到 172.217.6.78。 当您查询 google.com 时,您的计算机会将 google.com 的 DNS 查询发送到 DNS 服务器。 假设配置正确并且 google.com 有一个有效的对应地址,您将收到来自权威服务器的响应,其实质上是“google.com 有 IP 地址” x.x.x.x”.

现在让我们稍微消除一下这个黑魔法……

DNS 记录

DNS 服务器以资源记录 (RR) 的形式存储数据。 资源记录本质上是(名称、值、类型、TTL)的元组。 虽然 DNS 记录的类型多种多样,但我们最关心的是

  1. 一条记录 名称 = 主机名 值 = IP 地址

    该记录非常简单,包含给定主机名的 IP 地址,本质上是我们最终想要得到的信息。

  2. 国民服役记录 名称=域名 值 = 域的 DNS 服务器名称

    该记录指向另一个可以为该域提供权威答案的 DNS 服务器。 将此视为将您重定向到另一个名称服务器。

  3. CNAME 记录 名称 = 别名 值=规范名称

    这些记录指向给定别名的规范名称,例如 docs.google.com 将是一个仅指向 document.google.com 的别名 尝试 <www.facebook.com>

  4. MX记录 邮件服务使用的记录。

TCP 和 UDP

现在我们将讨论传输层的协议。 这一层最著名的两个协议是传输控制协议(TCP)和用户数据报协议(UDP)。

TCP 是一种面向有状态流的协议,可确保可靠的传输。 可靠的传输本质上保证信息完整且有序地到达目的地。

TCP 是面向连接的协议,这意味着它在发送任何数据之前必须首先建立连接。 此连接交换信息,这是 TCP 用于在其他功能中提供可靠传输的机制。 TCP 连接以 TCP 握手开始。

TCP 握手包括在发送方和接收方之间交换的数据包的 TCP 标头中设置某些标志。 发送方首先发送 SYN(设置了 SYN 标志的数据包)来启动 TCP 连接。 服务器通过发回 SYN-ACK(一个同时设置了 SYN 和 ACK 标志的数据包)来确认此连接请求。 客户端通过向服务器发送一个最终 ACK 来确认这一点,然后建立连接。

TCP 然后开始传输数据,如果数据成功到达连接的另一端,则会发出 ACK。 因此,如果数据丢失、重新排序或损坏,TCP 能够识别这一点并发送重传任何丢失数据的请求。

TCP 也有一个关闭连接的过程。 我们在这里只考虑优雅终止,突然终止有不同的过程,我们不会讨论。 如果您有兴趣,CS168 这里 有一些很棒的材料。 假设机器 A 想关闭与机器 B 的连接。

A 首先发送 FIN。 B 必须通过发送 FIN 和 ACK 进行响应。 如果 B 仅发送 ACK,则连接将持续存在,并且可以发送其他数据,直到发送 FIN。 另一方面,如果 B 准备好关闭连接并且不需要发送额外的数据,则 B 也可以只发送一个同时设置了 FIN 和 ACK 标志的数据包,即 FIN+ACK。发送最后一个 ACK​​ 来表示连接终止。

UDP是无状态无连接协议。 UDP 专注于以数据报的形式发送消息。 无连接 UDP 也不会产生 TCP 握手和终止的开销。 UDP 也不保证可靠传输,因此消息可能会损坏、无序到达或根本不到达。 因此,UDP 有时被称为不可靠数据报协议。

虽然 UDP 不保证可靠传输,但它不会像 TCP 那样遭受建立和关闭连接的开销。 因此,UDP 非常适合我们只想快速发送数据包并且丢失一些数据包也不会造成灾难性后果的使用情况。

此外,与 TCP 相比,发送的每个 UDP 数据报都需要单独接收。 而对于 TCP,您传递的数据流被透明地分成一定数量的发送,并且数据流在另一端透明地重建为一个整体。

端口

广义上讲,端口定义了服务端点——端口标记了流量的入口和出口点。 IP 地址连接主机,而端口则连接在此类主机上运行的进程。 一次只能将一个进程绑定到一个端口。 端口由 16 位数字表示,范围从 0 到 65535。从 0 到 1023 的端口是众所周知的端口,即系统端口。 使用这些端口通常有更严格的要求。 1024 到 49151 是注册端口。 官方 列表 IANA 维护着知名和注册范围的 。 从 49152 到 65535 的其余端口是临时端口,可以根据每个请求动态分配给通信会话。

systemd unit

unit的介绍和写法 Linux 发行版越来越多地采用 systemd初始化系统。 这套功能强大的软件可以管理服务器的许多方面,从服务到安装的设备和系统状态。

systemd, A unit指系统知道如何操作和管理的任何资源。 这是主要对象 systemd工具知道如何处理。 这些资源是使用称为单元文件的配置文件定义的。

单位是对象 systemd知道如何管理。 这些基本上是系统资源的标准化表示,可以由守护程序套件管理并由提供的实用程序操作。

单元可以说类似于其他 init 系统中的服务或作业。 然而,单元具有更广泛的定义,因为它们可用于抽象服务、网络资源、设备、文件系统挂载和隔离资源池。 系统的单元文件副本一般保存在 /lib/systemd/system目录。 当软件在系统上安装单元文件时,这是它们默认放置的位置。

存储在此处的单元文件可以在会话期间按需启动和停止。 这将是通用的普通单元文件,通常由上游项目的维护人员编写,应该适用于部署的任何系统 systemd在其标准实施中。 您不应编辑此目录中的文件。 相反,如果有必要,您应该使用另一个单元文件位置来覆盖该文件,该位置将取代该位置中的文件。 正确的方法是创建一个以单元文件命名的目录 .d附加在最后。 所以对于一个叫做 example.service,一个名为 example.service.d可以被创建。 在此目录中,有一个以以下结尾的文件 .conf可用于覆盖或扩展系统单元文件的属性。

大多数单元文件中的第一部分是 [Unit]部分。 这通常用于定义单元的元数据并配置单元与其他单元的关系。

尽管部分顺序并不重要 systemd解析文件时,此部分通常放置在顶部,因为它提供了单元的概述。 您可以在以下位置找到一些常见指令 [Unit]部分是:

  • Description=:该指令可用于描述单元的名称和基本功能。 它由各种返回 systemd工具,因此最好将其设置为简短、具体且信息丰富的内容。
  • Documentation=:该指令提供了文档 URI 列表的位置。 这些可以是内部可用的 man页面或网络可访问的 URL。 这 systemctl status命令将公开此信息,以便于轻松发现。
  • Requires=:该指令列出了该单元本质上依赖的所有单元。 如果当前单位已激活,则此处列出的单位也必须成功激活,否则该单位将失败。 默认情况下,这些单元与当前单元并行启动。
  • Wants=:该指令类似于 Requires=,但不太严格。 Systemd当此单元被激活时,将尝试启动此处列出的任何单元。 如果未找到这些单元或无法启动,当前单元将继续运行。 这是配置大多数依赖关系的推荐方法。 同样,这意味着并行激活,除非被其他指令修改。
  • BindsTo=:该指令类似于 Requires=,但也会导致当前单元在关联单元终止时停止。
  • Before=:如果同时激活了该指令中列出的单元,则只有当前单元被标记为已启动后,它们才会启动。 这并不意味着依赖关系,并且如果需要的话必须与上述指令之一结合使用。
  • After=:该指令中列出的单元将在启动当前单元之前启动。 这并不意味着依赖关系,如果需要,必须通过上述指令建立依赖关系。
  • Conflicts=:这可用于列出不能与当前单元同时运行的单元。 启动具有这种关系的单元将导致其他单元停止。
  • Condition...=: 有许多指令以 Condition这允许管理员在启动设备之前测试某些条件。 这可用于提供仅在适当的系统上运行的通用单元文件。 如果不满足条件,则会正常跳过该单元。
  • Assert...=:类似于以 Condition,这些指令检查运行环境的不同方面,以决定是否应激活该单元。 然而,与 Condition指令,负结果会导致该指令失败。

安全管理

加密与解密

基础知识

加密采用明文和密钥,返回密文。 解密需要密文和密钥,仅当解密密钥有效时才恢复并返回原始明文。 加密和解密的密钥是由随机位组成的长字符串,这使得攻击者在计算上无法猜测密钥并解密密文。

一切 安全性是指在面对攻击时保持系统按预期运行 这可以采取多种形式:

  1. 保密性
  2. 完整性/真实性
  3. 可用性

模块:

  1. 认证
  2. 加密:防止攻击者读取您的文件,直到它们得到 联邦调查局和他们的密码学家参与其中
  3. 哈希:将大数据转化为小数据
  4. 签名和证书:确保您就是您所说的人 假设我想使用你的公钥来验证你的身份。 我 可以用它加密一些东西,并要求你解密它并且 显示正确的值。 如果您可以解密该值,那么您必须拥有密钥的私有部分并且可以进行身份​​验证。 假设你想证明你发送的消息实际上是由您发送。 您可以使用您的私钥来“签署”消息通过对其进行加密,您的公钥可用于解密签名以验证您(由您发布的公开信息识别)键)实际上确实发送了消息,因为只有您而不是其他人对手将拥有相应的私钥。 根证书:操作系统包含许多根证书 这是网络信任的基础。 证书是在通向根的链中签名; 如果链有效,则最后的 cert 被认为是可信的。

网络攻击: 攻击网络系统的方法有很多: 窃听、中间人、拒绝服务、应用程序 缓冲区/堆溢出、SQL 注入等漏洞 目录遍历、CSRF、SSRF、XSS、蠕虫、rootkit、垃圾邮件、加密挖矿、勒索软件、网络钓鱼等等……

对称密码学

在对称密码学中,用于加密和解密的密钥是相同的。

尝试一下:

  1. gpg --symmetric [FILE]在任何文件上输出 [FILE].gpg文件是输入文件的加密版本。 加密文件时需要输入密码。
  2. gpg --decrypt [FILE].gpg在原始文件的加密版本上,您需要输入原始密码。

在此 GPG 实现中,文件的加密和解密都需要知道单个密码,在本例中该密码充当对称密钥。

非对称密码学

在非对称加密中,两个单独的密钥分别用于加密和解密。 这两个密钥是一对公私密钥。 公钥是公开的并用于加密数据。 而私钥由所有者保密并用于解密数据。 使用公钥加密文件意味着只有拥有相应私钥的人才能解密生成的加密文件。

GPG 钥匙圈抽象

GPG 使用“密钥环”作为集中位置来保存用户的所有密钥。 如果您想使用并保留它,则需要向密钥环添加/导入密钥。 同样,如果您希望与其他人共享密钥,您可以导出您的密钥(这会生成您的密钥的副本)并让他们将其导入到他们的密钥环中。

尝试一下:

  1. gpg --full-generate-key生成 GPG 公私密钥对。 它会要求输入密码。 如果您的机器需要一段时间才能生成密钥,则可能是由于缺乏长随机密钥所需的熵(随机性)。 sudo apt-get install haveged将安装一个生成熵的守护进程。
  2. gpg --recipient [RECIPIENT] --encrypt [FILE]这将加密 [FILE][RECIPIENT]的公钥(目前,尝试使用您自己的公钥加密文件)。
  3. gpg --decrypt [FILE].gpg将搜索您的密钥环并使用适当的私钥解密文件(当然,如果您拥有正确的私钥)。 您无需指定使用哪个密钥来解密文件,因为 GPG 加密的文件和密钥包含元数据,允许 GPG 从密钥环中选择正确的密钥来解密文件。

签名

公钥加密、私钥解密的非对称方案也可以反过来实现数字签名,其作用相当于物理签名。 在这个相反的方案中,私钥用于对文件进行签名,从而在该文件上生成签名。 并使用相应的公钥来验证签名。 因此,只有拥有私钥的人才能生成签名,但拥有相应公钥的任何人都可以验证该签名。

UNIX 权限模型有 3 个组成部分:授予文件的 (1) 所有者用户、(2) 所有者组和 (3) 其他人/其他所有人的权限。 权限本身有 3 个子组件:(1) 读取、(2) 写入和 (3) 执行,强制执行读取、写入或执行文件的能力。

gpg

  1. 解密b8/file1.txt.gpg:
1
gpg --decrypt b8/file1.txt.gpg 
  1. 输入密码ocfdecal后,解密内容为: mYp@sw0rd2. 导入密钥的命令是:
1
gpg --import {key_file}
  1. 将密钥导出到文件的命令:
1
gpg --export --armor {key_id} > {output_file}
  1. 查看钥匙圈所有钥匙的命令:
1
gpg --list-keys
  1. 使用私钥b8/lab8privkey解密b8/file2.txt.gpg:
1
2
gpg --import ./lab8privkey
gpg --decrypt ./file2.txt.gpg

hash

  1. sha1sum [FILE]获取 SHA1 哈希值 [FILE].
  2. md5sum [FILE]获取 MD5 哈希值 [FILE].

安全系统

威胁模型

设计安全系统时要记住的最重要的事情是 了解您的威胁模型。 没有系统能够保证安全或能够 能够抵挡所有的攻击,甚至在极端的情况下也是不可能的。 对手。 但是,您可以(并且应该)针对威胁采取预防措施 你很可能会面临。 平衡授权用户访问的需求 在将未经授权的用户拒之门外的情况下,很容易出错。 幸运的是,聪明人已经将安全原则提炼为 中得到了很好的 第一个讲义 一些公理,在CS 161 的 介绍 (归功于大卫·瓦格纳教授)。 建议阅读讲义。

构建威胁模型时,请记住以下问题:

  1. 你在保护什么?
  2. 谁是你的对手?
  3. 您需要保护它的可能性有多大?
  4. 如果不加以保护,会产生什么后果?
  5. 您应该投入多少资源来保护它?

加密解密

对称密钥加密几乎对所有事物都有用,尤其是属于以下类别的事物:

  • 加密传输中的数据(例如 HTTPS)
  • 加密静态数据(例如手机上存储的数据)

作为示例,我们来探讨一下 iPhone 如何使用加密来保证数据安全:

  1. iPhone 的内部存储使用一组 AES 密钥进行加密,这些密钥存储在手机内部芯片上,并在工厂生成。
  2. 这些密钥又使用您的 PIN 进行加密。 您的 PIN 码允许手机解锁密钥,从而解密文件系统的其余部分。

与对称密钥加密不同,公钥加密中有 2 个密钥 ,密码系统由公钥私钥组成 。 顾名思义, 公钥是公开共享的,这是其他人可以使用的方式 加密适合您的数据。 您使用您的私钥来解密此内容 数据。 只要没有人拥有你的私钥,任何人都可以使用你的公钥 加密数据并确保只有您可以解密它。 这是一个强大的 对称密钥范式的扩展,除了加密之外,它还允许 签名和不可否认性 公钥密码学与 RSA 算法 同义, 是最早经过验证的双密钥方案之一。 RSA 公钥加密工作原理的简要概述

  1. RSA算法,通过一些高等数学(涉及素数和模数) 算术),返回 3 个数字:一个公共指数(又名密钥),一个私有指数, 和一个模数。 两个密钥的工作方式使得用一个密钥加密的数据只能 可以用另一个密钥解密。
  2. 为了加密数据,需要使用指数和模数之一对数据执行模幂运算。
  3. 为了解密数据,对加密数据进行模幂运算 与合作伙伴密钥和模数。 常用时,使用较大的指数 作为私钥,用于解密数据和创建签名, 较小的指数作为公钥,用于加密数据 并验证签名。 比如:
1
ssh-keygen -t rsa -b 4096

该命令将生成两个文件, ~/.ssh/id_rsa~/.ssh/id_rsa.pub。 正如命令所示,此命令生成 4096 位 RSA 密钥对。 你 应该能够猜测哪个文件代表公钥以及哪个文件必须 因此是私钥。 为了影响安全 SSH 登录,请使用 RSA密钥,用户必须首先将他们想要使用的公钥传输到 提前向服务器表明自己的身份。 然后,一旦会话结束 服务器和客户端之间建立的,服务器会加密一个随机数 号码与用户的公钥并发送给用户。 用户将 然后使用他们的私钥解密该值并返回该值的哈希值 到服务器,然后服务器可以自己散列该值以确定用户是否 能够成功解密随机数,从而表明拥有 匹配的密钥并作为身份验证的证据。

签名和证书

一开始,您 将发布 Natoshi 的公钥,此后,对于您发布的每个帖子,您 将使用您(Natoshi)的私钥对消息内容进行加密,并且 将其与您的原始消息一起发布。 那么,想验证的人 Natoshi(即公钥对应的私钥的所有者 属于 Natoshi)实际上确实发布了一条特定的消息,可以简单地 使用 Natoshi 的公钥解密加密签名并比较 内容与原始消息相反。

Natoshi 王位的觊觎者将是 无法签署他们的虚假声明,以便可以与他们核实 Natoshi 公开了公钥,因为他们没有 Natoshi 的私钥, 您可以放心,没有人会过度影响您的项目 当你躲避 IRS 和 DEA 时,除非他们碰巧有 仓库里装满了 ASIC 和大量廉价电力。

然而,在这个方案中,如何防止对手发布虚假信息 公钥并声称是您? (他们可以对此进行有效签名 假公钥)不知何故,你需要“引导”信任:有人需要 验证您的身份并公开确认您的公钥实际上 对应于你。

我们通过 证书 来做到这一点:签署的声明 声称特定的公钥实际上属于它所声称的人 属于。

谁签署此证书? 一个 证书颁发机构 ,我们的某人 信任负责验证身份和发布签名。

但是我们如何知道要信任哪些 CA,以及我们如何才能信任声称 真正值得信赖的是? 他们可能还需要证书。 它 听起来好像一路下来都是海龟; 然而,链条确实结束了 某处:所谓的信任根,根 CA。 这些 CA 的 证书是由浏览器和操作系统预安装的,因此 本质上受信任,无需任何进一步的证书。 如果根 CA 签署您的证书,我们假设他们已经完成了必要的尽职调查 愿意冒着声誉风险签署您的证书,并且基本上 相信他们的话。 这种模型被称为“ 信任网络” ,是网络如何 今天的安全工作正常进行。

不幸的是,它并不像我们希望的那样可靠: 有些 CA 很卑鄙,只要有足够的钱就会签署任何东西,从而导致有效的 为 microsoft.com 和 github.com 等域颁发的证书 显然不是 Microsoft 或 GitHub 的实体。 1 此外, 任何拥有足够边境控制的实体都可以强制安装自己的 根证书(例如哈萨克斯坦政府 2 ) 并截取 通过为任何域颁发自己的伪造证书来窃取任何流量。

您可能没有意识到,但 您使用并依赖证书和签名 每天。 每当您在网站地址栏附近看到绿色锁时, 访问,您正在通过 TLS 或 HTTPS 连接访问该网站,并且数据 您和网站之间的传输是加密的。 当你的浏览器 连接到网站的服务器,它会按顺序请求服务器的公钥 设置加密连接和服务器证书以便 验证其作为授权为您拥有的域提供服务的服务器的身份 要求。 然后,您的浏览器通过验证公钥来验证公钥 证书上的签名。 如果有人试图执行 对您进行中间人攻击,此证书验证步骤将失败, 因为受信任的 CA 不太可能颁发签名的证书 将您的域名转让给您以外的实体(除非您不幸 居住在哈萨克斯坦)。 您将收到一条非常侵入性的通知 这个事实,忽略证书验证是一个坏主意 失败通知。

怎么为自己的网站设置https加密传输数据 现在您有了一个网站,您决定,作为一个优秀的互联网公民,您 希望保护您的访客免受政府的窥探,通过 设置 HTTPS。 您已经知道您将需要一个公钥和一个 为此,由受信任的根 CA 签署的证书。 你怎么去 关于得到一个? 在互联网上搜索,你发现了一个很棒的项目,名为 Let's Encrypt 提供免费、签名的服务 证书。

文件安全

作为 root用户。 当程序启动时,它会继承其用户 ID 和组 ID 父进程,并保留它们,除非手动删除权限。 如果你 以 root 用户身份启动程序,因为,例如,它需要更深入的 系统访问,程序中的漏洞意味着攻击者可以 以 root 用户身份与您的计算机进行交互。 这是一个常见问题 错误配置的网络服务器,其中服务器以根目录运行 遍历漏洞可能允许攻击者读取秘密凭证 存储在服务器的文件系统上。

这个故事的寓意与最小特权原则紧密相连:无论在哪里 可能的话,只给予尽可能少的许可或特权。 如果 程序不需要 root 凭据,请勿以特权用户身份运行它。 如果 文件包含敏感内容,请勿使其可读。

如何更改权限? 有两个主要命令可以执行此操作: chmodchown. chmod更改文件模式,即权限,以及 其语法示例如下:

1
2
3
4
5
6
7
8
9
10
11
$ ls -la ~/
drwxr-xr-x 3 admin admin 4096 Oct 3 12:38 test
$ chmod 644 test
$ ls -la
drw-r--r-- 3 admin admin 4096 Oct 3 12:38 test
$ chmod u+x test
drwxr--r-- 3 admin admin 4096 Oct 3 12:38 test
$ chmod 000 test
d--------- 3 admin admin 4096 Oct 3 12:38 test
$ chmod +r test
dr--r--r-- 3 admin admin 4096 Oct 3 12:38 test

chmod接受八进制表示法的文件权限,即 下列的:

#读写
7读写
6RW-
5接收
4r–
3-wx
2-在-
1-X
0

pueept

● 流行的配置管理软件 ● 用于配置单个机器 ● 声明性哲学,必要时带有一些命令式组件 ● 最初基于 Ruby 构建,现在拥有自己的配置语言 流程: ● 客户端向服务器请求更新 ○ “我想配置为 Minecraft 服务器” ● 服务器向客户端询问事实列表 ○ “好的,请将您的主机名和 RAM 发送给我” ● 客户用事实回应 ○ “我的主机名是僵尸.ocf.berkeley.edu,我有 4GB RAM” ● 服务器响应配置 ○ “确保 Minecraft 服务器正在运行,主机名为僵尸.ocf.berkeley.edu,4GB RAM, 这个配置文件 ● 客户端进行必要的更改以确保其当前配置与 服务器给出的配置 ○ “minecraft服务器当前正在运行,但配置文件已更新,我将获取 更新后的版本 Puppet是一个配置管理工具,通过Puppet可以实现对大量服务器/主机的集中化、自动化的配置管理。Puppet的工作原理是:

  1. 在Puppet Master服务器上面编写Puppet Manifests(配置文件)。这些文件使用Puppet语言定义了服务器的最终状态。
  2. Puppet Agent安装在被管理的主机上面,它会定期从Puppet Master拉取配置。
  3. Puppet Agent对本地服务器状态进行检查,然后根据Manifests对服务器进行配置,确保服务器状态与预期状态一致。
  4. 如果配置发生变化,Puppet会自动应用这些变化,无需手动操作。
  5. Puppet Agent会定期运行,如果配置失效会再次修正。所以Puppet脚本就是编写Puppet Manifests的文件,它定义了需要配置什么,怎么配置。常见的配置包括:- 安装软件
  • 管理服务
  • 配置文件内容
  • 用户和权限
  • 安全设置
  • 定时任务 等等通过Puppet脚本可以实现服务器配置的版本控制、自动化部署,大幅减少管理时间成本。它适用于需要管理大量Linux/Unix主机的场景。

git

创建一个分支:

1
git checkout -b dice

这使得一个新的本地分支称为 dice基于我们所在的分支机构 目前在( master)并将您切换到 dice分支。 这个命令是 基本上简写为:

1
2
git branch dice       # Create new branch called 'dice'
git checkout dice # Switch to branch called 'dice'

您可以通过键入来查看您创建的分支 git branch。 你应该看到 此时有两个分支,一个称为 master和一个叫 dice。 一个 星号位于您当前签出的分支旁边。 git log查看历史提交。 每个提交都有一些信息,例如提交的作者、 创建提交的时间戳和提交消息。

  • 每个提交条目的第一行都有一个长的十六进制字符串。 这是 commit hash :将其视为可用于引用的唯一 ID 具体提交。

  • 有些提交在提交哈希旁边的括号中包含分支信息, 表明它们是最近的提交或 HEAD那个分支的。 你的 最近的提交应该有类似的内容 (HEAD -> dice)。 第四个 提交应该有 (origin/master, origin/HEAD)因为我们的分支机构 关闭 master并在其之上添加了三个新的提交。 请注意,如果 有人向本地或远程添加新提交 master, 分支 信息可能会更改或过时。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
commit adc45cd5110b59f76cefc2b862d0e4d550ccb183 (HEAD -> dice)
Author: thinklive1 <469631989@qq.com>
Date: Thu Oct 12 15:32:35 2023 +0800

Restrict input range for dice iterations and sides

commit a79a770157449a9d2fb1595a0b83ecc99070eabf
Author: thinklive1 <469631989@qq.com>
Date: Thu Oct 12 15:31:56 2023 +0800

Add dice rolling logic and output dice sum and sequence

commit 924d0b1ebf050a043da434114187a290280ec660
Author: thinklive1 <469631989@qq.com>
Date: Thu Oct 12 15:30:45 2023 +0800

Add -s flag for number of sides on a die

commit 3acb62af3eff4a1dbbe875e81ec1485d9d10c44b (origin/master, origin/HEAD, master)
Merge: 4e2aac7 2aefa6c
Author: Ishaan Dham <56564174+Ishaandham19@users.noreply.github.com>
Date: Tue Mar 21 21:39:51 2023 -0700

Merge pull request #34 from 0xcf/demo

Demo

commit 2aefa6c51449ffcd39d945e3d74ce2b5e50acf7f (origin/demo)
Author: Ishaan Dham <ishaandham01@gmail.com>

除了查看提交历史记录之外,您可能还想查看实际的更改 在代码中。 您可以使用 git diff <old commit> <new commit>查看 两次提交之间的差异。

除了查看提交历史记录之外,您可能还想查看实际的更改 在代码中。 您可以使用 git diff <old commit> <new commit>查看 两次提交之间的差异。 有几种不同的方式可以引用 一次提交。 之前提到的一个是复制提交的哈希值(请注意 您的提交哈希值将与下面的示例不同):

1
git diff 3368313c0afb6e306133d604ca72b0287124e8f2 762053064506810dee895219e5b2c2747a202829

您还可以复制提交哈希开头的一小块,而不是 整个哈希。 由于哈希的工作方式,您不太可能 有两个具有完全相同的起始序列的提交。

1
git diff 3368313 7620530

如果你想尝试 diff两个提交非常接近 日志,一种更简单的方法是通过距提交的距离来引用提交 HEAD (最近)使用以下格式提交 HEAD~<number>。 由于我们添加了三个 提交新的提交 dice,我们可以查看之间的差异 dicemaster使用以下命令:

1
git diff HEAD~3 HEAD

有多种方法可以处理合并冲突,但我们将采用的方法 在这个实验室中向您展示正在使用 git rebase。 我们的 dice分支是“基于” 这 master在某个时间点有分支,但是 master分行有 向前离开 dice基于过时的 master。 因此,我们想要 “重新基地” dice就目前的状态而言 master。 当你的 dice分支, 跑步 git rebase master。 Git 将回滚您所做的提交 dice, 复制 任何新的提交 master,并尝试在顶部重放您的提交。 有时 rebase无需您的干预即可运行完成,但是如果 存在合并冲突,您需要解决它。

Git 会告诉你如果遇到合并冲突该怎么办 在变基期间。 在这种情况下,打开 rand.py并找到冲突区域 应具有以下格式:

1
2
3
4
5
<<<<<<< HEAD
Lines of code from the base branch (in this case master)
=======
Lines of code from the branch you're rebasing (in this case dice)
>>>>>>> Commit message of the commit that conflicts with the base branch

要解决冲突,只需保留您想要的行(您的行来自 dice) 和 删除冲突区域中的其他行(

1
`<<<<<<< HEAD`, `=======`, `>>>>>>> dice`

,以及来自 master 的不需要的代码),然后保存并退出 文件。 Git 会将您保存的内容作为文件的确切形式 看起来像在变基结束时,所以你所做的本质上是修复 文件,以便代码正常运行。 这意味着如果您有多个 合并冲突,您决定混合保留基础分支中的一些行 还有一些来自您的功能分支,您需要确保代码确实有效 正确。

现在您已经解决了合并冲突,请按照变基说明进行操作 暂存您的固定文件( git add rand.py),然后运行 git rebase --continue。 如果 Git 发现其他文件有更多合并冲突,您将遵循相同的操作 程序如上。 然而,我们只有一个有冲突的文件,所以我们的变基是 完成的! 跑步 git log查看我们 rebase 的结果。 你现在应该看到了 你想象中的队友 "dice rolling WIP"提交您分支的历史记录, 你的提交高于他们的提交。

docker

安装 Docker wsl2不支持systemctl命令,而是支持systemed命令 所以需要执行如下命令启动docker

1
service docker start

虚拟机 你的电脑里有一台电脑! ● 通过软件模拟抽象物理硬件 ● 虚拟机管理程序运行多个虚拟机 ● 隔离应用:更好的安全性、稳定性 ● 一些开销:需要不同的客户操作系统和模拟 每个应用程序的虚拟硬件数量 ● 需要一些时间来启动

容器 ● 通常与虚拟机进行比较,但更像是捆绑的进程 环境 ● 提供类似的隔离 ○ 然而,比虚拟机要少得多! 出于这个原因,我们仍然经常在虚拟机内运行容器(但是 每个虚拟机可以运行 >1 个容器) ● 启动速度比虚拟机快得多 ● 目标是通过共享代码提供轻量级隔离环境 ● 轻松打包应用程序以实现一致的部署 ● 常见的容器:Docker、rkt、LXC ● 很确定这是加州大学伯克利分校唯一使用的课程

CommandDescription
docker searchSearch Docker Hub for pre-built images
docker pullPull an image or a repository from a registry
docker imagesList images
docker buildBuild an image from a Dockerfile
docker runRun a command in a new container
docker psList containers
docker start/stop/restartStart/stop/restart a container
docker execRun a command in a running container
docker inspectReturn low-level information on Docker objects
docker rmRemove one or more containers
docker rmiRemove one or more images

docker ● 需要构建镜像 ● 通常使用 Dockerfile 来指定 如何构建快照 ● 快照是分层构建的 ○ 像洋葱一样 ○ 允许基于相同的快照层构建速度更快 ● 保持每一层最少化资源

自动化配置管理工具 ● 声明式:说出你想要什么,而不是如何做 ○ 应用程序弄清楚如何 ● 可以定义要安装的应用程序、要包含的文件等 ● 可以在不同“类别”的机器上安装不同的东西 (桌面与服务器) ● 常用工具:Puppet、Ansible、Chef

docker的使用

docker run hello-world

您应该看到一些友好的输出,如下所示:

1
2
3
4
5
6
7
8
9
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
1b930d010525: Pull complete
Digest: sha256:c3b4ada4687bbaa170745b3e4dd8ac3f194ca95b2d0518b417fb47e5879d9b5f
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.
...

此消息表明您的安装似乎运行正常。 为了生成此消息,Docker 采取了以下步骤:

  1. Docker 客户端联系了 Docker 守护进程。
  2. Docker 守护进程从 Docker Hub 中提取“hello-world”镜像。
  3. Docker 守护进程从该映像创建了一个新容器,该容器运行生成您当前正在读取的输出的可执行文件。
  4. Docker 守护进程将该输出传输到 Docker 客户端,然后将其发送到您的终端。 在容器中默认以root用户身份登录。

以交互方式运行容器。 如果您需要在裸系统上尝试和安装东西而不弄乱当前系统,那么这非常有用。 尝试运行以下命令:

docker run -it ubuntu:latest

-iflag 告诉 docker 保留 STDIN打开你的容器,然后 -t分配一个 伪 TTY flag为您 。 基本上,您需要两者才能在新启动的容器中拥有一个 shell。 尝试安装一些软件包 apt或者只是玩玩。 它看起来应该像一个裸露的 Linux 系统。

使用 CTRL+D 退出容器。 自然的问题是,Docker 镜像是如何构建的? Dockerfile 就像镜像的源代码 相反,Dockerfile允许您通过指定手动键入创建镜像的所有命令来定义镜像。 然后 Docker 可以从指定Dockerfile 构建镜像。 这些 Dockerfile 可以放入版本控制中,并将镜像上传到在线存储库。

Docker可以通过读取来自Dockerfile的指令来自动构建镜像 。 Dockerfile是一个文本文档,其中包含所有命令 用户可以在命令行上调用来构建镜像。 eg.下面是一个 Dockerfile ,通过将 Python 3 和软件包安装到基础 Fedora Linux 映像上

1
2
3
4
5
6
7
8
9
10
11
12
13
# Specify Fedora Linux as base image
FROM fedora:latest

# Install Python with yum (Fedora's Package Manager)
# Install required Python packages
RUN yum update -y && yum install -y python3 python3-pip && \
python3 -m pip install pyfiglet termcolor

# Add the missile.py file to the final image
ADD missile.py /

# Specify the command to be run on container creation
CMD ["/usr/bin/python3", "missile.py"]

docker build -t missile:latest .

这告诉 Docker 在当前目录中查找 Dockerfile,并用该文件构建一个镜像。 这 -tflag 告诉 Docker 使用名称标记此构建 missile:latest

查看系统上正在运行的容器。 使用以下命令:

docker ps

由于您(可能)没有运行任何容器,因此您可能不会看到任何有趣的东西。 但是,如果您传入 -a标志,您还可以看到已停止的容器:

要获取有关容器的更多信息,您可以使用 docker logs命令 获取容器的日志(无论它仍在运行还是已退出):

docker logs <container_id_or_name>

在某些时候,您可能想要清理已退出且不打算再使用的容器:

docker rm <container_id_or_name>

将移除容器。

查看已经下载的镜像: docker images 图像可能会占用计算机上相当多的空间,因此您可能需要清理不打算使用的图像 使用。 如果您收到有关计算机上没有足够磁盘空间的错误,这一点尤其重要:

docker rmi <image_id>

镜像文件以及容器的各种文件系统都存储在 /var/lib/docker

分离容器

容器可以以后台服务的形式运行,这适用于一些后台服务的场合,Docker 支持这种方式 以 -d标志,见 分离 方式启动容器 模式

Docker 为容器创建一个单独的虚拟网络,因此您需要将主机端口转发到您的 容器的端口(这称为 端口转发 或端口映射)。 容器正在侦听端口 80,因此让我们尝试将主机的端口 5050 转发到容器的端口 :

docker run -d -p=5050:80 httpd

-p 接受冒号分隔的一对 HOST_PORT:CONTAINER_PORT

您实际上可以“附加”到正在运行的容器并在其中运行更多命令,类似于 docker run作品。 使用 这 docker exec命令:

docker exec <container_id_or_name> <command>

要停止此容器,请使用 docker stop <container_id_or_name>.

您可以使用以下命令重新启动容器 docker restart <container_id_or_name>.

关于 docker-compose

docker-compose允许您定义需要多个容器才能运行的应用程序。 例如,在网络上 应用程序,您可能希望实际的 Web 应用程序在单个容器内运行,并且数据库在其中运行 一个不同的容器。

通常,您根据 服务 来定义应用程序。 同样,以 Web 应用程序为例,有 两个不同的服务:应用程序本身和支持它的数据库。 docker-compose让您定义不同的服务 在 YAML 文件中并相应地运行服务。

其中一件好事是 docker-compose是它会自动为您的容器设置一个网络,其中:

  • 服务的每个容器都位于网络上,并且可以从网络上的其他容器访问
  • 每个容器都可以通过其容器名称在网络上发现

使用 Docker 官方网站上的说明安装 Docker Compose

一些小脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#!/bin/bash



PHONEBOOK_ENTRIES="phonelist.txt"




if [ "$#" -lt 1 ]; then

    exit 1



elif [ "$1" = "new" ]; then

    # YOUR CODE HERE #

    echo $2 $3 >> phonelist.txt



elif [ "$1" = "list" ]; then

    if [ ! -e $PHONEBOOK_ENTRIES ] || [ ! -s $PHONEBOOK_ENTRIES ]; then

        echo "phonebook is empty"

    else

        # YOUR CODE HERE #

        cat phonelist.txt

    fi



elif [ "$1" = "lookup" ]; then

    # YOUR CODE HERE #

    grep $2 phonelist.txt




elif [ "$1" = "remove" ]; then

    # YOUR CODE HERE #

    sed -i "s/$2//g" phonelist.txt




elif [ "$1" = "clear" ]; then

    # YOUR CODE HERE #

    rm phonelist.txt



else

     # YOUR CODE HERE #

     echo nothing

fi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash

host=$1

ping -c 1 $host >> log.txt

if [ $? -eq 0 ]; then

    echo "OK"

else

    echo "can't access"

fi
1
2
3
4
#1/bin/bash

ip addr show | grep "link/ether" | head -n 1 | cut -d' ' -f 6

]]>
- <p><a href="http://www.numpy.org/">Numpy</a> 是 Python 中科学计算的核心库。 它提供了高性能的多维数组对象以及使用这些对象的工具 数组。</p> -<h2 id="数组">数组</h2> -<p>numpy 数组是一个值网格,所有值都具有相同的类型,并由非负整数组成的元组索引。 它的维度就是数组的秩 ;它的shape就是每个维度的大小组成的元组 + <h1 id="shell脚本">shell脚本</h1> +<p>Shell 脚本通常以 shebang 行开头:#!path/to/interpreter。</p> +<p><code>#!</code>是一个人类可读的 <a href="https://en.wikipedia.org/wiki/Shebang_(Unix)#Magic_number">幻数表示</a> <code>0x23 0x21</code>它可以告诉 shell 将文件其余部分的执行传递给 指定翻译。 如果您的脚本作为可执行文件运行(例如 <code>./awesome_shell_script</code>) 加上 shebang 行,那么 shell 将调用 可执行文件(通常是解释器)位于 <code>path/to/interpreter</code>运行你的 脚本。 如果您的脚本作为参数传递给解释器,例如 <code>bash awesome_shell_script</code>,那么 shebang 没有效果并且 <code>bash</code>会处理 脚本的执行。 - + - - - + - + - 基于伯克利Sysadmin decal的linux笔记 - - https://thinklive1.github.io/2023/10/12/sysadmin/ - 2023-10-12T12:54:12.472Z + 基于伯克利ds100和cs231n的numpy笔记 + + https://thinklive1.github.io/2023/10/09/numpy/ + 2023-10-09T12:02:04.679Z 2023-11-27T12:50:13.887Z - shell脚本

Shell 脚本通常以 shebang 行开头:#!path/to/interpreter。

#!是一个人类可读的 幻数表示 0x23 0x21它可以告诉 shell 将文件其余部分的执行传递给 指定翻译。 如果您的脚本作为可执行文件运行(例如 ./awesome_shell_script) 加上 shebang 行,那么 shell 将调用 可执行文件(通常是解释器)位于 path/to/interpreter运行你的 脚本。 如果您的脚本作为参数传递给解释器,例如 bash awesome_shell_script,那么 shebang 没有效果并且 bash会处理 脚本的执行。 为什么这很重要? shebang 可以被认为是一个有用的部分 执行脚本的关注 如何 元数据传递了用户 给程序的作者。 awesome_shell_script可能是一个 bash脚本,一个 python脚本,一个 ruby脚本等。这个想法是只有脚本的 对于调用的用户来说,行为而不是其实现细节应该重要。

您可能已经看到过一些变体 #!/bin/sh。 虽然最初参考的是 现代系统上的 Bourne shell sh已经提到了 Shell Command Language ,这是一个具有多种实现的 POSIX 规范。 sh通常符号链接到这些符合 POSIX 标准的 shell 之一 实现 Shell 命令语言。 以 Debian 为例, sh是 符号链接到 shell dash。 重要的是要注意 bash不 **_** 遵守这个标准,虽然运行 bash作为 bash --posix做到了 更合规。

管道

我们可以使用 |字符将多个命令链接在一行中。 例如: command1 | command2 将传递的输出 command1作为输入 command2。 我们可以根据需要多次重复此操作。

循环使用 for

Bash 可以使用 for 循环对多个对象重复操作。 语法如下:

1
2
3
4
5
for VARIABLE in LIST; do

CONSEQUENT-COMMANDS

done

缩进不是必需的,但使代码更易于阅读。 这 LIST可以是包含多个文件的目录,也可以是包含多行 init 的文件、文件列表( file1 file2 file3),甚至是一系列数字( {start..end}).

有用的命令

一些对于完成实验可能有用的命令。 当然,解决问题的方法有很多,并不需要使用这些命令。

cat

cat 打印 将文件 到标准输出 。 对于打印一些内容以通过管道输入其他命令非常有用!

cut

cut [options] [filename]提取文件的某些部分(或管道输入) 参数 根据使用的 。 一些可能有用的:

-d允许我们更改分隔符,或更改字符 cut寻找将字符串分成块。 如果省略该选项, tab用来。

-f允许我们指定与要返回的字段对应的数字,例如 cut -f1 -d" "将返回句子中的第一个单词。 数字后跟一个 -也返回指定字段之后的所有字段,因此 cut -f1- -d" "将返回整个字符串。

--complement告诉 cut返回除 之外的所有内容。 指定字段

grep

grep [pattern] [filename] 过滤 并返回文件(或管道输入)中包含指定模式的行。

sed

sed可以做 很多事情 ,比如编辑字符串和匹配正则表达式。 我们可以用 sed将一种模式替换为另一种模式,如下所示:

sed 's/<PATTERN-TO-REPLACE>/<NEW-PATTERN>/g <INPUT>'

sed` 还可以从其他东西获取管道输入,而不是显式输入。

g最后告诉 sed替换所有出现的模式; 如果我们只想替换模式的第一次出现,则可以省略它,或者用数字替换以仅替换一定次数的出现。

xargs

xargs让我们将命令应用于从管道重定向的输出。 例如, output | xargs command会适用 commandoutput。 一些有用的 选项

-n1告诉 xargs将命令应用到中的每个项目 output如果输出中有多个项目(例如多个字符串的列表),则一次

-0告诉 xargs用空字符(表示字符串的结尾)分割输出中的项目,而不是使用空格。 搭配 -n1, 这意味着 xargs会将命令应用于每个字符串,而不是将字符串分解为单个单词并将命令应用于每个单词。

与往常一样,有更多方法可以使用这些命令,因此请使用 Google 或 手册页 来了解更多信息

语法

Shell 变量和类型

与大多数其他编程语言一样, bash促进有状态分配 名称到值作为变量。

变量可以被赋值 bash语法如下: NAME=value。 请注意 赋值运算符之间缺少空格 =及其操作数。 任务 对空格敏感。

您可以通过在前面添加一个来检索变量的值 $以它的名字。 获取值 NAME必须完成 $NAME。 这就是所谓的变量 插值。

1
2
3
4
5
6
7
8
$ NAME = "Tux" # Incorrect
-bash: NAME: command not found
$ NAME="Tux" # Correct
$ echo NAME # Incorrect. We want the value we assigned to NAME, not the text
# NAME itself.
NAME
$ echo $NAME # Correct
Tux

$?保存最近执行的命令的退出代码。 在这个 上下文、退出代码 0一般表示程序已经执行 成功地。 其他 退出代码 指的是错误的性质 导致程序失败。

特殊 位置参数 允许将参数传递到脚本中。 $0是脚本的名称, $1是传递给的第一个参数 脚本, $2是传递给脚本的第二个参数, $3是第三个 论证等 $#给出传递给脚本的参数数量。

所以 ./awesome_shell_script foo bar可以访问 foo$1bar$2.

Bash 变量是 无类型的 。 它们通常被视为文本(字符串),但是 如果变量包含数字和算术运算,则可以将其视为数字 对其应用操作。 请注意,这与大多数编程不同 语言。 变量 本身没有类型,但 运算符 会处理 在不同的环境下他们的价值观也不同。 换句话说, bash变量是文本,没有任何固有的行为或属性 可以操作的文本,但操作员会解释该文本 根据其内容(数字或无数字?)和上下文 表达。

算术

Bash 支持整数算术 let内置。

1
2
3
4
5
6
$ x=1+1
$ echo $x # Incorrect. We wanted 2, not the text 1+1.
1+1
$ let x=1+1
$ echo $x # Correct
2

注意 let对空格敏感。 操作数和运算符不得 用空格分隔。

bash本身不支持浮点运算,所以我们必须依赖 如果我们想处理十进制数字,请使用外部实用程序。 一个常见的选择 这是 bc。 有趣的事实: bc实际上是它自己的完整语言!

我们经常访问 bc通过 管道 (表示为 |),这允许 将一个命令的输出用作另一命令的输入。 我们包括 -l 选项 bc为了启用浮点运算。

1
2
$ echo 1/2 | bc -l
.50000000000000000000

test

Bash 脚本经常使用 [(同义词为 test) shell 内置的 表达式的条件评估。 test计算一个表达式并 以任一状态代码退出 0(true) 或状态代码 1(错误的)。

test支持常见的字符串和数字运算符,以及许多 额外的二元和一元运算符在大多数情况下没有直接类似物 其他编程语言。 您可以看到这些运算符的列表,以及 其他有用的信息,通过输入 help test在你的壳里。 的输出 如下所示。 注意 help类似于 man,除非它用于 bash 函数而不是其他程序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
$ help test
test: test [expr]
Exits with a status of 0 (true) or 1 (false) depending on
the evaluation of EXPR. Expressions may be unary or binary. Unary
expressions are often used to examine the status of a file. There
are string operators as well, and numeric comparison operators.

File operators:

-a FILE True if file exists.
-b FILE True if file is block special.
-c FILE True if file is character special.
-d FILE True if file is a directory.
-e FILE True if file exists.
-f FILE True if file exists and is a regular file.
-g FILE True if file is set-group-id.
-h FILE True if file is a symbolic link.
-L FILE True if file is a symbolic link.
-k FILE True if file has its `sticky' bit set.
-p FILE True if file is a named pipe.
-r FILE True if file is readable by you.
-s FILE True if file exists and is not empty.
-S FILE True if file is a socket.
-t FD True if FD is opened on a terminal.
-u FILE True if the file is set-user-id.
-w FILE True if the file is writable by you.
-x FILE True if the file is executable by you.
-O FILE True if the file is effectively owned by you.
-G FILE True if the file is effectively owned by your group.
-N FILE True if the file has been modified since it was last
read.

FILE1 -nt FILE2 True if file1 is newer than file2 (according to
modification date).

FILE1 -ot FILE2 True if file1 is older than file2.

FILE1 -ef FILE2 True if file1 is a hard link to file2.

String operators:

-z STRING True if string is empty.

-n STRING
STRING True if string is not empty.

STRING1 = STRING2
True if the strings are equal.
STRING1 != STRING2
True if the strings are not equal.
STRING1 < STRING2
True if STRING1 sorts before STRING2 lexicographically.
STRING1 > STRING2
True if STRING1 sorts after STRING2 lexicographically.

Other operators:

-o OPTION True if the shell option OPTION is enabled.
! EXPR True if expr is false.
EXPR1 -a EXPR2 True if both expr1 AND expr2 are true.
EXPR1 -o EXPR2 True if either expr1 OR expr2 is true.

arg1 OP arg2 Arithmetic tests. OP is one of -eq, -ne,
-lt, -le, -gt, or -ge.

Arithmetic binary operators return true if ARG1 is equal, not-equal,
less-than, less-than-or-equal, greater-than, or greater-than-or-equal
than ARG2.

我们可以测试整数相等

1
2
3
4
$ [ 0 -eq 0 ]; echo $? # exit code 0 means true
0
$ [ 0 -eq 1 ]; echo $? # exit code 1 means false
1

字符串相等

1
2
3
4
$ [ zero = zero ]; echo $? # exit code 0 means true
0
$ [ zero = one ]; echo $? # exit code 1 means false
1

以及您可以自由进行的许多其他字符串和数字运算 探索。

控制结构

bash包括大多数编程语言典型的控制结构 – if-then-elif-else, while for-in等等。您可以阅读更多有关 条件语句迭代 中的 Bash 指南 初学者 Linux 文档项目 (LDP) 的 。 我们鼓励您 请阅读这些部分,因为本指南仅提供了一些内容的简短摘要 重要特征。

if-then-elif-else

if 语句的一般形式 bash

1
2
3
4
5
6
7
8
9
10
11
12
13
if TEST-COMMANDS; then

CONSEQUENT-COMMANDS

elif MORE-TEST-COMMANDS; then

MORE-CONSEQUENT-COMMANDS

else

ALTERNATE-CONSEQUENT-COMMANDS;

fi

缩进是一种很好的做法,但不是必需的。

例如,如果我们写

1
2
3
4
5
6
7
8
#!/bin/bash
# contents of awesome_shell_script

if [ $1 -eq $2 ]; then
echo args are equal
else
echo args are not equal
fi

我们看

1
2
3
4
$ ./awesome_shell_script 0 0
args are equal
$ ./awesome_shell_script 0 1
args are not equal

尽管

while 循环的一般形式 bash

1
2
3
4
5
while TEST-COMMANDS; do

CONSEQUENT-COMMANDS

done

如果 TEST-COMMANDS退出并带有状态码 0, CONSEQUENT-COMMANDS将要 执行。 这些步骤将重复,直到 TEST-COMMANDS退出时带有一些非零值 地位。

例如,如果我们写

1
2
3
4
5
6
7
8
#!/bin/bash
# contents of awesome_shell_script

n=$1
while [ $n -gt 0 ]; do
echo $n
let n=$n-1
done

我们看

1
2
3
4
5
6
$ ./awesome_shell_script 5
5
4
3
2
1

函数

bash supports functions, albeit in a crippled form relative to many other languages. Some notable differences include:

  • 函数不 返回 任何内容,它们只是产生输出流(例如 echo到标准输出)
  • bash严格来说是按值调用。 也就是说,只有原子值(字符串)可以 被传递到函数中。
  • 变量没有词法作用域。 bash使用一个非常简单的本地系统 范围接近动态范围。
  • bash没有一流的函数(即没有将函数传递给 其他函数)、匿名函数或闭包。

功能于 bash定义为

1
2
3
4
5
name_of_function() {

FUNCTION_BODY

}

并由

1
name_of_function $arg1 $arg2 ... $argN

请注意函数签名中缺少参数。 参数在 bash 函数的处理方式与全局位置参数类似,其中 $1 含有 $arg1, $2含有 $arg2, ETC。

例如,如果我们写

1
2
3
4
5
6
7
8
#!/bin/bash
# contents of awesome_shell_script

foo() {
echo hello $1
}

foo $1

我们看

1
2
$ ./awesome_shell_script world
hello world

实例

斐波那契

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#!/bin/bash
# contents of fibonacci

if [ $# -eq 0 ]; then
echo "fibonacci needs an argument"
exit 1
fi

fib() {
N="$1"
if [ -z "${N##*[!0-9]*}" ]; then
echo "fibonacci only makes sense for nonnegative integers"
exit 1
fi

if [ "$N" -eq 0 ]; then
echo 0
elif [ "$N" -eq 1 ]; then
echo 1
else
echo $(($(fib $((N-2))) + $(fib $((N-1)))))
fi
}

fib "$1"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
read -p “send: ” FOO
# enter “hi”
echo “sent: $FOO”
sent: hi

FOO=$(expr 1 + 1)
echo “$FOO”
2

-eq ==
-ne !=
-gt >
-ge >=
-lt <
-le <=

test zero = zero; echo $?
0 # 0 means true
test zero = one; echo $?
1 # 1 means false

if [ “$1” -eq 69 ];
then
echo “nice”
elif [ “$1” -eq 42 ];
then
echo “the answer!”
else
echo “wat r numbers”
fi

read -p "are you 21?" ANSWER
case "$ANSWER" in
“yes”)
echo "i give u cookie";;
“no”)
echo "thats illegal";;
“are you?”)
echo “lets not”;;
*)
echo "please answer"
esac

NAMES="a b c d"
for NAME in $NAMES
do
echo "Hello $NAME"
done

while true
do
echo "Hello $NAME"
done

Bash 支持整数算术 let内置的。

1
2
3
4
5
6
$ x=1+1
$ echo $x # Incorrect. We wanted 2, not the text 1+1.
1+1
$ let x=1+1
$ echo $x # Correct
2

注意 let对空格敏感。 操作数和运算符不得 用空格分隔。 test计算一个表达式并 以任一状态代码退出 0(true) 或状态代码 1(错误的)

bash支持函数,尽管相对于许多其他函数而言,其形式有缺陷 语言。 一些显着的差异包括:

  • 函数不 返回 任何内容,它们只是产生输出流(例如 echo到标准输出)
  • bash严格来说是按值调用。 也就是说,只有原子值(字符串)可以 被传递到函数中。
  • 变量没有词法作用域。 bash使用一个非常简单的本地系统 范围接近动态范围。
  • bash没有一流的函数(即没有将函数传递给 其他函数)、匿名函数或闭包

请注意函数签名中缺少参数。 参数在 bash 函数的处理方式与全局位置参数类似,其中 $1 含有 $arg1, $2含有 $arg2, ETC。

例如,如果我们写

1
2
3
4
5
6
7
8
#!/bin/bash
# contents of awesome_shell_script

foo() {
echo hello $1
}

foo $1

我们看

1
2
$ ./awesome_shell_script world
hello world

shell命令

SSH(安全外壳)

SSH 允许您通过互联网登录远程计算机。 这相当于在远程计算机上打开 shell。

用法是 ssh [remote username]@[remote host].

问题

  1. 登录到 tsunami.ocf.berkeley.edu使用您的 OCF 用户名和密码。 有一个文件在 ~staff/public_html/decal。 打开它。 文件中到底隐藏着什么秘密?

管道和重定向

将命令链接在一起对于自动化 shell 操作至关重要。 这是一个快速备忘单:

>:将 标准 输出重定向到文件(将覆盖该文件)。

>>:将标准输出附加到文件(与 >除非不覆盖)。

<:从文件中读取输入。

|:将一个程序的输出发送到下一个程序的输入。

下面是一个示例:假设您正在参加一门课程,需要您提交一个包含您的 SID 的文本文件。 您的第一反应可能是打开一个文本编辑器(例如 vim)并简单地输入它,但是有一种更快的方法来创建文件! 这里是:

echo '123456789' > sid.txt

tmux

为什么是 tmux?

  • 当通过 ssh 连接到一台计算机时,您可以打开多个窗口。
  • 您可以在编辑程序的同时对其进行编译和运行。
  • 您可以注销并通过 ssh 重新登录,而无需重新打开所有文件。

入门

  • 开始会话 tmux.
  • 从会话中分离 Ctrl-b d(释放后按 d Ctrl-b)
  • 分成 2 个窗格 Ctrl-b %(垂直)或 Ctrl-b "(水平的)
  • 交换当前窗格 Ctrl-b o
  • 在线查找有关 tmux 的更多信息。 您可能会发现 此备忘单 很有帮助!

包管理

Debian:简介 aptdpkg

在本课程中,我们将重点关注 Debian 的使用。 正如本周讲座中提到的,Debian 使用 apt/dpkg 作为其包管理器。 其他发行版使用不同的包管理器。

apt

Debian 的前端包管理器是 apt。 大多数时候,当您需要与包管理器打交道时, apt通常是要走的路。 在做任何事情之前 apt,更新包列表通常是一个好习惯,以便包管理器可以找到并获取各种包的最新版本。 为此,您可以运行:

apt update

要查找要安装的包:

apt search [package|description]

要安装包:

apt install [package]

要删除包:

apt remove [package]

使用安装的软件包一段时间后,您可能会注意到它们不会自动更新,这一功能可能存在于为其他操作系统编写的程序中。 要更新已安装的软件包,请运行:

apt upgrade或有时 apt dist-upgrade

使用起来比较普遍 apt upgrade更新你的包,但有时你需要使用 apt dist-upgrade。 阅读有关两者之间差异的更多信息 您可以在此处

在某些情况下,您希望完全确定要安装的软件包的版本。 要列出可以安装的潜在版本,您可以运行:

apt policy [package]

这根据其引脚优先级列出了要安装的候选版本以及与系统兼容的其他版本。 要安装特定目标版本的 aa 版本,您可以运行:

apt -t [targetrelease] install [package]

还有其他命令可以删除不需要的依赖项并清除包,但这就是 man页面是为了。 请注意,您将必须使用 sudo对于上述命令,因为您实际上是在修改系统本身。

dpkg

后端包管理器是 dpkg。 传统上, dpkg用于安装本地软件包。 使用 dpkg,您还可以检查软件包并修复损坏的安装。 要安装本地软件包,请运行:

dpkg -i [packagefilename]

删除系统包:

dpkg --remove [package]

要检查包以获取有关该包的更多信息:

dpkg -I [packagefilename]

要修复/配置所有已解压但未完成的安装:

dpkg --configure -a

入门

创建一个简单的包

现在,我们将使用您将在接下来的步骤中创建的 hellopenguin 可执行文件创建一个简单的包。 首先,移至您在入门部分克隆的存储库中的 a2 文件夹:

cd decal-labs/a2

现在我们将创建一个文件夹来进行此练习:

mkdir ex1

现在进入该文件夹:

cd ex1

编写和编译程序

现在,我们将用 C 语言制作一个非常简单的应用程序,打印“Hello Penguin!” 名为地狱企鹅。 调用:

touch hellopenguin.c

这将创建一个名为的空文件 hellopenguin.c。 现在,使用您选择的首选文本编辑器,例如 vim, emacs, 或者 nano,将以下代码插入 hellopenguin.c

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>

int main()

{

printf("Hello Penguin!\n");

return 0;

}

我们现在将编译您刚刚编写的源文件:

gcc hellopenguin.c -o hellopenguin

其作用是获取源文件 hellopenguin.c并将其编译为名为的可执行文件 hellopenguin-o输出标志。

打包可执行文件

现在,我们将创建可执行文件所在的文件夹结构。在 Debian 中,用户级包通常驻留在该文件夹中 /usr/bin/:

mkdir -p packpenguin/usr/bin

现在移动你编译的 hellopenguin可执行到 packpenguin/usr/bin/文件夹。

mv hellopenguin packpenguin/usr/bin/

现在我们将创建一个名为 hellopenguin。 移动到父目录 packpenguin文件夹并调用以下命令:

fpm -s dir -t deb -n hellopenguin -v 1.0~ocf1 -C packpenguin

这指定您要使用目录 -s标志,并输出 .deb包使用 -t旗帜。 它接受一个名为的目录 packpenguin, 使用 -C标志,并输出 .deb文件名为 hellopenguin, 使用 -n,版本号为 1.0~ocf1, 使用 -v旗帜。

现在通过调用 apt 并安装它来测试它:

sudo dpkg -i ./hellopenguin_1.0~ocf1_amd64.deb

现在你应该能够运行 hellopenguin通过执行以下操作:

hellopenguin

计算机网络

概述

不可否认,互联网是一个重新定义了我们世界的重要系统。 开发网络和允许设备通信的能力对于现代计算机系统至关重要。 本实验将研究计算机网络的基础知识,然后从系统管理员的角度检查网络。

我们将使用网页浏览作为类比来了解网络的基础知识。 当我上网浏览猫的图片时到底会发生什么?

但首先让我们简要了解一下网络的细节。


硬件地址mac

媒体访问控制 (MAC) 地址是唯一分配给网络接口的标识符。 所有文字

由于 MAC 地址是唯一的,因此通常称为物理地址。 八位位组通常以十六进制书写并用冒号分隔。 MAC 地址示例是 00:14:22:01:23:45。 请注意,前 3 个八位位组指的是组织唯一标识符 (OUI),它可以帮助识别制造商。 有趣的事实—— 00:14:22以上是 Dell 的 OUI。

ip

IP 地址是识别根据互联网协议连接到网络的设备的方法。 互联网协议有两个版本:IPv4 和 IPv6,它们的地址大小不同。 IPv6 地址示例是 2001:0db8:85a3:0000:0000:8a2e:0370:7334它比 IPv4 地址长得多,例如 127.0.0.1。 由于时间关系,我们只讨论 IPv4,但 IPv6 确实正在取得进展,值得一试!

IPv4 地址为 32 位,即 4 个字节,每个字节由点 (.) 分隔。 IPv4 地址示例是 127.0.0.1。 巧合的是,这个地址被称为环回地址,它映射到您自己机器上的环回接口。 这允许网络应用程序在同一台计算机(在本例中是您的计算机)上运行时相互通信。 但为什么 127.0.0.1并不是 127.0.0.0或者 127.0.0.2?

答案是 127.0.0.1是简单的约定,但从技术上讲,网络块中的任何地址 127.0.0.0/8是一个有效的环回地址。 但网络块到底是什么?

在 IPv4 中,我们可以将地址块划分为子网。 这是以 CIDR 格式编写的。 我们以上面的子网为例 127.0.0.0/8。 斜杠后面的数字 ( /),在本例中为 8,是子网掩码。 这表示网络地址中有多少位,其余位标识网络内的主机。 在这种情况下,网络地址是 127.0.0.0面具是 255.0.0.0。 所以 127.0.0.1将是第一个主机 127.0.0.0/8网络等等。

该图提供了 CIDR 寻址的可视化细分 所有文字

ARP

地址解析协议 (ARP) 是用于将 IP 地址解析为 MAC 地址的协议。 为了理解ARP,我们首先讨论发送帧的两种方式,单播和广播。 在第 2 层上下文中,单播帧意味着将该帧发送到一个 MAC 地址。 另一方面,通过将帧发送到广播地址来广播帧意味着该帧应该发送到网络上的每个设备,从而有效地“淹没”本地网络。

例如,让我们想象一个发送者 A,他有 MAC 00:DE:AD:BE:EF:00,广播一条消息,本质上是询问“谁拥有 IP 地址 42.42.42.42请在 00:DE:AD:BE:EF:00 告诉 A”。

如果一台机器B,有MAC 12:34:56:78:9a:bc有IP地址 42.42.42.42他们向发件人发送单播回复,其中包含以下信息“ 12:34:56:78:9a:bc42.42.42.42”。 发送方将此信息存储在 arp 表中,因此每当它收到发往机器 B 的数据包时,即目标 IP 地址为 42.42.42.42它将数据包发送到从 B 收到的 MAC。

为了路由 IP 数据包,设备具有所谓的路由表。 路由条目存储在路由表中,它们本质上是告诉设备应如何基于 IP 转发数据包的规则。 路由条目指定子网以及与该条目对应的接口。 设备选择具有最特定于给定数据包的子网的条目,并将其转发出该条目上的接口。

路由表通常也有一个默认网关。 在没有更具体的匹配条目的情况下,这将用作数据包的默认捕获所有内容。

以此路由表为例。

1
2
3
4
default via 10.0.2.2 dev eth0
10.0.2.0/24 dev eth0 proto kernel scope link src 10.0.2.15
10.0.2.128/25 dev eth0 proto kernel scope link src 10.0.2.15
192.168.162.0/24 dev eth1 proto kernel scope link src 192.168.162.162

一个数据包的目的地是 8.8.8.8将从默认网关 eth0 转发出去。 一个数据包的目的地是 10.0.2.1将根据第二个条目从 eth0 转发。 一个数据包的目的地是 10.0.2.254将根据第三个条目从 eth0 转发。 一个数据包的目的地是 192.168.162.254将根据第四个条目从 eth1 转发。

域名

我们已经讨论了 IP 地址以及它们如何通过 IP 与主机进行通信,但是虽然 IP 地址是机器友好的(计算机喜欢数字),但它们并不完全是人类友好的。 记住电话号码已经够难了,记住 32 位 IP 地址也不会更容易。

但我们更容易记住 <www.google.com、www.facebook.com> 或 Coolmath-games.com 等名称。 因此,在这种冲突中,域名系统 (DNS) 诞生了,它是机器友好的 IP 地址和人类友好的域名之间的折衷方案。

DNS 是一个将 google.com 等域名映射到 172.217.6.78。 当您查询 google.com 时,您的计算机会将 google.com 的 DNS 查询发送到 DNS 服务器。 假设配置正确并且 google.com 有一个有效的对应地址,您将收到来自权威服务器的响应,其实质上是“google.com 有 IP 地址” x.x.x.x”.

现在让我们稍微消除一下这个黑魔法……

DNS 记录

DNS 服务器以资源记录 (RR) 的形式存储数据。 资源记录本质上是(名称、值、类型、TTL)的元组。 虽然 DNS 记录的类型多种多样,但我们最关心的是

  1. 一条记录 名称 = 主机名 值 = IP 地址

    该记录非常简单,包含给定主机名的 IP 地址,本质上是我们最终想要得到的信息。

  2. 国民服役记录 名称=域名 值 = 域的 DNS 服务器名称

    该记录指向另一个可以为该域提供权威答案的 DNS 服务器。 将此视为将您重定向到另一个名称服务器。

  3. CNAME 记录 名称 = 别名 值=规范名称

    这些记录指向给定别名的规范名称,例如 docs.google.com 将是一个仅指向 document.google.com 的别名 尝试 <www.facebook.com>

  4. MX记录 邮件服务使用的记录。

TCP 和 UDP

现在我们将讨论传输层的协议。 这一层最著名的两个协议是传输控制协议(TCP)和用户数据报协议(UDP)。

TCP 是一种面向有状态流的协议,可确保可靠的传输。 可靠的传输本质上保证信息完整且有序地到达目的地。

TCP 是面向连接的协议,这意味着它在发送任何数据之前必须首先建立连接。 此连接交换信息,这是 TCP 用于在其他功能中提供可靠传输的机制。 TCP 连接以 TCP 握手开始。

TCP 握手包括在发送方和接收方之间交换的数据包的 TCP 标头中设置某些标志。 发送方首先发送 SYN(设置了 SYN 标志的数据包)来启动 TCP 连接。 服务器通过发回 SYN-ACK(一个同时设置了 SYN 和 ACK 标志的数据包)来确认此连接请求。 客户端通过向服务器发送一个最终 ACK 来确认这一点,然后建立连接。

TCP 然后开始传输数据,如果数据成功到达连接的另一端,则会发出 ACK。 因此,如果数据丢失、重新排序或损坏,TCP 能够识别这一点并发送重传任何丢失数据的请求。

TCP 也有一个关闭连接的过程。 我们在这里只考虑优雅终止,突然终止有不同的过程,我们不会讨论。 如果您有兴趣,CS168 这里 有一些很棒的材料。 假设机器 A 想关闭与机器 B 的连接。

A 首先发送 FIN。 B 必须通过发送 FIN 和 ACK 进行响应。 如果 B 仅发送 ACK,则连接将持续存在,并且可以发送其他数据,直到发送 FIN。 另一方面,如果 B 准备好关闭连接并且不需要发送额外的数据,则 B 也可以只发送一个同时设置了 FIN 和 ACK 标志的数据包,即 FIN+ACK。发送最后一个 ACK​​ 来表示连接终止。

UDP是无状态无连接协议。 UDP 专注于以数据报的形式发送消息。 无连接 UDP 也不会产生 TCP 握手和终止的开销。 UDP 也不保证可靠传输,因此消息可能会损坏、无序到达或根本不到达。 因此,UDP 有时被称为不可靠数据报协议。

虽然 UDP 不保证可靠传输,但它不会像 TCP 那样遭受建立和关闭连接的开销。 因此,UDP 非常适合我们只想快速发送数据包并且丢失一些数据包也不会造成灾难性后果的使用情况。

此外,与 TCP 相比,发送的每个 UDP 数据报都需要单独接收。 而对于 TCP,您传递的数据流被透明地分成一定数量的发送,并且数据流在另一端透明地重建为一个整体。

端口

广义上讲,端口定义了服务端点——端口标记了流量的入口和出口点。 IP 地址连接主机,而端口则连接在此类主机上运行的进程。 一次只能将一个进程绑定到一个端口。 端口由 16 位数字表示,范围从 0 到 65535。从 0 到 1023 的端口是众所周知的端口,即系统端口。 使用这些端口通常有更严格的要求。 1024 到 49151 是注册端口。 官方 列表 IANA 维护着知名和注册范围的 。 从 49152 到 65535 的其余端口是临时端口,可以根据每个请求动态分配给通信会话。

systemd unit

unit的介绍和写法 Linux 发行版越来越多地采用 systemd初始化系统。 这套功能强大的软件可以管理服务器的许多方面,从服务到安装的设备和系统状态。

systemd, A unit指系统知道如何操作和管理的任何资源。 这是主要对象 systemd工具知道如何处理。 这些资源是使用称为单元文件的配置文件定义的。

单位是对象 systemd知道如何管理。 这些基本上是系统资源的标准化表示,可以由守护程序套件管理并由提供的实用程序操作。

单元可以说类似于其他 init 系统中的服务或作业。 然而,单元具有更广泛的定义,因为它们可用于抽象服务、网络资源、设备、文件系统挂载和隔离资源池。 系统的单元文件副本一般保存在 /lib/systemd/system目录。 当软件在系统上安装单元文件时,这是它们默认放置的位置。

存储在此处的单元文件可以在会话期间按需启动和停止。 这将是通用的普通单元文件,通常由上游项目的维护人员编写,应该适用于部署的任何系统 systemd在其标准实施中。 您不应编辑此目录中的文件。 相反,如果有必要,您应该使用另一个单元文件位置来覆盖该文件,该位置将取代该位置中的文件。 正确的方法是创建一个以单元文件命名的目录 .d附加在最后。 所以对于一个叫做 example.service,一个名为 example.service.d可以被创建。 在此目录中,有一个以以下结尾的文件 .conf可用于覆盖或扩展系统单元文件的属性。

大多数单元文件中的第一部分是 [Unit]部分。 这通常用于定义单元的元数据并配置单元与其他单元的关系。

尽管部分顺序并不重要 systemd解析文件时,此部分通常放置在顶部,因为它提供了单元的概述。 您可以在以下位置找到一些常见指令 [Unit]部分是:

  • Description=:该指令可用于描述单元的名称和基本功能。 它由各种返回 systemd工具,因此最好将其设置为简短、具体且信息丰富的内容。
  • Documentation=:该指令提供了文档 URI 列表的位置。 这些可以是内部可用的 man页面或网络可访问的 URL。 这 systemctl status命令将公开此信息,以便于轻松发现。
  • Requires=:该指令列出了该单元本质上依赖的所有单元。 如果当前单位已激活,则此处列出的单位也必须成功激活,否则该单位将失败。 默认情况下,这些单元与当前单元并行启动。
  • Wants=:该指令类似于 Requires=,但不太严格。 Systemd当此单元被激活时,将尝试启动此处列出的任何单元。 如果未找到这些单元或无法启动,当前单元将继续运行。 这是配置大多数依赖关系的推荐方法。 同样,这意味着并行激活,除非被其他指令修改。
  • BindsTo=:该指令类似于 Requires=,但也会导致当前单元在关联单元终止时停止。
  • Before=:如果同时激活了该指令中列出的单元,则只有当前单元被标记为已启动后,它们才会启动。 这并不意味着依赖关系,并且如果需要的话必须与上述指令之一结合使用。
  • After=:该指令中列出的单元将在启动当前单元之前启动。 这并不意味着依赖关系,如果需要,必须通过上述指令建立依赖关系。
  • Conflicts=:这可用于列出不能与当前单元同时运行的单元。 启动具有这种关系的单元将导致其他单元停止。
  • Condition...=: 有许多指令以 Condition这允许管理员在启动设备之前测试某些条件。 这可用于提供仅在适当的系统上运行的通用单元文件。 如果不满足条件,则会正常跳过该单元。
  • Assert...=:类似于以 Condition,这些指令检查运行环境的不同方面,以决定是否应激活该单元。 然而,与 Condition指令,负结果会导致该指令失败。

安全管理

加密与解密

基础知识

加密采用明文和密钥,返回密文。 解密需要密文和密钥,仅当解密密钥有效时才恢复并返回原始明文。 加密和解密的密钥是由随机位组成的长字符串,这使得攻击者在计算上无法猜测密钥并解密密文。

一切 安全性是指在面对攻击时保持系统按预期运行 这可以采取多种形式:

  1. 保密性
  2. 完整性/真实性
  3. 可用性

模块:

  1. 认证
  2. 加密:防止攻击者读取您的文件,直到它们得到 联邦调查局和他们的密码学家参与其中
  3. 哈希:将大数据转化为小数据
  4. 签名和证书:确保您就是您所说的人 假设我想使用你的公钥来验证你的身份。 我 可以用它加密一些东西,并要求你解密它并且 显示正确的值。 如果您可以解密该值,那么您必须拥有密钥的私有部分并且可以进行身份​​验证。 假设你想证明你发送的消息实际上是由您发送。 您可以使用您的私钥来“签署”消息通过对其进行加密,您的公钥可用于解密签名以验证您(由您发布的公开信息识别)键)实际上确实发送了消息,因为只有您而不是其他人对手将拥有相应的私钥。 根证书:操作系统包含许多根证书 这是网络信任的基础。 证书是在通向根的链中签名; 如果链有效,则最后的 cert 被认为是可信的。

网络攻击: 攻击网络系统的方法有很多: 窃听、中间人、拒绝服务、应用程序 缓冲区/堆溢出、SQL 注入等漏洞 目录遍历、CSRF、SSRF、XSS、蠕虫、rootkit、垃圾邮件、加密挖矿、勒索软件、网络钓鱼等等……

对称密码学

在对称密码学中,用于加密和解密的密钥是相同的。

尝试一下:

  1. gpg --symmetric [FILE]在任何文件上输出 [FILE].gpg文件是输入文件的加密版本。 加密文件时需要输入密码。
  2. gpg --decrypt [FILE].gpg在原始文件的加密版本上,您需要输入原始密码。

在此 GPG 实现中,文件的加密和解密都需要知道单个密码,在本例中该密码充当对称密钥。

非对称密码学

在非对称加密中,两个单独的密钥分别用于加密和解密。 这两个密钥是一对公私密钥。 公钥是公开的并用于加密数据。 而私钥由所有者保密并用于解密数据。 使用公钥加密文件意味着只有拥有相应私钥的人才能解密生成的加密文件。

GPG 钥匙圈抽象

GPG 使用“密钥环”作为集中位置来保存用户的所有密钥。 如果您想使用并保留它,则需要向密钥环添加/导入密钥。 同样,如果您希望与其他人共享密钥,您可以导出您的密钥(这会生成您的密钥的副本)并让他们将其导入到他们的密钥环中。

尝试一下:

  1. gpg --full-generate-key生成 GPG 公私密钥对。 它会要求输入密码。 如果您的机器需要一段时间才能生成密钥,则可能是由于缺乏长随机密钥所需的熵(随机性)。 sudo apt-get install haveged将安装一个生成熵的守护进程。
  2. gpg --recipient [RECIPIENT] --encrypt [FILE]这将加密 [FILE][RECIPIENT]的公钥(目前,尝试使用您自己的公钥加密文件)。
  3. gpg --decrypt [FILE].gpg将搜索您的密钥环并使用适当的私钥解密文件(当然,如果您拥有正确的私钥)。 您无需指定使用哪个密钥来解密文件,因为 GPG 加密的文件和密钥包含元数据,允许 GPG 从密钥环中选择正确的密钥来解密文件。

签名

公钥加密、私钥解密的非对称方案也可以反过来实现数字签名,其作用相当于物理签名。 在这个相反的方案中,私钥用于对文件进行签名,从而在该文件上生成签名。 并使用相应的公钥来验证签名。 因此,只有拥有私钥的人才能生成签名,但拥有相应公钥的任何人都可以验证该签名。

UNIX 权限模型有 3 个组成部分:授予文件的 (1) 所有者用户、(2) 所有者组和 (3) 其他人/其他所有人的权限。 权限本身有 3 个子组件:(1) 读取、(2) 写入和 (3) 执行,强制执行读取、写入或执行文件的能力。

gpg

  1. 解密b8/file1.txt.gpg:
1
gpg --decrypt b8/file1.txt.gpg 
  1. 输入密码ocfdecal后,解密内容为: mYp@sw0rd2. 导入密钥的命令是:
1
gpg --import {key_file}
  1. 将密钥导出到文件的命令:
1
gpg --export --armor {key_id} > {output_file}
  1. 查看钥匙圈所有钥匙的命令:
1
gpg --list-keys
  1. 使用私钥b8/lab8privkey解密b8/file2.txt.gpg:
1
2
gpg --import ./lab8privkey
gpg --decrypt ./file2.txt.gpg

hash

  1. sha1sum [FILE]获取 SHA1 哈希值 [FILE].
  2. md5sum [FILE]获取 MD5 哈希值 [FILE].

安全系统

威胁模型

设计安全系统时要记住的最重要的事情是 了解您的威胁模型。 没有系统能够保证安全或能够 能够抵挡所有的攻击,甚至在极端的情况下也是不可能的。 对手。 但是,您可以(并且应该)针对威胁采取预防措施 你很可能会面临。 平衡授权用户访问的需求 在将未经授权的用户拒之门外的情况下,很容易出错。 幸运的是,聪明人已经将安全原则提炼为 中得到了很好的 第一个讲义 一些公理,在CS 161 的 介绍 (归功于大卫·瓦格纳教授)。 建议阅读讲义。

构建威胁模型时,请记住以下问题:

  1. 你在保护什么?
  2. 谁是你的对手?
  3. 您需要保护它的可能性有多大?
  4. 如果不加以保护,会产生什么后果?
  5. 您应该投入多少资源来保护它?

加密解密

对称密钥加密几乎对所有事物都有用,尤其是属于以下类别的事物:

  • 加密传输中的数据(例如 HTTPS)
  • 加密静态数据(例如手机上存储的数据)

作为示例,我们来探讨一下 iPhone 如何使用加密来保证数据安全:

  1. iPhone 的内部存储使用一组 AES 密钥进行加密,这些密钥存储在手机内部芯片上,并在工厂生成。
  2. 这些密钥又使用您的 PIN 进行加密。 您的 PIN 码允许手机解锁密钥,从而解密文件系统的其余部分。

与对称密钥加密不同,公钥加密中有 2 个密钥 ,密码系统由公钥私钥组成 。 顾名思义, 公钥是公开共享的,这是其他人可以使用的方式 加密适合您的数据。 您使用您的私钥来解密此内容 数据。 只要没有人拥有你的私钥,任何人都可以使用你的公钥 加密数据并确保只有您可以解密它。 这是一个强大的 对称密钥范式的扩展,除了加密之外,它还允许 签名和不可否认性 公钥密码学与 RSA 算法 同义, 是最早经过验证的双密钥方案之一。 RSA 公钥加密工作原理的简要概述

  1. RSA算法,通过一些高等数学(涉及素数和模数) 算术),返回 3 个数字:一个公共指数(又名密钥),一个私有指数, 和一个模数。 两个密钥的工作方式使得用一个密钥加密的数据只能 可以用另一个密钥解密。
  2. 为了加密数据,需要使用指数和模数之一对数据执行模幂运算。
  3. 为了解密数据,对加密数据进行模幂运算 与合作伙伴密钥和模数。 常用时,使用较大的指数 作为私钥,用于解密数据和创建签名, 较小的指数作为公钥,用于加密数据 并验证签名。 比如:
1
ssh-keygen -t rsa -b 4096

该命令将生成两个文件, ~/.ssh/id_rsa~/.ssh/id_rsa.pub。 正如命令所示,此命令生成 4096 位 RSA 密钥对。 你 应该能够猜测哪个文件代表公钥以及哪个文件必须 因此是私钥。 为了影响安全 SSH 登录,请使用 RSA密钥,用户必须首先将他们想要使用的公钥传输到 提前向服务器表明自己的身份。 然后,一旦会话结束 服务器和客户端之间建立的,服务器会加密一个随机数 号码与用户的公钥并发送给用户。 用户将 然后使用他们的私钥解密该值并返回该值的哈希值 到服务器,然后服务器可以自己散列该值以确定用户是否 能够成功解密随机数,从而表明拥有 匹配的密钥并作为身份验证的证据。

签名和证书

一开始,您 将发布 Natoshi 的公钥,此后,对于您发布的每个帖子,您 将使用您(Natoshi)的私钥对消息内容进行加密,并且 将其与您的原始消息一起发布。 那么,想验证的人 Natoshi(即公钥对应的私钥的所有者 属于 Natoshi)实际上确实发布了一条特定的消息,可以简单地 使用 Natoshi 的公钥解密加密签名并比较 内容与原始消息相反。

Natoshi 王位的觊觎者将是 无法签署他们的虚假声明,以便可以与他们核实 Natoshi 公开了公钥,因为他们没有 Natoshi 的私钥, 您可以放心,没有人会过度影响您的项目 当你躲避 IRS 和 DEA 时,除非他们碰巧有 仓库里装满了 ASIC 和大量廉价电力。

然而,在这个方案中,如何防止对手发布虚假信息 公钥并声称是您? (他们可以对此进行有效签名 假公钥)不知何故,你需要“引导”信任:有人需要 验证您的身份并公开确认您的公钥实际上 对应于你。

我们通过 证书 来做到这一点:签署的声明 声称特定的公钥实际上属于它所声称的人 属于。

谁签署此证书? 一个 证书颁发机构 ,我们的某人 信任负责验证身份和发布签名。

但是我们如何知道要信任哪些 CA,以及我们如何才能信任声称 真正值得信赖的是? 他们可能还需要证书。 它 听起来好像一路下来都是海龟; 然而,链条确实结束了 某处:所谓的信任根,根 CA。 这些 CA 的 证书是由浏览器和操作系统预安装的,因此 本质上受信任,无需任何进一步的证书。 如果根 CA 签署您的证书,我们假设他们已经完成了必要的尽职调查 愿意冒着声誉风险签署您的证书,并且基本上 相信他们的话。 这种模型被称为“ 信任网络” ,是网络如何 今天的安全工作正常进行。

不幸的是,它并不像我们希望的那样可靠: 有些 CA 很卑鄙,只要有足够的钱就会签署任何东西,从而导致有效的 为 microsoft.com 和 github.com 等域颁发的证书 显然不是 Microsoft 或 GitHub 的实体。 1 此外, 任何拥有足够边境控制的实体都可以强制安装自己的 根证书(例如哈萨克斯坦政府 2 ) 并截取 通过为任何域颁发自己的伪造证书来窃取任何流量。

您可能没有意识到,但 您使用并依赖证书和签名 每天。 每当您在网站地址栏附近看到绿色锁时, 访问,您正在通过 TLS 或 HTTPS 连接访问该网站,并且数据 您和网站之间的传输是加密的。 当你的浏览器 连接到网站的服务器,它会按顺序请求服务器的公钥 设置加密连接和服务器证书以便 验证其作为授权为您拥有的域提供服务的服务器的身份 要求。 然后,您的浏览器通过验证公钥来验证公钥 证书上的签名。 如果有人试图执行 对您进行中间人攻击,此证书验证步骤将失败, 因为受信任的 CA 不太可能颁发签名的证书 将您的域名转让给您以外的实体(除非您不幸 居住在哈萨克斯坦)。 您将收到一条非常侵入性的通知 这个事实,忽略证书验证是一个坏主意 失败通知。

怎么为自己的网站设置https加密传输数据 现在您有了一个网站,您决定,作为一个优秀的互联网公民,您 希望保护您的访客免受政府的窥探,通过 设置 HTTPS。 您已经知道您将需要一个公钥和一个 为此,由受信任的根 CA 签署的证书。 你怎么去 关于得到一个? 在互联网上搜索,你发现了一个很棒的项目,名为 Let's Encrypt 提供免费、签名的服务 证书。

文件安全

作为 root用户。 当程序启动时,它会继承其用户 ID 和组 ID 父进程,并保留它们,除非手动删除权限。 如果你 以 root 用户身份启动程序,因为,例如,它需要更深入的 系统访问,程序中的漏洞意味着攻击者可以 以 root 用户身份与您的计算机进行交互。 这是一个常见问题 错误配置的网络服务器,其中服务器以根目录运行 遍历漏洞可能允许攻击者读取秘密凭证 存储在服务器的文件系统上。

这个故事的寓意与最小特权原则紧密相连:无论在哪里 可能的话,只给予尽可能少的许可或特权。 如果 程序不需要 root 凭据,请勿以特权用户身份运行它。 如果 文件包含敏感内容,请勿使其可读。

如何更改权限? 有两个主要命令可以执行此操作: chmodchown. chmod更改文件模式,即权限,以及 其语法示例如下:

1
2
3
4
5
6
7
8
9
10
11
$ ls -la ~/
drwxr-xr-x 3 admin admin 4096 Oct 3 12:38 test
$ chmod 644 test
$ ls -la
drw-r--r-- 3 admin admin 4096 Oct 3 12:38 test
$ chmod u+x test
drwxr--r-- 3 admin admin 4096 Oct 3 12:38 test
$ chmod 000 test
d--------- 3 admin admin 4096 Oct 3 12:38 test
$ chmod +r test
dr--r--r-- 3 admin admin 4096 Oct 3 12:38 test

chmod接受八进制表示法的文件权限,即 下列的:

#读写
7读写
6RW-
5接收
4r–
3-wx
2-在-
1-X
0

pueept

● 流行的配置管理软件 ● 用于配置单个机器 ● 声明性哲学,必要时带有一些命令式组件 ● 最初基于 Ruby 构建,现在拥有自己的配置语言 流程: ● 客户端向服务器请求更新 ○ “我想配置为 Minecraft 服务器” ● 服务器向客户端询问事实列表 ○ “好的,请将您的主机名和 RAM 发送给我” ● 客户用事实回应 ○ “我的主机名是僵尸.ocf.berkeley.edu,我有 4GB RAM” ● 服务器响应配置 ○ “确保 Minecraft 服务器正在运行,主机名为僵尸.ocf.berkeley.edu,4GB RAM, 这个配置文件 ● 客户端进行必要的更改以确保其当前配置与 服务器给出的配置 ○ “minecraft服务器当前正在运行,但配置文件已更新,我将获取 更新后的版本 Puppet是一个配置管理工具,通过Puppet可以实现对大量服务器/主机的集中化、自动化的配置管理。Puppet的工作原理是:

  1. 在Puppet Master服务器上面编写Puppet Manifests(配置文件)。这些文件使用Puppet语言定义了服务器的最终状态。
  2. Puppet Agent安装在被管理的主机上面,它会定期从Puppet Master拉取配置。
  3. Puppet Agent对本地服务器状态进行检查,然后根据Manifests对服务器进行配置,确保服务器状态与预期状态一致。
  4. 如果配置发生变化,Puppet会自动应用这些变化,无需手动操作。
  5. Puppet Agent会定期运行,如果配置失效会再次修正。所以Puppet脚本就是编写Puppet Manifests的文件,它定义了需要配置什么,怎么配置。常见的配置包括:- 安装软件
  • 管理服务
  • 配置文件内容
  • 用户和权限
  • 安全设置
  • 定时任务 等等通过Puppet脚本可以实现服务器配置的版本控制、自动化部署,大幅减少管理时间成本。它适用于需要管理大量Linux/Unix主机的场景。

git

创建一个分支:

1
git checkout -b dice

这使得一个新的本地分支称为 dice基于我们所在的分支机构 目前在( master)并将您切换到 dice分支。 这个命令是 基本上简写为:

1
2
git branch dice       # Create new branch called 'dice'
git checkout dice # Switch to branch called 'dice'

您可以通过键入来查看您创建的分支 git branch。 你应该看到 此时有两个分支,一个称为 master和一个叫 dice。 一个 星号位于您当前签出的分支旁边。 git log查看历史提交。 每个提交都有一些信息,例如提交的作者、 创建提交的时间戳和提交消息。

  • 每个提交条目的第一行都有一个长的十六进制字符串。 这是 commit hash :将其视为可用于引用的唯一 ID 具体提交。

  • 有些提交在提交哈希旁边的括号中包含分支信息, 表明它们是最近的提交或 HEAD那个分支的。 你的 最近的提交应该有类似的内容 (HEAD -> dice)。 第四个 提交应该有 (origin/master, origin/HEAD)因为我们的分支机构 关闭 master并在其之上添加了三个新的提交。 请注意,如果 有人向本地或远程添加新提交 master, 分支 信息可能会更改或过时。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
commit adc45cd5110b59f76cefc2b862d0e4d550ccb183 (HEAD -> dice)
Author: thinklive1 <469631989@qq.com>
Date: Thu Oct 12 15:32:35 2023 +0800

Restrict input range for dice iterations and sides

commit a79a770157449a9d2fb1595a0b83ecc99070eabf
Author: thinklive1 <469631989@qq.com>
Date: Thu Oct 12 15:31:56 2023 +0800

Add dice rolling logic and output dice sum and sequence

commit 924d0b1ebf050a043da434114187a290280ec660
Author: thinklive1 <469631989@qq.com>
Date: Thu Oct 12 15:30:45 2023 +0800

Add -s flag for number of sides on a die

commit 3acb62af3eff4a1dbbe875e81ec1485d9d10c44b (origin/master, origin/HEAD, master)
Merge: 4e2aac7 2aefa6c
Author: Ishaan Dham <56564174+Ishaandham19@users.noreply.github.com>
Date: Tue Mar 21 21:39:51 2023 -0700

Merge pull request #34 from 0xcf/demo

Demo

commit 2aefa6c51449ffcd39d945e3d74ce2b5e50acf7f (origin/demo)
Author: Ishaan Dham <ishaandham01@gmail.com>

除了查看提交历史记录之外,您可能还想查看实际的更改 在代码中。 您可以使用 git diff <old commit> <new commit>查看 两次提交之间的差异。

除了查看提交历史记录之外,您可能还想查看实际的更改 在代码中。 您可以使用 git diff <old commit> <new commit>查看 两次提交之间的差异。 有几种不同的方式可以引用 一次提交。 之前提到的一个是复制提交的哈希值(请注意 您的提交哈希值将与下面的示例不同):

1
git diff 3368313c0afb6e306133d604ca72b0287124e8f2 762053064506810dee895219e5b2c2747a202829

您还可以复制提交哈希开头的一小块,而不是 整个哈希。 由于哈希的工作方式,您不太可能 有两个具有完全相同的起始序列的提交。

1
git diff 3368313 7620530

如果你想尝试 diff两个提交非常接近 日志,一种更简单的方法是通过距提交的距离来引用提交 HEAD (最近)使用以下格式提交 HEAD~<number>。 由于我们添加了三个 提交新的提交 dice,我们可以查看之间的差异 dicemaster使用以下命令:

1
git diff HEAD~3 HEAD

有多种方法可以处理合并冲突,但我们将采用的方法 在这个实验室中向您展示正在使用 git rebase。 我们的 dice分支是“基于” 这 master在某个时间点有分支,但是 master分行有 向前离开 dice基于过时的 master。 因此,我们想要 “重新基地” dice就目前的状态而言 master。 当你的 dice分支, 跑步 git rebase master。 Git 将回滚您所做的提交 dice, 复制 任何新的提交 master,并尝试在顶部重放您的提交。 有时 rebase无需您的干预即可运行完成,但是如果 存在合并冲突,您需要解决它。

Git 会告诉你如果遇到合并冲突该怎么办 在变基期间。 在这种情况下,打开 rand.py并找到冲突区域 应具有以下格式:

1
2
3
4
5
<<<<<<< HEAD
Lines of code from the base branch (in this case master)
=======
Lines of code from the branch you're rebasing (in this case dice)
>>>>>>> Commit message of the commit that conflicts with the base branch

要解决冲突,只需保留您想要的行(您的行来自 dice) 和 删除冲突区域中的其他行(

1
`<<<<<<< HEAD`, `=======`, `>>>>>>> dice`

,以及来自 master 的不需要的代码),然后保存并退出 文件。 Git 会将您保存的内容作为文件的确切形式 看起来像在变基结束时,所以你所做的本质上是修复 文件,以便代码正常运行。 这意味着如果您有多个 合并冲突,您决定混合保留基础分支中的一些行 还有一些来自您的功能分支,您需要确保代码确实有效 正确。

现在您已经解决了合并冲突,请按照变基说明进行操作 暂存您的固定文件( git add rand.py),然后运行 git rebase --continue。 如果 Git 发现其他文件有更多合并冲突,您将遵循相同的操作 程序如上。 然而,我们只有一个有冲突的文件,所以我们的变基是 完成的! 跑步 git log查看我们 rebase 的结果。 你现在应该看到了 你想象中的队友 "dice rolling WIP"提交您分支的历史记录, 你的提交高于他们的提交。

docker

安装 Docker wsl2不支持systemctl命令,而是支持systemed命令 所以需要执行如下命令启动docker

1
service docker start

虚拟机 你的电脑里有一台电脑! ● 通过软件模拟抽象物理硬件 ● 虚拟机管理程序运行多个虚拟机 ● 隔离应用:更好的安全性、稳定性 ● 一些开销:需要不同的客户操作系统和模拟 每个应用程序的虚拟硬件数量 ● 需要一些时间来启动

容器 ● 通常与虚拟机进行比较,但更像是捆绑的进程 环境 ● 提供类似的隔离 ○ 然而,比虚拟机要少得多! 出于这个原因,我们仍然经常在虚拟机内运行容器(但是 每个虚拟机可以运行 >1 个容器) ● 启动速度比虚拟机快得多 ● 目标是通过共享代码提供轻量级隔离环境 ● 轻松打包应用程序以实现一致的部署 ● 常见的容器:Docker、rkt、LXC ● 很确定这是加州大学伯克利分校唯一使用的课程

CommandDescription
docker searchSearch Docker Hub for pre-built images
docker pullPull an image or a repository from a registry
docker imagesList images
docker buildBuild an image from a Dockerfile
docker runRun a command in a new container
docker psList containers
docker start/stop/restartStart/stop/restart a container
docker execRun a command in a running container
docker inspectReturn low-level information on Docker objects
docker rmRemove one or more containers
docker rmiRemove one or more images

docker ● 需要构建镜像 ● 通常使用 Dockerfile 来指定 如何构建快照 ● 快照是分层构建的 ○ 像洋葱一样 ○ 允许基于相同的快照层构建速度更快 ● 保持每一层最少化资源

自动化配置管理工具 ● 声明式:说出你想要什么,而不是如何做 ○ 应用程序弄清楚如何 ● 可以定义要安装的应用程序、要包含的文件等 ● 可以在不同“类别”的机器上安装不同的东西 (桌面与服务器) ● 常用工具:Puppet、Ansible、Chef

docker的使用

docker run hello-world

您应该看到一些友好的输出,如下所示:

1
2
3
4
5
6
7
8
9
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
1b930d010525: Pull complete
Digest: sha256:c3b4ada4687bbaa170745b3e4dd8ac3f194ca95b2d0518b417fb47e5879d9b5f
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.
...

此消息表明您的安装似乎运行正常。 为了生成此消息,Docker 采取了以下步骤:

  1. Docker 客户端联系了 Docker 守护进程。
  2. Docker 守护进程从 Docker Hub 中提取“hello-world”镜像。
  3. Docker 守护进程从该映像创建了一个新容器,该容器运行生成您当前正在读取的输出的可执行文件。
  4. Docker 守护进程将该输出传输到 Docker 客户端,然后将其发送到您的终端。 在容器中默认以root用户身份登录。

以交互方式运行容器。 如果您需要在裸系统上尝试和安装东西而不弄乱当前系统,那么这非常有用。 尝试运行以下命令:

docker run -it ubuntu:latest

-iflag 告诉 docker 保留 STDIN打开你的容器,然后 -t分配一个 伪 TTY flag为您 。 基本上,您需要两者才能在新启动的容器中拥有一个 shell。 尝试安装一些软件包 apt或者只是玩玩。 它看起来应该像一个裸露的 Linux 系统。

使用 CTRL+D 退出容器。 自然的问题是,Docker 镜像是如何构建的? Dockerfile 就像镜像的源代码 相反,Dockerfile允许您通过指定手动键入创建镜像的所有命令来定义镜像。 然后 Docker 可以从指定Dockerfile 构建镜像。 这些 Dockerfile 可以放入版本控制中,并将镜像上传到在线存储库。

Docker可以通过读取来自Dockerfile的指令来自动构建镜像 。 Dockerfile是一个文本文档,其中包含所有命令 用户可以在命令行上调用来构建镜像。 eg.下面是一个 Dockerfile ,通过将 Python 3 和软件包安装到基础 Fedora Linux 映像上

1
2
3
4
5
6
7
8
9
10
11
12
13
# Specify Fedora Linux as base image
FROM fedora:latest

# Install Python with yum (Fedora's Package Manager)
# Install required Python packages
RUN yum update -y && yum install -y python3 python3-pip && \
python3 -m pip install pyfiglet termcolor

# Add the missile.py file to the final image
ADD missile.py /

# Specify the command to be run on container creation
CMD ["/usr/bin/python3", "missile.py"]

docker build -t missile:latest .

这告诉 Docker 在当前目录中查找 Dockerfile,并用该文件构建一个镜像。 这 -tflag 告诉 Docker 使用名称标记此构建 missile:latest

查看系统上正在运行的容器。 使用以下命令:

docker ps

由于您(可能)没有运行任何容器,因此您可能不会看到任何有趣的东西。 但是,如果您传入 -a标志,您还可以看到已停止的容器:

要获取有关容器的更多信息,您可以使用 docker logs命令 获取容器的日志(无论它仍在运行还是已退出):

docker logs <container_id_or_name>

在某些时候,您可能想要清理已退出且不打算再使用的容器:

docker rm <container_id_or_name>

将移除容器。

查看已经下载的镜像: docker images 图像可能会占用计算机上相当多的空间,因此您可能需要清理不打算使用的图像 使用。 如果您收到有关计算机上没有足够磁盘空间的错误,这一点尤其重要:

docker rmi <image_id>

镜像文件以及容器的各种文件系统都存储在 /var/lib/docker

分离容器

容器可以以后台服务的形式运行,这适用于一些后台服务的场合,Docker 支持这种方式 以 -d标志,见 分离 方式启动容器 模式

Docker 为容器创建一个单独的虚拟网络,因此您需要将主机端口转发到您的 容器的端口(这称为 端口转发 或端口映射)。 容器正在侦听端口 80,因此让我们尝试将主机的端口 5050 转发到容器的端口 :

docker run -d -p=5050:80 httpd

-p 接受冒号分隔的一对 HOST_PORT:CONTAINER_PORT

您实际上可以“附加”到正在运行的容器并在其中运行更多命令,类似于 docker run作品。 使用 这 docker exec命令:

docker exec <container_id_or_name> <command>

要停止此容器,请使用 docker stop <container_id_or_name>.

您可以使用以下命令重新启动容器 docker restart <container_id_or_name>.

关于 docker-compose

docker-compose允许您定义需要多个容器才能运行的应用程序。 例如,在网络上 应用程序,您可能希望实际的 Web 应用程序在单个容器内运行,并且数据库在其中运行 一个不同的容器。

通常,您根据 服务 来定义应用程序。 同样,以 Web 应用程序为例,有 两个不同的服务:应用程序本身和支持它的数据库。 docker-compose让您定义不同的服务 在 YAML 文件中并相应地运行服务。

其中一件好事是 docker-compose是它会自动为您的容器设置一个网络,其中:

  • 服务的每个容器都位于网络上,并且可以从网络上的其他容器访问
  • 每个容器都可以通过其容器名称在网络上发现

使用 Docker 官方网站上的说明安装 Docker Compose

一些小脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#!/bin/bash



PHONEBOOK_ENTRIES="phonelist.txt"




if [ "$#" -lt 1 ]; then

    exit 1



elif [ "$1" = "new" ]; then

    # YOUR CODE HERE #

    echo $2 $3 >> phonelist.txt



elif [ "$1" = "list" ]; then

    if [ ! -e $PHONEBOOK_ENTRIES ] || [ ! -s $PHONEBOOK_ENTRIES ]; then

        echo "phonebook is empty"

    else

        # YOUR CODE HERE #

        cat phonelist.txt

    fi



elif [ "$1" = "lookup" ]; then

    # YOUR CODE HERE #

    grep $2 phonelist.txt




elif [ "$1" = "remove" ]; then

    # YOUR CODE HERE #

    sed -i "s/$2//g" phonelist.txt




elif [ "$1" = "clear" ]; then

    # YOUR CODE HERE #

    rm phonelist.txt



else

     # YOUR CODE HERE #

     echo nothing

fi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash

host=$1

ping -c 1 $host >> log.txt

if [ $? -eq 0 ]; then

    echo "OK"

else

    echo "can't access"

fi
1
2
3
4
#1/bin/bash

ip addr show | grep "link/ether" | head -n 1 | cut -d' ' -f 6

]]>
+ Numpy 是 Python 中科学计算的核心库。 它提供了高性能的多维数组对象以及使用这些对象的工具 数组。

数组

numpy 数组是一个值网格,所有值都具有相同的类型,并由非负整数组成的元组索引。 它的维度就是数组的秩 ;它的shape就是每个维度的大小组成的元组

1
2
3
b = np.array([[1,2,3],[4,5,6]])    # Create a rank 2 array
print(b.shape) # Prints "(2, 3)"
print(b[0, 0], b[0, 1], b[1, 0]) # Prints "1 2 4"

官方数组创建教程 ds100的numpy教程 cs231n的python numpy教程

创建数组的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
>>>np.array([[1.,2.], [3.,4.]])

array([[ 1., 2.],
[ 3., 4.]])

>>>np.array([x for x in range(5)])

array([0, 1, 2, 3, 4])

>>>np.array([["A", "matrix"], ["of", "words."]])

array([['A', 'matrix'],
['of', 'words.']],
dtype='<U6')

>>>np.ones([3,2])

array([[ 1., 1.],
[ 1., 1.],
[ 1., 1.]])

>>>np.random.randn(3,2)

array([[ 0.3601399 , 1.31206686],
[-0.95112397, 0.62475726],
[-1.24179768, 1.63392069]])

1
2
3
4
5
6
7
>>>c = np.full((2,2), 7)  # Create a constant array
print(c) # Prints "[[ 7. 7.]
# [ 7. 7.]]"

>>>d = np.eye(2) # Create a 2x2 identity matrix
print(d) # Prints "[[ 1. 0.]
# [ 0. 1.]]"

数组属性

  • dtype
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
>>>np.arange(1,5).dtype

dtype('int64')

>>>np.array(["Hello", "Worlddddd!"]).dtype

dtype('<U10')
/*
What does `<U6` mean?
- `<` Little Endian
- `U` Unicode
- `6` length of longest string
*/

>>> np.array([1,2,3]).astype(float)

array([ 1., 2., 3.])

数组的类型与其包含的数据类型相对应,可以用.astype改变类型

数组编辑

重组和展开

1
2
3
4
5
6
7
8
9
>>>np.arange(1,13).reshape(4,3)

array([[ 1, 2, 3],
[ 4, 5, 6],
[ 7, 8, 9],
[10, 11, 12]])

>>>A.flatten()
array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])

切片索引和整数索引

切片时,第一个参数是行,第二个是列,切片形成的是对原来数组的引用,修改子数组也会影响原数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Create the following rank 2 array with shape (3, 4)
# [[ 1 2 3 4]
# [ 5 6 7 8]
# [ 9 10 11 12]]
a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])

# Use slicing to pull out the subarray consisting of the first 2 rows
# and columns 1 and 2; b is the following array of shape (2, 2):
# [[2 3]
# [6 7]]
b = a[:2, 1:3]

# A slice of an array is a view into the same data, so modifying it
# will modify the original array.
print(a[0, 1]) # Prints "2"
b[0, 0] = 77 # b[0, 0] is the same piece of data as a[0, 1]
print(a[0, 1]) # Prints "77"

可以混合整数索引和切片索引,这样做会产生一个比原始数组的秩更低的数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Create the following rank 2 array with shape (3, 4)
# [[ 1 2 3 4]
# [ 5 6 7 8]
# [ 9 10 11 12]]
a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])

# Two ways of accessing the data in the middle row of the array.
# Mixing integer indexing with slices yields an array of lower rank,
# while using only slices yields an array of the same rank as the
# original array:
row_r1 = a[1, :] # Rank 1 view of the second row of a
row_r2 = a[1:2, :] # Rank 2 view of the second row of a
print(row_r1, row_r1.shape) # Prints "[5 6 7 8] (4,)"
print(row_r2, row_r2.shape) # Prints "[[5 6 7 8]] (1, 4)"

# We can make the same distinction when accessing columns of an array:
col_r1 = a[:, 1]
col_r2 = a[:, 1:2]
print(col_r1, col_r1.shape) # Prints "[ 2 6 10] (3,)"
print(col_r2, col_r2.shape) # Prints "[[ 2]
# [ 6]
# [10]] (3, 1)"

整数数组 索引允许你使用另一个数组的数据构造任意数组 大批。 这是一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import numpy as np

a = np.array([[1,2], [3, 4], [5, 6]])

# An example of integer array indexing.
# The returned array will have shape (3,) and
print(a[[0, 1, 2], [0, 1, 0]]) # Prints "[1 4 5]"

# The above example of integer array indexing is equivalent to this:
print(np.array([a[0, 0], a[1, 1], a[2, 0]])) # Prints "[1 4 5]"

# When using integer array indexing, you can reuse the same
# element from the source array:
print(a[[0, 0], [1, 1]]) # Prints "[2 2]"

# Equivalent to the previous integer array indexing example
print(np.array([a[0, 1], a[0, 1]])) # Prints "[2 2]"

可以用整数数组索引修改数组部分值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import numpy as np

# Create a new array from which we will select elements
a = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])

print(a) # prints "array([[ 1, 2, 3],
# [ 4, 5, 6],
# [ 7, 8, 9],
# [10, 11, 12]])"

# Create an array of indices
b = np.array([0, 2, 0, 1])

# Select one element from each row of a using the indices in b
print(a[np.arange(4), b]) # Prints "[ 1 6 7 11]"

# Mutate one element from each row of a using the indices in b
a[np.arange(4), b] += 10

print(a) # prints "array([[11, 2, 3],
# [ 4, 5, 16],
# [17, 8, 9],
# [10, 21, 12]])

数组的数学运算

numpy 提供的数学函数的完整列表 文档 Numpy 提供了更多用于操作数组的函数; 完整的列表 文档

Numpy 提供了许多有用的函数来执行计算 数组; 最有用的之一是 sum:

1
2
3
4
5
6
7
import numpy as np

x = np.array([[1,2],[3,4]])

print(np.sum(x)) # Compute sum of all elements; prints "10"
print(np.sum(x, axis=0)) # Compute sum of each column; prints "[4 6]"
print(np.sum(x, axis=1)) # Compute sum of each row; prints "[3 7]"

转置矩阵, 只需使用 T数组对象的属性:

1
2
3
4
5
6
7
8
9
10
11
12
import numpy as np

x = np.array([[1,2], [3,4]])
print(x) # Prints "[[1 2]
# [3 4]]"
print(x.T) # Prints "[[1 3]
# [2 4]]"

# Note that taking the transpose of a rank 1 array does nothing:
v = np.array([1,2,3])
print(v) # Prints "[1 2 3]"
print(v.T) # Prints "[1 2 3]"

广播

我们有一个较小的数组和一个 较大的数组,并且我们想多次使用较小的数组来执行某些操作 在更大的阵列上。

例如,假设我们要向每个添加一个常数向量 矩阵的行。 我们可以这样做:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import numpy as np

# We will add the vector v to each row of the matrix x,
# storing the result in the matrix y
x = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
v = np.array([1, 0, 1])
y = np.empty_like(x) # Create an empty matrix with the same shape as x

# Add the vector v to each row of the matrix x with an explicit loop
for i in range(4):
y[i, :] = x[i, :] + v

# Now y is the following
# [[ 2 2 4]
# [ 5 5 7]
# [ 8 8 10]
# [11 11 13]]
print(y)

Numpy 广播允许我们执行此计算,而无需实际执行 创建多个副本 v。 考虑这个版本,使用广播:

1
2
3
4
5
6
7
8
9
10
11
import numpy as np

# We will add the vector v to each row of the matrix x,
# storing the result in the matrix y
x = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
v = np.array([1, 0, 1])
y = x + v # Add v to each row of x using broadcasting
print(y) # Prints "[[ 2 2 4]
# [ 5 5 7]
# [ 8 8 10]
# [11 11 13]]"

线路 y = x + v尽管有效 x有形状 (4, 3)v有形状 (3,)由于广播; 这条线的工作原理就像 v实际上有形状 (4, 3), 其中每一行都是一个副本 v,并且按元素求和。

一起广播两个数组遵循以下规则:

  1. 如果数组没有相同的秩,则在前面添加较低秩数组的形状 1s 直到两个形状具有相同的长度。
  2. 如果两个数组具有相同的维度,则称 兼容 它们在维度上 维度中的大小,或者如果其中一个数组在该维度中的大小为 1。
  3. 如果数组在所有维度上都兼容,则可以一起广播。
  4. 广播后,每个数组的行为就好像它的形状等于元素方向 两个输入数组的形状的最大值。
  5. 在一个数组的大小为 1 而另一个数组的大小大于 1 的任何维度中, 第一个数组的行为就好像它是沿着该维度复制的

一些应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import numpy as np

# Compute outer product of vectors
v = np.array([1,2,3]) # v has shape (3,)
w = np.array([4,5]) # w has shape (2,)
# To compute an outer product, we first reshape v to be a column
# vector of shape (3, 1); we can then broadcast it against w to yield
# an output of shape (3, 2), which is the outer product of v and w:
# [[ 4 5]
# [ 8 10]
# [12 15]]
print(np.reshape(v, (3, 1)) * w)

# Add a vector to each row of a matrix
x = np.array([[1,2,3], [4,5,6]])
# x has shape (2, 3) and v has shape (3,) so they broadcast to (2, 3),
# giving the following matrix:
# [[2 4 6]
# [5 7 9]]
print(x + v)

# Add a vector to each column of a matrix
# x has shape (2, 3) and w has shape (2,).
# If we transpose x then it has shape (3, 2) and can be broadcast
# against w to yield a result of shape (3, 2); transposing this result
# yields the final result of shape (2, 3) which is the matrix x with
# the vector w added to each column. Gives the following matrix:
# [[ 5 6 7]
# [ 9 10 11]]
print((x.T + w).T)
# Another solution is to reshape w to be a column vector of shape (2, 1);
# we can then broadcast it directly against x to produce the same
# output.
print(x + np.reshape(w, (2, 1)))

# Multiply a matrix by a constant:
# x has shape (2, 3). Numpy treats scalars as arrays of shape ();
# these can be broadcast together to shape (2, 3), producing the
# following array:
# [[ 2 4 6]
# [ 8 10 12]]
print(x * 2)
]]>
- <h1 id="shell脚本">shell脚本</h1> -<p>Shell 脚本通常以 shebang 行开头:#!path/to/interpreter。</p> -<p><code>#!</code>是一个人类可读的 <a href="https://en.wikipedia.org/wiki/Shebang_(Unix)#Magic_number">幻数表示</a> <code>0x23 0x21</code>它可以告诉 shell 将文件其余部分的执行传递给 指定翻译。 如果您的脚本作为可执行文件运行(例如 <code>./awesome_shell_script</code>) 加上 shebang 行,那么 shell 将调用 可执行文件(通常是解释器)位于 <code>path/to/interpreter</code>运行你的 脚本。 如果您的脚本作为参数传递给解释器,例如 <code>bash awesome_shell_script</code>,那么 shebang 没有效果并且 <code>bash</code>会处理 脚本的执行。 + <p><a href="http://www.numpy.org/">Numpy</a> 是 Python 中科学计算的核心库。 它提供了高性能的多维数组对象以及使用这些对象的工具 数组。</p> +<h2 id="数组">数组</h2> +<p>numpy 数组是一个值网格,所有值都具有相同的类型,并由非负整数组成的元组索引。 它的维度就是数组的秩 ;它的shape就是每个维度的大小组成的元组 - + - + - + + +
@@ -571,6 +571,27 @@ + + 爱丽丝的回忆 + + https://thinklive1.github.io/2023/09/28/%E7%A7%98%E5%AF%861/ + 2023-09-28T13:12:21.000Z + 2023-11-27T12:47:59.707Z + +
]]> + + + 心爱的少女,她诞生的时日是? + + + + + + + + + + 基于苏大ppt的计算机硬件笔记 @@ -605,38 +626,39 @@ - 爱丽丝的回忆 - - https://thinklive1.github.io/2023/09/28/%E7%A7%98%E5%AF%861/ - 2023-09-28T13:12:21.000Z + 迪瑞克拉世界观设定集 + + https://thinklive1.github.io/2023/09/29/%E8%BF%AA%E7%91%9E%E5%85%8B%E6%8B%89%E4%B8%96%E7%95%8C%E8%A7%82/ + 2023-09-29T02:18:45.993Z 2023-11-27T12:47:59.707Z -
]]>
+
1
起初,世界是一团思索,它向所有的方向迈了一步,于是万物由此而生……

这是邪神辛克莱温教徒传颂的创世神话,也是目前为止我们所知最早的创世神话,可以说后世诸多关于创世的传说都有它的影子。

邪神辛克莱温的信徒有着自己的语言,这种符号文字晦涩难懂,虽然给传播教义造成了困难,却成为维系着邪神教绵延几千年信仰的纽带。 邪神辛克莱温是……

——选自帝国学者载丝莉《邪神起源探究》

克雷多斯族

      平庸是进化论所给我们最后的仁慈——帝国医学教科书扉页

奥诺斯是社会达尔文主义者的神,他的教义就是物竞天择,适者生存,让优秀的种族淘汰低劣的种族。放到现在他肯定会被当做邪神。奥诺斯创造过很多种族,大部分在穷兵黩武中走向了灭亡,然而其中有一个民族最为他所垂青——克雷多斯族。这一种族刚出现时平平无奇,但他们的眼中只有强者,尊严的力量促使着他们不断发挥着潜力,追逐着比自己强大无数倍的敌人。他们逐渐走向强盛,但后来因为自相残杀导致族人寥寥无几。这时,一位天才创造出了一种把他们一分为二的方法,以此来把自己当做对手,起初,克雷多斯族凭借这一方法几乎成为世界上最令人恐惧的种族,深深地让奥诺斯感到自豪。然而,在与自己的斗争中,有的族人学会了“阴谋”,将另一个自己与其他敌人算计致死,有的人学会了“隐忍”,进而学会了妥协与认输,最终,他们都选择了“平庸”。为了心爱的子民惋惜不止的奥诺斯神来到了最后一个保持着绝对尊严的战士面前:

“我也给予你选择平庸的权利。”

“你要我变得和他们一样吗?绝不!!!”

战士怒吼着冲向了最后一个对手。从此,奥诺斯和他的战士消失于迪瑞克拉世界。

沉默峡谷

沉默不是逃避,而是一种选择——沉默沼泽路牌上的涂鸦

沉默峡谷被命名并正式标在官方地图上是帝国历387年的事了,在此之前它只是个普通的荒凉之处而已,当然,还是偶尔进入的旅客发现这里——但他们有的没能走出来,有的在出来后被别人或自己当成了疯子。

沉默峡谷的土壤和两侧的山岩有种特殊的性质,能几乎把所有的声音消除,巴比伦塔的学者曾对此展开研究,然而他们一无所获。除此以外,沉默峡谷就是个普通的荒凉峡谷,稀疏的杂草养不出大型动物,对一个经验丰富的旅行者而言,找到水源,辨别方向和驱散毒虫都不算难 ——只要他能忍受无尽的沉默

在被载入地图后,这里逐渐成了修士的圣地,当然,也有人进去后再也没有出来

幻影沼泽

警告!魔术师慎入!

这是沉默峡谷一处著名的景点,和峡谷本身一样,这里也几乎没什么异常,对有防备的旅行者而言并没什么危险。传说中一位善于擅长表演幻影魔术的魔术师来到这里时,将自己当做了幻影,而把幻影当成了真实。于是他迷失在这里,将此处化成了一片沼泽,如果一位有真才实学的魔术师来到这里,那么他绝对无法精神正常地离开,尽管对其他人而言,这里能看到的异象仅仅是偶尔出现魔术师忧郁的身影而已。

沉默王国

………………………………

沉默王国一直是个传说,一开始只是有少数人怀疑那些进了峡谷再没有出来的人到底去了哪里?这些怀疑逐渐被时间埋葬,直到帝国标记了沉默峡谷的存在导致一批旅行者来此游览,,有些旅行家发现了沉默王国的存在,很难想象一个王国会存在于荒野,事实上,那里只是寥寥几个人的聚居处。住民们给了旅行家一些食物和饮水,并为他指明了道路,从始至终,他们都带着沉默,从未试图张开嘴唇过。

此后又陆陆续续地出现了类似住民目击报告,但都被帝国封锁,最终,这一切成为了传说或是怪谈,奇怪的是,帝国似乎对此颇为忌惮,从此以后沉默峡谷再也没有出现在官方文件上过。

我们认为那些住民的存在涉及了达瑞克拉世界的源论,可以肯定那是一些向往沉默的人,不知何时他们聚集起来,用各自的思虑创造了一个无声的世界——或许跟0号研究所揭示的结果一致,这十分危险,一旦被人们知道,达瑞克拉世界或许会因此毁灭。

                                 ——《关于沉默王国的报告》

0号研究所

我思故我在,我在故我思。——帝国哲学家卡尔迪

0号研究是科学组织浮士德所进行的一场实验,没错,与大多数我同事的想法相反,它并不是个邪教组织,从同行的角度来说,我很佩服他们的开创性。

0号研究所本是个普通的小镇,如果不是那件事的发生,我们永远不会知道这里曾发生过这样的实验。

帝国的审讯所抓到过一个浮士德的高层,今天他们终于设法让他开口了,由此我们终于知道他们是怎么进行实验的。首先,小镇只是出现了一些以屠戮人民,掠夺财物为乐的人,他们穿着迥异的衣服,却意外有着纯正的当地口音,经过一番协力,这些人不久就被送上了断头台。

奇怪的是,他们面对死亡毫无畏惧,自称“玩家”的他们发出了下次进犯的预告,然后在断头台上化成白光消失了。

当天,一切有关他们的消息被政府封锁,几乎同时不少“智者”跳了,要求让民众得知真相,惴惴不安中,很多小册子在民众中传阅——上面说这个世界只是虚构,完全为了让那些玩家取乐而存在(至于为何能让民众了解虚幻的概念,或许浮士德的教育机制还是挺有成效的)

第二天,更多所谓的“玩家从天而降”,所有住民都陷入了绝望与怀疑,就在这时我们所知的异变发生了,没人知道这是怎么做到的,但整个克罗利安镇就这么化为一片混沌之地,我们的不少调查员在第一眼看到它的遗址时就发疯了——我们没人知道为什么。

现在那里应该已经封闭了,我的建议是,永远封闭下去,或许邪神辛克莱温是对的,这个世界确实由我们的思想决定。我希望所有人都能对此提高警惕,永远不要让类似的事故重演

帕斯卡王国

世上哪有不建立在剥削上的幸福?

帝国前36年,在正片大陆一个名不见经传的角落有一个小国,这个国家物资贫瘠,人口稀疏,尽管气候不算恶劣,但人民常常处于食不果腹的状态。

国王帕列斯是位平庸的君主,他的儿子——王子恩西斯却是位有想法的年轻人,尽管刚刚成年,他已经开始思索如何壮大自己的国家,这位王子曾经游学诸国,每次看到国民因营养不良而矮小纤弱的身材,他都会在心中发誓一定要找到让子民过上幸福快乐生活的方法

有一天,他带着这个愿望,带着几位侍从出门远行,在一番艰难跋涉后,王子在荒野中迷路了,他仿徨了几天,终于有一天他发现了一个村落

这个村落贫瘠弱小,王子注意到他们大量以烤制生肉,野菜,甚至昆虫而食,他们没有国王或者地位高于其他居民的人,尽管如此,他们的脸上却常常洋溢着笑容

王子作为外来人并没有对这些野人产生太多影响,于是他也学着野人的样子,用茅草和树枝搭起简易的居所,尝试融入野人的生活

一个月后,当国王派出的宫廷军顺着王子迷路时留下的标记找到他时,王子正喃喃自语道:我要找到的道路,就在这里啊

归国后几月,王子继位成为了国王,他实现了自己的诺言,在他的治理下,他的子民过上了物质丰富,精神充足的生活——凭借着王子制定并实现的驯养土著成为奴隶的方法。建立帕索斯帝国后五年,王子临终,面对伏在病榻前痛苦的子孙,他淡淡地说:他们以前就没有国王,以后也不会有吧。随后他保持着沉默,任凭御医记录他由有到无的脉搏直至最后

帝国历364年,历经三百年的不懈斗争,萨曼人杰出的领袖终于为族人争取到了自由,帝国,这一最先实现奴隶制的国家,最终成为了民主共和的起源…… ——《帝国通史》

]]>
- 心爱的少女,她诞生的时日是? + <figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">起初,世界是一团思索,它向所有的方向迈了一步,于是万物由此而生……</span><br></pre></td></tr></table></figure> +<p>这是邪神辛克莱温教徒传颂的创世神话,也是目前为止我们所知最早的创世神话,可以说后世诸多关于创世的传说都有它的影子。 - + - +
- 迪瑞克拉世界观设定集 - - https://thinklive1.github.io/2023/09/29/%E8%BF%AA%E7%91%9E%E5%85%8B%E6%8B%89%E4%B8%96%E7%95%8C%E8%A7%82/ + 迪瑞克拉世界观轶事集 + + https://thinklive1.github.io/2023/09/29/%E8%BF%AA%E7%91%9E%E5%85%8B%E6%8B%89%E8%BD%B6%E4%BA%8B%E9%9B%86/ 2023-09-29T02:18:45.993Z 2023-11-27T12:47:59.707Z -
1
起初,世界是一团思索,它向所有的方向迈了一步,于是万物由此而生……

这是邪神辛克莱温教徒传颂的创世神话,也是目前为止我们所知最早的创世神话,可以说后世诸多关于创世的传说都有它的影子。

邪神辛克莱温的信徒有着自己的语言,这种符号文字晦涩难懂,虽然给传播教义造成了困难,却成为维系着邪神教绵延几千年信仰的纽带。 邪神辛克莱温是……

——选自帝国学者载丝莉《邪神起源探究》

克雷多斯族

      平庸是进化论所给我们最后的仁慈——帝国医学教科书扉页

奥诺斯是社会达尔文主义者的神,他的教义就是物竞天择,适者生存,让优秀的种族淘汰低劣的种族。放到现在他肯定会被当做邪神。奥诺斯创造过很多种族,大部分在穷兵黩武中走向了灭亡,然而其中有一个民族最为他所垂青——克雷多斯族。这一种族刚出现时平平无奇,但他们的眼中只有强者,尊严的力量促使着他们不断发挥着潜力,追逐着比自己强大无数倍的敌人。他们逐渐走向强盛,但后来因为自相残杀导致族人寥寥无几。这时,一位天才创造出了一种把他们一分为二的方法,以此来把自己当做对手,起初,克雷多斯族凭借这一方法几乎成为世界上最令人恐惧的种族,深深地让奥诺斯感到自豪。然而,在与自己的斗争中,有的族人学会了“阴谋”,将另一个自己与其他敌人算计致死,有的人学会了“隐忍”,进而学会了妥协与认输,最终,他们都选择了“平庸”。为了心爱的子民惋惜不止的奥诺斯神来到了最后一个保持着绝对尊严的战士面前:

“我也给予你选择平庸的权利。”

“你要我变得和他们一样吗?绝不!!!”

战士怒吼着冲向了最后一个对手。从此,奥诺斯和他的战士消失于迪瑞克拉世界。

沉默峡谷

沉默不是逃避,而是一种选择——沉默沼泽路牌上的涂鸦

沉默峡谷被命名并正式标在官方地图上是帝国历387年的事了,在此之前它只是个普通的荒凉之处而已,当然,还是偶尔进入的旅客发现这里——但他们有的没能走出来,有的在出来后被别人或自己当成了疯子。

沉默峡谷的土壤和两侧的山岩有种特殊的性质,能几乎把所有的声音消除,巴比伦塔的学者曾对此展开研究,然而他们一无所获。除此以外,沉默峡谷就是个普通的荒凉峡谷,稀疏的杂草养不出大型动物,对一个经验丰富的旅行者而言,找到水源,辨别方向和驱散毒虫都不算难 ——只要他能忍受无尽的沉默

在被载入地图后,这里逐渐成了修士的圣地,当然,也有人进去后再也没有出来

幻影沼泽

警告!魔术师慎入!

这是沉默峡谷一处著名的景点,和峡谷本身一样,这里也几乎没什么异常,对有防备的旅行者而言并没什么危险。传说中一位善于擅长表演幻影魔术的魔术师来到这里时,将自己当做了幻影,而把幻影当成了真实。于是他迷失在这里,将此处化成了一片沼泽,如果一位有真才实学的魔术师来到这里,那么他绝对无法精神正常地离开,尽管对其他人而言,这里能看到的异象仅仅是偶尔出现魔术师忧郁的身影而已。

沉默王国

………………………………

沉默王国一直是个传说,一开始只是有少数人怀疑那些进了峡谷再没有出来的人到底去了哪里?这些怀疑逐渐被时间埋葬,直到帝国标记了沉默峡谷的存在导致一批旅行者来此游览,,有些旅行家发现了沉默王国的存在,很难想象一个王国会存在于荒野,事实上,那里只是寥寥几个人的聚居处。住民们给了旅行家一些食物和饮水,并为他指明了道路,从始至终,他们都带着沉默,从未试图张开嘴唇过。

此后又陆陆续续地出现了类似住民目击报告,但都被帝国封锁,最终,这一切成为了传说或是怪谈,奇怪的是,帝国似乎对此颇为忌惮,从此以后沉默峡谷再也没有出现在官方文件上过。

我们认为那些住民的存在涉及了达瑞克拉世界的源论,可以肯定那是一些向往沉默的人,不知何时他们聚集起来,用各自的思虑创造了一个无声的世界——或许跟0号研究所揭示的结果一致,这十分危险,一旦被人们知道,达瑞克拉世界或许会因此毁灭。

                                 ——《关于沉默王国的报告》

0号研究所

我思故我在,我在故我思。——帝国哲学家卡尔迪

0号研究是科学组织浮士德所进行的一场实验,没错,与大多数我同事的想法相反,它并不是个邪教组织,从同行的角度来说,我很佩服他们的开创性。

0号研究所本是个普通的小镇,如果不是那件事的发生,我们永远不会知道这里曾发生过这样的实验。

帝国的审讯所抓到过一个浮士德的高层,今天他们终于设法让他开口了,由此我们终于知道他们是怎么进行实验的。首先,小镇只是出现了一些以屠戮人民,掠夺财物为乐的人,他们穿着迥异的衣服,却意外有着纯正的当地口音,经过一番协力,这些人不久就被送上了断头台。

奇怪的是,他们面对死亡毫无畏惧,自称“玩家”的他们发出了下次进犯的预告,然后在断头台上化成白光消失了。

当天,一切有关他们的消息被政府封锁,几乎同时不少“智者”跳了,要求让民众得知真相,惴惴不安中,很多小册子在民众中传阅——上面说这个世界只是虚构,完全为了让那些玩家取乐而存在(至于为何能让民众了解虚幻的概念,或许浮士德的教育机制还是挺有成效的)

第二天,更多所谓的“玩家从天而降”,所有住民都陷入了绝望与怀疑,就在这时我们所知的异变发生了,没人知道这是怎么做到的,但整个克罗利安镇就这么化为一片混沌之地,我们的不少调查员在第一眼看到它的遗址时就发疯了——我们没人知道为什么。

现在那里应该已经封闭了,我的建议是,永远封闭下去,或许邪神辛克莱温是对的,这个世界确实由我们的思想决定。我希望所有人都能对此提高警惕,永远不要让类似的事故重演

帕斯卡王国

世上哪有不建立在剥削上的幸福?

帝国前36年,在正片大陆一个名不见经传的角落有一个小国,这个国家物资贫瘠,人口稀疏,尽管气候不算恶劣,但人民常常处于食不果腹的状态。

国王帕列斯是位平庸的君主,他的儿子——王子恩西斯却是位有想法的年轻人,尽管刚刚成年,他已经开始思索如何壮大自己的国家,这位王子曾经游学诸国,每次看到国民因营养不良而矮小纤弱的身材,他都会在心中发誓一定要找到让子民过上幸福快乐生活的方法

有一天,他带着这个愿望,带着几位侍从出门远行,在一番艰难跋涉后,王子在荒野中迷路了,他仿徨了几天,终于有一天他发现了一个村落

这个村落贫瘠弱小,王子注意到他们大量以烤制生肉,野菜,甚至昆虫而食,他们没有国王或者地位高于其他居民的人,尽管如此,他们的脸上却常常洋溢着笑容

王子作为外来人并没有对这些野人产生太多影响,于是他也学着野人的样子,用茅草和树枝搭起简易的居所,尝试融入野人的生活

一个月后,当国王派出的宫廷军顺着王子迷路时留下的标记找到他时,王子正喃喃自语道:我要找到的道路,就在这里啊

归国后几月,王子继位成为了国王,他实现了自己的诺言,在他的治理下,他的子民过上了物质丰富,精神充足的生活——凭借着王子制定并实现的驯养土著成为奴隶的方法。建立帕索斯帝国后五年,王子临终,面对伏在病榻前痛苦的子孙,他淡淡地说:他们以前就没有国王,以后也不会有吧。随后他保持着沉默,任凭御医记录他由有到无的脉搏直至最后

帝国历364年,历经三百年的不懈斗争,萨曼人杰出的领袖终于为族人争取到了自由,帝国,这一最先实现奴隶制的国家,最终成为了民主共和的起源…… ——《帝国通史》

]]>
+ 泰特斯

正如童话故事常见的开头一样,泰特斯是个贫穷而有志气的青年,有一天当他在王国的大街上闲逛时,他遇到了公主的轿子,年轻的泰特斯对美丽淑慧的公主一见钟情,他下定决心一定要当上王国的驸马爷。 当时开国皇帝恩西斯去世没有多久,年轻的皇帝卡奥斯也是为年轻气盛的青年,泰特斯认为这是成为皇帝亲信的好机会。

当时无权无势的人想要上位有两种办法,一是参军博得战功,二是进入帝国大学谋求文官职位,泰特斯身体虚弱,而且厌恶战争,但却有个不错的头脑,于是在他刻苦攻读下终于进入了帝国的最高学府学习数学,十年后,泰特斯已经是位小有名气的数学家了。

新帝卡奥斯是个奇怪的皇帝,他不甚喜欢锦衣玉食,也不爱美人或者诗琴书赋,唯独对数学很感兴趣,帝国的数学家往往是些老古董,唯有泰特斯名声卓著,血气方刚,二人一见如故,泰特斯如愿以偿成为皇帝的亲信。

卡奥斯将各项赋税与各种工程的设计实施交给了泰特斯,结果无不让他满意,为了表示对泰特斯的欣赏,皇帝决定将自己的妹妹嫁给他。

当公主府的使臣带着婚书拜访泰特斯时,他礼貌而不失坚决地回绝了,此时在他看来任何不懂数学之美的人都是庸俗的,除了数学女神的青睐,他对任何女人不屑一顾。

当然,这件事传到了皇帝的耳朵里,同时传导的还有群臣的议论,皇帝敏感地察觉到在大部分人眼中泰特斯才是帝国最聪明的人,心怀不满的皇帝半强迫地让公主嫁给了泰特斯。当然,皇帝并不无情,否则如果他将所有比他强的数学家都杀了,那么帝国早就没几个大数学家了——要知道他的水平只是二流的

为了自己与泰特斯的安危,贤惠的公主规劝丈夫,聪明的泰特斯恍然大悟,从此以后他收敛锋芒,沉迷于公主府奢华的生活,最终,他与公主幸福地生活到了最后。

泰特斯关于数学研究的遗著于共和历11年首次出现在公众面前,最后屡经辗转进入了共和国首都博物馆的展馆

黎明

外交官是位三十出头的年轻人(就他的职位而言),一个月前,他被尊贵的皇帝陛下召见,并被赋予和葛雷氏族谈判的任务。他精于谈判之道,自从帝国决定用经济而不是武力的手段来征服那些遮布隆(帝国语,未开化的人)他变成了谈判桌上最可怕的对手,有人说他的鹰眼能轻易看穿对手的心理底线,有人说他的眼线分布各地,实际上,在外交官的心中,他的才能无关轻重,仅仅是帝国的威亚所致罢了,在早先的黑暗岁月中,遮布隆大多被帝国的屠杀,谎言与掠夺打败。

葛雷族有着一支装备精良的武装,他们背靠大陆大方最大的矿系,然而在帝国面前,这一切毫无意义,诚然,他们完全可以炸毁矿道,但那并不能躲避他们沦为帝国仆从的命运。

当我走进葛雷族的营地时,几乎所有人都对我怒目而视,其中大多是野性,却也带着几份文明,族长是位很硬朗的老人。

“知道吗,按我们的习俗,只要学到知识,就是师徒,你毕业于帝国大学,而我读过帝国大学出版的书,所以我们应该是师兄弟”

我对这老人不合时宜的幽默搞得一点摸不清头脑,“过来,我想让你看个东西”老人领着我向营地的深处走去,在巨大的仓库群前停了下来。

当他打开大门的时候我就知道了——金子,宝石,帝国经济体系中不可或缺的存在,自此帝国历234年定下贵金属和帝国货币的兑换关系后,它们就成了帝国最坚实的支柱。

“这是祖先为我们留下的,留着我们营地的大约只有十分之一””

“你们没有告诉我们这里的矿脉有黄金和宝石?”

“我现在不是告诉你们了吗?”

“……”

“你们帝国的经济命脉就是流通在市场上的黄金吧,如果这种规模的黄金瞬间涌入你们的市场,会发生什么?”

“……”

“好了,开始谈判吧”

历时3天的谈判后,帝国开出了有史以来最宽松的条件,葛雷族的所有自治权予以保留,唯一的条件是,必须与帝国展开全方面的贸易

度量

1
只是两个小人物的故事

一般来说,这年头很难遇到算命的,至于在酒吧里看到算命的就更少见了,用算命来骗酒喝已经是不知多少年前的老故事了,然而,在此时此刻,却有两个中年男人在酒吧里对饮。

“你是刚来这座城市吗?”

“恰恰相反,我在这待了很多年了”

发问者并没有追问

“你活过3000帝国币吗?”

莫名其妙的问题,乡巴佬的叫法,发问者心想,一时间他不知对方是什么意思

“我的父亲在活到566布朗时咽了气,他本指望着活到700布朗的,呵呵,然后我就到这里来了”

和一个不知从哪个穷乡僻壤来的家伙聊天或许能让自己以后酒场吹牛添一些料,中年人想,于是他决定听下去。

“来到这里后,一时间我很不适应,你们似乎总喜欢用在时间和空间上均匀分布的事物当做度量的标准,真是奇怪”

提问者忍不住做出了回答“你是说你们甚至没有时空的概念?”

“用你们的话说,我们的时间是经济学,空间则是社会学。当然,你们的语言和概念是无法完全解释的,300克朗昭示着步入成年,数不过来的人意味着一个国家,扎在一定的一堆人意味着一个省,这只是比喻。”

他自嘲般地说“我来的时候觉得在那地方我始终是客子,来到这里后又感觉并非家乡”

窗外一只先前飞走的蝴蝶盘旋一圈后又回到了树梢。

“知道吗?你会活过394杯酒。”他没头没脑地说了一句。

另一位中年人沉默着,他每周的同一时间都会来这里点一杯酒。

“而我,会活过自己度量过的第1944位客户”

“你指望我为你的疯话付钱吗?”

”我不适应你们的语言,我也不适应你们的思维……每一秒,每一厘米对你们而言都是无法更改的,你为什么觉得作为我故乡度量——金钱是能更改的呢?对你来说这是一天,对我而言这是6帝国币,二者都是神圣不可更改的。”

中年人有些可悲地看着他“你需要去补补数学和物理的课”

“我只想知道自己该用什么来度量”他显得有些颓废。

“结账,他那杯也算我的”占卜师指着中年男人桌上的酒,向服务员喊道。

占卜师离开酒吧的背影显得并不年轻,“我是他的第几个客户?”中年男人想到。

中年人从此再也没有喝过酒,一年后,一种以果汁为主成分的硬饮料在帝国风靡一时,中年人在一次应酬中举起了一杯苹果汁,当他察觉到一丝酒味后已经晚了,作为一个厌恶半途而废的男人,他选择一饮而尽,随后咽了气。

]]>
- <figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">起初,世界是一团思索,它向所有的方向迈了一步,于是万物由此而生……</span><br></pre></td></tr></table></figure> -<p>这是邪神辛克莱温教徒传颂的创世神话,也是目前为止我们所知最早的创世神话,可以说后世诸多关于创世的传说都有它的影子。 + <h2 id="泰特斯">泰特斯</h2> +<p>正如童话故事常见的开头一样,泰特斯是个贫穷而有志气的青年,有一天当他在王国的大街上闲逛时,他遇到了公主的轿子,年轻的泰特斯对美丽淑慧的公主一见钟情,他下定决心一定要当上王国的驸马爷。 @@ -673,28 +695,6 @@
- - 迪瑞克拉世界观轶事集 - - https://thinklive1.github.io/2023/09/29/%E8%BF%AA%E7%91%9E%E5%85%8B%E6%8B%89%E8%BD%B6%E4%BA%8B%E9%9B%86/ - 2023-09-29T02:18:45.993Z - 2023-11-27T12:47:59.707Z - - 泰特斯

正如童话故事常见的开头一样,泰特斯是个贫穷而有志气的青年,有一天当他在王国的大街上闲逛时,他遇到了公主的轿子,年轻的泰特斯对美丽淑慧的公主一见钟情,他下定决心一定要当上王国的驸马爷。 当时开国皇帝恩西斯去世没有多久,年轻的皇帝卡奥斯也是为年轻气盛的青年,泰特斯认为这是成为皇帝亲信的好机会。

当时无权无势的人想要上位有两种办法,一是参军博得战功,二是进入帝国大学谋求文官职位,泰特斯身体虚弱,而且厌恶战争,但却有个不错的头脑,于是在他刻苦攻读下终于进入了帝国的最高学府学习数学,十年后,泰特斯已经是位小有名气的数学家了。

新帝卡奥斯是个奇怪的皇帝,他不甚喜欢锦衣玉食,也不爱美人或者诗琴书赋,唯独对数学很感兴趣,帝国的数学家往往是些老古董,唯有泰特斯名声卓著,血气方刚,二人一见如故,泰特斯如愿以偿成为皇帝的亲信。

卡奥斯将各项赋税与各种工程的设计实施交给了泰特斯,结果无不让他满意,为了表示对泰特斯的欣赏,皇帝决定将自己的妹妹嫁给他。

当公主府的使臣带着婚书拜访泰特斯时,他礼貌而不失坚决地回绝了,此时在他看来任何不懂数学之美的人都是庸俗的,除了数学女神的青睐,他对任何女人不屑一顾。

当然,这件事传到了皇帝的耳朵里,同时传导的还有群臣的议论,皇帝敏感地察觉到在大部分人眼中泰特斯才是帝国最聪明的人,心怀不满的皇帝半强迫地让公主嫁给了泰特斯。当然,皇帝并不无情,否则如果他将所有比他强的数学家都杀了,那么帝国早就没几个大数学家了——要知道他的水平只是二流的

为了自己与泰特斯的安危,贤惠的公主规劝丈夫,聪明的泰特斯恍然大悟,从此以后他收敛锋芒,沉迷于公主府奢华的生活,最终,他与公主幸福地生活到了最后。

泰特斯关于数学研究的遗著于共和历11年首次出现在公众面前,最后屡经辗转进入了共和国首都博物馆的展馆

黎明

外交官是位三十出头的年轻人(就他的职位而言),一个月前,他被尊贵的皇帝陛下召见,并被赋予和葛雷氏族谈判的任务。他精于谈判之道,自从帝国决定用经济而不是武力的手段来征服那些遮布隆(帝国语,未开化的人)他变成了谈判桌上最可怕的对手,有人说他的鹰眼能轻易看穿对手的心理底线,有人说他的眼线分布各地,实际上,在外交官的心中,他的才能无关轻重,仅仅是帝国的威亚所致罢了,在早先的黑暗岁月中,遮布隆大多被帝国的屠杀,谎言与掠夺打败。

葛雷族有着一支装备精良的武装,他们背靠大陆大方最大的矿系,然而在帝国面前,这一切毫无意义,诚然,他们完全可以炸毁矿道,但那并不能躲避他们沦为帝国仆从的命运。

当我走进葛雷族的营地时,几乎所有人都对我怒目而视,其中大多是野性,却也带着几份文明,族长是位很硬朗的老人。

“知道吗,按我们的习俗,只要学到知识,就是师徒,你毕业于帝国大学,而我读过帝国大学出版的书,所以我们应该是师兄弟”

我对这老人不合时宜的幽默搞得一点摸不清头脑,“过来,我想让你看个东西”老人领着我向营地的深处走去,在巨大的仓库群前停了下来。

当他打开大门的时候我就知道了——金子,宝石,帝国经济体系中不可或缺的存在,自此帝国历234年定下贵金属和帝国货币的兑换关系后,它们就成了帝国最坚实的支柱。

“这是祖先为我们留下的,留着我们营地的大约只有十分之一””

“你们没有告诉我们这里的矿脉有黄金和宝石?”

“我现在不是告诉你们了吗?”

“……”

“你们帝国的经济命脉就是流通在市场上的黄金吧,如果这种规模的黄金瞬间涌入你们的市场,会发生什么?”

“……”

“好了,开始谈判吧”

历时3天的谈判后,帝国开出了有史以来最宽松的条件,葛雷族的所有自治权予以保留,唯一的条件是,必须与帝国展开全方面的贸易

度量

1
只是两个小人物的故事

一般来说,这年头很难遇到算命的,至于在酒吧里看到算命的就更少见了,用算命来骗酒喝已经是不知多少年前的老故事了,然而,在此时此刻,却有两个中年男人在酒吧里对饮。

“你是刚来这座城市吗?”

“恰恰相反,我在这待了很多年了”

发问者并没有追问

“你活过3000帝国币吗?”

莫名其妙的问题,乡巴佬的叫法,发问者心想,一时间他不知对方是什么意思

“我的父亲在活到566布朗时咽了气,他本指望着活到700布朗的,呵呵,然后我就到这里来了”

和一个不知从哪个穷乡僻壤来的家伙聊天或许能让自己以后酒场吹牛添一些料,中年人想,于是他决定听下去。

“来到这里后,一时间我很不适应,你们似乎总喜欢用在时间和空间上均匀分布的事物当做度量的标准,真是奇怪”

提问者忍不住做出了回答“你是说你们甚至没有时空的概念?”

“用你们的话说,我们的时间是经济学,空间则是社会学。当然,你们的语言和概念是无法完全解释的,300克朗昭示着步入成年,数不过来的人意味着一个国家,扎在一定的一堆人意味着一个省,这只是比喻。”

他自嘲般地说“我来的时候觉得在那地方我始终是客子,来到这里后又感觉并非家乡”

窗外一只先前飞走的蝴蝶盘旋一圈后又回到了树梢。

“知道吗?你会活过394杯酒。”他没头没脑地说了一句。

另一位中年人沉默着,他每周的同一时间都会来这里点一杯酒。

“而我,会活过自己度量过的第1944位客户”

“你指望我为你的疯话付钱吗?”

”我不适应你们的语言,我也不适应你们的思维……每一秒,每一厘米对你们而言都是无法更改的,你为什么觉得作为我故乡度量——金钱是能更改的呢?对你来说这是一天,对我而言这是6帝国币,二者都是神圣不可更改的。”

中年人有些可悲地看着他“你需要去补补数学和物理的课”

“我只想知道自己该用什么来度量”他显得有些颓废。

“结账,他那杯也算我的”占卜师指着中年男人桌上的酒,向服务员喊道。

占卜师离开酒吧的背影显得并不年轻,“我是他的第几个客户?”中年男人想到。

中年人从此再也没有喝过酒,一年后,一种以果汁为主成分的硬饮料在帝国风靡一时,中年人在一次应酬中举起了一杯苹果汁,当他察觉到一丝酒味后已经晚了,作为一个厌恶半途而废的男人,他选择一饮而尽,随后咽了气。

]]>
- - - <h2 id="泰特斯">泰特斯</h2> -<p>正如童话故事常见的开头一样,泰特斯是个贫穷而有志气的青年,有一天当他在王国的大街上闲逛时,他遇到了公主的轿子,年轻的泰特斯对美丽淑慧的公主一见钟情,他下定决心一定要当上王国的驸马爷。 - - - - - - - - -
- 不予播出——极端意识形态大乱斗 @@ -857,17 +857,18 @@ - blacksouls剧情解析 - - https://thinklive1.github.io/2023/09/29/black%20souls%E5%89%A7%E6%83%85%E8%A7%A3%E6%9E%90/ + blacksouls人物解析 + + https://thinklive1.github.io/2023/09/29/black%20souls%E4%BA%BA%E7%89%A9%E8%A7%A3%E6%9E%90/ 2023-09-29T02:18:45.993Z 2023-11-27T12:47:59.687Z - 冬之钟

由于black souls的故事远远没有完结,因此现阶段我们很难对红白女王梅贝尔这些与格林牵扯极深的支配者们进行什么定论,只能就已有的剧情和文本进行一些归纳,本期视频我将就bs2比较难懂的一处地方,冬之钟的主线事件,进行一些个人向的分析。 在冬之钟最后一章地图能遇到5个白熊,白熊的身份迄今为止依然是谜团,但他们提供了整整五段发生在支配者之间的重要对话,我将概括一下这五段对话提供的主要信息以便进一步的分析 我们按解包后的地图顺序开始, 第一段对话发生于梅贝尔和妹妹爱丽丝之间,可以猜测妹妹爱丽丝属于支配者之一,数量众多的支配者都在奈亚的箱庭占据一个角色以便和格林繁殖,但随着时间推移,支配者们发现扮演角色的同时,他们也在被角色同化(梅贝尔所言),因此纷纷退场,妹妹爱丽丝也逐渐被角色影响对格林产生好感,此外,姐姐爱丽丝不知何故地退场。 第二场对话发生于梅贝尔和白之女王之间,对话中提及冬之钟正是白女王的箱庭,而白之女王由于爱上了格林自愿放弃女王的身份去守护他,而梅贝尔则对这场追寻爱的闹剧,以及陪着胡闹的其他支配者感到无聊,向白女王提出一个让格林摆脱循环,并且能够独占他的计划。 第三第四场对话都发生于红白女王之间,红女王为陷入痛苦轮回的格林而痛苦,不断进行自残,白女王制止了她,两人由于同样爱上格林而心意相通 第四场对话则告诉我们,红女王接过了白女王的权王冠(推测为箱庭权限),并以此创造出库因兰德,并使其能排除奈亚的监视,两人密谋让格林挣脱循环的方法,红女王恳请白女王放弃对格林的独占欲,白女王同意了,此外,梅贝尔也知晓这一计划,并根据后面的行动来看,她不知为何也参与了这个计划 第五场对话发生于白女王和玛丽苏之间,白女王夺走了玛丽苏的改变能力,并且根据混沌迷宫的情报,将其赋予了古兰剧场,玛丽苏察觉白女王爱上了格林,并且等待着格林的到来,结尾,玛丽苏等到了一个神秘人(黑山羊?) 总结这些信息,我们可以推测出针对格林,一共提出了两个计划,一个是梅贝尔怂恿的独占计划,一个是红偶像策划的拯救计划,这两个计划都必须有诺登的参与,但此时我们并不知道诺登的真正想法是哪个 在推进h结局的过程后,格林会有两个选择,1是和暗黑舞台合二为一2是打败舞台,夺取舞台的改变能力, “此时”的冬之钟虽然沉睡,但相信诺登依旧有一定的控制能力,然而不同于G结局的阻拦,此时的诺登选择了旁观,并在最后支持格林任意一个选择 总结一下大致发生的事件(以下事件的时间顺序难以具体确定) 1诺登作为支配者之一管理着自己的箱庭冬之钟,和奈亚创造自己箱庭的时间关系未知 2奈亚将格林带到箱庭,邀请支配者们参加繁殖游戏,根据牛津学院人偶爱丽丝的说法,是舞台装置创造出了让格林在舞台上登场的皮套(格林的灵魂出自玛丽苏的手笔,因此推测只能创造皮套),并且在创造格林时两者间确立了深远的联系,白女王也参加了这个游戏,可以肯定白女王为了心爱的格林才舍弃了王冠(王冠可能指代管理箱庭的权能),因此推测白女王在爱上格林后可能以放弃王冠为代价,得到了管理奈亚箱庭的权限和陪伴在格林身边的权力 3红偶像被奈亚切割,由于茶会时期她曾经打倒初代红之女王,因此此刻可以说她的身份是第二任红之女王,为格林自责的她不断紫餐,得到了白女王的同情,白女王将自己原来的王冠权能移交给被奈亚切割的红女王,让她在原冬之钟的地盘上创造出自己的箱庭。 4红白女王合谋,或者其中之一从奈亚手中夺走了玛丽苏并囚禁起来,为了避免红白女王相互猜疑,二者将从玛丽苏手上得到的改变能力赋予舞台装置古兰,创造出一个新的支配者暗黑舞台,藏于处于过去时间线的冬之钟,同时由于处于过去的时间线,冬之钟几乎没有被发现的风险,通过dlc3经常出现的齿轮与其他信息可以推测,舞台装置拥有着影响整个箱庭以及舞台上大部分“演员”的能力,即在部分地图的bg和格林脑中的“齿轮声”,是不思议之国这场戏的核心,此外,由于诺登为了管理这个箱庭必须借助舞台的力量,而红白女王理论上权能接近,因此本视频中猜测红白女王都有部分操控舞台的权限 4由于支配者们发现扮演箱庭的角色会改变自己的本质,因此纷纷退出,白女王被迫用自己和格林的子嗣填补空缺 5梅贝尔认为这场游戏无聊透顶,一场剧本烂透的戏剧重复多少遍也只会让人厌倦(她自己是这么说的),因此她怂恿白女王让格林脱出循环,并抢先独占他 6红女王努力让自己的领域能排除奈亚的监视,并在此向白女王提出了拯救格林的计划,这个计划梅贝尔也知情,白女王同意了拯救计划,我们不知道白女王听到这两个计划的顺序,但他们明显是冲突的 7可能是人为,可能是自发,舞台觉醒了自我意识呼唤着格林的爱,同时在梅贝尔的指引下格林也朝着舞台进发,一场死斗在所难免,可以推测,在夺取舞台能力的结局中,诺登执行了红女王的拯救计划,舍身为格林断后,使其在爱丽丝01,即现在的红偶像的帮助下回到现实。在舞台与格林合一的bad end中,诺登执行了梅贝尔提出的独占计划,该结局中诺登辅佐着通过合体得到创作能力的格林与奈亚进行斗争,并且前往世界尽头来逃避一切纷争和毁灭,顺便一提,我觉得这结局也不算坏,白女王很可能会确保格林在融合中占据主导,此时格林成为了名副其实的支配者,和白女王的结合甚至能和奈亚势均力敌,不过寿司在采访中提到执着于爱丽丝身份的奈亚无法发挥全力就是了,毫无疑问这时的格林是目前为止的(格林)战力巅峰。 这就是冬之钟里发生的主要事件了,下面我将对事件的主要参与者,红白女王和虚无的少女进行分析。 首先是参与程度较低的梅贝尔梅贝尔虽然入局较浅,但却是格林的引导者,并帮助拖延了一下奈亚,也是她告诉我们打破这一循环只能正面和舞台装置对决,那么她的目的是什么呢? 首先,梅贝尔在混沌迷宫中会直接提及支配者间不可避免将爆发战争,并且导致阿撒托斯的苏醒毁灭一切,而身份不是支配者却可能得到支配者之器的格林,才能发动不会惊醒阿撒托斯的箱庭战争,这可能是她帮助格林的首要目的 其次,梅贝尔是个不可救药的收藏狂,她的箱庭是个巨大的垃圾场,什么都有,因此她也想把格林培养成一个完美收藏品或者棋子 最后,在个人感情上,很难定论梅贝尔到底产生了多少感情,她自称对永无止境的劣质戏剧循环感到厌倦,才会帮助格林创造自己的故事,但又在背叛剧情中声称想要让格林得到更高的器随后利用他,最后如果试图救她又会说自己涌现出了一些对格林的爱,由于信息过少,很难知道她到底觉醒了多少感情。 不过可以肯定的是,如果是梅贝尔真有意背叛动机是不充分的,如果她只需要格林成为拥有支配者之器的棋子,那么独占和拯救计划都能实现这个目的,并且由于白女王看着,融合后大概率是格林占主导地位,无非是好不好操控的问题,因此猜测梅贝尔实际上是真心帮助格林,只是在用激将法,或者习惯性毒舌。 冬之钟的棋局不管怎么走梅贝尔都不是输家,如果独占计划成功,白女王和格林则会成为一股对抗奈亚甚至其他支配者的强大力量,如果拯救计划成功,格林则会成为一个有着支配者的器,却对大部分支配者恨之入骨的棋子或潜在盟友,不论哪个结果都对梅贝尔阻止阿撒托斯苏醒的目的有利,而她的损失不过是万千分身中的一个而已 随后则是红之女王,尽管游戏中没有直接说红女王就是一代的爱丽丝01,以及茶会中的爱丽丝,但大量证据表明她和爱丽丝01有着千丝万缕的关系,爱丽丝01也极有可能就是茶会爱丽丝,所以本视频采纳这一说法,可以说最早钻进人类皮套的她是人性化最深的支配者,她人类的一面深爱格林,但又恐惧支配者的一面暴露,因此自觉配不上格林,甚至认为是自己导致了格林的一切悲剧,顺便一提关于茶会以及更早时期的资料实在太少,所以我们现在对这段剧情的讨论很可能是不完整甚至有较大误解的,因此在此我只能尽可能保守地做一些推测,由于支配者本性难以剥离,在她身上有着强烈的自毁倾向,想爱,却又自觉没有资格去爱,因此她只能用紫餐的方式填补内心的负罪感,H结局中,她以几乎自杀的方式当着奈亚的面帮助格林逃离了奈亚的掌控,可以说为了格林,红女王自降身份把自己变成了棋子,而且是必死的棋子,只为了能在后续将奈亚一军。 等待着这个叛徒的是什么结局,我们只能发挥一下想象力了 最后则是冬之钟的核心人物,白之女王诺登诺登的原型之一是爱丽丝梦游仙境的白兔先生,白兔最明显的元素就是他永远匆忙的样子和怀表,这点也在诺登身上得以体现,白女王作为这场繁殖游戏事实上的管理者,为了协调任性的演员们可谓操碎了心,在轮回的最后,台上的演员几乎全部是她的子嗣(兔子可是繁殖力非常强的生物),可以猜测在制定剧本和排练上她也得下不少功夫,而dlc3的核心意象,齿轮,其实可以说既指着暗黑舞台的齿轮带动了戏码的上演,也指着诺登怀表的齿轮,诺登就是那个负责在指针快点到达终点前让齿轮倒转,重新开始计时的人,这也是为何她会在结局中说为齿轮停止感到害怕,让齿轮转动是她的职责,在她的内心深处或许也有着对无尽循环中格林真正爱上自己并一起逃到世界尽头的希望,但最后她选择成全格林真正的爱,而放弃管理齿轮的职责则意味着她与自己支配者的身份完全决裂,将一切奉献给人类的爱。此外,诺登的支配者原型则是所谓的幻梦境之主,这或许解释了为何是她在实际上管理着二代这个巨大的梦境 我在尸龙的人物解析说,类似尸龙的独占欲在红白女王身上也出现过,但红女王由于害怕自己的支配者本性选择放手,那么白女王呢?在h结局中,梅贝尔被古兰(推测,也可能是奈亚)针对性的陷阱解决,但拥有舞台权限的红白女王应该不受影响,红女王为了最后拯救格林必须蛰伏,因此辅助格林对抗古兰以及奈亚的任务只能交给白女王,但即使在此时此刻,白女王依旧有着独占格林的选项,如果她控制或者协助舞台装置强迫和格林融合,就可以抢先一步独占所有支配者都垂涎的格林,但如果把舞台的改变能力给予格林,那么失去王冠和舞台的诺登则会失去自己在棋局上的几乎所有棋子,面对这种选择,诺登将选择权给了格林,不能说她是完全无私的,但面对这样的诱惑,她也会尊重格林的选择,这不得不说是非常伟大的爱 可以说白女王是一个有着两面性的角色,她支配者的一面始终对格林有着独占欲,但她人性的一面始终压抑着这些黑暗的感情,她是一个徘徊于人与神界限的存在,但无论如何,她都尊重并支持着格林的选择,所以她闪耀着人性光辉的一面始终是压过支配者的黑暗一面的。 让我们给这幕疯狂剧场的落幕做一个总结吧,这局棋是红白女王和梅贝尔设下的,目的是为了让格林得到古兰的改变能力并逃离奈亚的箱庭,其中没有舞台权限的梅贝尔负责引导格林,红女王则在最后帮助得到改变能力的格林摆脱奈亚掌控,而白女王则有着最关键的决策权,即是否利用舞台独占格林,但她最后将决定权给了格林,而格林真正的选择应该是夺取舞台的改变能力,因此最后白女王舍弃了一切帮助格林逃离崩坏的舞台。 这场棋局中,梅贝尔横竖不亏,红女王陷入必死之局,最关键的棋手就是白女王,只要她愿意,随时可以下出必赢的一着,但最后她依旧选择了放弃自己的棋子,把终结棋局的希望留给了格林 在经历如此多的牺牲之后,格林终于从棋子升为了棋手,只是不知道他又会下出怎样的一着

]]>
+ 尸龙贾巴沃克
1
在天之繁星哟!命数已定之众哟!尽管去为爱所煎熬吧,为嫉妒之苦吧!呜呼!感激涕零吧!为这幸灾乐祸暗黑舞台点缀色彩就好!!!

象征着腐败与神秘的紫黑色,遍布全身的缝合痕迹与绷带,恶魔一样的卷曲角,晦暗如死尸的肤色,以及左眼燃烧着的灵魂之火(致敬黑岩射手可能性微存),尸龙姐姐的人物形象无时无刻不在传达着神秘强大而阴暗的气氛,本视频将对尸龙的整个人物进行解析 尸龙在爱丽丝镜中奇遇的原型是一首小诗,这首诗的大意是勇者手提沃伯尔之剑斩杀邪龙贾巴沃克,游戏中也承袭了这一设定,贾巴沃克一直都以死尸的形象登场 要解析这一角色,我们首先从最直接的行为说起,按游戏的时间线,尸龙姐姐大概做了以下这些事 1把童话(具体哪本未知,根据混沌迷宫的狼外婆信息推测可能是小红帽)给了渴望母爱的玛丽.苏,从而激发了虫虫的创作能力,导致她创造出一代的箱庭。顺便一提,关于尸龙玛丽苏的关系,游戏里没有直接证据支持姐妹说,混沌迷宫提到黑山羊有两个子嗣,米兰达认为尸龙有黑山羊的气息,且明显尸龙玛丽苏有一定关系,这些是确定的,但并未明说姐妹,有人从克苏鲁的设定中寻找论据,但本人对克系了解不多在此不评价。 2红偶像约会中电影《三人的茶会》提及茶会时期的三人曾经打倒过贾巴沃奇,不知是否和尸龙有关,此外尸龙也曾被昔日的勇者,如今的猎头兔打倒,自称在之后洗心革面,但相关资料太少,我们不知道是不是她放水或另有隐情 3格林被引导进玛丽苏的箱庭开始一代的故事,此时尸龙(不知道玛丽苏是否知情)已经乱入到一代的不思议之国,为格林一行人提供帮助,通关d结局后找她对话,她会直接把二代给剧透了,不过由于时间线上d结局应该直接接上二代,所以“正史”上可能没有这件事,顺便一提,一代的不思议之国是爱丽丝的箱庭,或者说玛丽苏的仿造品,也没有定论,所以很难推测尸龙是入侵还是本来就在那里 4来到二代时间线,由于不思议之国是奈亚的箱庭,而黑山羊则是奈亚的“配偶”,所以尸龙出现在这倒是理所应当,此时的尸龙以四噩梦之一的身份登场,,但工作内容则是在卡罗尔川上堆雪人,以及在格林面前装出温柔大姐姐的形象,十足的关系户做派。 里路线中,格林和米兰达等人可以先后对战三噩梦,以及杀死其余两个噩梦后现出真身的尸龙,值得一提的是这似乎是她全系列中唯一一次全力出手,并且在此战中死亡,但考虑到支配者的特性,是否死透了依旧存疑 以上就是尸龙在系列中的行动,接下来我将对这些行动的目的与尸龙的性格进行归纳。 尸龙首先是一个安静的观察者,一代中她只是在一棵树下扮尸体,二代则在河边堆雪人,如果格林不找她,在里线之前不会和她有任何交集,然而,隐藏和善表面下的真相是尸龙其实是个性格扭曲唯恐天下不乱的乐子人,是她启发了玛丽苏创造自己的黑童话箱庭,间接引发之后所有的故事,而一开始的目的可能只是以玛丽苏面对求而不得的母爱痛苦挣扎的样子为乐,也是她诅咒了狩猎邪龙的英雄,使兔子一族成为贪食尸体的魔兽,其中被沃波尔斩下头颅可能是她行事风格的分界线,其自述死前曾是无恶不作的邪龙,在复活后变得收敛,但其实依旧不改邪龙本质,只是变得只在关键时刻推波助澜 而将这两种性格统一起来的则是她的创作欲,没错,和玛丽苏一样,尸龙对创作也有自己的执念,在玛丽苏涌现起黑暗的创作力之后,尸龙意识到,玛丽苏那邪恶的灵魂一定程度其实是自己的作品,如果说玛丽苏是支配者中第一个创造故事的人,尸龙就是第一个“创作者”,这激发出她内心最深层的欲望,那就是创作出足够黑暗污秽的灵魂,方法则是让一个灵魂在无尽的痛苦与求而不得中循环。 可以说在这点上尸龙和奈亚有一定的共同点,就是让格林经历无数次的痛苦循环,但二者还是有着分歧,奈亚想要的是格林求而不得的爱,尸龙则想要格林本就污秽的灵魂更加黑暗。 这时我们就可以理解尸龙的行为了,由于里线实际上也处于轮回之中,所以对尸龙来说,告诉格林一些真相只会让他的反抗更加激烈,也会在反抗之后更加绝望,这样才符合她的目的。 而以上依旧是贾巴沃克的表层性格,而她隐藏最深的性格则是扭曲的独占欲,在卡罗尔川的地牢中有个四个雪人,分别是玛丽苏,小红帽,爱丽丝和格林,此外,班达斯奈奇的住处也有着一个写着想将其变为收藏品的雪人(sen0才能看到真相),可见尸龙内心最深的欲望其实是独占欲,培育最污秽的灵魂,随后将其收藏起来,这才是尸龙的愿景,但她为何要隐藏这一欲望呢,在qf尸龙失败的逆监禁剧情里,由于尸龙发现格林的灵魂已经黑暗到想要独占自己,尸龙就会唯一一次直接暴露自己的独占欲来收割这个丰硕的成果,然而,奈亚或者其他支配者绝不会容忍这种行为,所以一旦尸龙试图独占格林就会立刻被排除出世界,这就是尸龙一直压抑着独占欲的原因。 此外,根据dlc3入口处的对话以及数量庞大的雪人,或许可以猜测尸龙曾经一边观察一边玩弄过很多灵魂,但这些灵魂最后都因为经历过多的痛苦和绝望后变得麻木,因此才会对有着无穷成长性的格林视若珍宝 一切温柔的言语都不过是为了将格林引导向更绝望的结局,独占污秽的黑之魂,玩到腻后就扔掉,对贾巴沃克之魂的描述为包藏在虚伪的母性之下的独占欲之影可谓恰如其分。 值得一提的是,独占欲这种感情不止在尸龙一人上出现,大部分支配者都有着这种感情,如白之女王诺登就承认自己多次有独占格林的想法,爱丽丝01也曾吐露自己害怕不可控制地想要独占格林,但她们与尸龙的区别则是,她们能够理解人类的爱,并为了人类的幸福选择放手,与红白女王的对比或许也是尸龙人物形象设计的一个目的 现在可以做一个总结了,尸龙姐姐是一个对格林有着强烈爱意的角色,她的母性是虚伪的,但这种爱意却不是,尽管她扭曲,残酷,自私,虚伪,但是她始终知道自己要做什么并理性地付出行动,即使失败了也不失风度从容自若,相较于虫虫几乎写在脸上的扭曲性格,直截了当的作恶行径,以及一有挫败就大呼小叫的行径,尸龙的感情更加内敛,行事也更加隐秘,但可谓是个很有恶人魅力的反派角色 同时,由于bs的碎片化叙事并且尚未完结,关于尸龙依旧有很多谜团,例如她和玛丽苏以及其他支配者的具体关系,里线中她是不是仍然在演戏,她究竟为何会给玛丽苏童话书,尸龙等三噩梦和三个爱丽丝的关系等等,就期待续作的解答了 大家都来和尸龙姐姐做朋友吧,尸门

玛丽苏

玛丽苏,作为bs中自称的女主角,是bs唯二个三代都有出场(包括红森)的支配者,还有一个是贾巴沃克),在此过程中做过的好事可谓数不胜数,罄竹难书,我们来按着时间线整理一下 1一开始的玛丽苏是个渴望母爱的孩子,尽管我们不知道bs设定下一开始的支配者到底会不会有类似人类的亲情,她掌管自己的世界,倾听子民的祈祷,开始感到厌烦,这时贾巴沃克不知出于什么目的,送了她一本童话书,这本书,我们不知道是哪个童话,但本人猜测很可能这本书的作者是玛丽苏第一个抓住的,并在黑之魂的融合中有重要地位,根据青鸟的文本,卡罗尔并不是第一个抓住的素材,所以基本可以排除梦游仙境,结合男主角格林的名字和混沌迷宫的狼外婆,我个人猜测是小红帽,她开始渴望创作自己的故事来打动母亲,至少一开始是这样,她派遣属下四处收集童话作者的灵魂作为素材,同时肆意进行同人创作。 2玛丽苏的处女作是小红帽,也是她第二得意的作品,根据一些信息,小红帽的灵魂可能以现实世界的一个女学生为素材,在魔改剧情的同时,她还给了小红帽注定20岁早逝的设定,并可能赋予了小红帽通过镜子穿梭位面之类的特殊能力来担任女主角,但不知道为什么她又不满意,想做一个男主角出来,但她对小红帽的善后却颇有些问题,小红帽不仅杀穿了红森,而且还能意识到她这个黑幕的存在。 3缝合了众多童话作家灵魂的格林诞生了,并被赋予了给周围的女主角带来不幸的设定,格林污秽的黑之魂有成为支配者的潜质,玛丽苏甚至还大胆地保留了他的部分创作能力,因为最关键的改变权能在她手上,为什么叫做格林则未知,可能是最初的童话书就是格林童话的一本,这之后格林不知道为什么,以什么身份在一个叫不思议之国的地方和叫爱丽丝和祈祷主的存在开起了茶会,随后格林与爱丽丝01相恋,嫉妒的祈祷主呼唤了玛丽苏,导致格林被带走了,连同格林不知何时创造出的故事们也被篡改 4基于以上提到的各种童话故事素材,玛丽苏魔改出了失落帝国的箱庭,把格林放进去经历一次次绝望故事的轮回,自己则担任女主角欣赏故事,还设计把母亲叫了进来欣赏自己的大作。不知多少次循环后,这个大好局面被打破了,母亲黑山羊为了逃离这个世界和她战斗,连圣森都磨灭了,战胜母亲后,奈亚丽丝前来捡漏带走格林进行新一轮追寻爱的游戏,本来想顺带着把玛丽苏也灭了,但在诺登的劝阻以及可能的其他考量下放过了她 5奈亚,红女王,白女王中的某位或若干位剥夺了她的改变权能,把她囚禁在库因兰德,失去权能的她改名为玛丽安,但不知何时也不知何人前来探访了她,到格林试图从梦中醒来的里线,玛丽安乘乱逃出,由于正史上不太可能发生f结局,所以此时应该是g结局,也有可能正史上g结局有少许与游戏不同,不管怎么说此时的玛丽安应该被格林小红帽两人打败,但h结局中可以看到她没有死,而且不知道怎么逃了出来 可以说,bs中的一切悲剧,玛丽苏至少有五成功劳,接下来让我们来分析一下玛丽苏的角色特质。 首先,最直接的一点,玛丽苏是个典型的支配者,高高在上地支配着人类这样的低等种族,但玛丽苏特殊之处在于,她可能是最能理解人类感情的支配者之一,首先我们就可以看到她居然渴望所谓的母爱,而根据2代大部分支配者的表现,即使因融入皮套逐渐有了感情,也没有第二个有亲情这种非常类似人类感情的支配者,此外,她还以玩弄人类的灵魂为乐,当然有这种兴趣的支配者恐怕不少,但这股风气可以说是玛丽苏带起来的,也是她最先玩出各种花样。 因此可以引出玛丽苏的第二个特点了,她是很像人类的一个支配者,尽管理解非常片面,但她确实懂得并拥有不少人性,而她为什么这么喜欢玩弄人类呢?这也很容易理解,一般来说越通人性的动物越被人类亲近,逗猫逗狗远远比逗蚂蚁有意思,因为这些宠物的智力和人类更接近,人类可以很容易地理解它们在想什么,然后在逗弄它们的过程中获得一种智力上的优越感,以及一种“支配感”,这恐怕就是玛丽苏看到自己编排的好戏上演的感觉。 这点可以说是我们对玛丽苏进行解析的基石,毕竟任何角色首先都是人的投影,而人性越丰富,就有越多的性格侧面。 玛丽苏第三个特点就是由此衍生的纯粹性,当然,此处并不是说纯洁善良云云,而是某种意义上的纯粹之恶,很多支配者在扮演人类后都会被皮套影响而恐慌或纠结,但玛丽苏却没有这种烦恼,她以融入人类扮演人类为乐(小精灵也算类人种族),她作为支配者的漆黑本性和人性之恶完美地兼容了,不会有徘徊二者之间的身份认同问题,而她大部分所作所为也就是为了践行人性之恶,什么是恶呢,比较狭隘的解释就是为了为了自己的利益或者取乐而伤害他人,而玛丽苏的邪恶就很纯粹,就是为了取乐,甚至有损自己利益也要作恶,如果解救了被囚禁的玛丽苏,此时她会自认为东山再起,但她想的不是第一时间抹杀已经成长了的格林或者藏起来,而是想再让格林经历一次悲惨的故事,可以说她作恶的动机相当纯粹,也相当执着。 在此之上的第四个特点,就是她的创作者身份,很多支配者都会赞扬她的创作能力,连奈亚构建的不思议之国都有不少玛丽苏箱庭的影子,但这种创造力也只是对于支配者来说了,如果我们用人类的视角看如何呢?寿司在访谈时轻蔑地说到“她说到底也只是玛丽苏,也只能整点二次创作了”可以说道出了玛丽苏所谓创作的本质,说到底,玛丽苏就是那种典型的黑深残小鬼,把一个可能有很多种解释的作品曲解为单一的猎奇世界观,当然不是说这样不行,如果原创一个黑深残世界观自娱自乐当然是可以接受的,但玛丽苏的行为就是最恶劣的一种同人女行为,魔改原来的作品,把自己做成角色代入进去搞cp,还要把所有其他角色踩一遍,情节和人物关系只要对自己代入的角色有利就行,然后把这部除了自己看谁也不会喜欢的同人拿给原作者看,我就不详细说这种行为的恶劣程度了,但这种作品折射出来的创作观我必须要辩驳一下。 当然,本视频所有讨论只局限于二次元文化内, 荒木飞吕彦认为漫画有四要素,角色、剧情、世界观、主题,我们就用这四个维度来剖析玛丽苏的所谓创作。 首先是角色,直接创作一个鲜活的灵魂对强大的支配者来说也是一件难事,所以对于角色的选取,玛丽苏很可能都是使用现实存在的灵魂然后再魔改来适配进童话或者传说的人物,因此她笔下所谓角色虽然很多但其实并不是她自己的功劳,而她为了把这些灵魂塞进角色对设定随意删改,把小红帽的外婆和母亲缝成了一笔烂账,人物关系更是一团乱麻,怎么方便怎么来,角色设定连基本的自洽也做不到,水平着实不敢恭维 随后是世界观,失落帝国这个箱庭本质上来说就是个童话故事的缝合体,没有历史演化,没有详细设定,这并不是一个鲜活的世界观,只不过是一个临时搭建的舞台而已,当然,很多线性的故事并不需要一个多详尽的世界观,在这点上玛丽苏只能说无功无过 最后是剧情和主题,玛丽苏的主题是简单粗暴的黑深残,剧情则是当常规的rpg剧本演到最后的happy end时毫无铺垫伏笔地急转直下变成bad end,当然,能设置这么大规模的箱庭,还写了不少支线剧情,证明玛丽苏确实是有一些笔力的,但首先,她的角色基本靠抓人,故事则都有童话原型,故事演变她只需要把握大方向,其他可以让角色自己来,而最后没有任何铺垫的bad end依旧表明了她创作的失败,如果一个设定没有任何铺垫和暗示,直到使用时才抛出,那只能证明这部作品情节编排的失败,因为一部作品的生命周期不是作者创作出来就结束了的,而要等到读者看完理解了故事才会结束,这个过程作者读者应该处于相对公平的地位,根据故事的设定,人物有充分的理由这样行动,这样才能让读者认同这个故事,而玛丽苏却完全相反,滥用作者的权能让故事不仅没有逻辑,还自相矛盾,很明显,对玛丽苏来说她是作者也自认为是唯一的读者,那些被抓走被改造的灵魂不过是用完即扔的工具罢了,不需要自圆其说,只要自己看得高兴就行了,或许就支配者的立场来说她不过是自娱自乐罢了,但对人类(至少灵魂上是人类),以及同样作为创作者的格林来说,首先就绝不可能认同这种恶行,更不可能认同自己的作品被改成这样的烂作 说到这里,就可以讨论一下玛丽苏对于格林的看法了,直观地说,是玛丽苏创造了名为格林的污秽黑之魂,但其实在最初,是格林等童话作家激发了玛丽苏的创作欲,因此,事实上,两者是相互创造的关系,玛丽苏创造格林的目的,首先是为了成为她作品的男主角,让她能够代入女主角的位置欣赏这个故事,这样说来似乎格林除了男主角的身份和其他角色也没什么本质的不同。但格林还有一点对玛丽苏有着重大意义,就是他童话作家灵魂集合体的身份,即使自我中心如玛丽苏这种存在,也会有对别人欣赏自己作品的渴望,因此玛丽苏特地设置了一个c结局,用演戏的形式让格林得以了解她的整个创作生涯,至于目的,除了单纯的表现欲和欣赏格林的痛苦以外,恐怕也有一丝希望作为原作者的格林认同自己的心情,哪怕是厌恶,玛丽苏也想得到一些对创作的反馈,而格林是唯一能在创作这个领域和她有一些共鸣的人,作者,读者,男主角,格林三位一体的身份对玛丽苏来说,可以说是难得的知己,尽管这种关系非常扭曲,但不能否认,在这点上玛丽苏作为创作者的心情是有些真心的。而玛丽苏会渴望认同这点,一开始是希望得到母爱,但在得到格林这个玩具之后,玛丽苏就一点也不在意黑山羊的死活了,这也是佐证。 最后不得不提的是,玛丽苏的特殊性质,很大程度上她是寿司这个作者的投影,我个人觉得玛丽苏这个角色有不少表达寿司自己创作观的成分,这也解释了寿司为何这么偏爱她当然,一部好的作品,任何角色都是基于自己的设定和世界观行动,不可能因为是作者的投影就有特别待遇,所以可以说,玛丽苏虽然很大程度上是寿司的投影,但投影的目的其实是对比,玛丽苏的创作肤浅,笔下的故事只是无聊的黑深残,但寿司却喜欢在绝望时写一些希望,在希望中铺设绝望,最后的反转再怎么说都是有因可循,单论创作的层次来说就高出绿虫子太多了,当然,我也不是在吹寿司笔力多高,因为高出玛丽苏这个水平的创作者多如牛毛。 寿司设置玛丽苏这个角色,其实是使用了一种嵌套的结构来讲故事,首层是童话的原作,这些是毋庸置疑的好故事,随后是虫子和奈亚魔改出的箱庭,是烂故事的典型,最后一层寿司想讲的重点其实是格林怎么察觉真相,挣脱出烂故事的循环,书写自己的结局的故事,在这三层中,第一层玛丽苏是读者,格林等人是作者,只出现在设定层面,第二层玛丽苏是一半作者一半角色,格林是一半读者一半角色,体现在abc结局,最后一层中寿司是唯一的作者,玛丽苏和格林就都是角色了,体现在d结局以及之后的二代,这种层层演变虽然有些炫技,但确实非常有意思。 就玛丽苏这个角色而言,整个泛二次元文化里她这样的反派也不常见,究其原因,则是因为一个有能力玩弄主角取乐的boss必然会导致战力失衡,冲突不起来,让读者感到憋屈,因此想要打败这种boss要么机械降神唯心爆发,比如一代c结局(虽然是演的),要么引入新的boss和同伴体系取代她如d结局,也因此,虽然我个人很喜欢一代,但一代的真结局d结局远没有2代h结局震撼 来做个总结吧,玛丽苏无疑是个纯粹邪恶的支配者,一个烂到骨子里的创作者,她作为创作者无疑是失败的,但作为bs这个故事里的角色反而是很成功的,不仅纯粹有特点,还有很多角色侧面可以挖掘,寿司巧妙地利用她读者,创作者和角色的三重身份来塑造她的多面性,颇有荒木在漫画术中写的“在作恶道路上高歌猛进”的成功反派角色风格。

]]>
- <h1 id="冬之钟">冬之钟</h1> -<p>由于black souls的故事远远没有完结,因此现阶段我们很难对<code>红白女王</code>与<code>梅贝尔</code>这些与格林牵扯极深的支配者们进行什么定论,只能就已有的剧情和文本进行一些归纳,本期视频我将就bs2比较难懂的一处地方,冬之钟的主线事件,进行一些个人向的分析。 + <h1 id="尸龙贾巴沃克">尸龙贾巴沃克</h1> +<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">在天之繁星哟!命数已定之众哟!尽管去为爱所煎熬吧,为嫉妒之苦吧!呜呼!感激涕零吧!为这幸灾乐祸暗黑舞台点缀色彩就好!!!</span><br></pre></td></tr></table></figure> +<p>象征着腐败与神秘的紫黑色,遍布全身的缝合痕迹与绷带,恶魔一样的卷曲角,晦暗如死尸的肤色,以及左眼燃烧着的灵魂之火(致敬黑岩射手可能性微存),<code>尸龙</code>姐姐的人物形象无时无刻不在传达着神秘强大而阴暗的气氛,本视频将对<code>尸龙</code>的整个人物进行解析 @@ -883,18 +884,17 @@
- blacksouls人物解析 - - https://thinklive1.github.io/2023/09/29/black%20souls%E4%BA%BA%E7%89%A9%E8%A7%A3%E6%9E%90/ + blacksouls剧情解析 + + https://thinklive1.github.io/2023/09/29/black%20souls%E5%89%A7%E6%83%85%E8%A7%A3%E6%9E%90/ 2023-09-29T02:18:45.993Z 2023-11-27T12:47:59.687Z - 尸龙贾巴沃克
1
在天之繁星哟!命数已定之众哟!尽管去为爱所煎熬吧,为嫉妒之苦吧!呜呼!感激涕零吧!为这幸灾乐祸暗黑舞台点缀色彩就好!!!

象征着腐败与神秘的紫黑色,遍布全身的缝合痕迹与绷带,恶魔一样的卷曲角,晦暗如死尸的肤色,以及左眼燃烧着的灵魂之火(致敬黑岩射手可能性微存),尸龙姐姐的人物形象无时无刻不在传达着神秘强大而阴暗的气氛,本视频将对尸龙的整个人物进行解析 尸龙在爱丽丝镜中奇遇的原型是一首小诗,这首诗的大意是勇者手提沃伯尔之剑斩杀邪龙贾巴沃克,游戏中也承袭了这一设定,贾巴沃克一直都以死尸的形象登场 要解析这一角色,我们首先从最直接的行为说起,按游戏的时间线,尸龙姐姐大概做了以下这些事 1把童话(具体哪本未知,根据混沌迷宫的狼外婆信息推测可能是小红帽)给了渴望母爱的玛丽.苏,从而激发了虫虫的创作能力,导致她创造出一代的箱庭。顺便一提,关于尸龙玛丽苏的关系,游戏里没有直接证据支持姐妹说,混沌迷宫提到黑山羊有两个子嗣,米兰达认为尸龙有黑山羊的气息,且明显尸龙玛丽苏有一定关系,这些是确定的,但并未明说姐妹,有人从克苏鲁的设定中寻找论据,但本人对克系了解不多在此不评价。 2红偶像约会中电影《三人的茶会》提及茶会时期的三人曾经打倒过贾巴沃奇,不知是否和尸龙有关,此外尸龙也曾被昔日的勇者,如今的猎头兔打倒,自称在之后洗心革面,但相关资料太少,我们不知道是不是她放水或另有隐情 3格林被引导进玛丽苏的箱庭开始一代的故事,此时尸龙(不知道玛丽苏是否知情)已经乱入到一代的不思议之国,为格林一行人提供帮助,通关d结局后找她对话,她会直接把二代给剧透了,不过由于时间线上d结局应该直接接上二代,所以“正史”上可能没有这件事,顺便一提,一代的不思议之国是爱丽丝的箱庭,或者说玛丽苏的仿造品,也没有定论,所以很难推测尸龙是入侵还是本来就在那里 4来到二代时间线,由于不思议之国是奈亚的箱庭,而黑山羊则是奈亚的“配偶”,所以尸龙出现在这倒是理所应当,此时的尸龙以四噩梦之一的身份登场,,但工作内容则是在卡罗尔川上堆雪人,以及在格林面前装出温柔大姐姐的形象,十足的关系户做派。 里路线中,格林和米兰达等人可以先后对战三噩梦,以及杀死其余两个噩梦后现出真身的尸龙,值得一提的是这似乎是她全系列中唯一一次全力出手,并且在此战中死亡,但考虑到支配者的特性,是否死透了依旧存疑 以上就是尸龙在系列中的行动,接下来我将对这些行动的目的与尸龙的性格进行归纳。 尸龙首先是一个安静的观察者,一代中她只是在一棵树下扮尸体,二代则在河边堆雪人,如果格林不找她,在里线之前不会和她有任何交集,然而,隐藏和善表面下的真相是尸龙其实是个性格扭曲唯恐天下不乱的乐子人,是她启发了玛丽苏创造自己的黑童话箱庭,间接引发之后所有的故事,而一开始的目的可能只是以玛丽苏面对求而不得的母爱痛苦挣扎的样子为乐,也是她诅咒了狩猎邪龙的英雄,使兔子一族成为贪食尸体的魔兽,其中被沃波尔斩下头颅可能是她行事风格的分界线,其自述死前曾是无恶不作的邪龙,在复活后变得收敛,但其实依旧不改邪龙本质,只是变得只在关键时刻推波助澜 而将这两种性格统一起来的则是她的创作欲,没错,和玛丽苏一样,尸龙对创作也有自己的执念,在玛丽苏涌现起黑暗的创作力之后,尸龙意识到,玛丽苏那邪恶的灵魂一定程度其实是自己的作品,如果说玛丽苏是支配者中第一个创造故事的人,尸龙就是第一个“创作者”,这激发出她内心最深层的欲望,那就是创作出足够黑暗污秽的灵魂,方法则是让一个灵魂在无尽的痛苦与求而不得中循环。 可以说在这点上尸龙和奈亚有一定的共同点,就是让格林经历无数次的痛苦循环,但二者还是有着分歧,奈亚想要的是格林求而不得的爱,尸龙则想要格林本就污秽的灵魂更加黑暗。 这时我们就可以理解尸龙的行为了,由于里线实际上也处于轮回之中,所以对尸龙来说,告诉格林一些真相只会让他的反抗更加激烈,也会在反抗之后更加绝望,这样才符合她的目的。 而以上依旧是贾巴沃克的表层性格,而她隐藏最深的性格则是扭曲的独占欲,在卡罗尔川的地牢中有个四个雪人,分别是玛丽苏,小红帽,爱丽丝和格林,此外,班达斯奈奇的住处也有着一个写着想将其变为收藏品的雪人(sen0才能看到真相),可见尸龙内心最深的欲望其实是独占欲,培育最污秽的灵魂,随后将其收藏起来,这才是尸龙的愿景,但她为何要隐藏这一欲望呢,在qf尸龙失败的逆监禁剧情里,由于尸龙发现格林的灵魂已经黑暗到想要独占自己,尸龙就会唯一一次直接暴露自己的独占欲来收割这个丰硕的成果,然而,奈亚或者其他支配者绝不会容忍这种行为,所以一旦尸龙试图独占格林就会立刻被排除出世界,这就是尸龙一直压抑着独占欲的原因。 此外,根据dlc3入口处的对话以及数量庞大的雪人,或许可以猜测尸龙曾经一边观察一边玩弄过很多灵魂,但这些灵魂最后都因为经历过多的痛苦和绝望后变得麻木,因此才会对有着无穷成长性的格林视若珍宝 一切温柔的言语都不过是为了将格林引导向更绝望的结局,独占污秽的黑之魂,玩到腻后就扔掉,对贾巴沃克之魂的描述为包藏在虚伪的母性之下的独占欲之影可谓恰如其分。 值得一提的是,独占欲这种感情不止在尸龙一人上出现,大部分支配者都有着这种感情,如白之女王诺登就承认自己多次有独占格林的想法,爱丽丝01也曾吐露自己害怕不可控制地想要独占格林,但她们与尸龙的区别则是,她们能够理解人类的爱,并为了人类的幸福选择放手,与红白女王的对比或许也是尸龙人物形象设计的一个目的 现在可以做一个总结了,尸龙姐姐是一个对格林有着强烈爱意的角色,她的母性是虚伪的,但这种爱意却不是,尽管她扭曲,残酷,自私,虚伪,但是她始终知道自己要做什么并理性地付出行动,即使失败了也不失风度从容自若,相较于虫虫几乎写在脸上的扭曲性格,直截了当的作恶行径,以及一有挫败就大呼小叫的行径,尸龙的感情更加内敛,行事也更加隐秘,但可谓是个很有恶人魅力的反派角色 同时,由于bs的碎片化叙事并且尚未完结,关于尸龙依旧有很多谜团,例如她和玛丽苏以及其他支配者的具体关系,里线中她是不是仍然在演戏,她究竟为何会给玛丽苏童话书,尸龙等三噩梦和三个爱丽丝的关系等等,就期待续作的解答了 大家都来和尸龙姐姐做朋友吧,尸门

玛丽苏

玛丽苏,作为bs中自称的女主角,是bs唯二个三代都有出场(包括红森)的支配者,还有一个是贾巴沃克),在此过程中做过的好事可谓数不胜数,罄竹难书,我们来按着时间线整理一下 1一开始的玛丽苏是个渴望母爱的孩子,尽管我们不知道bs设定下一开始的支配者到底会不会有类似人类的亲情,她掌管自己的世界,倾听子民的祈祷,开始感到厌烦,这时贾巴沃克不知出于什么目的,送了她一本童话书,这本书,我们不知道是哪个童话,但本人猜测很可能这本书的作者是玛丽苏第一个抓住的,并在黑之魂的融合中有重要地位,根据青鸟的文本,卡罗尔并不是第一个抓住的素材,所以基本可以排除梦游仙境,结合男主角格林的名字和混沌迷宫的狼外婆,我个人猜测是小红帽,她开始渴望创作自己的故事来打动母亲,至少一开始是这样,她派遣属下四处收集童话作者的灵魂作为素材,同时肆意进行同人创作。 2玛丽苏的处女作是小红帽,也是她第二得意的作品,根据一些信息,小红帽的灵魂可能以现实世界的一个女学生为素材,在魔改剧情的同时,她还给了小红帽注定20岁早逝的设定,并可能赋予了小红帽通过镜子穿梭位面之类的特殊能力来担任女主角,但不知道为什么她又不满意,想做一个男主角出来,但她对小红帽的善后却颇有些问题,小红帽不仅杀穿了红森,而且还能意识到她这个黑幕的存在。 3缝合了众多童话作家灵魂的格林诞生了,并被赋予了给周围的女主角带来不幸的设定,格林污秽的黑之魂有成为支配者的潜质,玛丽苏甚至还大胆地保留了他的部分创作能力,因为最关键的改变权能在她手上,为什么叫做格林则未知,可能是最初的童话书就是格林童话的一本,这之后格林不知道为什么,以什么身份在一个叫不思议之国的地方和叫爱丽丝和祈祷主的存在开起了茶会,随后格林与爱丽丝01相恋,嫉妒的祈祷主呼唤了玛丽苏,导致格林被带走了,连同格林不知何时创造出的故事们也被篡改 4基于以上提到的各种童话故事素材,玛丽苏魔改出了失落帝国的箱庭,把格林放进去经历一次次绝望故事的轮回,自己则担任女主角欣赏故事,还设计把母亲叫了进来欣赏自己的大作。不知多少次循环后,这个大好局面被打破了,母亲黑山羊为了逃离这个世界和她战斗,连圣森都磨灭了,战胜母亲后,奈亚丽丝前来捡漏带走格林进行新一轮追寻爱的游戏,本来想顺带着把玛丽苏也灭了,但在诺登的劝阻以及可能的其他考量下放过了她 5奈亚,红女王,白女王中的某位或若干位剥夺了她的改变权能,把她囚禁在库因兰德,失去权能的她改名为玛丽安,但不知何时也不知何人前来探访了她,到格林试图从梦中醒来的里线,玛丽安乘乱逃出,由于正史上不太可能发生f结局,所以此时应该是g结局,也有可能正史上g结局有少许与游戏不同,不管怎么说此时的玛丽安应该被格林小红帽两人打败,但h结局中可以看到她没有死,而且不知道怎么逃了出来 可以说,bs中的一切悲剧,玛丽苏至少有五成功劳,接下来让我们来分析一下玛丽苏的角色特质。 首先,最直接的一点,玛丽苏是个典型的支配者,高高在上地支配着人类这样的低等种族,但玛丽苏特殊之处在于,她可能是最能理解人类感情的支配者之一,首先我们就可以看到她居然渴望所谓的母爱,而根据2代大部分支配者的表现,即使因融入皮套逐渐有了感情,也没有第二个有亲情这种非常类似人类感情的支配者,此外,她还以玩弄人类的灵魂为乐,当然有这种兴趣的支配者恐怕不少,但这股风气可以说是玛丽苏带起来的,也是她最先玩出各种花样。 因此可以引出玛丽苏的第二个特点了,她是很像人类的一个支配者,尽管理解非常片面,但她确实懂得并拥有不少人性,而她为什么这么喜欢玩弄人类呢?这也很容易理解,一般来说越通人性的动物越被人类亲近,逗猫逗狗远远比逗蚂蚁有意思,因为这些宠物的智力和人类更接近,人类可以很容易地理解它们在想什么,然后在逗弄它们的过程中获得一种智力上的优越感,以及一种“支配感”,这恐怕就是玛丽苏看到自己编排的好戏上演的感觉。 这点可以说是我们对玛丽苏进行解析的基石,毕竟任何角色首先都是人的投影,而人性越丰富,就有越多的性格侧面。 玛丽苏第三个特点就是由此衍生的纯粹性,当然,此处并不是说纯洁善良云云,而是某种意义上的纯粹之恶,很多支配者在扮演人类后都会被皮套影响而恐慌或纠结,但玛丽苏却没有这种烦恼,她以融入人类扮演人类为乐(小精灵也算类人种族),她作为支配者的漆黑本性和人性之恶完美地兼容了,不会有徘徊二者之间的身份认同问题,而她大部分所作所为也就是为了践行人性之恶,什么是恶呢,比较狭隘的解释就是为了为了自己的利益或者取乐而伤害他人,而玛丽苏的邪恶就很纯粹,就是为了取乐,甚至有损自己利益也要作恶,如果解救了被囚禁的玛丽苏,此时她会自认为东山再起,但她想的不是第一时间抹杀已经成长了的格林或者藏起来,而是想再让格林经历一次悲惨的故事,可以说她作恶的动机相当纯粹,也相当执着。 在此之上的第四个特点,就是她的创作者身份,很多支配者都会赞扬她的创作能力,连奈亚构建的不思议之国都有不少玛丽苏箱庭的影子,但这种创造力也只是对于支配者来说了,如果我们用人类的视角看如何呢?寿司在访谈时轻蔑地说到“她说到底也只是玛丽苏,也只能整点二次创作了”可以说道出了玛丽苏所谓创作的本质,说到底,玛丽苏就是那种典型的黑深残小鬼,把一个可能有很多种解释的作品曲解为单一的猎奇世界观,当然不是说这样不行,如果原创一个黑深残世界观自娱自乐当然是可以接受的,但玛丽苏的行为就是最恶劣的一种同人女行为,魔改原来的作品,把自己做成角色代入进去搞cp,还要把所有其他角色踩一遍,情节和人物关系只要对自己代入的角色有利就行,然后把这部除了自己看谁也不会喜欢的同人拿给原作者看,我就不详细说这种行为的恶劣程度了,但这种作品折射出来的创作观我必须要辩驳一下。 当然,本视频所有讨论只局限于二次元文化内, 荒木飞吕彦认为漫画有四要素,角色、剧情、世界观、主题,我们就用这四个维度来剖析玛丽苏的所谓创作。 首先是角色,直接创作一个鲜活的灵魂对强大的支配者来说也是一件难事,所以对于角色的选取,玛丽苏很可能都是使用现实存在的灵魂然后再魔改来适配进童话或者传说的人物,因此她笔下所谓角色虽然很多但其实并不是她自己的功劳,而她为了把这些灵魂塞进角色对设定随意删改,把小红帽的外婆和母亲缝成了一笔烂账,人物关系更是一团乱麻,怎么方便怎么来,角色设定连基本的自洽也做不到,水平着实不敢恭维 随后是世界观,失落帝国这个箱庭本质上来说就是个童话故事的缝合体,没有历史演化,没有详细设定,这并不是一个鲜活的世界观,只不过是一个临时搭建的舞台而已,当然,很多线性的故事并不需要一个多详尽的世界观,在这点上玛丽苏只能说无功无过 最后是剧情和主题,玛丽苏的主题是简单粗暴的黑深残,剧情则是当常规的rpg剧本演到最后的happy end时毫无铺垫伏笔地急转直下变成bad end,当然,能设置这么大规模的箱庭,还写了不少支线剧情,证明玛丽苏确实是有一些笔力的,但首先,她的角色基本靠抓人,故事则都有童话原型,故事演变她只需要把握大方向,其他可以让角色自己来,而最后没有任何铺垫的bad end依旧表明了她创作的失败,如果一个设定没有任何铺垫和暗示,直到使用时才抛出,那只能证明这部作品情节编排的失败,因为一部作品的生命周期不是作者创作出来就结束了的,而要等到读者看完理解了故事才会结束,这个过程作者读者应该处于相对公平的地位,根据故事的设定,人物有充分的理由这样行动,这样才能让读者认同这个故事,而玛丽苏却完全相反,滥用作者的权能让故事不仅没有逻辑,还自相矛盾,很明显,对玛丽苏来说她是作者也自认为是唯一的读者,那些被抓走被改造的灵魂不过是用完即扔的工具罢了,不需要自圆其说,只要自己看得高兴就行了,或许就支配者的立场来说她不过是自娱自乐罢了,但对人类(至少灵魂上是人类),以及同样作为创作者的格林来说,首先就绝不可能认同这种恶行,更不可能认同自己的作品被改成这样的烂作 说到这里,就可以讨论一下玛丽苏对于格林的看法了,直观地说,是玛丽苏创造了名为格林的污秽黑之魂,但其实在最初,是格林等童话作家激发了玛丽苏的创作欲,因此,事实上,两者是相互创造的关系,玛丽苏创造格林的目的,首先是为了成为她作品的男主角,让她能够代入女主角的位置欣赏这个故事,这样说来似乎格林除了男主角的身份和其他角色也没什么本质的不同。但格林还有一点对玛丽苏有着重大意义,就是他童话作家灵魂集合体的身份,即使自我中心如玛丽苏这种存在,也会有对别人欣赏自己作品的渴望,因此玛丽苏特地设置了一个c结局,用演戏的形式让格林得以了解她的整个创作生涯,至于目的,除了单纯的表现欲和欣赏格林的痛苦以外,恐怕也有一丝希望作为原作者的格林认同自己的心情,哪怕是厌恶,玛丽苏也想得到一些对创作的反馈,而格林是唯一能在创作这个领域和她有一些共鸣的人,作者,读者,男主角,格林三位一体的身份对玛丽苏来说,可以说是难得的知己,尽管这种关系非常扭曲,但不能否认,在这点上玛丽苏作为创作者的心情是有些真心的。而玛丽苏会渴望认同这点,一开始是希望得到母爱,但在得到格林这个玩具之后,玛丽苏就一点也不在意黑山羊的死活了,这也是佐证。 最后不得不提的是,玛丽苏的特殊性质,很大程度上她是寿司这个作者的投影,我个人觉得玛丽苏这个角色有不少表达寿司自己创作观的成分,这也解释了寿司为何这么偏爱她当然,一部好的作品,任何角色都是基于自己的设定和世界观行动,不可能因为是作者的投影就有特别待遇,所以可以说,玛丽苏虽然很大程度上是寿司的投影,但投影的目的其实是对比,玛丽苏的创作肤浅,笔下的故事只是无聊的黑深残,但寿司却喜欢在绝望时写一些希望,在希望中铺设绝望,最后的反转再怎么说都是有因可循,单论创作的层次来说就高出绿虫子太多了,当然,我也不是在吹寿司笔力多高,因为高出玛丽苏这个水平的创作者多如牛毛。 寿司设置玛丽苏这个角色,其实是使用了一种嵌套的结构来讲故事,首层是童话的原作,这些是毋庸置疑的好故事,随后是虫子和奈亚魔改出的箱庭,是烂故事的典型,最后一层寿司想讲的重点其实是格林怎么察觉真相,挣脱出烂故事的循环,书写自己的结局的故事,在这三层中,第一层玛丽苏是读者,格林等人是作者,只出现在设定层面,第二层玛丽苏是一半作者一半角色,格林是一半读者一半角色,体现在abc结局,最后一层中寿司是唯一的作者,玛丽苏和格林就都是角色了,体现在d结局以及之后的二代,这种层层演变虽然有些炫技,但确实非常有意思。 就玛丽苏这个角色而言,整个泛二次元文化里她这样的反派也不常见,究其原因,则是因为一个有能力玩弄主角取乐的boss必然会导致战力失衡,冲突不起来,让读者感到憋屈,因此想要打败这种boss要么机械降神唯心爆发,比如一代c结局(虽然是演的),要么引入新的boss和同伴体系取代她如d结局,也因此,虽然我个人很喜欢一代,但一代的真结局d结局远没有2代h结局震撼 来做个总结吧,玛丽苏无疑是个纯粹邪恶的支配者,一个烂到骨子里的创作者,她作为创作者无疑是失败的,但作为bs这个故事里的角色反而是很成功的,不仅纯粹有特点,还有很多角色侧面可以挖掘,寿司巧妙地利用她读者,创作者和角色的三重身份来塑造她的多面性,颇有荒木在漫画术中写的“在作恶道路上高歌猛进”的成功反派角色风格。

]]>
+ 冬之钟

由于black souls的故事远远没有完结,因此现阶段我们很难对红白女王梅贝尔这些与格林牵扯极深的支配者们进行什么定论,只能就已有的剧情和文本进行一些归纳,本期视频我将就bs2比较难懂的一处地方,冬之钟的主线事件,进行一些个人向的分析。 在冬之钟最后一章地图能遇到5个白熊,白熊的身份迄今为止依然是谜团,但他们提供了整整五段发生在支配者之间的重要对话,我将概括一下这五段对话提供的主要信息以便进一步的分析 我们按解包后的地图顺序开始, 第一段对话发生于梅贝尔和妹妹爱丽丝之间,可以猜测妹妹爱丽丝属于支配者之一,数量众多的支配者都在奈亚的箱庭占据一个角色以便和格林繁殖,但随着时间推移,支配者们发现扮演角色的同时,他们也在被角色同化(梅贝尔所言),因此纷纷退场,妹妹爱丽丝也逐渐被角色影响对格林产生好感,此外,姐姐爱丽丝不知何故地退场。 第二场对话发生于梅贝尔和白之女王之间,对话中提及冬之钟正是白女王的箱庭,而白之女王由于爱上了格林自愿放弃女王的身份去守护他,而梅贝尔则对这场追寻爱的闹剧,以及陪着胡闹的其他支配者感到无聊,向白女王提出一个让格林摆脱循环,并且能够独占他的计划。 第三第四场对话都发生于红白女王之间,红女王为陷入痛苦轮回的格林而痛苦,不断进行自残,白女王制止了她,两人由于同样爱上格林而心意相通 第四场对话则告诉我们,红女王接过了白女王的权王冠(推测为箱庭权限),并以此创造出库因兰德,并使其能排除奈亚的监视,两人密谋让格林挣脱循环的方法,红女王恳请白女王放弃对格林的独占欲,白女王同意了,此外,梅贝尔也知晓这一计划,并根据后面的行动来看,她不知为何也参与了这个计划 第五场对话发生于白女王和玛丽苏之间,白女王夺走了玛丽苏的改变能力,并且根据混沌迷宫的情报,将其赋予了古兰剧场,玛丽苏察觉白女王爱上了格林,并且等待着格林的到来,结尾,玛丽苏等到了一个神秘人(黑山羊?) 总结这些信息,我们可以推测出针对格林,一共提出了两个计划,一个是梅贝尔怂恿的独占计划,一个是红偶像策划的拯救计划,这两个计划都必须有诺登的参与,但此时我们并不知道诺登的真正想法是哪个 在推进h结局的过程后,格林会有两个选择,1是和暗黑舞台合二为一2是打败舞台,夺取舞台的改变能力, “此时”的冬之钟虽然沉睡,但相信诺登依旧有一定的控制能力,然而不同于G结局的阻拦,此时的诺登选择了旁观,并在最后支持格林任意一个选择 总结一下大致发生的事件(以下事件的时间顺序难以具体确定) 1诺登作为支配者之一管理着自己的箱庭冬之钟,和奈亚创造自己箱庭的时间关系未知 2奈亚将格林带到箱庭,邀请支配者们参加繁殖游戏,根据牛津学院人偶爱丽丝的说法,是舞台装置创造出了让格林在舞台上登场的皮套(格林的灵魂出自玛丽苏的手笔,因此推测只能创造皮套),并且在创造格林时两者间确立了深远的联系,白女王也参加了这个游戏,可以肯定白女王为了心爱的格林才舍弃了王冠(王冠可能指代管理箱庭的权能),因此推测白女王在爱上格林后可能以放弃王冠为代价,得到了管理奈亚箱庭的权限和陪伴在格林身边的权力 3红偶像被奈亚切割,由于茶会时期她曾经打倒初代红之女王,因此此刻可以说她的身份是第二任红之女王,为格林自责的她不断紫餐,得到了白女王的同情,白女王将自己原来的王冠权能移交给被奈亚切割的红女王,让她在原冬之钟的地盘上创造出自己的箱庭。 4红白女王合谋,或者其中之一从奈亚手中夺走了玛丽苏并囚禁起来,为了避免红白女王相互猜疑,二者将从玛丽苏手上得到的改变能力赋予舞台装置古兰,创造出一个新的支配者暗黑舞台,藏于处于过去时间线的冬之钟,同时由于处于过去的时间线,冬之钟几乎没有被发现的风险,通过dlc3经常出现的齿轮与其他信息可以推测,舞台装置拥有着影响整个箱庭以及舞台上大部分“演员”的能力,即在部分地图的bg和格林脑中的“齿轮声”,是不思议之国这场戏的核心,此外,由于诺登为了管理这个箱庭必须借助舞台的力量,而红白女王理论上权能接近,因此本视频中猜测红白女王都有部分操控舞台的权限 4由于支配者们发现扮演箱庭的角色会改变自己的本质,因此纷纷退出,白女王被迫用自己和格林的子嗣填补空缺 5梅贝尔认为这场游戏无聊透顶,一场剧本烂透的戏剧重复多少遍也只会让人厌倦(她自己是这么说的),因此她怂恿白女王让格林脱出循环,并抢先独占他 6红女王努力让自己的领域能排除奈亚的监视,并在此向白女王提出了拯救格林的计划,这个计划梅贝尔也知情,白女王同意了拯救计划,我们不知道白女王听到这两个计划的顺序,但他们明显是冲突的 7可能是人为,可能是自发,舞台觉醒了自我意识呼唤着格林的爱,同时在梅贝尔的指引下格林也朝着舞台进发,一场死斗在所难免,可以推测,在夺取舞台能力的结局中,诺登执行了红女王的拯救计划,舍身为格林断后,使其在爱丽丝01,即现在的红偶像的帮助下回到现实。在舞台与格林合一的bad end中,诺登执行了梅贝尔提出的独占计划,该结局中诺登辅佐着通过合体得到创作能力的格林与奈亚进行斗争,并且前往世界尽头来逃避一切纷争和毁灭,顺便一提,我觉得这结局也不算坏,白女王很可能会确保格林在融合中占据主导,此时格林成为了名副其实的支配者,和白女王的结合甚至能和奈亚势均力敌,不过寿司在采访中提到执着于爱丽丝身份的奈亚无法发挥全力就是了,毫无疑问这时的格林是目前为止的(格林)战力巅峰。 这就是冬之钟里发生的主要事件了,下面我将对事件的主要参与者,红白女王和虚无的少女进行分析。 首先是参与程度较低的梅贝尔梅贝尔虽然入局较浅,但却是格林的引导者,并帮助拖延了一下奈亚,也是她告诉我们打破这一循环只能正面和舞台装置对决,那么她的目的是什么呢? 首先,梅贝尔在混沌迷宫中会直接提及支配者间不可避免将爆发战争,并且导致阿撒托斯的苏醒毁灭一切,而身份不是支配者却可能得到支配者之器的格林,才能发动不会惊醒阿撒托斯的箱庭战争,这可能是她帮助格林的首要目的 其次,梅贝尔是个不可救药的收藏狂,她的箱庭是个巨大的垃圾场,什么都有,因此她也想把格林培养成一个完美收藏品或者棋子 最后,在个人感情上,很难定论梅贝尔到底产生了多少感情,她自称对永无止境的劣质戏剧循环感到厌倦,才会帮助格林创造自己的故事,但又在背叛剧情中声称想要让格林得到更高的器随后利用他,最后如果试图救她又会说自己涌现出了一些对格林的爱,由于信息过少,很难知道她到底觉醒了多少感情。 不过可以肯定的是,如果是梅贝尔真有意背叛动机是不充分的,如果她只需要格林成为拥有支配者之器的棋子,那么独占和拯救计划都能实现这个目的,并且由于白女王看着,融合后大概率是格林占主导地位,无非是好不好操控的问题,因此猜测梅贝尔实际上是真心帮助格林,只是在用激将法,或者习惯性毒舌。 冬之钟的棋局不管怎么走梅贝尔都不是输家,如果独占计划成功,白女王和格林则会成为一股对抗奈亚甚至其他支配者的强大力量,如果拯救计划成功,格林则会成为一个有着支配者的器,却对大部分支配者恨之入骨的棋子或潜在盟友,不论哪个结果都对梅贝尔阻止阿撒托斯苏醒的目的有利,而她的损失不过是万千分身中的一个而已 随后则是红之女王,尽管游戏中没有直接说红女王就是一代的爱丽丝01,以及茶会中的爱丽丝,但大量证据表明她和爱丽丝01有着千丝万缕的关系,爱丽丝01也极有可能就是茶会爱丽丝,所以本视频采纳这一说法,可以说最早钻进人类皮套的她是人性化最深的支配者,她人类的一面深爱格林,但又恐惧支配者的一面暴露,因此自觉配不上格林,甚至认为是自己导致了格林的一切悲剧,顺便一提关于茶会以及更早时期的资料实在太少,所以我们现在对这段剧情的讨论很可能是不完整甚至有较大误解的,因此在此我只能尽可能保守地做一些推测,由于支配者本性难以剥离,在她身上有着强烈的自毁倾向,想爱,却又自觉没有资格去爱,因此她只能用紫餐的方式填补内心的负罪感,H结局中,她以几乎自杀的方式当着奈亚的面帮助格林逃离了奈亚的掌控,可以说为了格林,红女王自降身份把自己变成了棋子,而且是必死的棋子,只为了能在后续将奈亚一军。 等待着这个叛徒的是什么结局,我们只能发挥一下想象力了 最后则是冬之钟的核心人物,白之女王诺登诺登的原型之一是爱丽丝梦游仙境的白兔先生,白兔最明显的元素就是他永远匆忙的样子和怀表,这点也在诺登身上得以体现,白女王作为这场繁殖游戏事实上的管理者,为了协调任性的演员们可谓操碎了心,在轮回的最后,台上的演员几乎全部是她的子嗣(兔子可是繁殖力非常强的生物),可以猜测在制定剧本和排练上她也得下不少功夫,而dlc3的核心意象,齿轮,其实可以说既指着暗黑舞台的齿轮带动了戏码的上演,也指着诺登怀表的齿轮,诺登就是那个负责在指针快点到达终点前让齿轮倒转,重新开始计时的人,这也是为何她会在结局中说为齿轮停止感到害怕,让齿轮转动是她的职责,在她的内心深处或许也有着对无尽循环中格林真正爱上自己并一起逃到世界尽头的希望,但最后她选择成全格林真正的爱,而放弃管理齿轮的职责则意味着她与自己支配者的身份完全决裂,将一切奉献给人类的爱。此外,诺登的支配者原型则是所谓的幻梦境之主,这或许解释了为何是她在实际上管理着二代这个巨大的梦境 我在尸龙的人物解析说,类似尸龙的独占欲在红白女王身上也出现过,但红女王由于害怕自己的支配者本性选择放手,那么白女王呢?在h结局中,梅贝尔被古兰(推测,也可能是奈亚)针对性的陷阱解决,但拥有舞台权限的红白女王应该不受影响,红女王为了最后拯救格林必须蛰伏,因此辅助格林对抗古兰以及奈亚的任务只能交给白女王,但即使在此时此刻,白女王依旧有着独占格林的选项,如果她控制或者协助舞台装置强迫和格林融合,就可以抢先一步独占所有支配者都垂涎的格林,但如果把舞台的改变能力给予格林,那么失去王冠和舞台的诺登则会失去自己在棋局上的几乎所有棋子,面对这种选择,诺登将选择权给了格林,不能说她是完全无私的,但面对这样的诱惑,她也会尊重格林的选择,这不得不说是非常伟大的爱 可以说白女王是一个有着两面性的角色,她支配者的一面始终对格林有着独占欲,但她人性的一面始终压抑着这些黑暗的感情,她是一个徘徊于人与神界限的存在,但无论如何,她都尊重并支持着格林的选择,所以她闪耀着人性光辉的一面始终是压过支配者的黑暗一面的。 让我们给这幕疯狂剧场的落幕做一个总结吧,这局棋是红白女王和梅贝尔设下的,目的是为了让格林得到古兰的改变能力并逃离奈亚的箱庭,其中没有舞台权限的梅贝尔负责引导格林,红女王则在最后帮助得到改变能力的格林摆脱奈亚掌控,而白女王则有着最关键的决策权,即是否利用舞台独占格林,但她最后将决定权给了格林,而格林真正的选择应该是夺取舞台的改变能力,因此最后白女王舍弃了一切帮助格林逃离崩坏的舞台。 这场棋局中,梅贝尔横竖不亏,红女王陷入必死之局,最关键的棋手就是白女王,只要她愿意,随时可以下出必赢的一着,但最后她依旧选择了放弃自己的棋子,把终结棋局的希望留给了格林 在经历如此多的牺牲之后,格林终于从棋子升为了棋手,只是不知道他又会下出怎样的一着

]]>
- <h1 id="尸龙贾巴沃克">尸龙贾巴沃克</h1> -<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">在天之繁星哟!命数已定之众哟!尽管去为爱所煎熬吧,为嫉妒之苦吧!呜呼!感激涕零吧!为这幸灾乐祸暗黑舞台点缀色彩就好!!!</span><br></pre></td></tr></table></figure> -<p>象征着腐败与神秘的紫黑色,遍布全身的缝合痕迹与绷带,恶魔一样的卷曲角,晦暗如死尸的肤色,以及左眼燃烧着的灵魂之火(致敬黑岩射手可能性微存),<code>尸龙</code>姐姐的人物形象无时无刻不在传达着神秘强大而阴暗的气氛,本视频将对<code>尸龙</code>的整个人物进行解析 + <h1 id="冬之钟">冬之钟</h1> +<p>由于black souls的故事远远没有完结,因此现阶段我们很难对<code>红白女王</code>与<code>梅贝尔</code>这些与格林牵扯极深的支配者们进行什么定论,只能就已有的剧情和文本进行一些归纳,本期视频我将就bs2比较难懂的一处地方,冬之钟的主线事件,进行一些个人向的分析。 @@ -936,60 +936,60 @@
- 基于斯坦福cs106b的c++数据结构笔记 - - https://thinklive1.github.io/2023/09/29/cs106b%E6%80%BB%E5%92%8C%E7%AC%94%E8%AE%B0/ - 2023-09-29T02:18:45.993Z + 基于c++ primer plus的读书笔记 + + https://thinklive1.github.io/2023/10/05/cpp%20primer%20plus%E6%80%BB%E5%92%8C/ + 2023-10-05T14:45:42.281Z 2023-11-27T12:47:59.687Z - 一些查找和排序算法

二分查找法 图片 最坏情况:log2n 寻找最小排序 图片 向前插入算法 图片

合并算法接受两个排序的 列出并将它们组合成一个 排序列表。 ● 虽然两个列表都是非空的,但比较它们的 第一要素。 删除较小的元素 并将其附加到输出。 ● 一旦一个列表为空,添加所有元素 另一个列表输出。 ● 它运行时间为 O(n),其中 n 是总数 合并的元素数量。 图片 无限递归后的合并算法 图片 复杂度:nlog2n

容器类

set(集合):无序不允许重复的容器类,可以添加删除元素 You can add a value to a Set by writing set += value; s. ● You can remove a value from a Set by writing set -= value; ● You can check if a value exists in a Set by writing set.contains(value)map(键值对的集合) 如果没有对应key的value,返回默认值(见定义文件) `vector vector的remove根据移除元素的索引有1-n的复杂度,移除尾部为O(1),如果不在意索引,可以交换要移除元素和尾部元素再移除

哈希表

哈希表的负载因子α表示元素和表格键数量的比,决定了查找速度

检查表中是否存在元素

● 计算元素的散列码。 ● 跳转到表格中的那个位置。 ● 向前扫描——必要时环绕——直到项目或一个 发现空插槽。

将元素插入表中

● 如果项目已经存在,什么也不做。 ● 否则,跳转到元素哈希码给定的槽。 向前走——必要时环绕——直到一个空白点或 找到墓碑插槽。 然后,将项目放在那里。

从表中删除一个元素

● 跳转到由元素的散列码给定的槽。 ● 向前走——必要时环绕——直到物品或 发现空插槽。 如果找到该项目,请将其替换为 墓碑。

“罗宾汉哈希表”

  • 如果插入的值比其将插入的位置的值距离索引更远,则替换插入值和当前值
  • 删除值时,将后其离原键远的元素前移
  • ★ 罗宾汉哈希一览 ★
  • 检查表中是否存在元素:
  • ● 跳转到表中由元素的散列码给出的位置。
  • ● 向前扫描——如有必要环绕——记录有多少步 你拿走了。 当您找到该项目、找到一个空白槽或找到一个 离家更近的空位比你走的步数还多。
  • 将元素插入表中:
  • ● 如果该元素已在表中,则什么也不做。
  • ● 跳转到由元素的散列码给出的表槽。 向前扫描 - 换行 如有必要,四处走走——记录所走的步数。 如果你找到一个 空插槽,将元素放在那里。 否则,如果当前插槽已满并且 比您插入的元素更靠近家,将要插入的项目放在那里, 替换那个位置的元素,然后继续插入,就好像你 正在插入被置换的元素。
  • 从表中删除一个元素:
  • ● 跳转到由元素的散列码给定的槽。
  • ● 向前走——如有必要,环绕——直到物品或空槽被放置 成立。 如果找到该项目,请将其删除。 然后,继续前进——包裹 around as necessary – 将表中的元素向后移动一个槽位,直到 找到空插槽或位于其原始位置的项目

string类

str::npos表示容器的最后一个成员位置 if (s.find("e") != string::npos) //find函数找不到时返回npos if s in str: string obj; obj.substr(int pos) //pos为要包含的第一个字符串的位置 std::string a = "0123456789abcdefghij";

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

// count is npos, returns [pos, size())
[std::string](http://en.cppreference.com/w/cpp/string/basic_string) sub1 = a.substr(10);
[std::cout](http://en.cppreference.com/w/cpp/io/cout) << sub1 << '\n';

// both pos and pos+count are within bounds, returns [pos, pos+count)
[std::string](http://en.cppreference.com/w/cpp/string/basic_string) sub2 = a.substr(5, 3);
[std::cout](http://en.cppreference.com/w/cpp/io/cout) << sub2 << '\n';

// pos is within bounds, pos+count is not, returns [pos, size())
[std::string](http://en.cppreference.com/w/cpp/string/basic_string) sub4 = a.substr(a.size()-3, 50);
// this is effectively equivalent to
// std::string sub4 = a.substr(17, 3);
// since a.size() == 20, pos == a.size()-3 == 17, and a.size()-pos == 3

[std::cout](http://en.cppreference.com/w/cpp/io/cout) << sub4 << '\n';

try {
// pos is out of bounds, throws
[std::string](http://en.cppreference.com/w/cpp/string/basic_string) sub5 = a.substr(a.size()+3, 50);
[std::cout](http://en.cppreference.com/w/cpp/io/cout) << sub5 << '\n';
} catch(const [std::out_of_range](http://en.cppreference.com/w/cpp/error/out_of_range)& e) {
[std::cout](http://en.cppreference.com/w/cpp/io/cout) << "pos exceeds string size\n";
}
}
输出:
abcdefghij
567
hij
pos exceeds string size

`replace和insert str1.insert(start, str2) str1.replace(start, length, str2)

一些实现

优先队列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# include "HeapPQueue.h"
using namespace std;

HeapPQueue::HeapPQueue() {
elems = new DataPoint[INITIAL_SIZE] {};
for (int i=0;i<INITIAL_SIZE;i++)
{
elems[i].weight=0;
}
allocatedSize=INITIAL_SIZE;
}

HeapPQueue::~HeapPQueue() {
delete [] elems;
}

int HeapPQueue::size() const {
return logicalSize;
}

bool HeapPQueue::isEmpty() const {
return logicalSize==0;
}

void HeapPQueue::enqueue(const DataPoint& data) {
if (logicalSize+1<allocatedSize)
{
if (logicalSize==0)
{
elems[1]=data;
logicalSize++;
}
else
{
logicalSize++;
int i=1;
while (data.weight>elems[i].weight && i<=logicalSize && elems[i].weight!=0)
{
i++;
}
if (i<logicalSize)
{
DataPoint temp=elems[i];
elems[i]=data;
for(i;i<logicalSize;i++)
{
DataPoint temp_plus=elems[i+1];
elems[i+1]=temp;
temp=temp_plus;

}
}
else
{
elems[i]=data;
}

}
}
}

DataPoint HeapPQueue::peek() const {
return elems[logicalSize];
}

DataPoint HeapPQueue::dequeue() {
DataPoint to_return=elems[1];
if(!isEmpty())
{

for (int i=1;i<logicalSize;i++)
{
elems[i]=elems[i+1];
}
elems[logicalSize]={};
logicalSize--;
}
return to_return;
}

计数排序

首先算出最大值,然后用一个数组的索引存储待排序数组的成员,其索引对应值存储出现次数,然后用两个同步的for循环和递增的next参数表示排序中的索引值来进行排序(也就是重新赋值)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/* Given a Vector<int>, returns the largest number in that Vector. */
int maxOf(const Vector<int>& values) {
/* Bounds-check inputs. */
if (values.isEmpty()) {
error("Can't find the maximum of no values.");
}

int result = values[0];
for (int i = 1; i < values.size(); i++) {
result = max(result, values[i]);
}
return result;
}

/* Given a list of numbers, creates a histogram from those numbers. */
Vector<int> histogramFor(const Vector<int>& values) {
/* Create a histogram with the right number of slots. Initially, all values
* in the histogram will be zero.
*/
Vector<int> histogram(maxOf(values) + 1);

/* Scan across the input vector, incrementing the histogram values. */
for (int value: values) {
histogram[value]++;
}

return histogram;
}

void countingSort(Vector<int>& values) {
/* Edge Case: If the array is empty, then it's already sorted. This is
* needed because we can't take the maximum value of an empty vector.
*/
if (values.isEmpty()) {
return;
}

/* Form the histogram. */
auto histogram = histogramFor(values);

/* Scan across the histogram writing out the appropriate number of copies
* of each value. We track the index of the next free spot to write to,
* as it varies based on how many items we've written out so far.
*/
int next = 0;
for (int value = 0; value < histogram.size(); value++) {
/* Write out the right number of copies. */
for (int copy = 0; copy < histogram[value]; copy++) {
values[next] = value;
next++;
}
}
}

错题集

递归的效率优化

每次递归都会创造所有变量的临时复制 基于递归的这种性质,它会需要巨大的时间和空间来完成任务,并且会造成算力上的浪费。 通过记忆表机制能部分解决这个问题,方法是每次递归的返回值都会按索引存入一个表格,并且每次递归前查询表格中是否有结果,这样可以让每个临时副本的运算结果能被所有函数共享。

递归计算给定元素的不同结构哈夫曼树的数量

对每个给定元素集来说,首先要做到是确定根节点元素是第几个大的元素,确定之后,左子树和右子树的元素数也随之确定,在此之后分别对左节点和右节点作为根节点做同样的递归

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

int numBSTsOfSize(int n) {

/* Base case: There’s only one tree of size 0, namely, the empty BST. */
if (n == 0) return 1;

/* Recursive case: Imagine all possible ways to choose a root and build the
* left and right subtrees.
*/
int result = 0;

/* Put the the nodes at indices 0, 1, 2, ..., n-1 up at the root. */
for (int i = 0; i < n; i++) {
/* Each combination of a BST of i elements and a BST of n - 1 - i elements
* can be used to build one BST of n elements. The number of pairs of
* trees we can make this way is given by the product of the number of
* trees of each type.
*/
result += numBSTsOfSize(i) * numBSTsOfSize(n - 1 - i);
}

return result;
}

递归解决吃巧克力问题

求出吃法数量

1
2
3
4
5
6
7
8
9
10
11
12
if (numSquares<0)
{
error("输入数据不能为负数");
}
else if (numSquares<=1)
{
return 1;
}
else
{
return numWaysToEat(numSquares-1)+numWaysToEat(numSquares-2);
}

打印每种吃法

`需要一个辅助向量储存历史记录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/* Print all ways to eat numSquares more squares, given that we've
* already taken the bites given in soFar.
*/
void printWaysToEatRec(int numSquares, const Vector<int>& soFar) {
/* Base Case: If there are no squares left, the only option is to use
* the bites we've taken already in soFar.
*/
if (numSquares == 0) {
cout << soFar << endl;
}
/* Base Case: If there is one square lfet, the only option is to eat
* that square.
*/
else if (numSquares == 1) {
cout << soFar + 1 << endl;
}
/* Otherwise, we take take bites of size one or of size two. */
else {
printWaysToEatRec(numSquares - 1, soFar + 1);
printWaysToEatRec(numSquares - 2, soFar + 2);
}
}

void printWaysToEat(int numSquares) {
if (numSquares < 0) {
error("You owe me some chocolate!");
}

/* We begin without having made any bites. */
printWaysToEatRec(numSquares, {});
}

递归解决翻煎饼问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
bool isSorted(Stack<double> pancakes) {
double last = -1; // No pancakes have negative size;

while (!pancakes.isEmpty()) {
/* Check the next pancake. */
double next = pancakes.pop();
if (next < last) {
return false;
}

last = next;
}

/* Pancakes are in increasing order! */
return true;
}

/* Given a stack of pancakes and a flip size, flips that many pancakes
* on the top of the stack.
*/
Stack<double> flip(Stack<double> pancakes, int numToFlip) {
/* Take the top pancakes off the stack and run them into a queue.
* This preserves the order in which they were removed.
*/
Queue<double> buffer;
for (int i = 0; i < numToFlip; i++) {
buffer.enqueue(pancakes.pop());
}

/* Move the pancakes back. */
while (!buffer.isEmpty()) {
pancakes.push(buffer.dequeue());
}

return pancakes;
}

Optional<Vector<int>> sortStack(Stack<double> pancakes, int numFlips) {
/* Base Case: If the stack is sorted, great! We're done, and no flips
* were needed.
*/
if (isSorted(pancakes)) {
return { }; // No flips
}
/* Base Case: If the stack isn't sorted and we're out of flips, then
* there is no way to sort things.
*/
else if (numFlips == 0) {
return Nothing;
}
/* Recursive Case: The stack isn't sorted and we still have flips left.
* The next flip could flip 1, 2, 3, ..., or all N of the pancakes.
* Try each option and see whether any of them work.
*/
for (int numToFlip = 1; numToFlip <= pancakes.size(); numToFlip++) {
/* Make the flip and see if it works. */
auto result = sortStack(flip(pancakes, numToFlip), numFlips - 1);
if (result != Nothing) {
/* The result holds all the remaining flips but doesn't know about
* the flip we just did. Insert that flip at the beginning.
*/
result.value().insert(0, numToFlip);
return result;
}
}

/* If we're here, then no matter which flip we make first, we cannot
* get the pancakes sorted. Give up.
*/
return Nothing;
}

递归解决天平问题

1
2
3
4
5
6
7
8
9
10
11
12
13
bool isMeasurableRec(int amount, const Vector<int>& weights, int index) {
if (index == weights.size()) {
return amount == 0;
} else {
return isMeasurableRec(amount, weights, index + 1) ||
isMeasurableRec(amount + weights[index], weights, index + 1) ||
isMeasurableRec(amount - weights[index], weights, index + 1);
}
}

bool isMeasurable(int amount, const Vector<int>& weights) {
return isMeasurableRec(amount, weights, 0);
}

想象一下,我们首先将要测量的数量(称为 n )放在天平的左侧。 这使得规模上的不平衡等于 n 。 想象一下,有某种方法可以测量 n 。 如果我们一次将一个重量放在秤上,我们可以查看第一个重量的放置位置(假设它的重量为 w )。 它必须:

  • 向左走,使规模上的净不平衡 n + w ,或
  • 向右走,使规模上的净不平衡 n – w ,或
  • 根本不习惯,留下净不平衡 n

如果确实有可能测量 n ,那么这三个选项之一必须是实现它的方法,即使我们不知道它是哪一个。 然后我们要问的问题是,是否有可能使用剩余的权重来衡量新的净失衡——我们可以递归地确定! 另一方面,如果无法测量 n ,那么无论我们选择哪个选项,我们都会发现没有办法使用剩余的权重来使一切平衡!

如果我们递归地进行,我们在这里,我们需要考虑我们的基本情况。 我们可以选择的选项有很多。 一个简单的方法如下:假设我们根本没有任何重量,我们被要求查看是否可以不使用重量来测量某些重量。 在什么情况下我们可以这样做? 好吧,如果我们称重的东西有一个非零重量,我们就不可能测量它——把它放在秤上会使它倾斜到某一边,但这并不能告诉我们它有多少重量。 另一方面,如果我们称量的东西是完全失重的,那么把它放在秤上也不会导致它倾斜,让我们相信它确实是失重的! 因此,作为我们的基本情况,我们会说当我们减少到没有剩余权重时, ,我们可以精确测量n 如果 n = 0 。 考虑到这一点,这是我们的代码:

递归解决找零问题

不使用记忆的情况

`从第一个硬币开始遍历,并穷举它的所有枚数,将其作为下一枚硬币的参数传递

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
int fewestCoinsFor(int cents, const Set<int>& coins) {
/* Can't have a negative number of cents. */
if (cents < 0) {
error("You owe me money, not the other way around!");
}
/* Base case: You need no coins to give change for no cents. */
else if (cents == 0) {
return 0;
}
/* Base case: No coins exist. Then it's not possible to make the
* amount. In that case, give back a really large value as a
* sentinel.
*/
else if (coins.isEmpty()) {
return cents + 1;
}
/* Recursive case: Pick a coin, then try using each distinct number of
* copies of it that we can.
*/
else {
/* The best we've found so far. We initialize this to a large value so
* that it's replaced on the first iteration of the loop. Do you see
* why cents + 1 is a good choice?
*/
int bestSoFar = cents + 1;
/* Pick a coin. */
int coin = coins.first();
/* Try all amounts of it. */
for (int copies = 0; copies * coin <= cents; copies++) {
/* See what happens if we make this choice. Once we use this
* coin, we won't use the same coin again in the future.
*/
int thisChoice = copies + fewestCoinsFor(cents - copies * coin,
coins - coin);
/* Is this better than what we have so far? */
if (thisChoice < bestSoFar) {
bestSoFar = thisChoice;
}
}
/* Return whatever worked best. */
return bestSoFar;
}
}

使用记忆进行优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
/* How few coins are needed to make the total, given that we can only use
* coins from index startIndex and onward?
*/
int fewestCoinsRec(int cents, const Vector<int>& coins, int startIndex,Grid<int>& memo) {
/* Base case: You need no coins to give change for no cents. */
if (cents == 0) {
return 0;
}
/* Base case: No coins exist. Then it's not possible to make the
* amount. In that case, give back a really large value as a
* sentinel.
*/
else if (startIndex == coins.size()) {
return cents + 1;
}
/* Base case: We already know the answer. */
else if (memo[cents][startIndex] != -1) {
return memo[cents][startIndex];
}
/* Recursive case: Pick a coin, then try using each distinct number of
* copies of it that we can.
*/
else {
/* The best we've found so far. We initialize this to a large value so
* that it's replaced on the first iteration of the loop. Do you see
* why cents + 1 is a good choice?
*/
int bestSoFar = cents + 1;

/* Pick a coin. */
int coin = coins[startIndex];

/* Try all amounts of it. */
for (int copies = 0; copies * coin <= cents; copies++) {
/* See what happens if we make this choice. Once we use this
* coin, we won't use the same coin again in the future.
*/
int thisChoice = copies + fewestCoinsRec(cents - copies * coin,
coins, startIndex + 1,
memo);

/* Is this better than what we have so far? */
if (thisChoice < bestSoFar) {
bestSoFar = thisChoice;
}
}

/* Return whatever worked best. */
memo[cents][startIndex] = bestSoFar;
return bestSoFar;
}
}

int fewestCoinsFor(int cents, const Set<int>& coins) {
/* Can't have a negative number of cents. */
if (cents < 0) {
error("You owe me money, not the other way around!");
}

/* Convert from a Set<int> to a Vector<int> so we have a nice ordering
* on things.
*/
Vector<int> coinVec;
for (int coin: coins) {
coinVec += coin;
}

/* Build our memoization table. Since the number of cents left ranges from
* 0 to cents, we need cents+1 rows. Since the start index of the coin
* ranges from 0 to coins.size(), we make coins.size() + 1 columns.
*
* -1 is used as a sentinel to indicate "nothing has been computed here
* yet."
*/
Grid<int> memo(cents + 1, coins.size() + 1, -1);

/* Now ask how many coins are needed to make the total, using any coins
* from index 0 onward.
*/
return fewestCoinsRec(cents, coinVec, 0, memo);
}

递归穷举付账单

递归机制:对第一个人来说,0-total所有金额都会付一遍,随后传递给下一个人,当只有一人时,付清所有余额并打印账单 传递参数:string,int的映射存储目前为止的账单,string集合存储所有付账者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void listPossiblePaymentsRec(int total, const Set<string>& people,const Map<string, int>& payments) {
/* Base case: if there's one person left, they have to pay the whole bill. */
if (people.size() == 1) {
Map<string, int> finalPayments = payments;
finalPayments[people.first()] = total;
cout << finalPayments << endl;
}
/* Recursive case: The first person has to pay some amount between 0 and the
* total amount. Try all of those possibilities.
*/
else {
for (int payment = 0; payment <= total; payment++) {
/* Create a new assignment of people to payments in which this first
* person pays this amount.
*/
Map<string, int> updatedPayments = payments;
updatedPayments[people.first()] = payment;
listPossiblePaymentsRec(total - payment, people - people.first(),updatedPayments);
}
}
}
void listPossiblePayments(int total, const Set<string>& people) {
/* Edge cases: we can't pay a negative total, and there must be at least one
* person.
*/
if (total < 0) error("Guess you're an employee?");
if (people.isEmpty()) error("Dine and dash?");
listPossiblePaymentsRec(total, people, {});
}

递归寻找完全平方数列

主要参数为sofar——用于存储目前的序列和一个set用于存储还没放入数列的数字,`确保这两者同时被传递,且其并集为所有数字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
Optional<Vector<int>> findSquareSequence(int n) {
/*Validate input.*/
if (n < 0) {
error("Don't be so negative!");
}

/* Build a set of the numbers 1, 2, 3, ..., n. */
Set<int> options;
for (int i = 1; i <= n; i++) {
options += i;
}
return findSequenceRec(options, { });
}

Optional<Vector<int>> findSequenceRec(const Set<int>& unused,
const Vector<int>& soFar) {
/*Base Case: If all numbers are used, we have our sequence!*/
if (unused.isEmpty()) {
return soFar;
}

/* Recursive Case: Some number comes next. Try each of them and see which
* one we should pick.
*/
for (int next: unused) {
/* We can use this if either
*
* 1. the sequence is empty, so we're first in line, or
* 2. the sequence is not empty, but we sum to a perfect square
* with the previous term.
*/
if (soFar.isEmpty() ||
isPerfectSquare(next + soFar[soFar.size() - 1])) {
/* See what happens if we extend with this number. */
auto result = findSequenceRec(unused - next, soFar + next);
if (result != Nothing) {
return result;
}
}
}

/* Tried all options and none of them worked. Oh well! */
return Nothing;
}

汉诺塔递归

假设有三座汉诺塔,start ,temp ,finish 对n层的汉诺塔问题,先考虑n-1层的,随后考虑n-2层,到最后只需要考虑两层问题,两层的汉诺塔非常容易解决,起点为start,终点是temp,临时塔为finish,最后我们得到temp上的两层汉诺塔 这时将start的3移动到finish塔,这时只要将两层汉诺塔转移到finish则完成了三层汉诺塔,这个过程中的起点为temp,终点是finish,临时塔是start 以此类推,四层塔基于三层塔,n层塔基于n-1塔,汉诺塔问题解决

1
2
3
4
5
6
7
8
9
10
11
int moveTower(int numDisks, char start, char finish, char temp) {
if (numDisks == 0) {
return 0;
} else {
int movesOne = moveTower(numDisks - 1, start, temp, finish);
moveSingleDisk(start, finish);
int movesTwo = moveTower(numDisks - 1, temp, finish, start);

return 1 + movesOne + movesTwo;
}
}
]]>
+ c语言部分

基本函数构成

将数组传递为函数参数

1
int fcname(int arg[],int n)

基本输入输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- cin及其衍生函数返回一个iostream函数的引用,即支持
cin,get().get()
iostream的其他成员
- cout.put()显示字符
- cout.write()显示字符串
- cout<<flush刷新缓冲区
- cout<<endl刷新缓冲区并提供换行符
- dec,hex,oct控制输出数制
hex(cout)控制cout为16进制
- int width()返回字段宽度当前设置
int width(int i)设置字段宽度,返回以前字段宽度
只影响下一次输出
- fill()设置填充用字符
- precision()设置精度,即保留几位小数
- setf()设置各种输出格式
- 流状态stream_state(eof,fail,bad)
- cin.get(ch)读取下一个字符,跳过换行符和空白
- cin.get()读取空白和换行符
- cin.get()get的基础上读取到换行符并丢弃
- cin.read()读取内容,但不会在末尾加空字符
- cin.peek()读取输入流下一个字符但不抽取
- cin.putback(ch)把一个字符放到输入流最前

文件输入输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
写入文件
ofstream fout;//ofstream继承ostream
fout.open("hello.txt");
fout << "i'm adding sth"
|| ofstream fout("hello.txt");
读取文件也类似
fin >> ch||string
关闭流
fout.close()
fin.close()
检测文件是否打开
if (!fin.is_open())
设置文件输入输出格式
ios_base::

基本逻辑运算符

break打断循环 continue,跳到更新表达式前开始执行 非const引用的函数不接受const参数

基本数据类型

结构数组

stname;
1
2
3
4
5
6
7
8
9
10
11
stname stobj\[int x] =
{
{}
{}
}
union(类似结构,但相同数据类型只存一种)
每个指针需要一个*用于初始化
int * intlist=new int [10]
delete-new
delete []-new []
typedef typename aliasname

名称空间

1
2
3
4
5
#ifndef HNAME_H
#define HNAME_H


#endif

如果在遇到另一个定义HNAME_H的头文件时,将他忽略

作用域: 1默认情况下,函数中声明的变量作用域位于代码块内,如果函数内外都声明一个同名变量,运行至内部代码块使用内部,离开代码块使用外部 2静态变量存在于整个程序运行周期,脱离作用域后只是无法使用并不消失 代码块外声明且不带static关键字:链接性外部,可以在其他程序使用 代码块外声明,且使用static:链接性内部,可以在整个程序使用 代码块内声明,且使用static:作用域于代码块内,但始终存在//由于静态变量只可以定义一次,所以即使离开代码块后变量依旧存在,且值不变,直到下一次修改 3运算符::放置于变量前时,使用同名变量(如果有)的全局版本 4namespace{

} 无法放置于代码块内,因此默认为全局名称,可以囊括声明和定义,可以随时添加 定义于类声明的函数自动成为内联函数

c++特性

class

1声明构造函数时,尽量使用explicit(显性转换)前缀,防止隐性转换带来的问题 mutable(摆动的)前缀声明变量,表示这些变量可能在const成员函数内被更改 用const_cast<>和static_cast<>与this指针可以实现const成员函数向非const的转变,反之则是错误的

2class初始化成员时,按构造函数声明变量的顺序,因此初始化成员时最好也以此顺序初始化 如果不希望class有copy和赋值(=)操作,则应该在private里定义copy和=运算符

3基类引用可以指向派生类对象,无需进行强制类型转换

4定义于类声明的函数自动成为内联函数

5类的函数对所有对象共用,但数据则各自私有

6要创造类对象数组,该类必须有默认构造函数

7只有一个构造函数参数的构造函数可以用于类的自动转换 classname t; t=20; 如果想禁止这种转换,可以声明explicit给构造函数

8类声明中可定义对于某种基本类型的转换函数 operator int();//可声明为显式转换,尽量避免过多的转换造成二义性

9如果定义类成员参数为static,则它在程序中只有一个地址,可以被所有类成员共享 但通过static实现共享成员时,需要重新定义复制和赋值函数来避免问题

动态类的注意事项

*构造函数中如果用new初始化指针成员,则应该在析构函数中使用delete new对应delete,new[]对应delete[] 对多个构造函数,应用和析构函数兼容的new来初始化成员 重构复制和赋值运算符来实现深复制

10对于使用new创建的类,使用delete时其析构函数才会被调用 如果在使用new时,将对象地址赋予一个指针时,如果删除指针,则对应的对象会调用自己的析构函数 对与使用定位new创建的类对象,需要显式调用析构函数 object->~classname(); 且应该以创建顺序的相反顺序调用,因为后创建的对象可能依赖于前者

类继承

公有继承

class sonclassname: public fatherclassname 派生类继承了基类的公有接口和数据 但只能用基类public和protected函数访问基类私有数据 派生类可添加函数和数据成员 派生类需要自己的构造函数,并由于权限问题,其构造函数必须包括基类构造函数,并且同样可以使用成员初始化列表 指针 基类指针和引用可以在不显式转化的情况下指向派生类对象反过来却不行 虚函数

  • 对于基类和派生类的同名函数: 如果函数通过引用或指针调用,将确定使用哪种方法 ¥如果没有使用关键字virual,将根据引用类型或指针类型选择方法。 如果使用了关键字virtual,将根据引用或指针指向对象的类型选择方法
  • 构造函数不能为虚函数
  • 析构函数应当为虚函数
  • 友元函数并非类成员,但可以使用虚函数
  • **重新定义继承方式(虚实)并非重载,会覆盖掉原先的虚函数定义,如果必须重新定义,则需要重新定义使用基类虚函数

纯虚函数 virual typename func() const=0; 含有虚函数的类不能创建实例,只能用作基类

访问控制(protected) 派生类成员函数可以访问protected成员,不能访问private成员

私有继承

使用私有继承,基类的公有成员和保护成员都成为派生类的私有成员,只可以在派生类的成员函数中使用,可以实现has_a关系 私有继承访问基类方法时需要调动基类的命名空间 访问基类对象 如果要直接访问基类对象,则需要调用强制类型转化将派生类转化为基类

保护继承

保护继承时,基类的公有和保护成员都成为派生类的保护成员,基类接口在派生类中可用

通过using指令可以让私有函数被当前作用域可用

命令行参数

int main(int argc,char* argv[]) argc为参数个数 argv为参数组成的字符串

字符输入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
cin >> ***(读取输入中的结束字符为结束标志,会将换行符留在输入流)
getline(stringname,length)通过换行符确定输入结束点
cin.get()读取到换行符之前,不带参数则读取下一个字符(用于清除换行符)
cin.clear()清空输入流
<string>
重载符号+实现拼接
str.size()
输入字符串使用getline(cin,str)
结构数组
struct stname;
stname stobj[int x] =
{
{}
{}
}
字符函数库<cctype>
isspace(ch)测试是否空白
isalpha(ch)是否字符
isdigit()是否数字
ispunct()是否标点

1
2
3
4
cin >> ***(读取输入中的结束字符为结束标志,会将换行符留在输入流)
getline(stringname,length)通过换行符确定输入结束点
cin.get()读取到换行符之前,不带参数则读取下一个字符(用于清除换行符)
cin.clear()清空输入流

<string> 重载符号+实现拼接 str.size() 输入字符串使用getline(cin,str) 结构数组 struct stname; stname stobj[int x] = { {} {} } 字符函数库<cctype> isspace(ch)测试是否空白 isalpha(ch)是否字符 isdigit()是否数字 ispunct()是否标点

指针

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1,c++没有溢出检测机制,
char name[]="hello";
char c =name[10]导致未定义行为
2,用一个常量指针指向常量需要两次const
const char* const name="hhh"
如果需要一个class专属常量,则使用
static const ***
实现文件中,const int classname:: ***
对于宏:
template <typename T>
inline functionname
3,const 出现在*左侧表示被指物为常量,右侧表示指针为常量指针
4,函数名就是函数的地址
double pam(int);
double(*pt)(int);
pt即为函数指针
如果需要一个函数以相同相同返回值和参数的函数为一个参数,则可以考虑函数指针
5,内联函数不能递归
6,引用容器时,如果迭代器不引用,仍然传递临时副本o
7,函数传递指针时按值传递,当向函数传递指针时,指针是按值传递的!这意味着你可以改变被指向的数组内容,因为在调用函数时,这些元素不会被复制!这意味着你可以改变被指向的数组的内容,因为这些元素在函数被调用时并没有被复制。另一方面,如果你改变了所指向的数组,这种改变在函数之外不会持续,因为你只改变了指针的拷贝,而不是原来的指针本身。

智能指针

auto_ptr<string> 和<unique_ptr>指针采用所有权模型,对特定对象只有一个智能指针可以拥有它,只有拥有它的指针可以删除它 shared_ptr<string>追踪引用对象的智能指针数量,最后一个指针过期时才会调用delete 使用new分配内存才能使用auto_ptr,unique_ptr

异常

try_catch

1
2
3
4
5
6
7
8
9
10
11
try{
func();
}
catch(errortype e1){

}
func()
{
do sth;
throw(error_type e1);8
}

栈解退 假设try块没有直接调用引发异常的函数,而是调用对引发异常的函数进行调用的函数,则程序从引发异常的函数跳到包含try块和处理程序的函数(追踪到一个地址位于try块的返回地址) 其他异常特性

  • throw-catch类似函数参数和返回,但函数返回语句将控制器交给调用函数的函数,但throw语句将控制权向上返回到第一个这样的函数,包含能捕获相应异常的try-catch组合
  • throw语句总是生成副本,但catch参数使用基类引用能捕获所有派生类的异常对象

exception类

exception类可作为其他异常类的基类,用what的虚函数(返回一个字符串)重载来指示错误类型 失败时返回空指针的语法

1
int * pi= new (std::nothrow) int;

未捕获异常

未捕获的异常会使程序调用函数terminate(),默认情况下,terminate()调用abort()函数,可以指定terminate()调用的函数来修改其行为

一些新特性

关键字

关键字nullptr表示空指针

RTTI(运行阶段类型识别)

dynamic——cast

danamic_cast<type *> (pt) 如果可以安全将pt转化为type*指针,返回对象地址,否则返回空指针 如果对引用使用,错误时返回bad_cast异常

typeid和type_info

typeid返回对type_info对象的引用,type_ifo是定义在typeinfo的类,重载==和!=预算符,例如 typeid(obj1)==typeid(obj2)

类型转换运算符

  • dynamic_cast
  • const_cast
  • static_cast
1
2
//用于执行各种类型的数值转换static_cast <typename> (expression)
//转换是允许隐式转换时才能通过(派生类和基类可以互相转换)
  • reinterpret_cast /执行危险的转换

移动语义 通过指针转移右值的地址给新对象 或通过std::move()将左值转化为右值

someclass()=default default关键字显式声明编译器创建默认构造函数,复制构造函数 delete用于禁止类中的函数

关键字override可用于覆盖虚函数定义

匿名函数

返回类型编译器自动确定,可直接作为函数指针使用

1
[] (double x) {return x%3==0;} 

可以返回类型后置

1
[] (double x)-> double{int y = x;return y-x;}

可以给匿名函数命名

]]>
- <h2 id="一些查找和排序算法">一些查找和排序算法</h2> -<p>二分查找法 <img src="/images/obsidian/20230226101843.png" title="image" alt="图片" /> 最坏情况:log2n + <h1 id="c语言部分">c语言部分</h1> +<h2 id="基本函数构成">基本函数构成</h2> +<p>将数组传递为函数参数</p> +<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">int fcname(int arg[],int n)</span><br></pre></td></tr></table></figure> - - - - + - - +
- 基于c++ primer plus的读书笔记 - - https://thinklive1.github.io/2023/10/05/cpp%20primer%20plus%E6%80%BB%E5%92%8C/ - 2023-10-05T14:45:42.281Z + 基于斯坦福cs106b的c++数据结构笔记 + + https://thinklive1.github.io/2023/09/29/cs106b%E6%80%BB%E5%92%8C%E7%AC%94%E8%AE%B0/ + 2023-09-29T02:18:45.993Z 2023-11-27T12:47:59.687Z - c语言部分

基本函数构成

将数组传递为函数参数

1
int fcname(int arg[],int n)

基本输入输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- cin及其衍生函数返回一个iostream函数的引用,即支持
cin,get().get()
iostream的其他成员
- cout.put()显示字符
- cout.write()显示字符串
- cout<<flush刷新缓冲区
- cout<<endl刷新缓冲区并提供换行符
- dec,hex,oct控制输出数制
hex(cout)控制cout为16进制
- int width()返回字段宽度当前设置
int width(int i)设置字段宽度,返回以前字段宽度
只影响下一次输出
- fill()设置填充用字符
- precision()设置精度,即保留几位小数
- setf()设置各种输出格式
- 流状态stream_state(eof,fail,bad)
- cin.get(ch)读取下一个字符,跳过换行符和空白
- cin.get()读取空白和换行符
- cin.get()get的基础上读取到换行符并丢弃
- cin.read()读取内容,但不会在末尾加空字符
- cin.peek()读取输入流下一个字符但不抽取
- cin.putback(ch)把一个字符放到输入流最前

文件输入输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
写入文件
ofstream fout;//ofstream继承ostream
fout.open("hello.txt");
fout << "i'm adding sth"
|| ofstream fout("hello.txt");
读取文件也类似
fin >> ch||string
关闭流
fout.close()
fin.close()
检测文件是否打开
if (!fin.is_open())
设置文件输入输出格式
ios_base::

基本逻辑运算符

break打断循环 continue,跳到更新表达式前开始执行 非const引用的函数不接受const参数

基本数据类型

结构数组

stname;
1
2
3
4
5
6
7
8
9
10
11
stname stobj\[int x] =
{
{}
{}
}
union(类似结构,但相同数据类型只存一种)
每个指针需要一个*用于初始化
int * intlist=new int [10]
delete-new
delete []-new []
typedef typename aliasname

名称空间

1
2
3
4
5
#ifndef HNAME_H
#define HNAME_H


#endif

如果在遇到另一个定义HNAME_H的头文件时,将他忽略

作用域: 1默认情况下,函数中声明的变量作用域位于代码块内,如果函数内外都声明一个同名变量,运行至内部代码块使用内部,离开代码块使用外部 2静态变量存在于整个程序运行周期,脱离作用域后只是无法使用并不消失 代码块外声明且不带static关键字:链接性外部,可以在其他程序使用 代码块外声明,且使用static:链接性内部,可以在整个程序使用 代码块内声明,且使用static:作用域于代码块内,但始终存在//由于静态变量只可以定义一次,所以即使离开代码块后变量依旧存在,且值不变,直到下一次修改 3运算符::放置于变量前时,使用同名变量(如果有)的全局版本 4namespace{

} 无法放置于代码块内,因此默认为全局名称,可以囊括声明和定义,可以随时添加 定义于类声明的函数自动成为内联函数

c++特性

class

1声明构造函数时,尽量使用explicit(显性转换)前缀,防止隐性转换带来的问题 mutable(摆动的)前缀声明变量,表示这些变量可能在const成员函数内被更改 用const_cast<>和static_cast<>与this指针可以实现const成员函数向非const的转变,反之则是错误的

2class初始化成员时,按构造函数声明变量的顺序,因此初始化成员时最好也以此顺序初始化 如果不希望class有copy和赋值(=)操作,则应该在private里定义copy和=运算符

3基类引用可以指向派生类对象,无需进行强制类型转换

4定义于类声明的函数自动成为内联函数

5类的函数对所有对象共用,但数据则各自私有

6要创造类对象数组,该类必须有默认构造函数

7只有一个构造函数参数的构造函数可以用于类的自动转换 classname t; t=20; 如果想禁止这种转换,可以声明explicit给构造函数

8类声明中可定义对于某种基本类型的转换函数 operator int();//可声明为显式转换,尽量避免过多的转换造成二义性

9如果定义类成员参数为static,则它在程序中只有一个地址,可以被所有类成员共享 但通过static实现共享成员时,需要重新定义复制和赋值函数来避免问题

动态类的注意事项

*构造函数中如果用new初始化指针成员,则应该在析构函数中使用delete new对应delete,new[]对应delete[] 对多个构造函数,应用和析构函数兼容的new来初始化成员 重构复制和赋值运算符来实现深复制

10对于使用new创建的类,使用delete时其析构函数才会被调用 如果在使用new时,将对象地址赋予一个指针时,如果删除指针,则对应的对象会调用自己的析构函数 对与使用定位new创建的类对象,需要显式调用析构函数 object->~classname(); 且应该以创建顺序的相反顺序调用,因为后创建的对象可能依赖于前者

类继承

公有继承

class sonclassname: public fatherclassname 派生类继承了基类的公有接口和数据 但只能用基类public和protected函数访问基类私有数据 派生类可添加函数和数据成员 派生类需要自己的构造函数,并由于权限问题,其构造函数必须包括基类构造函数,并且同样可以使用成员初始化列表 指针 基类指针和引用可以在不显式转化的情况下指向派生类对象反过来却不行 虚函数

  • 对于基类和派生类的同名函数: 如果函数通过引用或指针调用,将确定使用哪种方法 ¥如果没有使用关键字virual,将根据引用类型或指针类型选择方法。 如果使用了关键字virtual,将根据引用或指针指向对象的类型选择方法
  • 构造函数不能为虚函数
  • 析构函数应当为虚函数
  • 友元函数并非类成员,但可以使用虚函数
  • **重新定义继承方式(虚实)并非重载,会覆盖掉原先的虚函数定义,如果必须重新定义,则需要重新定义使用基类虚函数

纯虚函数 virual typename func() const=0; 含有虚函数的类不能创建实例,只能用作基类

访问控制(protected) 派生类成员函数可以访问protected成员,不能访问private成员

私有继承

使用私有继承,基类的公有成员和保护成员都成为派生类的私有成员,只可以在派生类的成员函数中使用,可以实现has_a关系 私有继承访问基类方法时需要调动基类的命名空间 访问基类对象 如果要直接访问基类对象,则需要调用强制类型转化将派生类转化为基类

保护继承

保护继承时,基类的公有和保护成员都成为派生类的保护成员,基类接口在派生类中可用

通过using指令可以让私有函数被当前作用域可用

命令行参数

int main(int argc,char* argv[]) argc为参数个数 argv为参数组成的字符串

字符输入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
cin >> ***(读取输入中的结束字符为结束标志,会将换行符留在输入流)
getline(stringname,length)通过换行符确定输入结束点
cin.get()读取到换行符之前,不带参数则读取下一个字符(用于清除换行符)
cin.clear()清空输入流
<string>
重载符号+实现拼接
str.size()
输入字符串使用getline(cin,str)
结构数组
struct stname;
stname stobj[int x] =
{
{}
{}
}
字符函数库<cctype>
isspace(ch)测试是否空白
isalpha(ch)是否字符
isdigit()是否数字
ispunct()是否标点

1
2
3
4
cin >> ***(读取输入中的结束字符为结束标志,会将换行符留在输入流)
getline(stringname,length)通过换行符确定输入结束点
cin.get()读取到换行符之前,不带参数则读取下一个字符(用于清除换行符)
cin.clear()清空输入流

<string> 重载符号+实现拼接 str.size() 输入字符串使用getline(cin,str) 结构数组 struct stname; stname stobj[int x] = { {} {} } 字符函数库<cctype> isspace(ch)测试是否空白 isalpha(ch)是否字符 isdigit()是否数字 ispunct()是否标点

指针

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1,c++没有溢出检测机制,
char name[]="hello";
char c =name[10]导致未定义行为
2,用一个常量指针指向常量需要两次const
const char* const name="hhh"
如果需要一个class专属常量,则使用
static const ***
实现文件中,const int classname:: ***
对于宏:
template <typename T>
inline functionname
3,const 出现在*左侧表示被指物为常量,右侧表示指针为常量指针
4,函数名就是函数的地址
double pam(int);
double(*pt)(int);
pt即为函数指针
如果需要一个函数以相同相同返回值和参数的函数为一个参数,则可以考虑函数指针
5,内联函数不能递归
6,引用容器时,如果迭代器不引用,仍然传递临时副本o
7,函数传递指针时按值传递,当向函数传递指针时,指针是按值传递的!这意味着你可以改变被指向的数组内容,因为在调用函数时,这些元素不会被复制!这意味着你可以改变被指向的数组的内容,因为这些元素在函数被调用时并没有被复制。另一方面,如果你改变了所指向的数组,这种改变在函数之外不会持续,因为你只改变了指针的拷贝,而不是原来的指针本身。

智能指针

auto_ptr<string> 和<unique_ptr>指针采用所有权模型,对特定对象只有一个智能指针可以拥有它,只有拥有它的指针可以删除它 shared_ptr<string>追踪引用对象的智能指针数量,最后一个指针过期时才会调用delete 使用new分配内存才能使用auto_ptr,unique_ptr

异常

try_catch

1
2
3
4
5
6
7
8
9
10
11
try{
func();
}
catch(errortype e1){

}
func()
{
do sth;
throw(error_type e1);8
}

栈解退 假设try块没有直接调用引发异常的函数,而是调用对引发异常的函数进行调用的函数,则程序从引发异常的函数跳到包含try块和处理程序的函数(追踪到一个地址位于try块的返回地址) 其他异常特性

  • throw-catch类似函数参数和返回,但函数返回语句将控制器交给调用函数的函数,但throw语句将控制权向上返回到第一个这样的函数,包含能捕获相应异常的try-catch组合
  • throw语句总是生成副本,但catch参数使用基类引用能捕获所有派生类的异常对象

exception类

exception类可作为其他异常类的基类,用what的虚函数(返回一个字符串)重载来指示错误类型 失败时返回空指针的语法

1
int * pi= new (std::nothrow) int;

未捕获异常

未捕获的异常会使程序调用函数terminate(),默认情况下,terminate()调用abort()函数,可以指定terminate()调用的函数来修改其行为

一些新特性

关键字

关键字nullptr表示空指针

RTTI(运行阶段类型识别)

dynamic——cast

danamic_cast<type *> (pt) 如果可以安全将pt转化为type*指针,返回对象地址,否则返回空指针 如果对引用使用,错误时返回bad_cast异常

typeid和type_info

typeid返回对type_info对象的引用,type_ifo是定义在typeinfo的类,重载==和!=预算符,例如 typeid(obj1)==typeid(obj2)

类型转换运算符

  • dynamic_cast
  • const_cast
  • static_cast
1
2
//用于执行各种类型的数值转换static_cast <typename> (expression)
//转换是允许隐式转换时才能通过(派生类和基类可以互相转换)
  • reinterpret_cast /执行危险的转换

移动语义 通过指针转移右值的地址给新对象 或通过std::move()将左值转化为右值

someclass()=default default关键字显式声明编译器创建默认构造函数,复制构造函数 delete用于禁止类中的函数

关键字override可用于覆盖虚函数定义

匿名函数

返回类型编译器自动确定,可直接作为函数指针使用

1
[] (double x) {return x%3==0;} 

可以返回类型后置

1
[] (double x)-> double{int y = x;return y-x;}

可以给匿名函数命名

]]>
+ 一些查找和排序算法

二分查找法 图片 最坏情况:log2n 寻找最小排序 图片 向前插入算法 图片

合并算法接受两个排序的 列出并将它们组合成一个 排序列表。 ● 虽然两个列表都是非空的,但比较它们的 第一要素。 删除较小的元素 并将其附加到输出。 ● 一旦一个列表为空,添加所有元素 另一个列表输出。 ● 它运行时间为 O(n),其中 n 是总数 合并的元素数量。 图片 无限递归后的合并算法 图片 复杂度:nlog2n

容器类

set(集合):无序不允许重复的容器类,可以添加删除元素 You can add a value to a Set by writing set += value; s. ● You can remove a value from a Set by writing set -= value; ● You can check if a value exists in a Set by writing set.contains(value)map(键值对的集合) 如果没有对应key的value,返回默认值(见定义文件) `vector vector的remove根据移除元素的索引有1-n的复杂度,移除尾部为O(1),如果不在意索引,可以交换要移除元素和尾部元素再移除

哈希表

哈希表的负载因子α表示元素和表格键数量的比,决定了查找速度

检查表中是否存在元素

● 计算元素的散列码。 ● 跳转到表格中的那个位置。 ● 向前扫描——必要时环绕——直到项目或一个 发现空插槽。

将元素插入表中

● 如果项目已经存在,什么也不做。 ● 否则,跳转到元素哈希码给定的槽。 向前走——必要时环绕——直到一个空白点或 找到墓碑插槽。 然后,将项目放在那里。

从表中删除一个元素

● 跳转到由元素的散列码给定的槽。 ● 向前走——必要时环绕——直到物品或 发现空插槽。 如果找到该项目,请将其替换为 墓碑。

“罗宾汉哈希表”

  • 如果插入的值比其将插入的位置的值距离索引更远,则替换插入值和当前值
  • 删除值时,将后其离原键远的元素前移
  • ★ 罗宾汉哈希一览 ★
  • 检查表中是否存在元素:
  • ● 跳转到表中由元素的散列码给出的位置。
  • ● 向前扫描——如有必要环绕——记录有多少步 你拿走了。 当您找到该项目、找到一个空白槽或找到一个 离家更近的空位比你走的步数还多。
  • 将元素插入表中:
  • ● 如果该元素已在表中,则什么也不做。
  • ● 跳转到由元素的散列码给出的表槽。 向前扫描 - 换行 如有必要,四处走走——记录所走的步数。 如果你找到一个 空插槽,将元素放在那里。 否则,如果当前插槽已满并且 比您插入的元素更靠近家,将要插入的项目放在那里, 替换那个位置的元素,然后继续插入,就好像你 正在插入被置换的元素。
  • 从表中删除一个元素:
  • ● 跳转到由元素的散列码给定的槽。
  • ● 向前走——如有必要,环绕——直到物品或空槽被放置 成立。 如果找到该项目,请将其删除。 然后,继续前进——包裹 around as necessary – 将表中的元素向后移动一个槽位,直到 找到空插槽或位于其原始位置的项目

string类

str::npos表示容器的最后一个成员位置 if (s.find("e") != string::npos) //find函数找不到时返回npos if s in str: string obj; obj.substr(int pos) //pos为要包含的第一个字符串的位置 std::string a = "0123456789abcdefghij";

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

// count is npos, returns [pos, size())
[std::string](http://en.cppreference.com/w/cpp/string/basic_string) sub1 = a.substr(10);
[std::cout](http://en.cppreference.com/w/cpp/io/cout) << sub1 << '\n';

// both pos and pos+count are within bounds, returns [pos, pos+count)
[std::string](http://en.cppreference.com/w/cpp/string/basic_string) sub2 = a.substr(5, 3);
[std::cout](http://en.cppreference.com/w/cpp/io/cout) << sub2 << '\n';

// pos is within bounds, pos+count is not, returns [pos, size())
[std::string](http://en.cppreference.com/w/cpp/string/basic_string) sub4 = a.substr(a.size()-3, 50);
// this is effectively equivalent to
// std::string sub4 = a.substr(17, 3);
// since a.size() == 20, pos == a.size()-3 == 17, and a.size()-pos == 3

[std::cout](http://en.cppreference.com/w/cpp/io/cout) << sub4 << '\n';

try {
// pos is out of bounds, throws
[std::string](http://en.cppreference.com/w/cpp/string/basic_string) sub5 = a.substr(a.size()+3, 50);
[std::cout](http://en.cppreference.com/w/cpp/io/cout) << sub5 << '\n';
} catch(const [std::out_of_range](http://en.cppreference.com/w/cpp/error/out_of_range)& e) {
[std::cout](http://en.cppreference.com/w/cpp/io/cout) << "pos exceeds string size\n";
}
}
输出:
abcdefghij
567
hij
pos exceeds string size

`replace和insert str1.insert(start, str2) str1.replace(start, length, str2)

一些实现

优先队列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# include "HeapPQueue.h"
using namespace std;

HeapPQueue::HeapPQueue() {
elems = new DataPoint[INITIAL_SIZE] {};
for (int i=0;i<INITIAL_SIZE;i++)
{
elems[i].weight=0;
}
allocatedSize=INITIAL_SIZE;
}

HeapPQueue::~HeapPQueue() {
delete [] elems;
}

int HeapPQueue::size() const {
return logicalSize;
}

bool HeapPQueue::isEmpty() const {
return logicalSize==0;
}

void HeapPQueue::enqueue(const DataPoint& data) {
if (logicalSize+1<allocatedSize)
{
if (logicalSize==0)
{
elems[1]=data;
logicalSize++;
}
else
{
logicalSize++;
int i=1;
while (data.weight>elems[i].weight && i<=logicalSize && elems[i].weight!=0)
{
i++;
}
if (i<logicalSize)
{
DataPoint temp=elems[i];
elems[i]=data;
for(i;i<logicalSize;i++)
{
DataPoint temp_plus=elems[i+1];
elems[i+1]=temp;
temp=temp_plus;

}
}
else
{
elems[i]=data;
}

}
}
}

DataPoint HeapPQueue::peek() const {
return elems[logicalSize];
}

DataPoint HeapPQueue::dequeue() {
DataPoint to_return=elems[1];
if(!isEmpty())
{

for (int i=1;i<logicalSize;i++)
{
elems[i]=elems[i+1];
}
elems[logicalSize]={};
logicalSize--;
}
return to_return;
}

计数排序

首先算出最大值,然后用一个数组的索引存储待排序数组的成员,其索引对应值存储出现次数,然后用两个同步的for循环和递增的next参数表示排序中的索引值来进行排序(也就是重新赋值)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/* Given a Vector<int>, returns the largest number in that Vector. */
int maxOf(const Vector<int>& values) {
/* Bounds-check inputs. */
if (values.isEmpty()) {
error("Can't find the maximum of no values.");
}

int result = values[0];
for (int i = 1; i < values.size(); i++) {
result = max(result, values[i]);
}
return result;
}

/* Given a list of numbers, creates a histogram from those numbers. */
Vector<int> histogramFor(const Vector<int>& values) {
/* Create a histogram with the right number of slots. Initially, all values
* in the histogram will be zero.
*/
Vector<int> histogram(maxOf(values) + 1);

/* Scan across the input vector, incrementing the histogram values. */
for (int value: values) {
histogram[value]++;
}

return histogram;
}

void countingSort(Vector<int>& values) {
/* Edge Case: If the array is empty, then it's already sorted. This is
* needed because we can't take the maximum value of an empty vector.
*/
if (values.isEmpty()) {
return;
}

/* Form the histogram. */
auto histogram = histogramFor(values);

/* Scan across the histogram writing out the appropriate number of copies
* of each value. We track the index of the next free spot to write to,
* as it varies based on how many items we've written out so far.
*/
int next = 0;
for (int value = 0; value < histogram.size(); value++) {
/* Write out the right number of copies. */
for (int copy = 0; copy < histogram[value]; copy++) {
values[next] = value;
next++;
}
}
}

错题集

递归的效率优化

每次递归都会创造所有变量的临时复制 基于递归的这种性质,它会需要巨大的时间和空间来完成任务,并且会造成算力上的浪费。 通过记忆表机制能部分解决这个问题,方法是每次递归的返回值都会按索引存入一个表格,并且每次递归前查询表格中是否有结果,这样可以让每个临时副本的运算结果能被所有函数共享。

递归计算给定元素的不同结构哈夫曼树的数量

对每个给定元素集来说,首先要做到是确定根节点元素是第几个大的元素,确定之后,左子树和右子树的元素数也随之确定,在此之后分别对左节点和右节点作为根节点做同样的递归

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

int numBSTsOfSize(int n) {

/* Base case: There’s only one tree of size 0, namely, the empty BST. */
if (n == 0) return 1;

/* Recursive case: Imagine all possible ways to choose a root and build the
* left and right subtrees.
*/
int result = 0;

/* Put the the nodes at indices 0, 1, 2, ..., n-1 up at the root. */
for (int i = 0; i < n; i++) {
/* Each combination of a BST of i elements and a BST of n - 1 - i elements
* can be used to build one BST of n elements. The number of pairs of
* trees we can make this way is given by the product of the number of
* trees of each type.
*/
result += numBSTsOfSize(i) * numBSTsOfSize(n - 1 - i);
}

return result;
}

递归解决吃巧克力问题

求出吃法数量

1
2
3
4
5
6
7
8
9
10
11
12
if (numSquares<0)
{
error("输入数据不能为负数");
}
else if (numSquares<=1)
{
return 1;
}
else
{
return numWaysToEat(numSquares-1)+numWaysToEat(numSquares-2);
}

打印每种吃法

`需要一个辅助向量储存历史记录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/* Print all ways to eat numSquares more squares, given that we've
* already taken the bites given in soFar.
*/
void printWaysToEatRec(int numSquares, const Vector<int>& soFar) {
/* Base Case: If there are no squares left, the only option is to use
* the bites we've taken already in soFar.
*/
if (numSquares == 0) {
cout << soFar << endl;
}
/* Base Case: If there is one square lfet, the only option is to eat
* that square.
*/
else if (numSquares == 1) {
cout << soFar + 1 << endl;
}
/* Otherwise, we take take bites of size one or of size two. */
else {
printWaysToEatRec(numSquares - 1, soFar + 1);
printWaysToEatRec(numSquares - 2, soFar + 2);
}
}

void printWaysToEat(int numSquares) {
if (numSquares < 0) {
error("You owe me some chocolate!");
}

/* We begin without having made any bites. */
printWaysToEatRec(numSquares, {});
}

递归解决翻煎饼问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
bool isSorted(Stack<double> pancakes) {
double last = -1; // No pancakes have negative size;

while (!pancakes.isEmpty()) {
/* Check the next pancake. */
double next = pancakes.pop();
if (next < last) {
return false;
}

last = next;
}

/* Pancakes are in increasing order! */
return true;
}

/* Given a stack of pancakes and a flip size, flips that many pancakes
* on the top of the stack.
*/
Stack<double> flip(Stack<double> pancakes, int numToFlip) {
/* Take the top pancakes off the stack and run them into a queue.
* This preserves the order in which they were removed.
*/
Queue<double> buffer;
for (int i = 0; i < numToFlip; i++) {
buffer.enqueue(pancakes.pop());
}

/* Move the pancakes back. */
while (!buffer.isEmpty()) {
pancakes.push(buffer.dequeue());
}

return pancakes;
}

Optional<Vector<int>> sortStack(Stack<double> pancakes, int numFlips) {
/* Base Case: If the stack is sorted, great! We're done, and no flips
* were needed.
*/
if (isSorted(pancakes)) {
return { }; // No flips
}
/* Base Case: If the stack isn't sorted and we're out of flips, then
* there is no way to sort things.
*/
else if (numFlips == 0) {
return Nothing;
}
/* Recursive Case: The stack isn't sorted and we still have flips left.
* The next flip could flip 1, 2, 3, ..., or all N of the pancakes.
* Try each option and see whether any of them work.
*/
for (int numToFlip = 1; numToFlip <= pancakes.size(); numToFlip++) {
/* Make the flip and see if it works. */
auto result = sortStack(flip(pancakes, numToFlip), numFlips - 1);
if (result != Nothing) {
/* The result holds all the remaining flips but doesn't know about
* the flip we just did. Insert that flip at the beginning.
*/
result.value().insert(0, numToFlip);
return result;
}
}

/* If we're here, then no matter which flip we make first, we cannot
* get the pancakes sorted. Give up.
*/
return Nothing;
}

递归解决天平问题

1
2
3
4
5
6
7
8
9
10
11
12
13
bool isMeasurableRec(int amount, const Vector<int>& weights, int index) {
if (index == weights.size()) {
return amount == 0;
} else {
return isMeasurableRec(amount, weights, index + 1) ||
isMeasurableRec(amount + weights[index], weights, index + 1) ||
isMeasurableRec(amount - weights[index], weights, index + 1);
}
}

bool isMeasurable(int amount, const Vector<int>& weights) {
return isMeasurableRec(amount, weights, 0);
}

想象一下,我们首先将要测量的数量(称为 n )放在天平的左侧。 这使得规模上的不平衡等于 n 。 想象一下,有某种方法可以测量 n 。 如果我们一次将一个重量放在秤上,我们可以查看第一个重量的放置位置(假设它的重量为 w )。 它必须:

  • 向左走,使规模上的净不平衡 n + w ,或
  • 向右走,使规模上的净不平衡 n – w ,或
  • 根本不习惯,留下净不平衡 n

如果确实有可能测量 n ,那么这三个选项之一必须是实现它的方法,即使我们不知道它是哪一个。 然后我们要问的问题是,是否有可能使用剩余的权重来衡量新的净失衡——我们可以递归地确定! 另一方面,如果无法测量 n ,那么无论我们选择哪个选项,我们都会发现没有办法使用剩余的权重来使一切平衡!

如果我们递归地进行,我们在这里,我们需要考虑我们的基本情况。 我们可以选择的选项有很多。 一个简单的方法如下:假设我们根本没有任何重量,我们被要求查看是否可以不使用重量来测量某些重量。 在什么情况下我们可以这样做? 好吧,如果我们称重的东西有一个非零重量,我们就不可能测量它——把它放在秤上会使它倾斜到某一边,但这并不能告诉我们它有多少重量。 另一方面,如果我们称量的东西是完全失重的,那么把它放在秤上也不会导致它倾斜,让我们相信它确实是失重的! 因此,作为我们的基本情况,我们会说当我们减少到没有剩余权重时, ,我们可以精确测量n 如果 n = 0 。 考虑到这一点,这是我们的代码:

递归解决找零问题

不使用记忆的情况

`从第一个硬币开始遍历,并穷举它的所有枚数,将其作为下一枚硬币的参数传递

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
int fewestCoinsFor(int cents, const Set<int>& coins) {
/* Can't have a negative number of cents. */
if (cents < 0) {
error("You owe me money, not the other way around!");
}
/* Base case: You need no coins to give change for no cents. */
else if (cents == 0) {
return 0;
}
/* Base case: No coins exist. Then it's not possible to make the
* amount. In that case, give back a really large value as a
* sentinel.
*/
else if (coins.isEmpty()) {
return cents + 1;
}
/* Recursive case: Pick a coin, then try using each distinct number of
* copies of it that we can.
*/
else {
/* The best we've found so far. We initialize this to a large value so
* that it's replaced on the first iteration of the loop. Do you see
* why cents + 1 is a good choice?
*/
int bestSoFar = cents + 1;
/* Pick a coin. */
int coin = coins.first();
/* Try all amounts of it. */
for (int copies = 0; copies * coin <= cents; copies++) {
/* See what happens if we make this choice. Once we use this
* coin, we won't use the same coin again in the future.
*/
int thisChoice = copies + fewestCoinsFor(cents - copies * coin,
coins - coin);
/* Is this better than what we have so far? */
if (thisChoice < bestSoFar) {
bestSoFar = thisChoice;
}
}
/* Return whatever worked best. */
return bestSoFar;
}
}

使用记忆进行优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
/* How few coins are needed to make the total, given that we can only use
* coins from index startIndex and onward?
*/
int fewestCoinsRec(int cents, const Vector<int>& coins, int startIndex,Grid<int>& memo) {
/* Base case: You need no coins to give change for no cents. */
if (cents == 0) {
return 0;
}
/* Base case: No coins exist. Then it's not possible to make the
* amount. In that case, give back a really large value as a
* sentinel.
*/
else if (startIndex == coins.size()) {
return cents + 1;
}
/* Base case: We already know the answer. */
else if (memo[cents][startIndex] != -1) {
return memo[cents][startIndex];
}
/* Recursive case: Pick a coin, then try using each distinct number of
* copies of it that we can.
*/
else {
/* The best we've found so far. We initialize this to a large value so
* that it's replaced on the first iteration of the loop. Do you see
* why cents + 1 is a good choice?
*/
int bestSoFar = cents + 1;

/* Pick a coin. */
int coin = coins[startIndex];

/* Try all amounts of it. */
for (int copies = 0; copies * coin <= cents; copies++) {
/* See what happens if we make this choice. Once we use this
* coin, we won't use the same coin again in the future.
*/
int thisChoice = copies + fewestCoinsRec(cents - copies * coin,
coins, startIndex + 1,
memo);

/* Is this better than what we have so far? */
if (thisChoice < bestSoFar) {
bestSoFar = thisChoice;
}
}

/* Return whatever worked best. */
memo[cents][startIndex] = bestSoFar;
return bestSoFar;
}
}

int fewestCoinsFor(int cents, const Set<int>& coins) {
/* Can't have a negative number of cents. */
if (cents < 0) {
error("You owe me money, not the other way around!");
}

/* Convert from a Set<int> to a Vector<int> so we have a nice ordering
* on things.
*/
Vector<int> coinVec;
for (int coin: coins) {
coinVec += coin;
}

/* Build our memoization table. Since the number of cents left ranges from
* 0 to cents, we need cents+1 rows. Since the start index of the coin
* ranges from 0 to coins.size(), we make coins.size() + 1 columns.
*
* -1 is used as a sentinel to indicate "nothing has been computed here
* yet."
*/
Grid<int> memo(cents + 1, coins.size() + 1, -1);

/* Now ask how many coins are needed to make the total, using any coins
* from index 0 onward.
*/
return fewestCoinsRec(cents, coinVec, 0, memo);
}

递归穷举付账单

递归机制:对第一个人来说,0-total所有金额都会付一遍,随后传递给下一个人,当只有一人时,付清所有余额并打印账单 传递参数:string,int的映射存储目前为止的账单,string集合存储所有付账者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void listPossiblePaymentsRec(int total, const Set<string>& people,const Map<string, int>& payments) {
/* Base case: if there's one person left, they have to pay the whole bill. */
if (people.size() == 1) {
Map<string, int> finalPayments = payments;
finalPayments[people.first()] = total;
cout << finalPayments << endl;
}
/* Recursive case: The first person has to pay some amount between 0 and the
* total amount. Try all of those possibilities.
*/
else {
for (int payment = 0; payment <= total; payment++) {
/* Create a new assignment of people to payments in which this first
* person pays this amount.
*/
Map<string, int> updatedPayments = payments;
updatedPayments[people.first()] = payment;
listPossiblePaymentsRec(total - payment, people - people.first(),updatedPayments);
}
}
}
void listPossiblePayments(int total, const Set<string>& people) {
/* Edge cases: we can't pay a negative total, and there must be at least one
* person.
*/
if (total < 0) error("Guess you're an employee?");
if (people.isEmpty()) error("Dine and dash?");
listPossiblePaymentsRec(total, people, {});
}

递归寻找完全平方数列

主要参数为sofar——用于存储目前的序列和一个set用于存储还没放入数列的数字,`确保这两者同时被传递,且其并集为所有数字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
Optional<Vector<int>> findSquareSequence(int n) {
/*Validate input.*/
if (n < 0) {
error("Don't be so negative!");
}

/* Build a set of the numbers 1, 2, 3, ..., n. */
Set<int> options;
for (int i = 1; i <= n; i++) {
options += i;
}
return findSequenceRec(options, { });
}

Optional<Vector<int>> findSequenceRec(const Set<int>& unused,
const Vector<int>& soFar) {
/*Base Case: If all numbers are used, we have our sequence!*/
if (unused.isEmpty()) {
return soFar;
}

/* Recursive Case: Some number comes next. Try each of them and see which
* one we should pick.
*/
for (int next: unused) {
/* We can use this if either
*
* 1. the sequence is empty, so we're first in line, or
* 2. the sequence is not empty, but we sum to a perfect square
* with the previous term.
*/
if (soFar.isEmpty() ||
isPerfectSquare(next + soFar[soFar.size() - 1])) {
/* See what happens if we extend with this number. */
auto result = findSequenceRec(unused - next, soFar + next);
if (result != Nothing) {
return result;
}
}
}

/* Tried all options and none of them worked. Oh well! */
return Nothing;
}

汉诺塔递归

假设有三座汉诺塔,start ,temp ,finish 对n层的汉诺塔问题,先考虑n-1层的,随后考虑n-2层,到最后只需要考虑两层问题,两层的汉诺塔非常容易解决,起点为start,终点是temp,临时塔为finish,最后我们得到temp上的两层汉诺塔 这时将start的3移动到finish塔,这时只要将两层汉诺塔转移到finish则完成了三层汉诺塔,这个过程中的起点为temp,终点是finish,临时塔是start 以此类推,四层塔基于三层塔,n层塔基于n-1塔,汉诺塔问题解决

1
2
3
4
5
6
7
8
9
10
11
int moveTower(int numDisks, char start, char finish, char temp) {
if (numDisks == 0) {
return 0;
} else {
int movesOne = moveTower(numDisks - 1, start, temp, finish);
moveSingleDisk(start, finish);
int movesTwo = moveTower(numDisks - 1, temp, finish, start);

return 1 + movesOne + movesTwo;
}
}
]]>
- <h1 id="c语言部分">c语言部分</h1> -<h2 id="基本函数构成">基本函数构成</h2> -<p>将数组传递为函数参数</p> -<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">int fcname(int arg[],int n)</span><br></pre></td></tr></table></figure> + <h2 id="一些查找和排序算法">一些查找和排序算法</h2> +<p>二分查找法 <img src="/images/obsidian/20230226101843.png" title="image" alt="图片" /> 最坏情况:log2n - + + + + + - +
@@ -1016,10 +1016,10 @@ - - + + diff --git a/categories/index.html b/categories/index.html index adfe298af..766e61e49 100644 --- a/categories/index.html +++ b/categories/index.html @@ -287,14 +287,14 @@

categories 站点总字数: - 191k + 194k
diff --git "a/categories/\345\273\272\347\253\231\347\273\217\351\252\214/index.html" "b/categories/\345\273\272\347\253\231\347\273\217\351\252\214/index.html" index 88c0a97d7..f6c15e480 100644 --- "a/categories/\345\273\272\347\253\231\347\273\217\351\252\214/index.html" +++ "b/categories/\345\273\272\347\253\231\347\273\217\351\252\214/index.html" @@ -294,14 +294,14 @@

建站经验 站点总字数: - 191k + 194k

diff --git "a/categories/\346\270\270\346\210\217\346\235\202\350\260\210/black-souls/index.html" "b/categories/\346\270\270\346\210\217\346\235\202\350\260\210/black-souls/index.html" index 1d7add97e..33bc5dba4 100644 --- "a/categories/\346\270\270\346\210\217\346\235\202\350\260\210/black-souls/index.html" +++ "b/categories/\346\270\270\346\210\217\346\235\202\350\260\210/black-souls/index.html" @@ -259,8 +259,8 @@

black souls

-
@@ -279,8 +279,8 @@

black souls
-
@@ -334,14 +334,14 @@

black souls 站点总字数: - 191k + 194k
diff --git "a/categories/\346\270\270\346\210\217\346\235\202\350\260\210/index.html" "b/categories/\346\270\270\346\210\217\346\235\202\350\260\210/index.html" index b7d2e4293..60d971758 100644 --- "a/categories/\346\270\270\346\210\217\346\235\202\350\260\210/index.html" +++ "b/categories/\346\270\270\346\210\217\346\235\202\350\260\210/index.html" @@ -399,8 +399,8 @@

游戏杂谈

-
@@ -419,8 +419,8 @@

游戏杂谈
-
@@ -474,14 +474,14 @@

游戏杂谈 站点总字数: - 191k + 194k
diff --git "a/categories/\346\270\270\346\210\217\346\235\202\350\260\210/wrpg/index.html" "b/categories/\346\270\270\346\210\217\346\235\202\350\260\210/wrpg/index.html" index a7e7e62e6..34eecfded 100644 --- "a/categories/\346\270\270\346\210\217\346\235\202\350\260\210/wrpg/index.html" +++ "b/categories/\346\270\270\346\210\217\346\235\202\350\260\210/wrpg/index.html" @@ -314,14 +314,14 @@

wrpg 站点总字数: - 191k + 194k

diff --git "a/categories/\346\270\270\346\210\217\346\235\202\350\260\210/\345\205\266\344\273\226\346\270\270\346\210\217/index.html" "b/categories/\346\270\270\346\210\217\346\235\202\350\260\210/\345\205\266\344\273\226\346\270\270\346\210\217/index.html" index cc0f885a7..144953ed0 100644 --- "a/categories/\346\270\270\346\210\217\346\235\202\350\260\210/\345\205\266\344\273\226\346\270\270\346\210\217/index.html" +++ "b/categories/\346\270\270\346\210\217\346\235\202\350\260\210/\345\205\266\344\273\226\346\270\270\346\210\217/index.html" @@ -314,14 +314,14 @@

其他游戏 站点总字数: - 191k + 194k

diff --git "a/categories/\346\270\270\346\210\217\346\235\202\350\260\210/\347\213\254\347\253\213\346\270\270\346\210\217/index.html" "b/categories/\346\270\270\346\210\217\346\235\202\350\260\210/\347\213\254\347\253\213\346\270\270\346\210\217/index.html" index 587b460ee..13c20bdb6 100644 --- "a/categories/\346\270\270\346\210\217\346\235\202\350\260\210/\347\213\254\347\253\213\346\270\270\346\210\217/index.html" +++ "b/categories/\346\270\270\346\210\217\346\235\202\350\260\210/\347\213\254\347\253\213\346\270\270\346\210\217/index.html" @@ -334,14 +334,14 @@

独立游戏 站点总字数: - 191k + 194k

diff --git "a/categories/\347\247\230\345\257\206/index.html" "b/categories/\347\247\230\345\257\206/index.html" index d49e15667..04f3c3135 100644 --- "a/categories/\347\247\230\345\257\206/index.html" +++ "b/categories/\347\247\230\345\257\206/index.html" @@ -294,14 +294,14 @@

秘密 站点总字数: - 191k + 194k

diff --git "a/categories/\350\200\203\347\240\224\347\254\224\350\256\260/index.html" "b/categories/\350\200\203\347\240\224\347\254\224\350\256\260/index.html" index b56af9336..be8a72d51 100644 --- "a/categories/\350\200\203\347\240\224\347\254\224\350\256\260/index.html" +++ "b/categories/\350\200\203\347\240\224\347\254\224\350\256\260/index.html" @@ -314,14 +314,14 @@

考研笔记 站点总字数: - 191k + 194k

diff --git "a/categories/\350\257\276\347\250\213\347\254\224\350\256\260/index.html" "b/categories/\350\257\276\347\250\213\347\254\224\350\256\260/index.html" index 3184c9b9d..88577373c 100644 --- "a/categories/\350\257\276\347\250\213\347\254\224\350\256\260/index.html" +++ "b/categories/\350\257\276\347\250\213\347\254\224\350\256\260/index.html" @@ -477,14 +477,14 @@

课程笔记 站点总字数: - 191k + 194k

diff --git "a/categories/\350\257\276\347\250\213\347\254\224\350\256\260/page/2/index.html" "b/categories/\350\257\276\347\250\213\347\254\224\350\256\260/page/2/index.html" index ebdd405d3..abcb25c59 100644 --- "a/categories/\350\257\276\347\250\213\347\254\224\350\256\260/page/2/index.html" +++ "b/categories/\350\257\276\347\250\213\347\254\224\350\256\260/page/2/index.html" @@ -299,8 +299,8 @@

课程笔记

-
@@ -319,8 +319,8 @@

课程笔记
-
@@ -339,8 +339,8 @@

课程笔记
-
@@ -359,8 +359,8 @@

课程笔记
-
@@ -417,14 +417,14 @@

课程笔记 站点总字数: - 191k + 194k
diff --git "a/categories/\350\257\276\347\250\213\347\254\224\350\256\260/\345\205\266\344\273\226/index.html" "b/categories/\350\257\276\347\250\213\347\254\224\350\256\260/\345\205\266\344\273\226/index.html" index c8d7db60a..4a764dbe3 100644 --- "a/categories/\350\257\276\347\250\213\347\254\224\350\256\260/\345\205\266\344\273\226/index.html" +++ "b/categories/\350\257\276\347\250\213\347\254\224\350\256\260/\345\205\266\344\273\226/index.html" @@ -314,14 +314,14 @@

其他 站点总字数: - 191k + 194k

diff --git "a/categories/\350\257\276\347\250\213\347\254\224\350\256\260/\346\223\215\344\275\234\347\263\273\347\273\237/index.html" "b/categories/\350\257\276\347\250\213\347\254\224\350\256\260/\346\223\215\344\275\234\347\263\273\347\273\237/index.html" index 73364a4ca..f7c9c1e6a 100644 --- "a/categories/\350\257\276\347\250\213\347\254\224\350\256\260/\346\223\215\344\275\234\347\263\273\347\273\237/index.html" +++ "b/categories/\350\257\276\347\250\213\347\254\224\350\256\260/\346\223\215\344\275\234\347\263\273\347\273\237/index.html" @@ -354,14 +354,14 @@

操作系统 站点总字数: - 191k + 194k

diff --git "a/categories/\350\257\276\347\250\213\347\254\224\350\256\260/\346\225\260\346\215\256\347\247\221\345\255\246/index.html" "b/categories/\350\257\276\347\250\213\347\254\224\350\256\260/\346\225\260\346\215\256\347\247\221\345\255\246/index.html" index 641d4ce5c..458cda45b 100644 --- "a/categories/\350\257\276\347\250\213\347\254\224\350\256\260/\346\225\260\346\215\256\347\247\221\345\255\246/index.html" +++ "b/categories/\350\257\276\347\250\213\347\254\224\350\256\260/\346\225\260\346\215\256\347\247\221\345\255\246/index.html" @@ -334,14 +334,14 @@

数据科学 站点总字数: - 191k + 194k

diff --git "a/categories/\350\257\276\347\250\213\347\254\224\350\256\260/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/index.html" "b/categories/\350\257\276\347\250\213\347\254\224\350\256\260/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/index.html" index fd049f9bf..32c467181 100644 --- "a/categories/\350\257\276\347\250\213\347\254\224\350\256\260/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/index.html" +++ "b/categories/\350\257\276\347\250\213\347\254\224\350\256\260/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/index.html" @@ -394,14 +394,14 @@

数据结构与算法 站点总字数: - 191k + 194k

diff --git "a/categories/\350\257\276\347\250\213\347\254\224\350\256\260/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/index.html" "b/categories/\350\257\276\347\250\213\347\254\224\350\256\260/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/index.html" index 1253384b7..8e84a4127 100644 --- "a/categories/\350\257\276\347\250\213\347\254\224\350\256\260/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/index.html" +++ "b/categories/\350\257\276\347\250\213\347\254\224\350\256\260/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/index.html" @@ -294,14 +294,14 @@

计算机网络 站点总字数: - 191k + 194k

diff --git "a/categories/\350\257\276\347\250\213\347\254\224\350\256\260/\350\256\241\347\273\204/index.html" "b/categories/\350\257\276\347\250\213\347\254\224\350\256\260/\350\256\241\347\273\204/index.html" index e11c3ae01..287b68830 100644 --- "a/categories/\350\257\276\347\250\213\347\254\224\350\256\260/\350\256\241\347\273\204/index.html" +++ "b/categories/\350\257\276\347\250\213\347\254\224\350\256\260/\350\256\241\347\273\204/index.html" @@ -294,14 +294,14 @@

计组 站点总字数: - 191k + 194k

diff --git "a/categories/\350\277\252\347\221\236\345\205\213\346\213\211/index.html" "b/categories/\350\277\252\347\221\236\345\205\213\346\213\211/index.html" index 67be6a77c..4ea2eb9cc 100644 --- "a/categories/\350\277\252\347\221\236\345\205\213\346\213\211/index.html" +++ "b/categories/\350\277\252\347\221\236\345\205\213\346\213\211/index.html" @@ -334,14 +334,14 @@

迪瑞克拉 站点总字数: - 191k + 194k

diff --git a/guestbook/index.html b/guestbook/index.html index 007456a94..c3d375c9a 100644 --- a/guestbook/index.html +++ b/guestbook/index.html @@ -289,14 +289,14 @@

请于此留下你的思想

站点总字数: - 191k + 194k
diff --git a/index.html b/index.html index c3cea03cb..660e2ee5b 100644 --- a/index.html +++ b/index.html @@ -388,7 +388,7 @@

- +

@@ -430,7 +430,7 @@

概论

操作系统:控制管理计算机的硬件,协调控制资源分配,并为应用程序和用户提供接口以供使用

基本特征

-

操作系统的基本特征包括开并发,共享,虚拟和异步

+

操作系统的基本特征包括并发,共享,虚拟和异步

  1. 并发
    并发是指两个或多个事件在同一时间间隔内发生。操作系统的并发性是指计算机系统中同时存在多个运行的程序,因此它具有处理和调度多个程序同时执行的能力。这是通过类似时间片轮转的机制实现的。
    @@ -1454,14 +1454,14 @@

    命名

    站点总字数: - 191k + 194k
    diff --git a/page/2/index.html b/page/2/index.html index 994766f4c..e6caf0219 100644 --- a/page/2/index.html +++ b/page/2/index.html @@ -363,7 +363,7 @@

    算法性质

    - +

    - +

    @@ -442,12 +442,12 @@

    -

    Numpy 是 Python 中科学计算的核心库。 它提供了高性能的多维数组对象以及使用这些对象的工具 数组。

    -

    数组

    -

    numpy 数组是一个值网格,所有值都具有相同的类型,并由非负整数组成的元组索引。 它的维度就是数组的秩 ;它的shape就是每个维度的大小组成的元组 +

    shell脚本

    +

    Shell 脚本通常以 shebang 行开头:#!path/to/interpreter。

    +

    #!是一个人类可读的 幻数表示 0x23 0x21它可以告诉 shell 将文件其余部分的执行传递给 指定翻译。 如果您的脚本作为可执行文件运行(例如 ./awesome_shell_script) 加上 shebang 行,那么 shell 将调用 可执行文件(通常是解释器)位于 path/to/interpreter运行你的 脚本。 如果您的脚本作为参数传递给解释器,例如 bash awesome_shell_script,那么 shebang 没有效果并且 bash会处理 脚本的执行。

    - + 阅读全文 »
    @@ -478,7 +478,7 @@

    数组

    - +

    - +

    @@ -557,12 +557,12 @@

    -

    shell脚本

    -

    Shell 脚本通常以 shebang 行开头:#!path/to/interpreter。

    -

    #!是一个人类可读的 幻数表示 0x23 0x21它可以告诉 shell 将文件其余部分的执行传递给 指定翻译。 如果您的脚本作为可执行文件运行(例如 ./awesome_shell_script) 加上 shebang 行,那么 shell 将调用 可执行文件(通常是解释器)位于 path/to/interpreter运行你的 脚本。 如果您的脚本作为参数传递给解释器,例如 bash awesome_shell_script,那么 shebang 没有效果并且 bash会处理 脚本的执行。 +

    Numpy 是 Python 中科学计算的核心库。 它提供了高性能的多维数组对象以及使用这些对象的工具 数组。

    +

    数组

    +

    numpy 数组是一个值网格,所有值都具有相同的类型,并由非负整数组成的元组索引。 它的维度就是数组的秩 ;它的shape就是每个维度的大小组成的元组

    - + 阅读全文 »
    @@ -1050,7 +1050,7 @@

    428被封锁的涩谷

    - +

    - +

    @@ -1129,16 +1125,10 @@

    -

    `冯·诺依曼计算机特点
    -– 计算机由五大部件组成
    -• 输入数据和程序的“输入设备”
    -• 记忆程序和数据的“存储器”
    -• 完成数据加工处理的“运算器”
    -• 控制程序执行的“控制器”
    -• 输出处理结果的“输出设备”

    + 心爱的少女,她诞生的时日是?
    - + 阅读全文 »
    @@ -1169,7 +1159,7 @@

    - +

    +

    由于black souls的故事远远没有完结,因此现阶段我们很难对红白女王梅贝尔这些与格林牵扯极深的支配者们进行什么定论,只能就已有的剧情和文本进行一些归纳,本期视频我将就bs2比较难懂的一处地方,冬之钟的主线事件,进行一些个人向的分析。 在冬之钟最后一章地图能遇到5个白熊,白熊的身份迄今为止依然是谜团,但他们提供了整整五段发生在支配者之间的重要对话,我将概括一下这五段对话提供的主要信息以便进一步的分析 我们按解包后的地图顺序开始, 第一段对话发生于梅贝尔和妹妹爱丽丝之间,可以猜测妹妹爱丽丝属于支配者之一,数量众多的支配者都在奈亚的箱庭占据一个角色以便和格林繁殖,但随着时间推移,支配者们发现扮演角色的同时,他们也在被角色同化(梅贝尔所言),因此纷纷退场,妹妹爱丽丝也逐渐被角色影响对格林产生好感,此外,姐姐爱丽丝不知何故地退场。 第二场对话发生于梅贝尔和白之女王之间,对话中提及冬之钟正是白女王的箱庭,而白之女王由于爱上了格林自愿放弃女王的身份去守护他,而梅贝尔则对这场追寻爱的闹剧,以及陪着胡闹的其他支配者感到无聊,向白女王提出一个让格林摆脱循环,并且能够独占他的计划。 第三第四场对话都发生于红白女王之间,红女王为陷入痛苦轮回的格林而痛苦,不断进行自残,白女王制止了她,两人由于同样爱上格林而心意相通 第四场对话则告诉我们,红女王接过了白女王的权王冠(推测为箱庭权限),并以此创造出库因兰德,并使其能排除奈亚的监视,两人密谋让格林挣脱循环的方法,红女王恳请白女王放弃对格林的独占欲,白女王同意了,此外,梅贝尔也知晓这一计划,并根据后面的行动来看,她不知为何也参与了这个计划 第五场对话发生于白女王和玛丽苏之间,白女王夺走了玛丽苏的改变能力,并且根据混沌迷宫的情报,将其赋予了古兰剧场,玛丽苏察觉白女王爱上了格林,并且等待着格林的到来,结尾,玛丽苏等到了一个神秘人(黑山羊?) 总结这些信息,我们可以推测出针对格林,一共提出了两个计划,一个是梅贝尔怂恿的独占计划,一个是红偶像策划的拯救计划,这两个计划都必须有诺登的参与,但此时我们并不知道诺登的真正想法是哪个 在推进h结局的过程后,格林会有两个选择,1是和暗黑舞台合二为一2是打败舞台,夺取舞台的改变能力, “此时”的冬之钟虽然沉睡,但相信诺登依旧有一定的控制能力,然而不同于G结局的阻拦,此时的诺登选择了旁观,并在最后支持格林任意一个选择 总结一下大致发生的事件(以下事件的时间顺序难以具体确定) 1诺登作为支配者之一管理着自己的箱庭冬之钟,和奈亚创造自己箱庭的时间关系未知 2奈亚将格林带到箱庭,邀请支配者们参加繁殖游戏,根据牛津学院人偶爱丽丝的说法,是舞台装置创造出了让格林在舞台上登场的皮套(格林的灵魂出自玛丽苏的手笔,因此推测只能创造皮套),并且在创造格林时两者间确立了深远的联系,白女王也参加了这个游戏,可以肯定白女王为了心爱的格林才舍弃了王冠(王冠可能指代管理箱庭的权能),因此推测白女王在爱上格林后可能以放弃王冠为代价,得到了管理奈亚箱庭的权限和陪伴在格林身边的权力 3红偶像被奈亚切割,由于茶会时期她曾经打倒初代红之女王,因此此刻可以说她的身份是第二任红之女王,为格林自责的她不断紫餐,得到了白女王的同情,白女王将自己原来的王冠权能移交给被奈亚切割的红女王,让她在原冬之钟的地盘上创造出自己的箱庭。 4红白女王合谋,或者其中之一从奈亚手中夺走了玛丽苏并囚禁起来,为了避免红白女王相互猜疑,二者将从玛丽苏手上得到的改变能力赋予舞台装置古兰,创造出一个新的支配者暗黑舞台,藏于处于过去时间线的冬之钟,同时由于处于过去的时间线,冬之钟几乎没有被发现的风险,通过dlc3经常出现的齿轮与其他信息可以推测,舞台装置拥有着影响整个箱庭以及舞台上大部分“演员”的能力,即在部分地图的bg和格林脑中的“齿轮声”,是不思议之国这场戏的核心,此外,由于诺登为了管理这个箱庭必须借助舞台的力量,而红白女王理论上权能接近,因此本视频中猜测红白女王都有部分操控舞台的权限 4由于支配者们发现扮演箱庭的角色会改变自己的本质,因此纷纷退出,白女王被迫用自己和格林的子嗣填补空缺 5梅贝尔认为这场游戏无聊透顶,一场剧本烂透的戏剧重复多少遍也只会让人厌倦(她自己是这么说的),因此她怂恿白女王让格林脱出循环,并抢先独占他 6红女王努力让自己的领域能排除奈亚的监视,并在此向白女王提出了拯救格林的计划,这个计划梅贝尔也知情,白女王同意了拯救计划,我们不知道白女王听到这两个计划的顺序,但他们明显是冲突的 7可能是人为,可能是自发,舞台觉醒了自我意识呼唤着格林的爱,同时在梅贝尔的指引下格林也朝着舞台进发,一场死斗在所难免,可以推测,在夺取舞台能力的结局中,诺登执行了红女王的拯救计划,舍身为格林断后,使其在爱丽丝01,即现在的红偶像的帮助下回到现实。在舞台与格林合一的bad end中,诺登执行了梅贝尔提出的独占计划,该结局中诺登辅佐着通过合体得到创作能力的格林与奈亚进行斗争,并且前往世界尽头来逃避一切纷争和毁灭,顺便一提,我觉得这结局也不算坏,白女王很可能会确保格林在融合中占据主导,此时格林成为了名副其实的支配者,和白女王的结合甚至能和奈亚势均力敌,不过寿司在采访中提到执着于爱丽丝身份的奈亚无法发挥全力就是了,毫无疑问这时的格林是目前为止的(格林)战力巅峰。 这就是冬之钟里发生的主要事件了,下面我将对事件的主要参与者,红白女王和虚无的少女进行分析。 首先是参与程度较低的梅贝尔梅贝尔虽然入局较浅,但却是格林的引导者,并帮助拖延了一下奈亚,也是她告诉我们打破这一循环只能正面和舞台装置对决,那么她的目的是什么呢? 首先,梅贝尔在混沌迷宫中会直接提及支配者间不可避免将爆发战争,并且导致阿撒托斯的苏醒毁灭一切,而身份不是支配者却可能得到支配者之器的格林,才能发动不会惊醒阿撒托斯的箱庭战争,这可能是她帮助格林的首要目的 其次,梅贝尔是个不可救药的收藏狂,她的箱庭是个巨大的垃圾场,什么都有,因此她也想把格林培养成一个完美收藏品或者棋子 最后,在个人感情上,很难定论梅贝尔到底产生了多少感情,她自称对永无止境的劣质戏剧循环感到厌倦,才会帮助格林创造自己的故事,但又在背叛剧情中声称想要让格林得到更高的器随后利用他,最后如果试图救她又会说自己涌现出了一些对格林的爱,由于信息过少,很难知道她到底觉醒了多少感情。 不过可以肯定的是,如果是梅贝尔真有意背叛动机是不充分的,如果她只需要格林成为拥有支配者之器的棋子,那么独占和拯救计划都能实现这个目的,并且由于白女王看着,融合后大概率是格林占主导地位,无非是好不好操控的问题,因此猜测梅贝尔实际上是真心帮助格林,只是在用激将法,或者习惯性毒舌。 冬之钟的棋局不管怎么走梅贝尔都不是输家,如果独占计划成功,白女王和格林则会成为一股对抗奈亚甚至其他支配者的强大力量,如果拯救计划成功,格林则会成为一个有着支配者的器,却对大部分支配者恨之入骨的棋子或潜在盟友,不论哪个结果都对梅贝尔阻止阿撒托斯苏醒的目的有利,而她的损失不过是万千分身中的一个而已 随后则是红之女王,尽管游戏中没有直接说红女王就是一代的爱丽丝01,以及茶会中的爱丽丝,但大量证据表明她和爱丽丝01有着千丝万缕的关系,爱丽丝01也极有可能就是茶会爱丽丝,所以本视频采纳这一说法,可以说最早钻进人类皮套的她是人性化最深的支配者,她人类的一面深爱格林,但又恐惧支配者的一面暴露,因此自觉配不上格林,甚至认为是自己导致了格林的一切悲剧,顺便一提关于茶会以及更早时期的资料实在太少,所以我们现在对这段剧情的讨论很可能是不完整甚至有较大误解的,因此在此我只能尽可能保守地做一些推测,由于支配者本性难以剥离,在她身上有着强烈的自毁倾向,想爱,却又自觉没有资格去爱,因此她只能用紫餐的方式填补内心的负罪感,H结局中,她以几乎自杀的方式当着奈亚的面帮助格林逃离了奈亚的掌控,可以说为了格林,红女王自降身份把自己变成了棋子,而且是必死的棋子,只为了能在后续将奈亚一军。 等待着这个叛徒的是什么结局,我们只能发挥一下想象力了 最后则是冬之钟的核心人物,白之女王诺登诺登的原型之一是爱丽丝梦游仙境的白兔先生,白兔最明显的元素就是他永远匆忙的样子和怀表,这点也在诺登身上得以体现,白女王作为这场繁殖游戏事实上的管理者,为了协调任性的演员们可谓操碎了心,在轮回的最后,台上的演员几乎全部是她的子嗣(兔子可是繁殖力非常强的生物),可以猜测在制定剧本和排练上她也得下不少功夫,而dlc3的核心意象,齿轮,其实可以说既指着暗黑舞台的齿轮带动了戏码的上演,也指着诺登怀表的齿轮,诺登就是那个负责在指针快点到达终点前让齿轮倒转,重新开始计时的人,这也是为何她会在结局中说为齿轮停止感到害怕,让齿轮转动是她的职责,在她的内心深处或许也有着对无尽循环中格林真正爱上自己并一起逃到世界尽头的希望,但最后她选择成全格林真正的爱,而放弃管理齿轮的职责则意味着她与自己支配者的身份完全决裂,将一切奉献给人类的爱。此外,诺登的支配者原型则是所谓的幻梦境之主,这或许解释了为何是她在实际上管理着二代这个巨大的梦境 我在尸龙的人物解析说,类似尸龙的独占欲在红白女王身上也出现过,但红女王由于害怕自己的支配者本性选择放手,那么白女王呢?在h结局中,梅贝尔被古兰(推测,也可能是奈亚)针对性的陷阱解决,但拥有舞台权限的红白女王应该不受影响,红女王为了最后拯救格林必须蛰伏,因此辅助格林对抗古兰以及奈亚的任务只能交给白女王,但即使在此时此刻,白女王依旧有着独占格林的选项,如果她控制或者协助舞台装置强迫和格林融合,就可以抢先一步独占所有支配者都垂涎的格林,但如果把舞台的改变能力给予格林,那么失去王冠和舞台的诺登则会失去自己在棋局上的几乎所有棋子,面对这种选择,诺登将选择权给了格林,不能说她是完全无私的,但面对这样的诱惑,她也会尊重格林的选择,这不得不说是非常伟大的爱 可以说白女王是一个有着两面性的角色,她支配者的一面始终对格林有着独占欲,但她人性的一面始终压抑着这些黑暗的感情,她是一个徘徊于人与神界限的存在,但无论如何,她都尊重并支持着格林的选择,所以她闪耀着人性光辉的一面始终是压过支配者的黑暗一面的。 让我们给这幕疯狂剧场的落幕做一个总结吧,这局棋是红白女王和梅贝尔设下的,目的是为了让格林得到古兰的改变能力并逃离奈亚的箱庭,其中没有舞台权限的梅贝尔负责引导格林,红女王则在最后帮助得到改变能力的格林摆脱奈亚掌控,而白女王则有着最关键的决策权,即是否利用舞台独占格林,但她最后将决定权给了格林,而格林真正的选择应该是夺取舞台的改变能力,因此最后白女王舍弃了一切帮助格林逃离崩坏的舞台。 这场棋局中,梅贝尔横竖不亏,红女王陷入必死之局,最关键的棋手就是白女王,只要她愿意,随时可以下出必赢的一着,但最后她依旧选择了放弃自己的棋子,把终结棋局的希望留给了格林 在经历如此多的牺牲之后,格林终于从棋子升为了棋手,只是不知道他又会下出怎样的一着

    ]]> 游戏杂谈 @@ -7436,98 +7516,6 @@ Inexpensive Disk)由美国加州大学伯克利分校提出。
    black souls - - 基于斯坦福cs106b的c++数据结构笔记 - /2023/09/29/cs106b%E6%80%BB%E5%92%8C%E7%AC%94%E8%AE%B0/ - 一些查找和排序算法

    -

    二分查找法 图片 最坏情况:log2n 寻找最小排序 图片 向前插入算法 图片

    -

    合并算法接受两个排序的 列出并将它们组合成一个 排序列表。 ● 虽然两个列表都是非空的,但比较它们的 第一要素。 删除较小的元素 并将其附加到输出。 ● 一旦一个列表为空,添加所有元素 另一个列表输出。 ● 它运行时间为 O(n),其中 n 是总数 合并的元素数量。 图片 无限递归后的合并算法 图片 复杂度:nlog2n

    -

    容器类

    -

    set(集合):无序不允许重复的容器类,可以添加删除元素 You can add a value to a Set by writing set += value; s. ● You can remove a value from a Set by writing set -= value; ● You can check if a value exists in a Set by writing set.contains(value)map(键值对的集合) 如果没有对应key的value,返回默认值(见定义文件) `vector vector的remove根据移除元素的索引有1-n的复杂度,移除尾部为O(1),如果不在意索引,可以交换要移除元素和尾部元素再移除

    -

    哈希表

    -

    哈希表的负载因子α表示元素和表格键数量的比,决定了查找速度

    -

    检查表中是否存在元素

    -

    ● 计算元素的散列码。 ● 跳转到表格中的那个位置。 ● 向前扫描——必要时环绕——直到项目或一个 发现空插槽。

    -

    将元素插入表中

    -

    ● 如果项目已经存在,什么也不做。 ● 否则,跳转到元素哈希码给定的槽。 向前走——必要时环绕——直到一个空白点或 找到墓碑插槽。 然后,将项目放在那里。

    -

    从表中删除一个元素

    -

    ● 跳转到由元素的散列码给定的槽。 ● 向前走——必要时环绕——直到物品或 发现空插槽。 如果找到该项目,请将其替换为 墓碑。

    -

    “罗宾汉哈希表”

    -
      -
    • 如果插入的值比其将插入的位置的值距离索引更远,则替换插入值和当前值
    • -
    • 删除值时,将后其离原键远的元素前移
    • -
    • ★ 罗宾汉哈希一览 ★
    • -
    • 检查表中是否存在元素:
    • -
    • ● 跳转到表中由元素的散列码给出的位置。
    • -
    • ● 向前扫描——如有必要环绕——记录有多少步 你拿走了。 当您找到该项目、找到一个空白槽或找到一个 离家更近的空位比你走的步数还多。
    • -
    • 将元素插入表中:
    • -
    • ● 如果该元素已在表中,则什么也不做。
    • -
    • ● 跳转到由元素的散列码给出的表槽。 向前扫描 - 换行 如有必要,四处走走——记录所走的步数。 如果你找到一个 空插槽,将元素放在那里。 否则,如果当前插槽已满并且 比您插入的元素更靠近家,将要插入的项目放在那里, 替换那个位置的元素,然后继续插入,就好像你 正在插入被置换的元素。
    • -
    • 从表中删除一个元素:
    • -
    • ● 跳转到由元素的散列码给定的槽。
    • -
    • ● 向前走——如有必要,环绕——直到物品或空槽被放置 成立。 如果找到该项目,请将其删除。 然后,继续前进——包裹 around as necessary – 将表中的元素向后移动一个槽位,直到 找到空插槽或位于其原始位置的项目
    • -
    -

    string类

    -

    str::npos表示容器的最后一个成员位置 if (s.find("e") != string::npos) //find函数找不到时返回npos if s in str: string obj; obj.substr(int pos) //pos为要包含的第一个字符串的位置 std::string a = "0123456789abcdefghij";

    -

    // count is npos, returns [pos, size())
    [std::string](http://en.cppreference.com/w/cpp/string/basic_string) sub1 = a.substr(10);
    [std::cout](http://en.cppreference.com/w/cpp/io/cout) << sub1 << '\n';

    // both pos and pos+count are within bounds, returns [pos, pos+count)
    [std::string](http://en.cppreference.com/w/cpp/string/basic_string) sub2 = a.substr(5, 3);
    [std::cout](http://en.cppreference.com/w/cpp/io/cout) << sub2 << '\n';

    // pos is within bounds, pos+count is not, returns [pos, size())
    [std::string](http://en.cppreference.com/w/cpp/string/basic_string) sub4 = a.substr(a.size()-3, 50);
    // this is effectively equivalent to
    // std::string sub4 = a.substr(17, 3);
    // since a.size() == 20, pos == a.size()-3 == 17, and a.size()-pos == 3

    [std::cout](http://en.cppreference.com/w/cpp/io/cout) << sub4 << '\n';

    try {
    // pos is out of bounds, throws
    [std::string](http://en.cppreference.com/w/cpp/string/basic_string) sub5 = a.substr(a.size()+3, 50);
    [std::cout](http://en.cppreference.com/w/cpp/io/cout) << sub5 << '\n';
    } catch(const [std::out_of_range](http://en.cppreference.com/w/cpp/error/out_of_range)& e) {
    [std::cout](http://en.cppreference.com/w/cpp/io/cout) << "pos exceeds string size\n";
    }
    }
    输出:
    abcdefghij
    567
    hij
    pos exceeds string size
    -

    `replace和insert str1.insert(start, str2) str1.replace(start, length, str2)

    -

    一些实现

    -

    优先队列

    -
    # include "HeapPQueue.h"
    using namespace std;

    HeapPQueue::HeapPQueue() {
    elems = new DataPoint[INITIAL_SIZE] {};
    for (int i=0;i<INITIAL_SIZE;i++)
    {
    elems[i].weight=0;
    }
    allocatedSize=INITIAL_SIZE;
    }

    HeapPQueue::~HeapPQueue() {
    delete [] elems;
    }

    int HeapPQueue::size() const {
    return logicalSize;
    }

    bool HeapPQueue::isEmpty() const {
    return logicalSize==0;
    }

    void HeapPQueue::enqueue(const DataPoint& data) {
    if (logicalSize+1<allocatedSize)
    {
    if (logicalSize==0)
    {
    elems[1]=data;
    logicalSize++;
    }
    else
    {
    logicalSize++;
    int i=1;
    while (data.weight>elems[i].weight && i<=logicalSize && elems[i].weight!=0)
    {
    i++;
    }
    if (i<logicalSize)
    {
    DataPoint temp=elems[i];
    elems[i]=data;
    for(i;i<logicalSize;i++)
    {
    DataPoint temp_plus=elems[i+1];
    elems[i+1]=temp;
    temp=temp_plus;

    }
    }
    else
    {
    elems[i]=data;
    }

    }
    }
    }

    DataPoint HeapPQueue::peek() const {
    return elems[logicalSize];
    }

    DataPoint HeapPQueue::dequeue() {
    DataPoint to_return=elems[1];
    if(!isEmpty())
    {

    for (int i=1;i<logicalSize;i++)
    {
    elems[i]=elems[i+1];
    }
    elems[logicalSize]={};
    logicalSize--;
    }
    return to_return;
    }

    -

    计数排序

    -

    首先算出最大值,然后用一个数组的索引存储待排序数组的成员,其索引对应值存储出现次数,然后用两个同步的for循环和递增的next参数表示排序中的索引值来进行排序(也就是重新赋值)

    -
    /* Given a Vector<int>, returns the largest number in that Vector. */
    int maxOf(const Vector<int>& values) {
    /* Bounds-check inputs. */
    if (values.isEmpty()) {
    error("Can't find the maximum of no values.");
    }

    int result = values[0];
    for (int i = 1; i < values.size(); i++) {
    result = max(result, values[i]);
    }
    return result;
    }

    /* Given a list of numbers, creates a histogram from those numbers. */
    Vector<int> histogramFor(const Vector<int>& values) {
    /* Create a histogram with the right number of slots. Initially, all values
    * in the histogram will be zero.
    */
    Vector<int> histogram(maxOf(values) + 1);

    /* Scan across the input vector, incrementing the histogram values. */
    for (int value: values) {
    histogram[value]++;
    }

    return histogram;
    }

    void countingSort(Vector<int>& values) {
    /* Edge Case: If the array is empty, then it's already sorted. This is
    * needed because we can't take the maximum value of an empty vector.
    */
    if (values.isEmpty()) {
    return;
    }

    /* Form the histogram. */
    auto histogram = histogramFor(values);

    /* Scan across the histogram writing out the appropriate number of copies
    * of each value. We track the index of the next free spot to write to,
    * as it varies based on how many items we've written out so far.
    */
    int next = 0;
    for (int value = 0; value < histogram.size(); value++) {
    /* Write out the right number of copies. */
    for (int copy = 0; copy < histogram[value]; copy++) {
    values[next] = value;
    next++;
    }
    }
    }

    -

    错题集

    -

    递归的效率优化

    -

    每次递归都会创造所有变量的临时复制 基于递归的这种性质,它会需要巨大的时间和空间来完成任务,并且会造成算力上的浪费。 通过记忆表机制能部分解决这个问题,方法是每次递归的返回值都会按索引存入一个表格,并且每次递归前查询表格中是否有结果,这样可以让每个临时副本的运算结果能被所有函数共享。

    -

    递归计算给定元素的不同结构哈夫曼树的数量

    -

    对每个给定元素集来说,首先要做到是确定根节点元素是第几个大的元素,确定之后,左子树和右子树的元素数也随之确定,在此之后分别对左节点和右节点作为根节点做同样的递归

    -

    int numBSTsOfSize(int n) {

    /* Base case: There’s only one tree of size 0, namely, the empty BST. */
    if (n == 0) return 1;

    /* Recursive case: Imagine all possible ways to choose a root and build the
    * left and right subtrees.
    */
    int result = 0;

    /* Put the the nodes at indices 0, 1, 2, ..., n-1 up at the root. */
    for (int i = 0; i < n; i++) {
    /* Each combination of a BST of i elements and a BST of n - 1 - i elements
    * can be used to build one BST of n elements. The number of pairs of
    * trees we can make this way is given by the product of the number of
    * trees of each type.
    */
    result += numBSTsOfSize(i) * numBSTsOfSize(n - 1 - i);
    }

    return result;
    }
    -

    递归解决吃巧克力问题

    -

    求出吃法数量

    -
    if (numSquares<0)
    {
    error("输入数据不能为负数");
    }
    else if (numSquares<=1)
    {
    return 1;
    }
    else
    {
    return numWaysToEat(numSquares-1)+numWaysToEat(numSquares-2);
    }
    -

    打印每种吃法

    -

    `需要一个辅助向量储存历史记录

    -
    /* Print all ways to eat numSquares more squares, given that we've
    * already taken the bites given in soFar.
    */
    void printWaysToEatRec(int numSquares, const Vector<int>& soFar) {
    /* Base Case: If there are no squares left, the only option is to use
    * the bites we've taken already in soFar.
    */
    if (numSquares == 0) {
    cout << soFar << endl;
    }
    /* Base Case: If there is one square lfet, the only option is to eat
    * that square.
    */
    else if (numSquares == 1) {
    cout << soFar + 1 << endl;
    }
    /* Otherwise, we take take bites of size one or of size two. */
    else {
    printWaysToEatRec(numSquares - 1, soFar + 1);
    printWaysToEatRec(numSquares - 2, soFar + 2);
    }
    }

    void printWaysToEat(int numSquares) {
    if (numSquares < 0) {
    error("You owe me some chocolate!");
    }

    /* We begin without having made any bites. */
    printWaysToEatRec(numSquares, {});
    }
    -

    递归解决翻煎饼问题

    -
    bool isSorted(Stack<double> pancakes) {
    double last = -1; // No pancakes have negative size;

    while (!pancakes.isEmpty()) {
    /* Check the next pancake. */
    double next = pancakes.pop();
    if (next < last) {
    return false;
    }

    last = next;
    }

    /* Pancakes are in increasing order! */
    return true;
    }

    /* Given a stack of pancakes and a flip size, flips that many pancakes
    * on the top of the stack.
    */
    Stack<double> flip(Stack<double> pancakes, int numToFlip) {
    /* Take the top pancakes off the stack and run them into a queue.
    * This preserves the order in which they were removed.
    */
    Queue<double> buffer;
    for (int i = 0; i < numToFlip; i++) {
    buffer.enqueue(pancakes.pop());
    }

    /* Move the pancakes back. */
    while (!buffer.isEmpty()) {
    pancakes.push(buffer.dequeue());
    }

    return pancakes;
    }

    Optional<Vector<int>> sortStack(Stack<double> pancakes, int numFlips) {
    /* Base Case: If the stack is sorted, great! We're done, and no flips
    * were needed.
    */
    if (isSorted(pancakes)) {
    return { }; // No flips
    }
    /* Base Case: If the stack isn't sorted and we're out of flips, then
    * there is no way to sort things.
    */
    else if (numFlips == 0) {
    return Nothing;
    }
    /* Recursive Case: The stack isn't sorted and we still have flips left.
    * The next flip could flip 1, 2, 3, ..., or all N of the pancakes.
    * Try each option and see whether any of them work.
    */
    for (int numToFlip = 1; numToFlip <= pancakes.size(); numToFlip++) {
    /* Make the flip and see if it works. */
    auto result = sortStack(flip(pancakes, numToFlip), numFlips - 1);
    if (result != Nothing) {
    /* The result holds all the remaining flips but doesn't know about
    * the flip we just did. Insert that flip at the beginning.
    */
    result.value().insert(0, numToFlip);
    return result;
    }
    }

    /* If we're here, then no matter which flip we make first, we cannot
    * get the pancakes sorted. Give up.
    */
    return Nothing;
    }
    -

    递归解决天平问题

    -
    bool isMeasurableRec(int amount, const Vector<int>& weights, int index) {
    if (index == weights.size()) {
    return amount == 0;
    } else {
    return isMeasurableRec(amount, weights, index + 1) ||
    isMeasurableRec(amount + weights[index], weights, index + 1) ||
    isMeasurableRec(amount - weights[index], weights, index + 1);
    }
    }

    bool isMeasurable(int amount, const Vector<int>& weights) {
    return isMeasurableRec(amount, weights, 0);
    }
    -

    想象一下,我们首先将要测量的数量(称为 n )放在天平的左侧。 这使得规模上的不平衡等于 n 。 想象一下,有某种方法可以测量 n 。 如果我们一次将一个重量放在秤上,我们可以查看第一个重量的放置位置(假设它的重量为 w )。 它必须:

    -
      -
    • 向左走,使规模上的净不平衡 n + w ,或
    • -
    • 向右走,使规模上的净不平衡 n – w ,或
    • -
    • 根本不习惯,留下净不平衡 n
    • -
    -

    如果确实有可能测量 n ,那么这三个选项之一必须是实现它的方法,即使我们不知道它是哪一个。 然后我们要问的问题是,是否有可能使用剩余的权重来衡量新的净失衡——我们可以递归地确定! 另一方面,如果无法测量 n ,那么无论我们选择哪个选项,我们都会发现没有办法使用剩余的权重来使一切平衡!

    -

    如果我们递归地进行,我们在这里,我们需要考虑我们的基本情况。 我们可以选择的选项有很多。 一个简单的方法如下:假设我们根本没有任何重量,我们被要求查看是否可以不使用重量来测量某些重量。 在什么情况下我们可以这样做? 好吧,如果我们称重的东西有一个非零重量,我们就不可能测量它——把它放在秤上会使它倾斜到某一边,但这并不能告诉我们它有多少重量。 另一方面,如果我们称量的东西是完全失重的,那么把它放在秤上也不会导致它倾斜,让我们相信它确实是失重的! 因此,作为我们的基本情况,我们会说当我们减少到没有剩余权重时, ,我们可以精确测量n 如果 n = 0 。 考虑到这一点,这是我们的代码:

    -

    递归解决找零问题

    -

    不使用记忆的情况

    -

    `从第一个硬币开始遍历,并穷举它的所有枚数,将其作为下一枚硬币的参数传递

    -
    int fewestCoinsFor(int cents, const Set<int>& coins) {
    /* Can't have a negative number of cents. */
    if (cents < 0) {
    error("You owe me money, not the other way around!");
    }
    /* Base case: You need no coins to give change for no cents. */
    else if (cents == 0) {
    return 0;
    }
    /* Base case: No coins exist. Then it's not possible to make the
    * amount. In that case, give back a really large value as a
    * sentinel.
    */
    else if (coins.isEmpty()) {
    return cents + 1;
    }
    /* Recursive case: Pick a coin, then try using each distinct number of
    * copies of it that we can.
    */
    else {
    /* The best we've found so far. We initialize this to a large value so
    * that it's replaced on the first iteration of the loop. Do you see
    * why cents + 1 is a good choice?
    */
    int bestSoFar = cents + 1;
    /* Pick a coin. */
    int coin = coins.first();
    /* Try all amounts of it. */
    for (int copies = 0; copies * coin <= cents; copies++) {
    /* See what happens if we make this choice. Once we use this
    * coin, we won't use the same coin again in the future.
    */
    int thisChoice = copies + fewestCoinsFor(cents - copies * coin,
    coins - coin);
    /* Is this better than what we have so far? */
    if (thisChoice < bestSoFar) {
    bestSoFar = thisChoice;
    }
    }
    /* Return whatever worked best. */
    return bestSoFar;
    }
    }

    -

    使用记忆进行优化

    -
    /* How few coins are needed to make the total, given that we can only use
    * coins from index startIndex and onward?
    */
    int fewestCoinsRec(int cents, const Vector<int>& coins, int startIndex,Grid<int>& memo) {
    /* Base case: You need no coins to give change for no cents. */
    if (cents == 0) {
    return 0;
    }
    /* Base case: No coins exist. Then it's not possible to make the
    * amount. In that case, give back a really large value as a
    * sentinel.
    */
    else if (startIndex == coins.size()) {
    return cents + 1;
    }
    /* Base case: We already know the answer. */
    else if (memo[cents][startIndex] != -1) {
    return memo[cents][startIndex];
    }
    /* Recursive case: Pick a coin, then try using each distinct number of
    * copies of it that we can.
    */
    else {
    /* The best we've found so far. We initialize this to a large value so
    * that it's replaced on the first iteration of the loop. Do you see
    * why cents + 1 is a good choice?
    */
    int bestSoFar = cents + 1;

    /* Pick a coin. */
    int coin = coins[startIndex];

    /* Try all amounts of it. */
    for (int copies = 0; copies * coin <= cents; copies++) {
    /* See what happens if we make this choice. Once we use this
    * coin, we won't use the same coin again in the future.
    */
    int thisChoice = copies + fewestCoinsRec(cents - copies * coin,
    coins, startIndex + 1,
    memo);

    /* Is this better than what we have so far? */
    if (thisChoice < bestSoFar) {
    bestSoFar = thisChoice;
    }
    }

    /* Return whatever worked best. */
    memo[cents][startIndex] = bestSoFar;
    return bestSoFar;
    }
    }

    int fewestCoinsFor(int cents, const Set<int>& coins) {
    /* Can't have a negative number of cents. */
    if (cents < 0) {
    error("You owe me money, not the other way around!");
    }

    /* Convert from a Set<int> to a Vector<int> so we have a nice ordering
    * on things.
    */
    Vector<int> coinVec;
    for (int coin: coins) {
    coinVec += coin;
    }

    /* Build our memoization table. Since the number of cents left ranges from
    * 0 to cents, we need cents+1 rows. Since the start index of the coin
    * ranges from 0 to coins.size(), we make coins.size() + 1 columns.
    *
    * -1 is used as a sentinel to indicate "nothing has been computed here
    * yet."
    */
    Grid<int> memo(cents + 1, coins.size() + 1, -1);

    /* Now ask how many coins are needed to make the total, using any coins
    * from index 0 onward.
    */
    return fewestCoinsRec(cents, coinVec, 0, memo);
    }
    -

    递归穷举付账单

    -

    递归机制:对第一个人来说,0-total所有金额都会付一遍,随后传递给下一个人,当只有一人时,付清所有余额并打印账单 传递参数:string,int的映射存储目前为止的账单,string集合存储所有付账者

    -
    void listPossiblePaymentsRec(int total, const Set<string>& people,const Map<string, int>& payments) {
    /* Base case: if there's one person left, they have to pay the whole bill. */
    if (people.size() == 1) {
    Map<string, int> finalPayments = payments;
    finalPayments[people.first()] = total;
    cout << finalPayments << endl;
    }
    /* Recursive case: The first person has to pay some amount between 0 and the
    * total amount. Try all of those possibilities.
    */
    else {
    for (int payment = 0; payment <= total; payment++) {
    /* Create a new assignment of people to payments in which this first
    * person pays this amount.
    */
    Map<string, int> updatedPayments = payments;
    updatedPayments[people.first()] = payment;
    listPossiblePaymentsRec(total - payment, people - people.first(),updatedPayments);
    }
    }
    }
    void listPossiblePayments(int total, const Set<string>& people) {
    /* Edge cases: we can't pay a negative total, and there must be at least one
    * person.
    */
    if (total < 0) error("Guess you're an employee?");
    if (people.isEmpty()) error("Dine and dash?");
    listPossiblePaymentsRec(total, people, {});
    }
    -

    递归寻找完全平方数列

    -

    主要参数为sofar——用于存储目前的序列和一个set用于存储还没放入数列的数字,`确保这两者同时被传递,且其并集为所有数字

    -
    Optional<Vector<int>> findSquareSequence(int n) {
    /*Validate input.*/
    if (n < 0) {
    error("Don't be so negative!");
    }

    /* Build a set of the numbers 1, 2, 3, ..., n. */
    Set<int> options;
    for (int i = 1; i <= n; i++) {
    options += i;
    }
    return findSequenceRec(options, { });
    }

    Optional<Vector<int>> findSequenceRec(const Set<int>& unused,
    const Vector<int>& soFar) {
    /*Base Case: If all numbers are used, we have our sequence!*/
    if (unused.isEmpty()) {
    return soFar;
    }

    /* Recursive Case: Some number comes next. Try each of them and see which
    * one we should pick.
    */
    for (int next: unused) {
    /* We can use this if either
    *
    * 1. the sequence is empty, so we're first in line, or
    * 2. the sequence is not empty, but we sum to a perfect square
    * with the previous term.
    */
    if (soFar.isEmpty() ||
    isPerfectSquare(next + soFar[soFar.size() - 1])) {
    /* See what happens if we extend with this number. */
    auto result = findSequenceRec(unused - next, soFar + next);
    if (result != Nothing) {
    return result;
    }
    }
    }

    /* Tried all options and none of them worked. Oh well! */
    return Nothing;
    }

    -

    汉诺塔递归

    -

    假设有三座汉诺塔,start ,temp ,finish 对n层的汉诺塔问题,先考虑n-1层的,随后考虑n-2层,到最后只需要考虑两层问题,两层的汉诺塔非常容易解决,起点为start,终点是temp,临时塔为finish,最后我们得到temp上的两层汉诺塔 这时将start的3移动到finish塔,这时只要将两层汉诺塔转移到finish则完成了三层汉诺塔,这个过程中的起点为temp,终点是finish,临时塔是start 以此类推,四层塔基于三层塔,n层塔基于n-1塔,汉诺塔问题解决

    -
    int moveTower(int numDisks, char start, char finish, char temp) {
    if (numDisks == 0) {
    return 0;
    } else {
    int movesOne = moveTower(numDisks - 1, start, temp, finish);
    moveSingleDisk(start, finish);
    int movesTwo = moveTower(numDisks - 1, temp, finish, start);

    return 1 + movesOne + movesTwo;
    }
    }
    -]]> - - 课程笔记 - 数据结构与算法 - - - 课程笔记 - 数据结构与算法 - 斯坦福 - c++ - - 基于c++ primer plus的读书笔记 /2023/10/05/cpp%20primer%20plus%E6%80%BB%E5%92%8C/ @@ -7637,8 +7625,100 @@ Inexpensive Disk)由美国加州大学伯克利分校提出。
    其他 - c++ 读书笔记 + c++ + +
    + + 基于斯坦福cs106b的c++数据结构笔记 + /2023/09/29/cs106b%E6%80%BB%E5%92%8C%E7%AC%94%E8%AE%B0/ + 一些查找和排序算法

    +

    二分查找法 图片 最坏情况:log2n 寻找最小排序 图片 向前插入算法 图片

    +

    合并算法接受两个排序的 列出并将它们组合成一个 排序列表。 ● 虽然两个列表都是非空的,但比较它们的 第一要素。 删除较小的元素 并将其附加到输出。 ● 一旦一个列表为空,添加所有元素 另一个列表输出。 ● 它运行时间为 O(n),其中 n 是总数 合并的元素数量。 图片 无限递归后的合并算法 图片 复杂度:nlog2n

    +

    容器类

    +

    set(集合):无序不允许重复的容器类,可以添加删除元素 You can add a value to a Set by writing set += value; s. ● You can remove a value from a Set by writing set -= value; ● You can check if a value exists in a Set by writing set.contains(value)map(键值对的集合) 如果没有对应key的value,返回默认值(见定义文件) `vector vector的remove根据移除元素的索引有1-n的复杂度,移除尾部为O(1),如果不在意索引,可以交换要移除元素和尾部元素再移除

    +

    哈希表

    +

    哈希表的负载因子α表示元素和表格键数量的比,决定了查找速度

    +

    检查表中是否存在元素

    +

    ● 计算元素的散列码。 ● 跳转到表格中的那个位置。 ● 向前扫描——必要时环绕——直到项目或一个 发现空插槽。

    +

    将元素插入表中

    +

    ● 如果项目已经存在,什么也不做。 ● 否则,跳转到元素哈希码给定的槽。 向前走——必要时环绕——直到一个空白点或 找到墓碑插槽。 然后,将项目放在那里。

    +

    从表中删除一个元素

    +

    ● 跳转到由元素的散列码给定的槽。 ● 向前走——必要时环绕——直到物品或 发现空插槽。 如果找到该项目,请将其替换为 墓碑。

    +

    “罗宾汉哈希表”

    +
      +
    • 如果插入的值比其将插入的位置的值距离索引更远,则替换插入值和当前值
    • +
    • 删除值时,将后其离原键远的元素前移
    • +
    • ★ 罗宾汉哈希一览 ★
    • +
    • 检查表中是否存在元素:
    • +
    • ● 跳转到表中由元素的散列码给出的位置。
    • +
    • ● 向前扫描——如有必要环绕——记录有多少步 你拿走了。 当您找到该项目、找到一个空白槽或找到一个 离家更近的空位比你走的步数还多。
    • +
    • 将元素插入表中:
    • +
    • ● 如果该元素已在表中,则什么也不做。
    • +
    • ● 跳转到由元素的散列码给出的表槽。 向前扫描 - 换行 如有必要,四处走走——记录所走的步数。 如果你找到一个 空插槽,将元素放在那里。 否则,如果当前插槽已满并且 比您插入的元素更靠近家,将要插入的项目放在那里, 替换那个位置的元素,然后继续插入,就好像你 正在插入被置换的元素。
    • +
    • 从表中删除一个元素:
    • +
    • ● 跳转到由元素的散列码给定的槽。
    • +
    • ● 向前走——如有必要,环绕——直到物品或空槽被放置 成立。 如果找到该项目,请将其删除。 然后,继续前进——包裹 around as necessary – 将表中的元素向后移动一个槽位,直到 找到空插槽或位于其原始位置的项目
    • +
    +

    string类

    +

    str::npos表示容器的最后一个成员位置 if (s.find("e") != string::npos) //find函数找不到时返回npos if s in str: string obj; obj.substr(int pos) //pos为要包含的第一个字符串的位置 std::string a = "0123456789abcdefghij";

    +

    // count is npos, returns [pos, size())
    [std::string](http://en.cppreference.com/w/cpp/string/basic_string) sub1 = a.substr(10);
    [std::cout](http://en.cppreference.com/w/cpp/io/cout) << sub1 << '\n';

    // both pos and pos+count are within bounds, returns [pos, pos+count)
    [std::string](http://en.cppreference.com/w/cpp/string/basic_string) sub2 = a.substr(5, 3);
    [std::cout](http://en.cppreference.com/w/cpp/io/cout) << sub2 << '\n';

    // pos is within bounds, pos+count is not, returns [pos, size())
    [std::string](http://en.cppreference.com/w/cpp/string/basic_string) sub4 = a.substr(a.size()-3, 50);
    // this is effectively equivalent to
    // std::string sub4 = a.substr(17, 3);
    // since a.size() == 20, pos == a.size()-3 == 17, and a.size()-pos == 3

    [std::cout](http://en.cppreference.com/w/cpp/io/cout) << sub4 << '\n';

    try {
    // pos is out of bounds, throws
    [std::string](http://en.cppreference.com/w/cpp/string/basic_string) sub5 = a.substr(a.size()+3, 50);
    [std::cout](http://en.cppreference.com/w/cpp/io/cout) << sub5 << '\n';
    } catch(const [std::out_of_range](http://en.cppreference.com/w/cpp/error/out_of_range)& e) {
    [std::cout](http://en.cppreference.com/w/cpp/io/cout) << "pos exceeds string size\n";
    }
    }
    输出:
    abcdefghij
    567
    hij
    pos exceeds string size
    +

    `replace和insert str1.insert(start, str2) str1.replace(start, length, str2)

    +

    一些实现

    +

    优先队列

    +
    # include "HeapPQueue.h"
    using namespace std;

    HeapPQueue::HeapPQueue() {
    elems = new DataPoint[INITIAL_SIZE] {};
    for (int i=0;i<INITIAL_SIZE;i++)
    {
    elems[i].weight=0;
    }
    allocatedSize=INITIAL_SIZE;
    }

    HeapPQueue::~HeapPQueue() {
    delete [] elems;
    }

    int HeapPQueue::size() const {
    return logicalSize;
    }

    bool HeapPQueue::isEmpty() const {
    return logicalSize==0;
    }

    void HeapPQueue::enqueue(const DataPoint& data) {
    if (logicalSize+1<allocatedSize)
    {
    if (logicalSize==0)
    {
    elems[1]=data;
    logicalSize++;
    }
    else
    {
    logicalSize++;
    int i=1;
    while (data.weight>elems[i].weight && i<=logicalSize && elems[i].weight!=0)
    {
    i++;
    }
    if (i<logicalSize)
    {
    DataPoint temp=elems[i];
    elems[i]=data;
    for(i;i<logicalSize;i++)
    {
    DataPoint temp_plus=elems[i+1];
    elems[i+1]=temp;
    temp=temp_plus;

    }
    }
    else
    {
    elems[i]=data;
    }

    }
    }
    }

    DataPoint HeapPQueue::peek() const {
    return elems[logicalSize];
    }

    DataPoint HeapPQueue::dequeue() {
    DataPoint to_return=elems[1];
    if(!isEmpty())
    {

    for (int i=1;i<logicalSize;i++)
    {
    elems[i]=elems[i+1];
    }
    elems[logicalSize]={};
    logicalSize--;
    }
    return to_return;
    }

    +

    计数排序

    +

    首先算出最大值,然后用一个数组的索引存储待排序数组的成员,其索引对应值存储出现次数,然后用两个同步的for循环和递增的next参数表示排序中的索引值来进行排序(也就是重新赋值)

    +
    /* Given a Vector<int>, returns the largest number in that Vector. */
    int maxOf(const Vector<int>& values) {
    /* Bounds-check inputs. */
    if (values.isEmpty()) {
    error("Can't find the maximum of no values.");
    }

    int result = values[0];
    for (int i = 1; i < values.size(); i++) {
    result = max(result, values[i]);
    }
    return result;
    }

    /* Given a list of numbers, creates a histogram from those numbers. */
    Vector<int> histogramFor(const Vector<int>& values) {
    /* Create a histogram with the right number of slots. Initially, all values
    * in the histogram will be zero.
    */
    Vector<int> histogram(maxOf(values) + 1);

    /* Scan across the input vector, incrementing the histogram values. */
    for (int value: values) {
    histogram[value]++;
    }

    return histogram;
    }

    void countingSort(Vector<int>& values) {
    /* Edge Case: If the array is empty, then it's already sorted. This is
    * needed because we can't take the maximum value of an empty vector.
    */
    if (values.isEmpty()) {
    return;
    }

    /* Form the histogram. */
    auto histogram = histogramFor(values);

    /* Scan across the histogram writing out the appropriate number of copies
    * of each value. We track the index of the next free spot to write to,
    * as it varies based on how many items we've written out so far.
    */
    int next = 0;
    for (int value = 0; value < histogram.size(); value++) {
    /* Write out the right number of copies. */
    for (int copy = 0; copy < histogram[value]; copy++) {
    values[next] = value;
    next++;
    }
    }
    }

    +

    错题集

    +

    递归的效率优化

    +

    每次递归都会创造所有变量的临时复制 基于递归的这种性质,它会需要巨大的时间和空间来完成任务,并且会造成算力上的浪费。 通过记忆表机制能部分解决这个问题,方法是每次递归的返回值都会按索引存入一个表格,并且每次递归前查询表格中是否有结果,这样可以让每个临时副本的运算结果能被所有函数共享。

    +

    递归计算给定元素的不同结构哈夫曼树的数量

    +

    对每个给定元素集来说,首先要做到是确定根节点元素是第几个大的元素,确定之后,左子树和右子树的元素数也随之确定,在此之后分别对左节点和右节点作为根节点做同样的递归

    +

    int numBSTsOfSize(int n) {

    /* Base case: There’s only one tree of size 0, namely, the empty BST. */
    if (n == 0) return 1;

    /* Recursive case: Imagine all possible ways to choose a root and build the
    * left and right subtrees.
    */
    int result = 0;

    /* Put the the nodes at indices 0, 1, 2, ..., n-1 up at the root. */
    for (int i = 0; i < n; i++) {
    /* Each combination of a BST of i elements and a BST of n - 1 - i elements
    * can be used to build one BST of n elements. The number of pairs of
    * trees we can make this way is given by the product of the number of
    * trees of each type.
    */
    result += numBSTsOfSize(i) * numBSTsOfSize(n - 1 - i);
    }

    return result;
    }
    +

    递归解决吃巧克力问题

    +

    求出吃法数量

    +
    if (numSquares<0)
    {
    error("输入数据不能为负数");
    }
    else if (numSquares<=1)
    {
    return 1;
    }
    else
    {
    return numWaysToEat(numSquares-1)+numWaysToEat(numSquares-2);
    }
    +

    打印每种吃法

    +

    `需要一个辅助向量储存历史记录

    +
    /* Print all ways to eat numSquares more squares, given that we've
    * already taken the bites given in soFar.
    */
    void printWaysToEatRec(int numSquares, const Vector<int>& soFar) {
    /* Base Case: If there are no squares left, the only option is to use
    * the bites we've taken already in soFar.
    */
    if (numSquares == 0) {
    cout << soFar << endl;
    }
    /* Base Case: If there is one square lfet, the only option is to eat
    * that square.
    */
    else if (numSquares == 1) {
    cout << soFar + 1 << endl;
    }
    /* Otherwise, we take take bites of size one or of size two. */
    else {
    printWaysToEatRec(numSquares - 1, soFar + 1);
    printWaysToEatRec(numSquares - 2, soFar + 2);
    }
    }

    void printWaysToEat(int numSquares) {
    if (numSquares < 0) {
    error("You owe me some chocolate!");
    }

    /* We begin without having made any bites. */
    printWaysToEatRec(numSquares, {});
    }
    +

    递归解决翻煎饼问题

    +
    bool isSorted(Stack<double> pancakes) {
    double last = -1; // No pancakes have negative size;

    while (!pancakes.isEmpty()) {
    /* Check the next pancake. */
    double next = pancakes.pop();
    if (next < last) {
    return false;
    }

    last = next;
    }

    /* Pancakes are in increasing order! */
    return true;
    }

    /* Given a stack of pancakes and a flip size, flips that many pancakes
    * on the top of the stack.
    */
    Stack<double> flip(Stack<double> pancakes, int numToFlip) {
    /* Take the top pancakes off the stack and run them into a queue.
    * This preserves the order in which they were removed.
    */
    Queue<double> buffer;
    for (int i = 0; i < numToFlip; i++) {
    buffer.enqueue(pancakes.pop());
    }

    /* Move the pancakes back. */
    while (!buffer.isEmpty()) {
    pancakes.push(buffer.dequeue());
    }

    return pancakes;
    }

    Optional<Vector<int>> sortStack(Stack<double> pancakes, int numFlips) {
    /* Base Case: If the stack is sorted, great! We're done, and no flips
    * were needed.
    */
    if (isSorted(pancakes)) {
    return { }; // No flips
    }
    /* Base Case: If the stack isn't sorted and we're out of flips, then
    * there is no way to sort things.
    */
    else if (numFlips == 0) {
    return Nothing;
    }
    /* Recursive Case: The stack isn't sorted and we still have flips left.
    * The next flip could flip 1, 2, 3, ..., or all N of the pancakes.
    * Try each option and see whether any of them work.
    */
    for (int numToFlip = 1; numToFlip <= pancakes.size(); numToFlip++) {
    /* Make the flip and see if it works. */
    auto result = sortStack(flip(pancakes, numToFlip), numFlips - 1);
    if (result != Nothing) {
    /* The result holds all the remaining flips but doesn't know about
    * the flip we just did. Insert that flip at the beginning.
    */
    result.value().insert(0, numToFlip);
    return result;
    }
    }

    /* If we're here, then no matter which flip we make first, we cannot
    * get the pancakes sorted. Give up.
    */
    return Nothing;
    }
    +

    递归解决天平问题

    +
    bool isMeasurableRec(int amount, const Vector<int>& weights, int index) {
    if (index == weights.size()) {
    return amount == 0;
    } else {
    return isMeasurableRec(amount, weights, index + 1) ||
    isMeasurableRec(amount + weights[index], weights, index + 1) ||
    isMeasurableRec(amount - weights[index], weights, index + 1);
    }
    }

    bool isMeasurable(int amount, const Vector<int>& weights) {
    return isMeasurableRec(amount, weights, 0);
    }
    +

    想象一下,我们首先将要测量的数量(称为 n )放在天平的左侧。 这使得规模上的不平衡等于 n 。 想象一下,有某种方法可以测量 n 。 如果我们一次将一个重量放在秤上,我们可以查看第一个重量的放置位置(假设它的重量为 w )。 它必须:

    +
      +
    • 向左走,使规模上的净不平衡 n + w ,或
    • +
    • 向右走,使规模上的净不平衡 n – w ,或
    • +
    • 根本不习惯,留下净不平衡 n
    • +
    +

    如果确实有可能测量 n ,那么这三个选项之一必须是实现它的方法,即使我们不知道它是哪一个。 然后我们要问的问题是,是否有可能使用剩余的权重来衡量新的净失衡——我们可以递归地确定! 另一方面,如果无法测量 n ,那么无论我们选择哪个选项,我们都会发现没有办法使用剩余的权重来使一切平衡!

    +

    如果我们递归地进行,我们在这里,我们需要考虑我们的基本情况。 我们可以选择的选项有很多。 一个简单的方法如下:假设我们根本没有任何重量,我们被要求查看是否可以不使用重量来测量某些重量。 在什么情况下我们可以这样做? 好吧,如果我们称重的东西有一个非零重量,我们就不可能测量它——把它放在秤上会使它倾斜到某一边,但这并不能告诉我们它有多少重量。 另一方面,如果我们称量的东西是完全失重的,那么把它放在秤上也不会导致它倾斜,让我们相信它确实是失重的! 因此,作为我们的基本情况,我们会说当我们减少到没有剩余权重时, ,我们可以精确测量n 如果 n = 0 。 考虑到这一点,这是我们的代码:

    +

    递归解决找零问题

    +

    不使用记忆的情况

    +

    `从第一个硬币开始遍历,并穷举它的所有枚数,将其作为下一枚硬币的参数传递

    +
    int fewestCoinsFor(int cents, const Set<int>& coins) {
    /* Can't have a negative number of cents. */
    if (cents < 0) {
    error("You owe me money, not the other way around!");
    }
    /* Base case: You need no coins to give change for no cents. */
    else if (cents == 0) {
    return 0;
    }
    /* Base case: No coins exist. Then it's not possible to make the
    * amount. In that case, give back a really large value as a
    * sentinel.
    */
    else if (coins.isEmpty()) {
    return cents + 1;
    }
    /* Recursive case: Pick a coin, then try using each distinct number of
    * copies of it that we can.
    */
    else {
    /* The best we've found so far. We initialize this to a large value so
    * that it's replaced on the first iteration of the loop. Do you see
    * why cents + 1 is a good choice?
    */
    int bestSoFar = cents + 1;
    /* Pick a coin. */
    int coin = coins.first();
    /* Try all amounts of it. */
    for (int copies = 0; copies * coin <= cents; copies++) {
    /* See what happens if we make this choice. Once we use this
    * coin, we won't use the same coin again in the future.
    */
    int thisChoice = copies + fewestCoinsFor(cents - copies * coin,
    coins - coin);
    /* Is this better than what we have so far? */
    if (thisChoice < bestSoFar) {
    bestSoFar = thisChoice;
    }
    }
    /* Return whatever worked best. */
    return bestSoFar;
    }
    }

    +

    使用记忆进行优化

    +
    /* How few coins are needed to make the total, given that we can only use
    * coins from index startIndex and onward?
    */
    int fewestCoinsRec(int cents, const Vector<int>& coins, int startIndex,Grid<int>& memo) {
    /* Base case: You need no coins to give change for no cents. */
    if (cents == 0) {
    return 0;
    }
    /* Base case: No coins exist. Then it's not possible to make the
    * amount. In that case, give back a really large value as a
    * sentinel.
    */
    else if (startIndex == coins.size()) {
    return cents + 1;
    }
    /* Base case: We already know the answer. */
    else if (memo[cents][startIndex] != -1) {
    return memo[cents][startIndex];
    }
    /* Recursive case: Pick a coin, then try using each distinct number of
    * copies of it that we can.
    */
    else {
    /* The best we've found so far. We initialize this to a large value so
    * that it's replaced on the first iteration of the loop. Do you see
    * why cents + 1 is a good choice?
    */
    int bestSoFar = cents + 1;

    /* Pick a coin. */
    int coin = coins[startIndex];

    /* Try all amounts of it. */
    for (int copies = 0; copies * coin <= cents; copies++) {
    /* See what happens if we make this choice. Once we use this
    * coin, we won't use the same coin again in the future.
    */
    int thisChoice = copies + fewestCoinsRec(cents - copies * coin,
    coins, startIndex + 1,
    memo);

    /* Is this better than what we have so far? */
    if (thisChoice < bestSoFar) {
    bestSoFar = thisChoice;
    }
    }

    /* Return whatever worked best. */
    memo[cents][startIndex] = bestSoFar;
    return bestSoFar;
    }
    }

    int fewestCoinsFor(int cents, const Set<int>& coins) {
    /* Can't have a negative number of cents. */
    if (cents < 0) {
    error("You owe me money, not the other way around!");
    }

    /* Convert from a Set<int> to a Vector<int> so we have a nice ordering
    * on things.
    */
    Vector<int> coinVec;
    for (int coin: coins) {
    coinVec += coin;
    }

    /* Build our memoization table. Since the number of cents left ranges from
    * 0 to cents, we need cents+1 rows. Since the start index of the coin
    * ranges from 0 to coins.size(), we make coins.size() + 1 columns.
    *
    * -1 is used as a sentinel to indicate "nothing has been computed here
    * yet."
    */
    Grid<int> memo(cents + 1, coins.size() + 1, -1);

    /* Now ask how many coins are needed to make the total, using any coins
    * from index 0 onward.
    */
    return fewestCoinsRec(cents, coinVec, 0, memo);
    }
    +

    递归穷举付账单

    +

    递归机制:对第一个人来说,0-total所有金额都会付一遍,随后传递给下一个人,当只有一人时,付清所有余额并打印账单 传递参数:string,int的映射存储目前为止的账单,string集合存储所有付账者

    +
    void listPossiblePaymentsRec(int total, const Set<string>& people,const Map<string, int>& payments) {
    /* Base case: if there's one person left, they have to pay the whole bill. */
    if (people.size() == 1) {
    Map<string, int> finalPayments = payments;
    finalPayments[people.first()] = total;
    cout << finalPayments << endl;
    }
    /* Recursive case: The first person has to pay some amount between 0 and the
    * total amount. Try all of those possibilities.
    */
    else {
    for (int payment = 0; payment <= total; payment++) {
    /* Create a new assignment of people to payments in which this first
    * person pays this amount.
    */
    Map<string, int> updatedPayments = payments;
    updatedPayments[people.first()] = payment;
    listPossiblePaymentsRec(total - payment, people - people.first(),updatedPayments);
    }
    }
    }
    void listPossiblePayments(int total, const Set<string>& people) {
    /* Edge cases: we can't pay a negative total, and there must be at least one
    * person.
    */
    if (total < 0) error("Guess you're an employee?");
    if (people.isEmpty()) error("Dine and dash?");
    listPossiblePaymentsRec(total, people, {});
    }
    +

    递归寻找完全平方数列

    +

    主要参数为sofar——用于存储目前的序列和一个set用于存储还没放入数列的数字,`确保这两者同时被传递,且其并集为所有数字

    +
    Optional<Vector<int>> findSquareSequence(int n) {
    /*Validate input.*/
    if (n < 0) {
    error("Don't be so negative!");
    }

    /* Build a set of the numbers 1, 2, 3, ..., n. */
    Set<int> options;
    for (int i = 1; i <= n; i++) {
    options += i;
    }
    return findSequenceRec(options, { });
    }

    Optional<Vector<int>> findSequenceRec(const Set<int>& unused,
    const Vector<int>& soFar) {
    /*Base Case: If all numbers are used, we have our sequence!*/
    if (unused.isEmpty()) {
    return soFar;
    }

    /* Recursive Case: Some number comes next. Try each of them and see which
    * one we should pick.
    */
    for (int next: unused) {
    /* We can use this if either
    *
    * 1. the sequence is empty, so we're first in line, or
    * 2. the sequence is not empty, but we sum to a perfect square
    * with the previous term.
    */
    if (soFar.isEmpty() ||
    isPerfectSquare(next + soFar[soFar.size() - 1])) {
    /* See what happens if we extend with this number. */
    auto result = findSequenceRec(unused - next, soFar + next);
    if (result != Nothing) {
    return result;
    }
    }
    }

    /* Tried all options and none of them worked. Oh well! */
    return Nothing;
    }

    +

    汉诺塔递归

    +

    假设有三座汉诺塔,start ,temp ,finish 对n层的汉诺塔问题,先考虑n-1层的,随后考虑n-2层,到最后只需要考虑两层问题,两层的汉诺塔非常容易解决,起点为start,终点是temp,临时塔为finish,最后我们得到temp上的两层汉诺塔 这时将start的3移动到finish塔,这时只要将两层汉诺塔转移到finish则完成了三层汉诺塔,这个过程中的起点为temp,终点是finish,临时塔是start 以此类推,四层塔基于三层塔,n层塔基于n-1塔,汉诺塔问题解决

    +
    int moveTower(int numDisks, char start, char finish, char temp) {
    if (numDisks == 0) {
    return 0;
    } else {
    int movesOne = moveTower(numDisks - 1, start, temp, finish);
    moveSingleDisk(start, finish);
    int movesTwo = moveTower(numDisks - 1, temp, finish, start);

    return 1 + movesOne + movesTwo;
    }
    }
    +]]> + + 课程笔记 + 数据结构与算法 + + + 课程笔记 + 数据结构与算法 + c++ + 斯坦福 @@ -7699,8 +7779,8 @@ used the next time std::cin >> is called
    课程笔记 - 斯坦福 c++ + 斯坦福
    diff --git a/sitemap.txt b/sitemap.txt index d0f2dddf1..f1d5d5aeb 100644 --- a/sitemap.txt +++ b/sitemap.txt @@ -9,28 +9,28 @@ https://thinklive1.github.io/2023/09/29/%E8%BF%AA%E7%91%9E%E5%85%8B%E6%8B%89rpg% https://thinklive1.github.io/2023/10/14/%E8%8B%8F%E5%A4%A7linux_ppt/ https://thinklive1.github.io/2023/10/14/mit6.006%E6%80%BB%E5%92%8C%E7%AC%94%E8%AE%B0/ https://thinklive1.github.io/2023/09/17/thinklive%E7%9A%84%E8%BF%AA%E7%91%9E%E5%85%8B%E6%8B%89%E5%9B%BE%E4%B9%A6%E9%A6%86/ -https://thinklive1.github.io/2023/10/09/numpy/ https://thinklive1.github.io/2023/10/12/sysadmin/ +https://thinklive1.github.io/2023/10/09/numpy/ https://thinklive1.github.io/2023/10/06/61b%E6%80%BB%E5%92%8C%E7%AC%94%E8%AE%B0/ https://thinklive1.github.io/2023/09/30/%E6%9D%80%E6%89%8B47/ https://thinklive1.github.io/2023/09/30/%E6%AD%A5%E8%A1%8C%E6%A8%A1%E6%8B%9F%E5%99%A8/ https://thinklive1.github.io/2023/09/30/%E6%B8%B8%E6%88%8F%E7%AE%80%E8%AF%84/ -https://thinklive1.github.io/2023/09/29/%E7%A1%AC%E4%BB%B6%E6%80%BB%E5%92%8C%E7%AC%94%E8%AE%B0/ https://thinklive1.github.io/2023/09/28/%E7%A7%98%E5%AF%861/ +https://thinklive1.github.io/2023/09/29/%E7%A1%AC%E4%BB%B6%E6%80%BB%E5%92%8C%E7%AC%94%E8%AE%B0/ https://thinklive1.github.io/2023/09/29/%E8%BF%AA%E7%91%9E%E5%85%8B%E6%8B%89%E4%B8%96%E7%95%8C%E8%A7%82/ -https://thinklive1.github.io/2023/09/30/%E9%BE%99%E8%85%BE%E4%B8%96%E7%BA%AA/ https://thinklive1.github.io/2023/09/29/%E8%BF%AA%E7%91%9E%E5%85%8B%E6%8B%89%E8%BD%B6%E4%BA%8B%E9%9B%86/ +https://thinklive1.github.io/2023/09/30/%E9%BE%99%E8%85%BE%E4%B8%96%E7%BA%AA/ https://thinklive1.github.io/2023/09/30/%E4%B8%8D%E4%BA%88%E6%92%AD%E5%87%BA/ https://thinklive1.github.io/2023/09/30/%E5%B7%AB%E5%B8%88%E4%BA%8C/ https://thinklive1.github.io/2023/10/05/%E5%BB%BA%E7%AB%99%E6%8C%87%E5%8C%97/ https://thinklive1.github.io/2023/09/30/%E5%BD%B1%E5%AD%90%E5%B7%A5%E5%8E%82/ https://thinklive1.github.io/2023/09/29/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E6%80%BB%E5%92%8C%E7%AC%94%E8%AE%B0/ https://thinklive1.github.io/2023/09/29/61a%E6%80%BB%E5%92%8C/ -https://thinklive1.github.io/2023/09/29/black%20souls%E5%89%A7%E6%83%85%E8%A7%A3%E6%9E%90/ https://thinklive1.github.io/2023/09/29/black%20souls%E4%BA%BA%E7%89%A9%E8%A7%A3%E6%9E%90/ +https://thinklive1.github.io/2023/09/29/black%20souls%E5%89%A7%E6%83%85%E8%A7%A3%E6%9E%90/ https://thinklive1.github.io/2023/09/29/blacksouls%E5%8E%9F%E8%91%97%E6%A2%97%E8%A7%A3%E6%9E%90/ -https://thinklive1.github.io/2023/09/29/cs106b%E6%80%BB%E5%92%8C%E7%AC%94%E8%AE%B0/ https://thinklive1.github.io/2023/10/05/cpp%20primer%20plus%E6%80%BB%E5%92%8C/ +https://thinklive1.github.io/2023/09/29/cs106b%E6%80%BB%E5%92%8C%E7%AC%94%E8%AE%B0/ https://thinklive1.github.io/2023/09/29/cs106l%E6%80%BB%E5%92%8C%E7%AC%94%E8%AE%B0/ https://thinklive1.github.io/2023/09/29/linux%E6%80%BB%E5%92%8C%E7%AC%94%E8%AE%B0/ https://thinklive1.github.io/categories/index.html @@ -47,16 +47,17 @@ https://thinklive1.github.io/tags/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E% https://thinklive1.github.io/tags/JAVA/ https://thinklive1.github.io/tags/%E6%B8%B8%E6%88%8F%E6%9D%82%E8%B0%88/ https://thinklive1.github.io/tags/black-souls/ -https://thinklive1.github.io/tags/%E6%96%AF%E5%9D%A6%E7%A6%8F/ -https://thinklive1.github.io/tags/c/ https://thinklive1.github.io/tags/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/ +https://thinklive1.github.io/tags/c/ +https://thinklive1.github.io/tags/%E6%96%AF%E5%9D%A6%E7%A6%8F/ +https://thinklive1.github.io/tags/%E6%95%B0%E6%8D%AE%E7%A7%91%E5%AD%A6/ +https://thinklive1.github.io/tags/pandas/ https://thinklive1.github.io/tags/%E9%BA%BB%E7%9C%81%E7%90%86%E5%B7%A5/ https://thinklive1.github.io/tags/%E5%8C%97%E4%BA%AC%E5%A4%A7%E5%AD%A6/ https://thinklive1.github.io/tags/linux/ https://thinklive1.github.io/tags/%E7%BC%96%E7%A8%8B%E5%B7%A5%E5%85%B7/ -https://thinklive1.github.io/tags/%E6%95%B0%E6%8D%AE%E7%A7%91%E5%AD%A6/ -https://thinklive1.github.io/tags/pandas/ https://thinklive1.github.io/tags/%E7%B3%BB%E7%BB%9F%E7%AE%A1%E7%90%86/ +https://thinklive1.github.io/tags/vim/ https://thinklive1.github.io/tags/not-for-broadcast/ https://thinklive1.github.io/tags/%E5%B7%AB%E5%B8%88%E4%BA%8C/ https://thinklive1.github.io/tags/hexo/ @@ -67,13 +68,12 @@ https://thinklive1.github.io/tags/%E5%BD%B1%E5%AD%90%E5%B7%A5%E5%8E%82/ https://thinklive1.github.io/tags/%E8%8B%8F%E5%B7%9E%E5%A4%A7%E5%AD%A6/ https://thinklive1.github.io/tags/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/ https://thinklive1.github.io/tags/hitman/ -https://thinklive1.github.io/tags/vim/ https://thinklive1.github.io/tags/%E6%AD%A5%E8%A1%8C%E6%A8%A1%E6%8B%9F%E5%99%A8/ -https://thinklive1.github.io/tags/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90/ https://thinklive1.github.io/tags/%E7%A7%98%E5%AF%86/ https://thinklive1.github.io/tags/%E4%B8%AD%E5%9B%BD%E7%A7%91%E5%AD%A6%E6%8A%80%E6%9C%AF%E5%A4%A7%E5%AD%A6/ https://thinklive1.github.io/tags/%E4%B8%AD%E7%A7%91%E5%A4%A7/ https://thinklive1.github.io/tags/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/ +https://thinklive1.github.io/tags/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90/ https://thinklive1.github.io/tags/%E8%BF%AA%E7%91%9E%E5%85%8B%E6%8B%89/ https://thinklive1.github.io/tags/%E9%BE%99%E8%85%BE%E4%B8%96%E7%BA%AA/ https://thinklive1.github.io/categories/%E8%AF%BE%E7%A8%8B%E7%AC%94%E8%AE%B0/ @@ -81,14 +81,14 @@ https://thinklive1.github.io/categories/%E6%B8%B8%E6%88%8F%E6%9D%82%E8%B0%88/ https://thinklive1.github.io/categories/%E8%AF%BE%E7%A8%8B%E7%AC%94%E8%AE%B0/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/ https://thinklive1.github.io/categories/%E8%AF%BE%E7%A8%8B%E7%AC%94%E8%AE%B0/%E5%85%B6%E4%BB%96/ https://thinklive1.github.io/categories/%E6%B8%B8%E6%88%8F%E6%9D%82%E8%B0%88/black-souls/ -https://thinklive1.github.io/categories/%E8%AF%BE%E7%A8%8B%E7%AC%94%E8%AE%B0/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/ https://thinklive1.github.io/categories/%E8%AF%BE%E7%A8%8B%E7%AC%94%E8%AE%B0/%E6%95%B0%E6%8D%AE%E7%A7%91%E5%AD%A6/ +https://thinklive1.github.io/categories/%E8%AF%BE%E7%A8%8B%E7%AC%94%E8%AE%B0/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/ https://thinklive1.github.io/categories/%E6%B8%B8%E6%88%8F%E6%9D%82%E8%B0%88/%E7%8B%AC%E7%AB%8B%E6%B8%B8%E6%88%8F/ https://thinklive1.github.io/categories/%E6%B8%B8%E6%88%8F%E6%9D%82%E8%B0%88/wrpg/ https://thinklive1.github.io/categories/%E5%BB%BA%E7%AB%99%E7%BB%8F%E9%AA%8C/ https://thinklive1.github.io/categories/%E6%B8%B8%E6%88%8F%E6%9D%82%E8%B0%88/%E5%85%B6%E4%BB%96%E6%B8%B8%E6%88%8F/ -https://thinklive1.github.io/categories/%E8%AF%BE%E7%A8%8B%E7%AC%94%E8%AE%B0/%E8%AE%A1%E7%BB%84/ https://thinklive1.github.io/categories/%E7%A7%98%E5%AF%86/ https://thinklive1.github.io/categories/%E8%80%83%E7%A0%94%E7%AC%94%E8%AE%B0/ https://thinklive1.github.io/categories/%E8%AF%BE%E7%A8%8B%E7%AC%94%E8%AE%B0/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/ +https://thinklive1.github.io/categories/%E8%AF%BE%E7%A8%8B%E7%AC%94%E8%AE%B0/%E8%AE%A1%E7%BB%84/ https://thinklive1.github.io/categories/%E8%BF%AA%E7%91%9E%E5%85%8B%E6%8B%89/ diff --git a/sitemap.xml b/sitemap.xml index 9c2f97ec2..8a2566d2d 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -101,7 +101,7 @@ - https://thinklive1.github.io/2023/10/09/numpy/ + https://thinklive1.github.io/2023/10/12/sysadmin/ 2023-11-27 @@ -110,7 +110,7 @@ - https://thinklive1.github.io/2023/10/12/sysadmin/ + https://thinklive1.github.io/2023/10/09/numpy/ 2023-11-27 @@ -155,7 +155,7 @@ - https://thinklive1.github.io/2023/09/29/%E7%A1%AC%E4%BB%B6%E6%80%BB%E5%92%8C%E7%AC%94%E8%AE%B0/ + https://thinklive1.github.io/2023/09/28/%E7%A7%98%E5%AF%861/ 2023-11-27 @@ -164,7 +164,7 @@ - https://thinklive1.github.io/2023/09/28/%E7%A7%98%E5%AF%861/ + https://thinklive1.github.io/2023/09/29/%E7%A1%AC%E4%BB%B6%E6%80%BB%E5%92%8C%E7%AC%94%E8%AE%B0/ 2023-11-27 @@ -182,7 +182,7 @@ - https://thinklive1.github.io/2023/09/30/%E9%BE%99%E8%85%BE%E4%B8%96%E7%BA%AA/ + https://thinklive1.github.io/2023/09/29/%E8%BF%AA%E7%91%9E%E5%85%8B%E6%8B%89%E8%BD%B6%E4%BA%8B%E9%9B%86/ 2023-11-27 @@ -191,7 +191,7 @@ - https://thinklive1.github.io/2023/09/29/%E8%BF%AA%E7%91%9E%E5%85%8B%E6%8B%89%E8%BD%B6%E4%BA%8B%E9%9B%86/ + https://thinklive1.github.io/2023/09/30/%E9%BE%99%E8%85%BE%E4%B8%96%E7%BA%AA/ 2023-11-27 @@ -254,7 +254,7 @@ - https://thinklive1.github.io/2023/09/29/black%20souls%E5%89%A7%E6%83%85%E8%A7%A3%E6%9E%90/ + https://thinklive1.github.io/2023/09/29/black%20souls%E4%BA%BA%E7%89%A9%E8%A7%A3%E6%9E%90/ 2023-11-27 @@ -263,7 +263,7 @@ - https://thinklive1.github.io/2023/09/29/black%20souls%E4%BA%BA%E7%89%A9%E8%A7%A3%E6%9E%90/ + https://thinklive1.github.io/2023/09/29/black%20souls%E5%89%A7%E6%83%85%E8%A7%A3%E6%9E%90/ 2023-11-27 @@ -281,7 +281,7 @@ - https://thinklive1.github.io/2023/09/29/cs106b%E6%80%BB%E5%92%8C%E7%AC%94%E8%AE%B0/ + https://thinklive1.github.io/2023/10/05/cpp%20primer%20plus%E6%80%BB%E5%92%8C/ 2023-11-27 @@ -290,7 +290,7 @@ - https://thinklive1.github.io/2023/10/05/cpp%20primer%20plus%E6%80%BB%E5%92%8C/ + https://thinklive1.github.io/2023/09/29/cs106b%E6%80%BB%E5%92%8C%E7%AC%94%E8%AE%B0/ 2023-11-27 @@ -429,7 +429,7 @@ - https://thinklive1.github.io/tags/%E6%96%AF%E5%9D%A6%E7%A6%8F/ + https://thinklive1.github.io/tags/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/ 2023-12-05 weekly 0.2 @@ -443,49 +443,49 @@ - https://thinklive1.github.io/tags/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/ + https://thinklive1.github.io/tags/%E6%96%AF%E5%9D%A6%E7%A6%8F/ 2023-12-05 weekly 0.2 - https://thinklive1.github.io/tags/%E9%BA%BB%E7%9C%81%E7%90%86%E5%B7%A5/ + https://thinklive1.github.io/tags/%E6%95%B0%E6%8D%AE%E7%A7%91%E5%AD%A6/ 2023-12-05 weekly 0.2 - https://thinklive1.github.io/tags/%E5%8C%97%E4%BA%AC%E5%A4%A7%E5%AD%A6/ + https://thinklive1.github.io/tags/pandas/ 2023-12-05 weekly 0.2 - https://thinklive1.github.io/tags/linux/ + https://thinklive1.github.io/tags/%E9%BA%BB%E7%9C%81%E7%90%86%E5%B7%A5/ 2023-12-05 weekly 0.2 - https://thinklive1.github.io/tags/%E7%BC%96%E7%A8%8B%E5%B7%A5%E5%85%B7/ + https://thinklive1.github.io/tags/%E5%8C%97%E4%BA%AC%E5%A4%A7%E5%AD%A6/ 2023-12-05 weekly 0.2 - https://thinklive1.github.io/tags/%E6%95%B0%E6%8D%AE%E7%A7%91%E5%AD%A6/ + https://thinklive1.github.io/tags/linux/ 2023-12-05 weekly 0.2 - https://thinklive1.github.io/tags/pandas/ + https://thinklive1.github.io/tags/%E7%BC%96%E7%A8%8B%E5%B7%A5%E5%85%B7/ 2023-12-05 weekly 0.2 @@ -498,6 +498,13 @@ 0.2 + + https://thinklive1.github.io/tags/vim/ + 2023-12-05 + weekly + 0.2 + + https://thinklive1.github.io/tags/not-for-broadcast/ 2023-12-05 @@ -568,13 +575,6 @@ 0.2 - - https://thinklive1.github.io/tags/vim/ - 2023-12-05 - weekly - 0.2 - - https://thinklive1.github.io/tags/%E6%AD%A5%E8%A1%8C%E6%A8%A1%E6%8B%9F%E5%99%A8/ 2023-12-05 @@ -583,35 +583,35 @@ - https://thinklive1.github.io/tags/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90/ + https://thinklive1.github.io/tags/%E7%A7%98%E5%AF%86/ 2023-12-05 weekly 0.2 - https://thinklive1.github.io/tags/%E7%A7%98%E5%AF%86/ + https://thinklive1.github.io/tags/%E4%B8%AD%E5%9B%BD%E7%A7%91%E5%AD%A6%E6%8A%80%E6%9C%AF%E5%A4%A7%E5%AD%A6/ 2023-12-05 weekly 0.2 - https://thinklive1.github.io/tags/%E4%B8%AD%E5%9B%BD%E7%A7%91%E5%AD%A6%E6%8A%80%E6%9C%AF%E5%A4%A7%E5%AD%A6/ + https://thinklive1.github.io/tags/%E4%B8%AD%E7%A7%91%E5%A4%A7/ 2023-12-05 weekly 0.2 - https://thinklive1.github.io/tags/%E4%B8%AD%E7%A7%91%E5%A4%A7/ + https://thinklive1.github.io/tags/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/ 2023-12-05 weekly 0.2 - https://thinklive1.github.io/tags/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/ + https://thinklive1.github.io/tags/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90/ 2023-12-05 weekly 0.2 @@ -669,14 +669,14 @@ - https://thinklive1.github.io/categories/%E8%AF%BE%E7%A8%8B%E7%AC%94%E8%AE%B0/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/ + https://thinklive1.github.io/categories/%E8%AF%BE%E7%A8%8B%E7%AC%94%E8%AE%B0/%E6%95%B0%E6%8D%AE%E7%A7%91%E5%AD%A6/ 2023-12-05 weekly 0.2 - https://thinklive1.github.io/categories/%E8%AF%BE%E7%A8%8B%E7%AC%94%E8%AE%B0/%E6%95%B0%E6%8D%AE%E7%A7%91%E5%AD%A6/ + https://thinklive1.github.io/categories/%E8%AF%BE%E7%A8%8B%E7%AC%94%E8%AE%B0/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/ 2023-12-05 weekly 0.2 @@ -711,28 +711,28 @@ - https://thinklive1.github.io/categories/%E8%AF%BE%E7%A8%8B%E7%AC%94%E8%AE%B0/%E8%AE%A1%E7%BB%84/ + https://thinklive1.github.io/categories/%E7%A7%98%E5%AF%86/ 2023-12-05 weekly 0.2 - https://thinklive1.github.io/categories/%E7%A7%98%E5%AF%86/ + https://thinklive1.github.io/categories/%E8%80%83%E7%A0%94%E7%AC%94%E8%AE%B0/ 2023-12-05 weekly 0.2 - https://thinklive1.github.io/categories/%E8%80%83%E7%A0%94%E7%AC%94%E8%AE%B0/ + https://thinklive1.github.io/categories/%E8%AF%BE%E7%A8%8B%E7%AC%94%E8%AE%B0/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/ 2023-12-05 weekly 0.2 - https://thinklive1.github.io/categories/%E8%AF%BE%E7%A8%8B%E7%AC%94%E8%AE%B0/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/ + https://thinklive1.github.io/categories/%E8%AF%BE%E7%A8%8B%E7%AC%94%E8%AE%B0/%E8%AE%A1%E7%BB%84/ 2023-12-05 weekly 0.2 diff --git a/tags/JAVA/index.html b/tags/JAVA/index.html index 957f262b5..795350904 100644 --- a/tags/JAVA/index.html +++ b/tags/JAVA/index.html @@ -294,14 +294,14 @@

    JAVA 站点总字数: - 191k + 194k

    diff --git a/tags/black-souls/index.html b/tags/black-souls/index.html index 7fb5c25ee..9df78162f 100644 --- a/tags/black-souls/index.html +++ b/tags/black-souls/index.html @@ -259,8 +259,8 @@

    black souls

    -
    @@ -279,8 +279,8 @@

    black souls

    -
    @@ -334,14 +334,14 @@

    black souls 站点总字数: - 191k + 194k
    diff --git a/tags/c/index.html b/tags/c/index.html index 4ef5d5a8e..d34c881d6 100644 --- a/tags/c/index.html +++ b/tags/c/index.html @@ -334,14 +334,14 @@

    c++ 站点总字数: - 191k + 194k

    diff --git a/tags/hexo/index.html b/tags/hexo/index.html index 90530157d..4356d5987 100644 --- a/tags/hexo/index.html +++ b/tags/hexo/index.html @@ -294,14 +294,14 @@

    hexo 站点总字数: - 191k + 194k

    diff --git a/tags/hitman/index.html b/tags/hitman/index.html index 90edd5590..cfd8847f7 100644 --- a/tags/hitman/index.html +++ b/tags/hitman/index.html @@ -294,14 +294,14 @@

    hitman 站点总字数: - 191k + 194k

    diff --git a/tags/icarus/index.html b/tags/icarus/index.html index a150829b8..4d1fee138 100644 --- a/tags/icarus/index.html +++ b/tags/icarus/index.html @@ -294,14 +294,14 @@

    icarus 站点总字数: - 191k + 194k

    diff --git a/tags/index.html b/tags/index.html index d707dbfc5..33250a4df 100644 --- a/tags/index.html +++ b/tags/index.html @@ -287,14 +287,14 @@

    tags 站点总字数: - 191k + 194k

    diff --git a/tags/linux/index.html b/tags/linux/index.html index e71eca041..9e4a36e81 100644 --- a/tags/linux/index.html +++ b/tags/linux/index.html @@ -334,14 +334,14 @@

    linux 站点总字数: - 191k + 194k

    diff --git a/tags/next/index.html b/tags/next/index.html index 3f4ad80ec..e28de707d 100644 --- a/tags/next/index.html +++ b/tags/next/index.html @@ -294,14 +294,14 @@

    next 站点总字数: - 191k + 194k

    diff --git a/tags/not-for-broadcast/index.html b/tags/not-for-broadcast/index.html index 746c2ab1a..0d6be0ca2 100644 --- a/tags/not-for-broadcast/index.html +++ b/tags/not-for-broadcast/index.html @@ -294,14 +294,14 @@

    not for broadcast 站点总字数: - 191k + 194k

    diff --git a/tags/pandas/index.html b/tags/pandas/index.html index 791e571af..de323143b 100644 --- a/tags/pandas/index.html +++ b/tags/pandas/index.html @@ -314,14 +314,14 @@

    pandas 站点总字数: - 191k + 194k

    diff --git a/tags/python/index.html b/tags/python/index.html index f407645d7..c421cd1aa 100644 --- a/tags/python/index.html +++ b/tags/python/index.html @@ -354,14 +354,14 @@

    python 站点总字数: - 191k + 194k

    diff --git a/tags/vim/index.html b/tags/vim/index.html index 037d61a14..543693f2d 100644 --- a/tags/vim/index.html +++ b/tags/vim/index.html @@ -294,14 +294,14 @@

    vim 站点总字数: - 191k + 194k

    diff --git a/tags/webstack/index.html b/tags/webstack/index.html index 620412593..0c6bc3e4f 100644 --- a/tags/webstack/index.html +++ b/tags/webstack/index.html @@ -294,14 +294,14 @@

    webstack 站点总字数: - 191k + 194k

    diff --git "a/tags/\344\270\255\345\233\275\347\247\221\345\255\246\346\212\200\346\234\257\345\244\247\345\255\246/index.html" "b/tags/\344\270\255\345\233\275\347\247\221\345\255\246\346\212\200\346\234\257\345\244\247\345\255\246/index.html" index 3a11bda18..353955727 100644 --- "a/tags/\344\270\255\345\233\275\347\247\221\345\255\246\346\212\200\346\234\257\345\244\247\345\255\246/index.html" +++ "b/tags/\344\270\255\345\233\275\347\247\221\345\255\246\346\212\200\346\234\257\345\244\247\345\255\246/index.html" @@ -294,14 +294,14 @@

    中国科学技术大学 站点总字数: - 191k + 194k

    diff --git "a/tags/\344\270\255\347\247\221\345\244\247/index.html" "b/tags/\344\270\255\347\247\221\345\244\247/index.html" index fa45593ec..3e7850b8b 100644 --- "a/tags/\344\270\255\347\247\221\345\244\247/index.html" +++ "b/tags/\344\270\255\347\247\221\345\244\247/index.html" @@ -294,14 +294,14 @@

    中科大 站点总字数: - 191k + 194k

    diff --git "a/tags/\344\274\257\345\205\213\345\210\251/index.html" "b/tags/\344\274\257\345\205\213\345\210\251/index.html" index 169e89789..8389b339e 100644 --- "a/tags/\344\274\257\345\205\213\345\210\251/index.html" +++ "b/tags/\344\274\257\345\205\213\345\210\251/index.html" @@ -374,14 +374,14 @@

    伯克利 站点总字数: - 191k + 194k

    diff --git "a/tags/\345\214\227\344\272\254\345\244\247\345\255\246/index.html" "b/tags/\345\214\227\344\272\254\345\244\247\345\255\246/index.html" index d4f9bfb22..d6ea8909d 100644 --- "a/tags/\345\214\227\344\272\254\345\244\247\345\255\246/index.html" +++ "b/tags/\345\214\227\344\272\254\345\244\247\345\255\246/index.html" @@ -314,14 +314,14 @@

    北京大学 站点总字数: - 191k + 194k

    diff --git "a/tags/\345\267\253\345\270\210\344\272\214/index.html" "b/tags/\345\267\253\345\270\210\344\272\214/index.html" index 2c4fe4a75..5195b4710 100644 --- "a/tags/\345\267\253\345\270\210\344\272\214/index.html" +++ "b/tags/\345\267\253\345\270\210\344\272\214/index.html" @@ -294,14 +294,14 @@

    巫师二 站点总字数: - 191k + 194k

    diff --git "a/tags/\345\275\261\345\255\220\345\267\245\345\216\202/index.html" "b/tags/\345\275\261\345\255\220\345\267\245\345\216\202/index.html" index a87dd4520..5ad47e6b7 100644 --- "a/tags/\345\275\261\345\255\220\345\267\245\345\216\202/index.html" +++ "b/tags/\345\275\261\345\255\220\345\267\245\345\216\202/index.html" @@ -294,14 +294,14 @@

    影子工厂 站点总字数: - 191k + 194k

    diff --git "a/tags/\346\223\215\344\275\234\347\263\273\347\273\237/index.html" "b/tags/\346\223\215\344\275\234\347\263\273\347\273\237/index.html" index 67c37ec74..64769c1ba 100644 --- "a/tags/\346\223\215\344\275\234\347\263\273\347\273\237/index.html" +++ "b/tags/\346\223\215\344\275\234\347\263\273\347\273\237/index.html" @@ -314,14 +314,14 @@

    操作系统 站点总字数: - 191k + 194k

    diff --git "a/tags/\346\225\260\346\215\256\347\247\221\345\255\246/index.html" "b/tags/\346\225\260\346\215\256\347\247\221\345\255\246/index.html" index d9d018d30..db3a3b0d4 100644 --- "a/tags/\346\225\260\346\215\256\347\247\221\345\255\246/index.html" +++ "b/tags/\346\225\260\346\215\256\347\247\221\345\255\246/index.html" @@ -334,14 +334,14 @@

    数据科学 站点总字数: - 191k + 194k

    diff --git "a/tags/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/index.html" "b/tags/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/index.html" index 0c4c314a1..d3dd5600d 100644 --- "a/tags/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/index.html" +++ "b/tags/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/index.html" @@ -394,14 +394,14 @@

    数据结构与算法 站点总字数: - 191k + 194k

    diff --git "a/tags/\346\226\257\345\235\246\347\246\217/index.html" "b/tags/\346\226\257\345\235\246\347\246\217/index.html" index 34cea3ad3..39ca16a36 100644 --- "a/tags/\346\226\257\345\235\246\347\246\217/index.html" +++ "b/tags/\346\226\257\345\235\246\347\246\217/index.html" @@ -314,14 +314,14 @@

    斯坦福 站点总字数: - 191k + 194k

    diff --git "a/tags/\346\255\245\350\241\214\346\250\241\346\213\237\345\231\250/index.html" "b/tags/\346\255\245\350\241\214\346\250\241\346\213\237\345\231\250/index.html" index 26d1e1f55..a17eef47b 100644 --- "a/tags/\346\255\245\350\241\214\346\250\241\346\213\237\345\231\250/index.html" +++ "b/tags/\346\255\245\350\241\214\346\250\241\346\213\237\345\231\250/index.html" @@ -294,14 +294,14 @@

    步行模拟器 站点总字数: - 191k + 194k

    diff --git "a/tags/\346\270\270\346\210\217\346\235\202\350\260\210/index.html" "b/tags/\346\270\270\346\210\217\346\235\202\350\260\210/index.html" index cbadf4473..81a37695e 100644 --- "a/tags/\346\270\270\346\210\217\346\235\202\350\260\210/index.html" +++ "b/tags/\346\270\270\346\210\217\346\235\202\350\260\210/index.html" @@ -399,8 +399,8 @@

    游戏杂谈

    -
    @@ -419,8 +419,8 @@

    游戏杂谈
    -
    @@ -474,14 +474,14 @@

    游戏杂谈 站点总字数: - 191k + 194k
    diff --git "a/tags/\347\247\230\345\257\206/index.html" "b/tags/\347\247\230\345\257\206/index.html" index ed3630aa5..c1d38c410 100644 --- "a/tags/\347\247\230\345\257\206/index.html" +++ "b/tags/\347\247\230\345\257\206/index.html" @@ -294,14 +294,14 @@

    秘密 站点总字数: - 191k + 194k

    diff --git "a/tags/\347\263\273\347\273\237\347\256\241\347\220\206/index.html" "b/tags/\347\263\273\347\273\237\347\256\241\347\220\206/index.html" index 948bee11c..fc89f599e 100644 --- "a/tags/\347\263\273\347\273\237\347\256\241\347\220\206/index.html" +++ "b/tags/\347\263\273\347\273\237\347\256\241\347\220\206/index.html" @@ -294,14 +294,14 @@

    系统管理 站点总字数: - 191k + 194k

    diff --git "a/tags/\347\274\226\347\250\213\345\267\245\345\205\267/index.html" "b/tags/\347\274\226\347\250\213\345\267\245\345\205\267/index.html" index f0eab4fc5..d38547642 100644 --- "a/tags/\347\274\226\347\250\213\345\267\245\345\205\267/index.html" +++ "b/tags/\347\274\226\347\250\213\345\267\245\345\205\267/index.html" @@ -314,14 +314,14 @@

    编程工具 站点总字数: - 191k + 194k

    diff --git "a/tags/\350\213\217\345\267\236\345\244\247\345\255\246/index.html" "b/tags/\350\213\217\345\267\236\345\244\247\345\255\246/index.html" index 315a07ba7..cf783a25c 100644 --- "a/tags/\350\213\217\345\267\236\345\244\247\345\255\246/index.html" +++ "b/tags/\350\213\217\345\267\236\345\244\247\345\255\246/index.html" @@ -334,14 +334,14 @@

    苏州大学 站点总字数: - 191k + 194k

    diff --git "a/tags/\350\256\241\347\256\227\346\234\272\347\273\204\346\210\220/index.html" "b/tags/\350\256\241\347\256\227\346\234\272\347\273\204\346\210\220/index.html" index b76ad2beb..b7140a98d 100644 --- "a/tags/\350\256\241\347\256\227\346\234\272\347\273\204\346\210\220/index.html" +++ "b/tags/\350\256\241\347\256\227\346\234\272\347\273\204\346\210\220/index.html" @@ -294,14 +294,14 @@

    计算机组成 站点总字数: - 191k + 194k

    diff --git "a/tags/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/index.html" "b/tags/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/index.html" index e15e56dde..d7b6c41c5 100644 --- "a/tags/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/index.html" +++ "b/tags/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/index.html" @@ -294,14 +294,14 @@

    计算机网络 站点总字数: - 191k + 194k

    diff --git "a/tags/\350\257\273\344\271\246\347\254\224\350\256\260/index.html" "b/tags/\350\257\273\344\271\246\347\254\224\350\256\260/index.html" index d3d5cd986..78372ee5b 100644 --- "a/tags/\350\257\273\344\271\246\347\254\224\350\256\260/index.html" +++ "b/tags/\350\257\273\344\271\246\347\254\224\350\256\260/index.html" @@ -294,14 +294,14 @@

    读书笔记 站点总字数: - 191k + 194k

    diff --git "a/tags/\350\257\276\347\250\213\347\254\224\350\256\260/index.html" "b/tags/\350\257\276\347\250\213\347\254\224\350\256\260/index.html" index aaec1de90..91e19ab20 100644 --- "a/tags/\350\257\276\347\250\213\347\254\224\350\256\260/index.html" +++ "b/tags/\350\257\276\347\250\213\347\254\224\350\256\260/index.html" @@ -477,14 +477,14 @@

    课程笔记 站点总字数: - 191k + 194k

    diff --git "a/tags/\350\257\276\347\250\213\347\254\224\350\256\260/page/2/index.html" "b/tags/\350\257\276\347\250\213\347\254\224\350\256\260/page/2/index.html" index 7fb937e76..90b0c92ff 100644 --- "a/tags/\350\257\276\347\250\213\347\254\224\350\256\260/page/2/index.html" +++ "b/tags/\350\257\276\347\250\213\347\254\224\350\256\260/page/2/index.html" @@ -259,8 +259,8 @@

    课程笔记

    -
    @@ -279,8 +279,8 @@

    课程笔记
    -
    @@ -299,8 +299,8 @@

    课程笔记
    -
    @@ -319,8 +319,8 @@

    课程笔记
    -
    @@ -377,14 +377,14 @@

    课程笔记 站点总字数: - 191k + 194k
    diff --git "a/tags/\350\277\252\347\221\236\345\205\213\346\213\211/index.html" "b/tags/\350\277\252\347\221\236\345\205\213\346\213\211/index.html" index 5984f770b..e0c7cfb07 100644 --- "a/tags/\350\277\252\347\221\236\345\205\213\346\213\211/index.html" +++ "b/tags/\350\277\252\347\221\236\345\205\213\346\213\211/index.html" @@ -334,14 +334,14 @@

    迪瑞克拉 站点总字数: - 191k + 194k

    diff --git "a/tags/\351\272\273\347\234\201\347\220\206\345\267\245/index.html" "b/tags/\351\272\273\347\234\201\347\220\206\345\267\245/index.html" index 73e7de19a..b11c4635f 100644 --- "a/tags/\351\272\273\347\234\201\347\220\206\345\267\245/index.html" +++ "b/tags/\351\272\273\347\234\201\347\220\206\345\267\245/index.html" @@ -354,14 +354,14 @@

    麻省理工 站点总字数: - 191k + 194k

    diff --git "a/tags/\351\276\231\350\205\276\344\270\226\347\272\252/index.html" "b/tags/\351\276\231\350\205\276\344\270\226\347\272\252/index.html" index fc6c20bc2..d889d3ea7 100644 --- "a/tags/\351\276\231\350\205\276\344\270\226\347\272\252/index.html" +++ "b/tags/\351\276\231\350\205\276\344\270\226\347\272\252/index.html" @@ -294,14 +294,14 @@

    龙腾世纪 站点总字数: - 191k + 194k

    diff --git a/thanks/index.html b/thanks/index.html index ac78af20e..6d2bb8424 100644 --- a/thanks/index.html +++ b/thanks/index.html @@ -289,14 +289,14 @@

    And you

    站点总字数: - 191k + 194k