-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsearch.xml
250 lines (120 loc) · 116 KB
/
search.xml
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>概率论与数理统计-3</title>
<link href="/8/"/>
<url>/8/</url>
<content type="html"><![CDATA[<h1 id="chap2-随机变量">Chap2 随机变量</h1><h2 id="维随机变量">1. (1维)随机变量</h2><blockquote><p>定义:样本空间上的实值函数</p></blockquote><table><thead><tr class="header"><th style="text-align: center;">试验</th><th style="text-align: center;">样本空间</th><th style="text-align: center;">随机变量</th><th style="text-align: center;">像集(新样本空间)</th></tr></thead><tbody><tr class="odd"><td style="text-align: center;">随机调查50人对某议题支持与否</td><td style="text-align: center;">一个<span class="math inline">\(2^{50}\)</span>次方的集合</td><td style="text-align: center;"><span class="math inline">\(X_1=1\)</span>的个数</td><td style="text-align: center;"><span class="math inline">\(\{0,1,2...50\}\)</span></td></tr><tr class="even"><td style="text-align: center;">随机抽取一个北京成年市民</td><td style="text-align: center;">集合由所有北京成年市民构成</td><td style="text-align: center;">其2022年的年收入</td><td style="text-align: center;"><span class="math inline">\((-\infty,\infty)\)</span></td></tr></tbody></table><p>注:</p><ul><li>随机变量——概括作用,提供实验结果的数值摘要</li><li>事件与变量;静态与动态</li></ul><p>分类:</p><ul><li>离散型:至多可数个取值</li><li>连续型:区间型取值(定义不严格)</li><li>其他</li></ul><p><span class="math display">\[\forall I\subset\mathbb{R},令Z^{-1}(I)表示\ I\ 在\ Z \ 下的原像集。\\定义:P_{X}(X\in I):=P(X^{-1}(I))\]</span></p><blockquote><p>定义累积分布函数(CDP): <span class="math display">\[F(x):=P(X\le x)(\forall\ x \in \mathbb{R})\\P(a\le Z\le b) = F(b)-F(a)\]</span></p></blockquote><p>性质: <span class="math display">\[(1)\ \ 0\le F(x)\le 1 \ \ 单调增(2)\ \ \lim_{x\rightarrow \infty}F(x)=1 \ \ \lim_{x\rightarrow -\infty}F(x)=0 \\(3)\ \ 右连续\]</span></p><h2 id="review">Review</h2><ul><li><p>概念:从随机试验开始,讲所有可能的事件组成一个集合,这就是样本空间 <span class="math inline">\(\Omega\)</span>,讲样本空间的所有子集作为一个更大的集合 <span class="math inline">\(2^{\Omega}\)</span></p><ul><li><p>通常用字母<span class="math inline">\(A\)</span>描述事件,<span class="math inline">\(A\subset \Omega\)</span>,<span class="math inline">\(A \in \mathscr{F}\)</span>,我们称<span class="math inline">\(\mathscr{F}\)</span>为事件集类。只需要关注<span class="math inline">\(\mathscr{F}\)</span>这一集合即可,赋以概率<span class="math inline">\((\Omega,\mathscr{F},P)\)</span></p></li><li><p>条件概率<span class="math inline">\(P(A|B)(A,B\in \mathscr{F})\)</span> <span class="math display">\[P(A|B) = \frac{P(AB)}{P(B)}( \ 需要 \ P(B)\gt 0 )\]</span></p></li></ul></li><li><p>运算:</p><blockquote><p>事件的运算和概率的运算</p></blockquote><ul><li><p>事件的运算:</p><ul><li><p>和:容斥公式,如果事件容斥,则为加法公式</p></li><li><p>积:乘法法则,如果事件独立,则为乘法公式</p></li><li><p>全概率公式: <span class="math display">\[P(A) = P(\sum_i(AB_i)) = \sum_iP(AB_i) = \sum_iP(A\mid B_i)P(B_i)\]</span></p></li><li><p>Bayes公式: <span class="math display">\[P(A) = P(\sum_i(AB_i))=\sum_iP(AB_i) = \sum_iP(A_i|B_i)P(B_i)\\P(B_i|A)=\frac{P(A|B_i)\cdot P(B_i)}{\sum P(A|B_j)P(B_j)}\]</span></p></li></ul></li></ul></li></ul><h3 id="有关概率的讨论">有关概率的讨论</h3><ul><li><p>什么是概率</p><ul><li>不确定性的一种度量</li><li>具有不同的解释</li><li>公理化定义</li></ul></li><li><p>为什么用概率</p><ul><li><p>不确定的来源</p><ul><li><p>被建模系统的内在随机性</p></li><li><p>不完全观测(Monfy Hall问题中游戏参与者角度)</p></li><li><p>不完全建模</p></li></ul></li><li><p>很多情况下,简单而不确定的规则比复杂而确定的规则更加实用</p></li></ul></li><li><p>怎么用概率</p><ul><li>计算正确的概率</li><li>正确地计算概率</li><li>正确地使用概率</li></ul></li></ul>]]></content>
<categories>
<category> Math </category>
<category> 概率论 </category>
</categories>
<tags>
<tag> Math </tag>
</tags>
</entry>
<entry>
<title>AI搜索算法</title>
<link href="/8/"/>
<url>/8/</url>
<content type="html"><![CDATA[<h1 id="搜索">搜索</h1><h2 id="搜索问题">搜索问题</h2><ul><li><p>内容:状态空间的搜索问题</p></li><li><p>搜索方式</p><ul><li>盲目搜索</li><li>启发式搜索</li></ul></li><li><p>关键问题:寻找最佳解</p></li><li><p>问题举例:地图路径、传教士与野人问题、华容道问题、八皇后问题</p></li></ul><h2 id="盲目搜索">盲目搜索</h2><ul><li><h3 id="深度优先搜索">深度优先搜索</h3><blockquote><p>优先拓展深度深的节点</p></blockquote><p>举例:八皇后问题</p><p><strong>性质</strong>:</p><ul><li>一般不能保证找到最优解</li><li>当深度限制不合理时有可能找不到解(限制搜索深度)</li><li>最坏情况下搜索空间等同于穷举法</li><li>通用方法,与实际要处理的问题没有关系</li><li>节省内存,只需要存储从初节点到当前节点的路径</li></ul></li><li><p>宽度优先搜索</p><blockquote><p>优先扩展深度浅的节点</p></blockquote><p><strong>性质</strong>:</p><ul><li>当问题有解的时候,一定能找到解</li><li>面对有解的单位耗散值问题时,一定能找到最优解</li><li>具有通用性</li><li>效率低,存储量大</li></ul><p>举例:Dijkstra 算法</p><blockquote><p>宽度优先算法在处理问题的时候有很多不足之处,没有考虑两个节点间的距离</p></blockquote><p>Dijkstra 算法优先拓展距离起点最近的节点,直到终点距离最短</p><p>优点:当问题有解时,可以找到最佳解</p><p>不足:只考虑了节点距离起点的距离,没有考虑距离终点的距离</p></li></ul><h2 id="启发式图搜索">启发式图搜索</h2><blockquote><p>引入启发知识,在找到最佳解的情况下,尽可能减少搜索范围</p></blockquote><h3 id="启发知识">启发知识</h3><blockquote><p>评估节点到达目标的距离</p></blockquote><ul><li>评价函数的格式: <span class="math display">\[f(n)=g(n)+h(n)\\f(n): \ \textbf{评价函数} \qquadg(n): \ \textbf{启发函数} \\g^*(n): \textbf{从 s 到 n 的最短路径的耗散值} \\h^*(n): \textbf{从 n 到 g 的最短路径的耗散值} \\f^*(n) = g^*(n)+h^*(n): \textbf{从 s 到 g 经过 n 的最短路径的耗散值} \\\]</span></li></ul><h3 id="最佳图搜索算法-a">最佳图搜索算法 A*</h3><blockquote><p>在 A 算法中,如果满足条件: <span class="math display">\[h(n)\le h^*(n)\]</span> 则称 A 算法为 A* 算法</p></blockquote><p><strong>过程</strong>:</p><p>A * 算法每次从优先队列中取出一个 <span class="math inline">\(f\)</span> 最小的元素,然后更新相邻的状态。</p><p>当 <span class="math inline">\(h=0\)</span>时,A * 算法变为 Dijkstra;当 <span class="math inline">\(h=0\)</span> 并且边权为 <span class="math inline">\(1\)</span> 时变为 <a href="https://oi-wiki.org/search/bfs/">BFS</a>。</p>]]></content>
<categories>
<category> AI </category>
<category> 搜索 </category>
</categories>
<tags>
<tag> 搜索 </tag>
</tags>
</entry>
<entry>
<title>概率论与数理统计-2</title>
<link href="/7/"/>
<url>/7/</url>
<content type="html"><![CDATA[<h3 id="概率论的公理化系统">5. 概率论的公理化系统</h3><ul><li>定义:</li></ul><p><span class="math display">\[P: \Im \rightarrow R \ \ 满足如下条件:\\(1)\ \ P(A)\ge0, \ \forall A \in \Im \ \\ (2)\ \ P(\Omega) = 1 (\Omega为全域)\\(3)\ \ P(\sum_{i=1}^{\infty}A_{i}) = \sum_{i=1}^{\infty}P(A_{i}) \ \ (加法定理) \\\]</span></p><p>满足如此条件,可以称 <span class="math inline">\(P\)</span> 为概率函数(如何证明一个函数是概率函数)</p><ul><li>衍生命题</li></ul><p><span class="math display">\[(1) \ P(A) \le 1,\forall A\in \Im \qquad (2) \ P(\phi) = 0 \qquad(3) \ P(A) = 1 - P(A^c) \\(4) \ P(\sum_{i=1}^{\infty}A_{i}) = \sum_{i=1}^{\infty}P(A_{i}) \quad A_iA_j = \phi,\forall i \neq j \\(5) \ 两事件 A、B, \quad A\subset B \Rightarrow P(A)\le P(B) \\(6) \ P(A+B) = P(A)+P(B)-P(AB)\]</span></p><p>对于第六点性质,存在推广的容斥定理: <span class="math display">\[P(\sum_{i=1}^nA_i) = \sum_{i=1}^nP(A_i) -\sum_{i_1<i_2}P(A_{i_1}A_{i_2})+....\]</span> <strong>例子:配对问题</strong></p><p>有 <span class="math inline">\(n\)</span> 个人,每人戴一顶帽子参加聚会,走的时候随机选择一顶帽子,请问:</p><ol type="1"><li><p>没有人拿到自己帽子的概率是多少</p></li><li><p>恰好有 <span class="math inline">\(k\)</span> 个人拿到自己的帽子的概率是多少</p></li></ol><p>解答:</p><p>(1)令 <span class="math inline">\(A_i\)</span> 为第 <span class="math inline">\(i\)</span> 个人拿到自己的帽子的事件,所以 <span class="math inline">\(P(A) = \frac {1} {n}\)</span></p><p>根据古典概型可以得到:<span class="math inline">\(P(A_{i_1}A_{i_2}....A_{i_r}) = \frac{(n-r)!}{n!}\)</span> <span class="math display">\[P_n = 1-(1-\frac{1}{2!}+\frac{1}{3!}-\frac{1}{4!}+...+(-1)^{n+1}\frac{1}{n!})\]</span> (2)恰好有 <span class="math inline">\(k\)</span> 个人拿到自己的帽子 <span class="math display">\[P=C_{n}^{k}P_{n-k}\]</span></p><h3 id="条件概率">6. 条件概率</h3><p><span class="math display">\[P(A|B) = \frac{P(AB)}{P(B)}( \ 需要 \ P(B)\gt 0 )\]</span></p><ul><li>计算<ul><li>缩小样本空间</li><li>根据定义进行计算</li></ul></li><li>性质</li></ul><p><span class="math display">\[P(AB)=P(A|B)P(B)=P(B|A)P(A)\]</span></p><p><strong>例子</strong></p><p>假设有 8 个红球,4 个白球,彼此之间无差别,进行一个无放回的摸球,取两个球都是红球的概率 <span class="math display">\[P(R_1R_2) = P(R_1)P(R_2|R_1) = \frac{8}{12}\times\frac{7}{11}\]</span> 将条件概率进行推广 <span class="math display">\[P(A_1A_2...A_n) = P(A_1)P(A_2|A_1)P(A_3|A_1A_2)...P(A_n|A_1A_2...A_{n-1})\]</span> 如此可以优化上面的配对问题算法</p><p><strong>条件概率函数</strong></p><p>给定 $B: P(B),P(|B):, 我们称 P(|B) 为概率函数 $</p><p>其中 <span class="math inline">\(P(A)\)</span> 与 <span class="math inline">\(P(A|B) 为一个先验和后验的过程\)</span>,对于一个已经观测到的事件 <span class="math inline">\(A\)</span>: <span class="math display">\[P(A|A)=1\]</span></p><h3 id="独立事件">7. 独立事件</h3><ul><li><p>若 <span class="math inline">\(P(AB) = P(A)P(B)\)</span>, 则称事件 <span class="math inline">\(A, B\)</span> 相互独立.</p></li><li><p>此时 <span class="math inline">\(P(A\mid B) = P(A)\)</span>, 即 <span class="math inline">\(\cfrac{P(AB)}{P(B)} = \cfrac{P(A\Omega)}{P(\Omega)}\)</span>, 事件 <span class="math inline">\(B\)</span> 的发生未改变 <span class="math inline">\(A\)</span> 发生的概率.</p></li><li><p>若可从实际角度判断独立性, 则可应用定义中的关系式; 一般地, 利用定义判断独立性.</p></li><li><p>事件 <span class="math inline">\(A, B\)</span> 相互独立, 则事件 <span class="math inline">\(A^c, B\)</span> 相互独立.</p></li><li><p>推广:</p></li><li><p><span class="math inline">\(A, B, C\,相互独立\Leftrightarrow P(ABC) = P(A)P(B)P(C)\,且\,A, B, C\,两两独立\)</span>.</p></li><li><p><span class="math inline">\(A, B, C\,两两独立\nRightarrow A, B, C\,相互独立\)</span></p></li><li><p>(反例) 甲乙两人抛掷 <span class="math inline">\(2\)</span> 枚硬币. <span class="math inline">\(A =\)</span> 甲正, <span class="math inline">\(B =\)</span> 乙正, <span class="math inline">\(C =\)</span> 甲乙同.</p><blockquote><p><span class="math inline">\(\textbf{定义}\)</span></p><p><span class="math inline">\(A_1, A_2, \cdots, A_n\,相互独立\Leftrightarrow 任选\,m\,个事件\,A_{i_1}, A_{i_2},\cdots, A_{i_m}, P(A_{i_1}A_{i_2}\cdots A_{i_m}) = P(A_{i_1})P(A_{i_2})\cdots P(A_{i_m}).\)</span></p></blockquote><blockquote><p><span class="math inline">\(\textbf{定义}\)</span></p><p><span class="math inline">\(A, B\)</span> 关于事件 <span class="math inline">\(E\)</span> 条件独立 <span class="math inline">\(\Leftrightarrow P(AB\mid E) = P(A\mid E)P(B\mid E)\)</span>.</p><p>条件独立与独立不可互推.</p></blockquote></li><li><p>条件独立 <span class="math display">\[A,B\ 关于事件\ E条件独立\Longleftrightarrow P(AB|E)= P(A|E) \times P(B|E)\]</span> 条件独立和独立二者不能互相推导</p></li></ul><h3 id="bayes-公式">8. Bayes 公式</h3><p>首先引入全概率公式的概念:</p><blockquote><p><span class="math inline">\(\textbf{全概率公式定义}\)</span></p><p><span class="math inline">\(\textbf{对于} \ \Omega \textbf{的一个分割 B}:\)</span> <span class="math display">\[(1)\sum B_i =\Omega \qquad (2)B_iB_j=\phi,\forall i \ne j \qquad (3)P(B_i)>0, \forall i\]</span> 我们有如下结论: <span class="math display">\[P(A) = P(\sum_i(AB_i))=\sum_iP(AB_i) = \sum_iP(A_i|B_i)P(B_i)\\P(B_i|A)=\frac{P(A|B_i)\cdot P(B_i)}{\sum P(A|B_j)P(B_j)}\]</span></p></blockquote>]]></content>
<categories>
<category> Math </category>
<category> 概率论 </category>
</categories>
<tags>
<tag> Math </tag>
</tags>
</entry>
<entry>
<title>C++ unordered_map</title>
<link href="/6/"/>
<url>/6/</url>
<content type="html"><![CDATA[<blockquote><p>unordered_map 容器:以键值对(pair类型)的形式存储数据,存储的各个键值对的键互不相同且不允许被修改。容器底层采用的是哈希表存储结构,该结构本身不具有对数据的排序功能,所以此容器内部不会自行对存储的键值对进行排序。</p></blockquote><p>在很多算法题中,我们可以通过使用这种容器建立一种映射关系,是一种高效的哈希表(至少我自己写的没有这么高效)</p><h3 id="具体用法">具体用法:</h3><ul><li><h5 id="构造容器">构造容器:</h5><p>通过调用 unordered_map 模板类的默认构造函数,可以创建空的 unordered_map 容器。比如:</p><pre class="line-numbers language-c++" data-language="c++"><code class="language-c++">std::unordered_map<std::string, std::string> umap;<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>由此,就创建好了一个可存储 <string,string> 类型键值对的 unordered_map 容器。</p><p>当然在构造的时候也能完成一些初始化操作:</p><pre class="line-numbers language-c++" data-language="c++"><code class="language-c++">std::unordered_map<std::string, std::string> umap{ {"Python教程","http://c.biancheng.net/python/"}, {"Java教程","http://c.biancheng.net/java/"}, {"Linux教程","http://c.biancheng.net/linux/"} };<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre></li><li><h5 id="一些常用的用法">一些常用的用法:</h5><table><colgroup><col style="width: 23%"><col style="width: 76%"></colgroup><thead><tr class="header"><th>成员方法</th><th>功能</th></tr></thead><tbody><tr class="odd"><td>begin()</td><td>返回指向容器中第一个键值对的正向迭代器。</td></tr><tr class="even"><td>end()</td><td>返回指向容器中最后一个键值对之后位置的正向迭代器。</td></tr><tr class="odd"><td>cbegin()</td><td>和 begin() 功能相同,只不过在其基础上增加了 const 属性,即该方法返回的迭代器不能用于修改容器内存储的键值对。</td></tr><tr class="even"><td>cend()</td><td>和 end() 功能相同,只不过在其基础上,增加了 const 属性,即该方法返回的迭代器不能用于修改容器内存储的键值对。</td></tr><tr class="odd"><td>empty()</td><td>若容器为空,则返回 true;否则 false。</td></tr><tr class="even"><td>size()</td><td>返回当前容器中存有键值对的个数。</td></tr><tr class="odd"><td>max_size()</td><td>返回容器所能容纳键值对的最大个数,不同的操作系统,其返回值亦不相同。</td></tr><tr class="even"><td>operator[key]</td><td>该模板类中重载了 [] 运算符,其功能是可以向访问数组中元素那样,只要给定某个键值对的键 key,就可以获取该键对应的值。注意,如果当前容器中没有以 key 为键的键值对,则其会使用该键向当前容器中插入一个新键值对。</td></tr><tr class="odd"><td>at(key)</td><td>返回容器中存储的键 key 对应的值,如果 key 不存在,则会抛出 out_of_range 异常。</td></tr><tr class="even"><td>find(key)</td><td>查找以 key 为键的键值对,如果找到,则返回一个指向该键值对的正向迭代器;反之,则返回一个指向容器中最后一个键值对之后位置的迭代器(如果 end() 方法返回的迭代器)。</td></tr><tr class="odd"><td>count(key)</td><td>在容器中查找以 key 键的键值对的个数。</td></tr><tr class="even"><td>equal_range(key)</td><td>返回一个 pair 对象,其包含 2 个迭代器,用于表明当前容器中键为 key 的键值对所在的范围。</td></tr><tr class="odd"><td>emplace()</td><td>向容器中添加新键值对,效率比 insert() 方法高。</td></tr><tr class="even"><td>emplace_hint()</td><td>向容器中添加新键值对,效率比 insert() 方法高。</td></tr><tr class="odd"><td>insert()</td><td>向容器中添加新键值对。</td></tr><tr class="even"><td>erase()</td><td>删除指定键值对。</td></tr><tr class="odd"><td>clear()</td><td>清空容器,即删除容器中存储的所有键值对。</td></tr><tr class="even"><td>swap()</td><td>交换 2 个 unordered_map 容器存储的键值对,前提是必须保证这 2 个容器的类型完全相等。</td></tr><tr class="odd"><td>bucket_count()</td><td>返回当前容器底层存储键值对时,使用桶(一个线性链表代表一个桶)的数量。</td></tr><tr class="even"><td>max_bucket_count()</td><td>返回当前系统中,unordered_map 容器底层最多可以使用多少桶。</td></tr><tr class="odd"><td>bucket_size(n)</td><td>返回第 n 个桶中存储键值对的数量。</td></tr><tr class="even"><td>bucket(key)</td><td>返回以 key 为键的键值对所在桶的编号。</td></tr><tr class="odd"><td>load_factor()</td><td>返回 unordered_map 容器中当前的负载因子。负载因子,指的是的当前容器中存储键值对的数量(size())和使用桶数(bucket_count())的比值,即 load_factor() = size() / bucket_count()。</td></tr><tr class="even"><td>max_load_factor()</td><td>返回或者设置当前 unordered_map 容器的负载因子。</td></tr><tr class="odd"><td>rehash(n)</td><td>将当前容器底层使用桶的数量设置为 n。</td></tr><tr class="even"><td>reserve()</td><td>将存储桶的数量(也就是 bucket_count() 方法的返回值)设置为至少容纳count个元(不超过最大负载因子)所需的数量,并重新整理容器。</td></tr><tr class="odd"><td>hash_function()</td><td>返回当前容器使用的哈希函数对象。</td></tr></tbody></table></li></ul><h3 id="一道小小的练习题来自leetcode">一道小小的练习题(来自Leetcode):</h3><p>给你字符串 <code>key</code> 和 <code>message</code> ,分别表示一个加密密钥和一段加密消息。解密 <code>message</code> 的步骤如下:</p><ol type="1"><li>使用 <code>key</code> 中 26 个英文小写字母第一次出现的顺序作为替换表中的字母 <strong>顺序</strong> 。</li><li>将替换表与普通英文字母表对齐,形成对照表。</li><li>按照对照表 <strong>替换</strong> <code>message</code> 中的每个字母。</li><li>空格 <code>' '</code> 保持不变。</li></ol><ul><li>例如,<code>key = "***hap***p***y*** ***bo***y"</code>(实际的加密密钥会包含字母表中每个字母 <strong>至少一次</strong>),据此,可以得到部分对照表(<code>'h' -> 'a'</code>、<code>'a' -> 'b'</code>、<code>'p' -> 'c'</code>、<code>'y' -> 'd'</code>、<code>'b' -> 'e'</code>、<code>'o' -> 'f'</code>)。</li></ul><p>题解:</p><pre class="line-numbers language-c++" data-language="c++"><code class="language-c++">class Solution {public: unordered_map<char,char>map; string decodeMessage(string key, string message) { int tot = 0; for(auto c:key) { if(map.count(c)==0&&c!=' ') map[c] = (char)('a'+tot++); } string ans; for(auto c:message) { if(c==' ') ans += c; else { ans += map[c]; } } return ans; }};<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>非常简单的一道小题目:https://leetcode.cn/problems/decode-the-message/description/</p>]]></content>
<categories>
<category> CS </category>
<category> OI </category>
</categories>
<tags>
<tag> OI </tag>
</tags>
</entry>
<entry>
<title>Set与Multiset</title>
<link href="/5/"/>
<url>/5/</url>
<content type="html"><![CDATA[<h3 id="leetcode题干">Leetcode题干</h3><p>给你两个整数 <code>m</code> 和 <code>k</code> ,以及数据流形式的若干整数。你需要实现一个数据结构,计算这个数据流的 <strong>MK 平均值</strong> 。</p><p><strong>MK 平均值</strong> 按照如下步骤计算:</p><ol type="1"><li>如果数据流中的整数少于 <code>m</code> 个,<strong>MK 平均值</strong> 为 <code>-1</code> ,否则将数据流中最后 <code>m</code> 个元素拷贝到一个独立的容器中。</li><li>从这个容器中删除最小的 <code>k</code> 个数和最大的 <code>k</code> 个数。</li><li>计算剩余元素的平均值,并 <strong>向下取整到最近的整数</strong> 。</li></ol><p>请你实现 <code>MKAverage</code> 类:</p><ul><li><code>MKAverage(int m, int k)</code> 用一个空的数据流和两个整数 <code>m</code> 和 <code>k</code> 初始化 <strong>MKAverage</strong> 对象。</li><li><code>void addElement(int num)</code> 往数据流中插入一个新的元素 <code>num</code> 。</li><li><code>int calculateMKAverage()</code> 对当前的数据流计算并返回 <strong>MK 平均数</strong> ,结果需 <strong>向下取整到最近的整数</strong> 。</li></ul><h3 id="解法总结">解法总结</h3><p>本题考查对于有序集合 set 的一些用法,与之不同的在于,本题的 set 中的元素可以重复,所以我们使用 multiset ,允许集合中的元素出现重复</p><h4 id="有序集合的一些基础用法">有序集合的一些基础用法:</h4><pre class="line-numbers language-c++" data-language="c++"><code class="language-c++">#include <set>#include <iostream>using namespace std;struct cmp{ bool operator()(const int ls, const int rs) const { return rs < ls; }};int main(){ set<int> test_1; for (int i = 10; i >= 0; i--) { test_1.insert(i); } for (auto s = test_1.begin(); s != test_1.end(); s++) { cout << *s << " "; } cout << endl; set<int, cmp> test_2; for (int i = 0; i <= 10; i++) { test_2.insert(i); } for (auto s = test_2.begin(); s != test_2.end(); s++) { cout << *s << " "; } return 0;}<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><ul><li>有序集合一般情况下都是从小到大排序</li><li>可以自己定义新排序函数,重载运算符即可</li></ul><h4 id="有序集合的访问与删除操作">有序集合的访问与删除操作</h4><ul><li>针对访问:迭代器访问</li></ul><pre class="line-numbers language-c++" data-language="c++"><code class="language-c++">#include <set>using namespace std;set<int>test;test.begin();// 第一个元素test.end(); // 最后一个元素的后一个test.rend(); //反向迭代器第一个的前一个test.rbegin(); //反向迭代器的最后一个prev(test.end()); //最后一个元素<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><ul><li><p>针对删除:迭代器删除</p><p>注意erase的时候不能使用反向迭代器</p></li></ul>]]></content>
<categories>
<category> CS </category>
<category> OI </category>
</categories>
<tags>
<tag> OI </tag>
</tags>
</entry>
<entry>
<title>Hello World</title>
<link href="/4/"/>
<url>/4/</url>
<content type="html"><![CDATA[<h3 id="写在一切一切的开始希望自己能有意义地走完这艰难的一路">写在一切一切的开始,希望自己能有意义地走完这艰难的一路。</h3>]]></content>
<categories>
<category> CS </category>
<category> OI </category>
</categories>
<tags>
<tag> OI </tag>
</tags>
</entry>
<entry>
<title>Git入门学习</title>
<link href="/2/"/>
<url>/2/</url>
<content type="html"><![CDATA[<h2 id="what-are-vcss">What Are VCSs?</h2><p>Version control systems (VCSs) are tools used to track changes to a folder and its contents in a series of snapshots. They also maintain metadata like who created each snapshot, messages associated with each snapshot, and so on.</p><p>While other VCSs exist, <strong>Git</strong> is the de facto standard for version control.</p><h2 id="data-model">Data Model</h2><p>Git has a well-thought-out model that enables maintaining history, supporting branches, and collaboration.</p><h3 id="snapshots">Snapshots</h3><p>Git models the history of a collection of files and folders within some top-level directory as a series of snapshots.</p><ul><li>File -- Blob</li><li>Directory -- Tree</li><li>Snapshot -- The top-level tree being tracked</li></ul><h3 id="history-relating-snapshots">History: Relating snapshots</h3><p>In Git, a history is a directed acyclic graph (DAG) of snapshots. This means that each snapshot in Git refers to a set of “parents”, the snapshots that preceded it. Moreover, a snapshot might descend from multiple parents due to combining (merging) two parallel branches of development.</p><h3 id="data-model-as-pseudocode">Data model: As pseudocode</h3><p>It is instructive to see Git’s data model written down in pseudocode.</p><pre class="line-numbers language-python" data-language="python"><code class="language-python"><span class="token builtin">type</span> blob <span class="token operator">=</span> array<span class="token operator"><</span>byte<span class="token operator">></span><span class="token builtin">type</span> tree <span class="token operator">=</span> <span class="token builtin">map</span><span class="token operator"><</span>string<span class="token punctuation">,</span> tree <span class="token operator">|</span> blob<span class="token operator">></span><span class="token builtin">type</span> commit <span class="token operator">=</span> struct <span class="token punctuation">{</span> parents<span class="token punctuation">:</span> array<span class="token operator"><</span>commit<span class="token operator">></span> author<span class="token punctuation">:</span> string message<span class="token punctuation">:</span> string snapshot<span class="token punctuation">:</span> tree<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="objects-and-content-addressing">Objects and Content-Addressing</h3><p>An “object” is a blob, tree, or commit. In Git data store, all objects are content-addressed by <a href="https://en.wikipedia.org/wiki/SHA-1">SHA-1 hash</a>.</p><pre class="line-numbers language-python" data-language="python"><code class="language-python"><span class="token builtin">type</span> <span class="token builtin">object</span> <span class="token operator">=</span> blob <span class="token operator">|</span> tree <span class="token operator">|</span> commitobjects <span class="token operator">=</span> <span class="token builtin">map</span><span class="token operator"><</span>string<span class="token punctuation">,</span> <span class="token builtin">object</span><span class="token operator">></span><span class="token keyword">def</span> <span class="token function">store</span><span class="token punctuation">(</span><span class="token builtin">object</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token builtin">id</span> <span class="token operator">=</span> sha1<span class="token punctuation">(</span><span class="token builtin">object</span><span class="token punctuation">)</span> objects<span class="token punctuation">[</span><span class="token builtin">id</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token builtin">object</span><span class="token keyword">def</span> <span class="token function">load</span><span class="token punctuation">(</span><span class="token builtin">id</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">return</span> objects<span class="token punctuation">[</span><span class="token builtin">id</span><span class="token punctuation">]</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="references">References</h3><p>Git’s solution is human-readable names for SHA-1 hashes, called "references". References are mutable pointers to commits. For example, the <code>master</code> reference usually points to the latest commit in the main branch of development. Moreover, "where we currently are" is a special reference called “HEAD”.</p><pre class="line-numbers language-python" data-language="python"><code class="language-python">references <span class="token operator">=</span> <span class="token builtin">map</span><span class="token operator"><</span>string<span class="token punctuation">,</span> string<span class="token operator">></span><span class="token keyword">def</span> <span class="token function">update_reference</span><span class="token punctuation">(</span>name<span class="token punctuation">,</span> <span class="token builtin">id</span><span class="token punctuation">)</span><span class="token punctuation">:</span> references<span class="token punctuation">[</span>name<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token builtin">id</span><span class="token keyword">def</span> <span class="token function">read_reference</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">return</span> references<span class="token punctuation">[</span>name<span class="token punctuation">]</span><span class="token keyword">def</span> <span class="token function">load_reference</span><span class="token punctuation">(</span>name_or_id<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">if</span> name_or_id <span class="token keyword">in</span> references<span class="token punctuation">:</span> <span class="token keyword">return</span> load<span class="token punctuation">(</span>references<span class="token punctuation">[</span>name_or_id<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token keyword">else</span><span class="token punctuation">:</span> <span class="token keyword">return</span> load<span class="token punctuation">(</span>name_or_id<span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="repositories">Repositories</h3><p>A Git <em>repository</em> is the data <code>objects</code> and <code>references</code>.</p><h2 id="staging-area">Staging Area</h2><p>For example, imagine a scenario where you have debugging print statements added all over your code, along with a bugfix; you want to commit the bugfix while discarding all the print statements.</p><p>Git accommodates such scenarios by allowing you to specify which modifications should be included in the next snapshot through a mechanism called the “staging area”.</p><h2 id="command-line-interface">Command-Line Interface</h2><h3 id="basics">Basics</h3><ul><li><code>git help <command></code>: get help for a command</li><li><code>git init</code>: create a new git repo with data stored in the <code>.git</code> directory</li><li><code>git status</code>: tell what is going on</li><li><code>git add <filename></code>: add files to staging area</li><li><code>git commit</code>: create a new commit<ul><li>Write <a href="https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html">good commit messages</a>!</li><li>More reasons to write <a href="https://chris.beams.io/posts/git-commit/">good commit messages</a>!</li></ul></li><li><code>git log</code>: show a flattened log of history</li><li><code>git log --all --graph --decorate</code>: visualizes history as a DAG</li><li><code>git diff <filename></code>: show changes made to the staging area</li><li><code>git diff <revision> <filename></code>: show differences in a file between snapshots</li><li><code>git checkout <revision></code>: update HEAD and current branch</li></ul><h3 id="branching-and-merging">Branching and Merging</h3><ul><li><code>git branch</code>: show branches</li><li><code>git branch <name></code>: create a branch</li><li><code>git checkout -b <name></code>: create a branch and switch to it</li><li><code>git merge <revision></code>: merge into current branch</li><li><code>git mergetool</code>: use a fancy tool to help resolve merge conflicts</li><li><code>git rebase</code>: rebase set of patches onto a new base</li></ul><h3 id="remotes">Remotes</h3><ul><li><code>git remote</code>: list remotes</li><li><code>git remote add <name> <url></code>: add a remote</li><li><code>git push <remote> <local branch>:<remote branch></code>: send objects to remote and update remote reference</li><li><code>git branch --set-upstream-to=<remote>/<remote branch></code>: set up correspondence between local and remote branch</li><li><code>git fetch</code>: retrieve objects/references from a remote</li><li><code>git pull</code>: same as <code>git fetch; git merge</code></li><li><code>git clone</code>: download repository from remote</li></ul><h3 id="undo">Undo</h3><ul><li><code>git config</code>: Git is <a href="https://git-scm.com/docs/git-config">highly customizable</a></li><li><code>git clone --depth=1</code>: shallow clone, without entire version history</li><li><code>git add -p</code>: interactive staging</li><li><code>git rebase -i</code>: interactive rebasing</li><li><code>git blame</code>: show who last edited which line</li><li><code>git stash</code>: temporarily remove modifications to working directory</li><li><code>git bisect</code>: binary search history</li><li><code>.gitignore</code>: <a href="https://git-scm.com/docs/gitignore">specify</a> intentionally untracked files to ignore</li></ul>]]></content>
<categories>
<category> CS </category>
<category> Git </category>
</categories>
<tags>
<tag> Git </tag>
</tags>
</entry>
<entry>
<title>Elasticsearch学习笔记</title>
<link href="/1/"/>
<url>/1/</url>
<content type="html"><![CDATA[<h2 id="elasticsearch引擎">Elasticsearch引擎</h2><h3 id="环境配置和部署">1. 环境配置和部署</h3><ul><li><h4 id="有关elasticsearch端口">有关Elasticsearch端口:</h4><p>进入/usr/local/bin,运行./elasticsearch,打开服务器</p><p>有关此处的bug处理,原因大多是多开了node,可以直接使用:ps -ef | grep elastic,然后 kill -9 进程号,杀死进程</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">ps</span> <span class="token parameter variable">-ef</span> <span class="token operator">|</span> <span class="token function">grep</span> elastic<span class="token function">kill</span> <span class="token parameter variable">-9</span> 进程号<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre></li><li><h4 id="有关kibana插件">有关kibana插件:</h4><p>进入kibana的bin文件夹下运行./kibana即可</p></li><li><h4 id="有关elasticsearchhead插件">有关elasticsearchhead插件:</h4><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token builtin class-name">cd</span> elasticsearch-head<span class="token function">npm</span> <span class="token function">install</span><span class="token function">npm</span> start<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><p>出现:Started connect web server on http://localhost:9100 代表运行成功</p></li></ul><h3 id="elasticsearch数据库相关">2. Elasticsearch数据库相关:</h3><ul><li><h4 id="概念相关">概念相关:</h4><ul><li><p>Index(索引表,也可以理解为数据库):</p><p>Elastic 数据管理的顶层单位就叫做 Index(索引)。它是单个数据库的同义词。每个 Index (即数据库)的名字<strong>必须是小写</strong>。</p></li><li><p>Document:</p><p>Index 里面单条的记录(数据)称为 Document(文档)。Document 使用 JSON 格式表示。</p></li><li><p>Type:</p><p>Document 可以分组,比如<code>weather</code>这个 Index 里面,可以按城市分组(北京和上海),也可以按气候分组(晴天和雨天)。这种分组就叫做 Type,它是虚拟的逻辑分组,用来过滤 Document。以下命令可以获得每个Index包含的Type:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">curl</span> <span class="token string">'localhost:9200/_mapping?pretty=true'</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre></li></ul></li><li><h4 id="数据库的相关操作">数据库的相关操作:</h4><ul><li><h5 id="新建删除index">新建、删除Index:</h5><p>使用PUT请求,新建一个名叫<code>weather</code>的 Index。</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">$ <span class="token function">curl</span> <span class="token parameter variable">-X</span> PUT <span class="token string">'localhost:9200/weather'</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>服务器会返回一个JSON对象:</p><pre class="line-numbers language-json" data-language="json"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"acknowledged"</span><span class="token operator">:</span><span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token property">"shards_acknowledged"</span><span class="token operator">:</span><span class="token boolean">true</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre><p>发出 DELETE 请求,删除这个 Index。</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">$ <span class="token function">curl</span> <span class="token parameter variable">-X</span> DELETE <span class="token string">'localhost:9200/weather'</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre></li><li><h5 id="分词设置">分词设置:</h5><p>分词器的安装,注意<strong>分词器的版本要和Elasticsearch一致</strong>:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">$ ./bin/elasticsearch-plugin <span class="token function">install</span> https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v5.5.1/elasticsearch-analysis-ik-5.5.1.zip<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>一个创建的例子:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">$ <span class="token function">curl</span> <span class="token parameter variable">-X</span> PUT <span class="token string">'localhost:9200/accounts'</span> <span class="token parameter variable">-d</span> <span class="token string">'{ "mappings": { "person": { "properties": { "user": { "type": "text", "analyzer": "ik_max_word", "search_analyzer": "ik_max_word" }, "title": { "type": "text", "analyzer": "ik_max_word", "search_analyzer": "ik_max_word" }, "desc": { "type": "text", "analyzer": "ik_max_word", "search_analyzer": "ik_max_word" } } } }}'</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>首先创建了一个名为accounts的Index,里面有一个名称为person的Type。Person中有:user、title、desc三个字段(其中的mapping相当于表定义)</p></li><li><h5 id="数据操作">数据操作</h5><ul><li><p>新增数据</p><p>向指定的 /Index/Type 发送 PUT 请求,就可以在 Index 里面新增一条记录。比如,向<code>/accounts/person</code>发送请求,就可以新增一条人员记录。</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">$ <span class="token function">curl</span> <span class="token parameter variable">-X</span> PUT <span class="token string">'localhost:9200/accounts/person/1'</span> <span class="token parameter variable">-d</span> <span class="token string">'{ "user": "张三", "title": "工程师", "desc": "数据库管理"}'</span> <span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>服务器会返回JSON对象,给出Index,Type,Id,Version等信息:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token punctuation">{</span> <span class="token string">"_index"</span><span class="token builtin class-name">:</span><span class="token string">"accounts"</span>, <span class="token string">"_type"</span><span class="token builtin class-name">:</span><span class="token string">"person"</span>, <span class="token string">"_id"</span><span class="token builtin class-name">:</span><span class="token string">"1"</span>, <span class="token string">"_version"</span>:1, <span class="token string">"result"</span><span class="token builtin class-name">:</span><span class="token string">"created"</span>, <span class="token string">"_shards"</span>:<span class="token punctuation">{</span><span class="token string">"total"</span>:2,<span class="token string">"successful"</span>:1,<span class="token string">"failed"</span>:0<span class="token punctuation">}</span>, <span class="token string">"created"</span>:true<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>在上面的操作中,指定了请求路径中的Id,但也可以使用POST请求,不指定Id:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">$ <span class="token function">curl</span> <span class="token parameter variable">-X</span> POST <span class="token string">'localhost:9200/accounts/person'</span> <span class="token parameter variable">-d</span> <span class="token string">'{ "user": "李四", "title": "工程师", "desc": "系统管理"}'</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></li><li><h5 id="查看记录">查看记录:</h5><p>向<code>/Index/Type/Id</code>发出 GET 请求,就可以查看这条记录。</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">$ <span class="token function">curl</span> <span class="token string">'localhost:9200/accounts/person/1?pretty=true'</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><pre class="line-numbers language-json" data-language="json"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"_index"</span> <span class="token operator">:</span> <span class="token string">"accounts"</span><span class="token punctuation">,</span> <span class="token property">"_type"</span> <span class="token operator">:</span> <span class="token string">"person"</span><span class="token punctuation">,</span> <span class="token property">"_id"</span> <span class="token operator">:</span> <span class="token string">"1"</span><span class="token punctuation">,</span> <span class="token property">"_version"</span> <span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token property">"found"</span> <span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token property">"_source"</span> <span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"user"</span> <span class="token operator">:</span> <span class="token string">"张三"</span><span class="token punctuation">,</span> <span class="token property">"title"</span> <span class="token operator">:</span> <span class="token string">"工程师"</span><span class="token punctuation">,</span> <span class="token property">"desc"</span> <span class="token operator">:</span> <span class="token string">"数据库管理"</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>返回的数据中,<code>found</code>字段表示查询成功,<code>_source</code>字段返回原始记录。Id不正确就会返回false</p></li><li><h5 id="删除记录">删除记录:</h5><p>发出 DELETE 请求。</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">$ <span class="token function">curl</span> <span class="token parameter variable">-X</span> DELETE <span class="token string">'localhost:9200/accounts/person/1'</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre></li><li><h5 id="更新记录">更新记录:</h5><p>使用 PUT 请求,重新发送一次数据。</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">$ <span class="token function">curl</span> <span class="token parameter variable">-X</span> PUT <span class="token string">'localhost:9200/accounts/person/1'</span> <span class="token parameter variable">-d</span> <span class="token string">'{ "user" : "张三", "title" : "工程师", "desc" : "数据库管理,软件开发"}'</span> <span class="token punctuation">{</span> <span class="token string">"_index"</span><span class="token builtin class-name">:</span><span class="token string">"accounts"</span>, <span class="token string">"_type"</span><span class="token builtin class-name">:</span><span class="token string">"person"</span>, <span class="token string">"_id"</span><span class="token builtin class-name">:</span><span class="token string">"1"</span>, <span class="token string">"_version"</span>:2, <span class="token string">"result"</span><span class="token builtin class-name">:</span><span class="token string">"updated"</span>, <span class="token string">"_shards"</span>:<span class="token punctuation">{</span><span class="token string">"total"</span>:2,<span class="token string">"successful"</span>:1,<span class="token string">"failed"</span>:0<span class="token punctuation">}</span>, <span class="token string">"created"</span>:false<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></li></ul></li><li><h4 id="数据查询">数据查询:</h4><ul><li><h5 id="返回所有数据">返回所有数据:</h5><p>使用 GET 方法,直接请求<code>/Index/Type/_search</code>,就会返回所有记录。</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">$ <span class="token function">curl</span> <span class="token string">'localhost:9200/accounts/person/_search'</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>返回如下JSON:</p><pre class="line-numbers language-json" data-language="json"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"took"</span><span class="token operator">:</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token property">"timed_out"</span><span class="token operator">:</span><span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token property">"_shards"</span><span class="token operator">:</span><span class="token punctuation">{</span><span class="token property">"total"</span><span class="token operator">:</span><span class="token number">5</span><span class="token punctuation">,</span><span class="token property">"successful"</span><span class="token operator">:</span><span class="token number">5</span><span class="token punctuation">,</span><span class="token property">"failed"</span><span class="token operator">:</span><span class="token number">0</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"hits"</span><span class="token operator">:</span><span class="token punctuation">{</span> <span class="token property">"total"</span><span class="token operator">:</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token property">"max_score"</span><span class="token operator">:</span><span class="token number">1.0</span><span class="token punctuation">,</span> <span class="token property">"hits"</span><span class="token operator">:</span> 此处为所有的数据 <span class="token punctuation">}</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></li><li><p>Match查询:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">$ <span class="token function">curl</span> <span class="token string">'localhost:9200/accounts/person/_search'</span> <span class="token parameter variable">-d</span> <span class="token string">'{ "query" : { "match" : { "desc" : "软件" }}, "size" : 1 , "from" : 1 ,}'</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>指定的匹配条件是<code>desc</code>字段里面包含"软件"这个词。返回结果如下:</p><pre class="line-numbers language-json" data-language="json"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"took"</span><span class="token operator">:</span><span class="token number">3</span><span class="token punctuation">,</span> <span class="token property">"timed_out"</span><span class="token operator">:</span><span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token property">"_shards"</span><span class="token operator">:</span><span class="token punctuation">{</span><span class="token property">"total"</span><span class="token operator">:</span><span class="token number">5</span><span class="token punctuation">,</span><span class="token property">"successful"</span><span class="token operator">:</span><span class="token number">5</span><span class="token punctuation">,</span><span class="token property">"failed"</span><span class="token operator">:</span><span class="token number">0</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"hits"</span><span class="token operator">:</span><span class="token punctuation">{</span> <span class="token property">"total"</span><span class="token operator">:</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token property">"max_score"</span><span class="token operator">:</span><span class="token number">0.28582606</span><span class="token punctuation">,</span> <span class="token property">"hits"</span><span class="token operator">:</span><span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token property">"_index"</span><span class="token operator">:</span><span class="token string">"accounts"</span><span class="token punctuation">,</span> <span class="token property">"_type"</span><span class="token operator">:</span><span class="token string">"person"</span><span class="token punctuation">,</span> <span class="token property">"_id"</span><span class="token operator">:</span><span class="token string">"1"</span><span class="token punctuation">,</span> <span class="token property">"_score"</span><span class="token operator">:</span><span class="token number">0.28582606</span><span class="token punctuation">,</span> <span class="token property">"_source"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"user"</span> <span class="token operator">:</span> <span class="token string">"张三"</span><span class="token punctuation">,</span> <span class="token property">"title"</span> <span class="token operator">:</span> <span class="token string">"工程师"</span><span class="token punctuation">,</span> <span class="token property">"desc"</span> <span class="token operator">:</span> <span class="token string">"数据库管理,软件开发"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>如果有多个关键词,Elastic默认他们是or的关系。如果想要执行多个关键词的<code>and</code>搜索,必须使用布尔查询。</p><pre class="line-numbers language-json" data-language="json"><code class="language-json">$ curl 'localhost<span class="token operator">:</span><span class="token number">9200</span>/accounts/person/_search' -d '<span class="token punctuation">{</span> <span class="token property">"query"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"bool"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"must"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token property">"match"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"desc"</span><span class="token operator">:</span> <span class="token string">"软件"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token property">"match"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"desc"</span><span class="token operator">:</span> <span class="token string">"系统"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">}</span>'<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></li></ul></li></ul></li></ul><h3 id="elasticsearch的python接口elasticsearch-dsl">3. Elasticsearch的Python接口(Elasticsearch-dsl)</h3><ul><li><h4 id="将数据写入es中">将数据写入ES中:</h4><ul><li><p>首先需要定义ES数据类型:</p><pre class="line-numbers language-python" data-language="python"><code class="language-python"> <span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre></li></ul></li></ul>]]></content>
<categories>
<category> CS </category>
<category> Elasticsearch </category>
</categories>
<tags>
<tag> Elasticsearch </tag>
</tags>
</entry>
<entry>
<title>OOP学习笔记</title>
<link href="/3/"/>
<url>/3/</url>
<content type="html"><![CDATA[<h2 id="l3-封装与接口">L3-封装与接口</h2><h4 id="函数重载与缺省值">3.1 函数重载与缺省值</h4><blockquote><p>为什么需要函数重载: 同一任务,但输入信息的类型不同;同一任务,函数输入信息的存储形式不同</p></blockquote><p>注意:多个同名的函数实现之间,必须保证至少有一个函数参数的类型有区别。<strong><em>返回值、参数名称</em></strong>等不能作为区分标识。</p><blockquote><p>有关函数的缺省值:</p><p>有缺省值的函数参数,必须是最后一个参数;</p><p>如果有多个带缺省值的函数参数,则这些函数参数都只能在没有缺省值的参数后面出现</p></blockquote><h4 id="基础知识">3.2 基础知识</h4><ol type="1"><li><p>auto(C++11):由编译器根据上下文自动确定变量的类型;</p><p>注意:auto 变量必须在编译期确定其类型;auto 变量必须在定义时初始化;参数不能被声明为auto;</p><p>需要注意的用法:追踪返回类型的函数声明形式;替换冗长变量声明;在定义模板函数时,用于声明依赖模板参数的变量类型。</p><pre class="line-numbers language-C++" data-language="C++"><code class="language-C++">auto func(char* ptr, int val) -> int;<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre></li><li><p>decltype:可以对变量或表达式结果的类型进行推导</p><p>比如对匿名的结构体进行推导</p></li><li><p>结合auto与decltype:</p><pre class="line-numbers language-c++" data-language="c++"><code class="language-c++">template <typename _Tx, typename _Ty> auto multiply(_Tx x, _Ty y)->decltype(x*y){ return x*y; }auto a = multiply(2, 3.3); //a=6.6<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></li><li><p>有关内存的动态申请与释放:略</p></li><li><p>零指针:0、NULL、nullptr</p><p>注意NULL=0,是个int型常量,所以为了避免重载函数时发生歧义,所以引入严格意义上的空指针nullptr</p></li></ol><h4 id="封装与数据抽象">3.3封装与数据抽象</h4><ol type="1"><li><p>注意访问权限问题:不允许在类外(非该类的成员函数)操作访问对象的私有成员和保护成员!</p></li><li><p>成员函数与普通函数的重要区别:隐含着一个指向当前对象的指针变量,其名称为this</p></li><li><p>有关内联函数:加快运行速度,宏定义与之相比存在许多不可避免的缺陷</p><blockquote><p>一些注意事项:</p><p>避免对大段代码使用内联修饰符;避免对包含循环或者复杂控制结构的函数使用内联定义;</p><p>避免将内联函数的声明和定义分开;定义在类声明中的函数默认为内联函数。</p></blockquote></li></ol><h2 id="l4-创建与销毁-1">L4-创建与销毁-1</h2><h4 id="构造函数">4.1构造函数</h4><blockquote><p>特点:</p><p>无返回值类型,可以重载,可以使用初始化列表(注意:<strong>初始化列表的成员是按照声明的顺序初始化的</strong>)</p><p>在构造函数的初始化列表中,还可以调用其他构造函数,称为“委派构造函数”。</p><p>c++11新增:就地初始化(只是一种简便的表达方式,实际操作仍然在对象构造的时候执行)</p></blockquote><p>有关默认构造函数的一些额外操作:</p><ol type="1"><li><p>会自动调用成员变量的默认构造函数:先调用成员变量的构造,再执行自己的构造函数!</p></li><li><p>编译器隐式地合成了默认构造函数(<strong><em>若用户已经定义了其他构造函数,编译器将不会隐式合成默认构造函数,需要显示声明</em></strong>)</p></li><li><p>用delete显式地删除构造函数,避免产生未预期行为的可能性。</p><pre class="line-numbers language-c++" data-language="c++"><code class="language-c++">class Student {private: int ID = 1; char class = 'a';public: Student() = default; Student(int i):ID(i) {} Student(char cls) = delete; };Student s('c'); // 编译错误<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></li><li><p>有关对象数组的初始化</p><pre class="line-numbers language-c++" data-language="c++"><code class="language-c++">A a[50]; // 定义了一个具有50个元素的A类对象数组A a[3] = {1, 3, 5}; // 三个实参分别传递给3个数组元素的构造函数A a[3] = {A(1, 2), A(3, 5), A(0, 7)}; // 构造函数有两个整型参数<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre></li></ol><h4 id="析构函数">4.2析构函数</h4><p>主要用于释放动态分配的内存等典型需要释放的资源。</p><p>有关析构函数的一些额外操作:</p><ol type="1"><li>会自动调用成员变量的析构函数:先执行自己的析构函数,再调用成员变量的析构!</li><li>当用户没有自定义析构函数时,编译器会自动合成一个隐式的析构函数(注意隐式定义的析构函数不会delete指针成员,导致内存泄漏)</li></ol><h5 id="一些其他的注意事项">一些其他的注意事项:</h5><ol type="1"><li>全局对象:在main()函数调用之前进行初始化。在同一编译单元中,按照定义顺序进行初始化。不同编译单元中,对象初始化顺序不确定。在main()函数执行完return之后,对象被析构。</li></ol><h4 id="引用">4.3引用</h4><blockquote><p>特点:创建时必须初始化、初始化后便不能指向其他对象,不存在空引用,相对指针更安全</p></blockquote><p>基本应用:</p><ol type="1"><li>函数参数可以是引用类型,表示函数的形式参数与实际参数是同一个变量,改变形参将改变实参。</li><li>函数返回值可以是引用类型,<strong><em>但不得指向函数的临时变量!</em></strong></li></ol><h4 id="类的运算符重载">4.4类的运算符重载</h4><p>运算符重载的两种方式:全局函数、成员函数。</p><p>一些运算符重载的常用形式:</p><pre class="line-numbers language-c++" data-language="c++"><code class="language-c++">Test& operator++ () {}//前缀++运算符Test operator++ (int) {}//后缀++运算符int& operator[] (const char* name) // 字符串作下标istream& operator>> (istream& in, Test& dst );ostream& operator<< (ostream& out, const Test& src );<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre><p><strong><em>注意:=,[],(),->只能通过成员函数来重载</em></strong></p><h2 id="l5-创建与销毁-2">L5-创建与销毁-2</h2><h4 id="友元">5.1友元</h4><blockquote><p>被声明为友元的函数或类,即可以访问该类的一切成员。</p><p>友元的声明只能在类内进行。可以声明别的类的成员函数,为当前类的友元。(其中,构造函数、析构函数也可以是友元);</p><p>友元的声明与当前所在域是否为private或public无关</p></blockquote><p>一些注意事项:!!!</p><ol type="1"><li>非对称关系:类A中声明B是A的友元类,则B可以访问A的私有成员,但A不能访问B的私有成员。</li><li>友元不传递;友元不继承;友元声明不能定义新的class</li></ol><h4 id="静态变量与静态函数">5.2静态变量与静态函数</h4><p>由于本人掌握的并不好,所以重点进行了一些复习回顾。</p><p>回顾C中的静态变量与静态函数:</p><blockquote><p>静态变量:使用static修饰的变量:static int i = 1; 1.初始化:初次定义时需要初始化,且只能初始化一次。 2.静态局部变量存储在静态存储区,生命周期将持续到整个程序结束 3.静态全局变量是内部可链接的,作用域仅限其声明的文件,不能被其他文件所用,可以避免和其他文件中的同名变量冲突</p><p>静态函数:使用static修饰的函数:static int func() {…} 静态函数是内部可链接的,作用域仅限其声明的文件,不能被其他文件所用,可以避免和其他文件中的同名函数冲突</p></blockquote><p>一些区别:</p><blockquote><p>静态全局变量/静态函数<strong><em>是内部可链接的</em></strong>,作用域仅限其声明的文件,不能被其他文件所用 非静态全局变量/非静态全局函数是<strong><em>外部可链接的,可以被其他文件所用</em></strong></p></blockquote><blockquote><p>==有关静态数据成员==:</p><p>静态数据成员被该类的所有对象共享;既可以通过对象来访问,也可以通过类名来访问;和全局变量一样,类的静态数据成员在程序开始前初始化;应该在.h文件中声明,在.cpp文件中定义。</p></blockquote><blockquote><p>==有关静态成员函数==:</p><p>既可以通过对象来访问,也可以通过类名来访问;属于整个类,<strong><em>在类实例化对象之前已经分配了内存空间</em></strong>。</p><p>==静态成员函数不能访问非静态成员==;</p></blockquote><p>回顾C语言中的const常量:</p><blockquote><p>修饰变量时(如const int n = 1;),必须就地初始化;</p><p>修饰引用/指针时(如int a=1; const int& b=a;),不能通过该引用/指针修改相应变量的值;</p><p>修饰函数返回值时(如const int* func() {…}),函数返回值的内容(或其指向的内容)不能被修改</p></blockquote><blockquote><p>有关常量数据成员:构造函数的初始化列表中被初始化;就地初始化;</p><p>注意:不允许在构造函数的函数体中通过赋值来设置</p></blockquote><blockquote><p>有关常量成员函数:</p><p>访问权限:实现语句不能修改类的数据成员,即不能改变对象状态(内容)</p><p>对象被定义为常量(const ClassName a;),则它只能调用以const修饰的成员函数</p></blockquote><p>常量静态变量:</p><p>需要在类外进行定义(但有两个例外:int和enum类型可以就地初始化)</p><p>注意:</p><blockquote><p>函数中静态对象:在函数内部定义的静态局部对象 在程序执行到该静态局部对象的代码时被初始化。 离开作用域不析构。 第二次执行到该对象代码时,不再初始化,直接使用上一次的对象 在main()函数结束后被析构。</p></blockquote><h2 id="l6-引用与复制">L6-引用与复制</h2><h4 id="常量引用">6.1常量引用</h4><blockquote><p><strong><em>最小特权原则:给函数足够的权限去完成相应的任务,但不要给予他多余的权限。</em></strong></p></blockquote><h4 id="拷贝构造函数">6.2拷贝构造函数</h4><blockquote><p><strong><em>拷贝构造函数是一种特殊的构造函数,它的参数是语言规定的,是同类对象的常量引用</em></strong></p></blockquote><p>被调用的三种情况:</p><ol type="1"><li><p>用一个类对象定义另一个新的类对象:Test a; Test b(a); Test c = a;</p></li><li><p>函数调用时以类的对象为形参:Func(Test a)</p></li><li><p>函数返回类对象:Test Func(void)</p></li></ol><p>隐式定义的拷贝构造函数:<strong><em>调用所有数据成员的拷贝构造函数(位拷贝)或拷贝赋值运算符</em></strong></p><p>==<strong><em>拷贝构造函数的问题</em></strong>==:</p><ol type="1"><li>当对象很大的时候或当对象含有指针的时候,频繁的拷贝构造会造成程序效率的显著下降,带来诸多不便</li></ol><p>解决办法:</p><ol start="2" type="1"><li>使用引用/常量引用传参数或返回对象;将拷贝构造函数声明为private;用delete关键字让编译器不生成拷贝构造函数的隐式定义版本。</li></ol><h4 id="右值引用与移动构造函数">6.3右值引用与移动构造函数</h4><p>c++11新特性:<strong><em>右值引用</em></strong></p><blockquote><p>右值:不能取地址、没有名字的值;常见于常值、函数返回值、表达式</p></blockquote><p>但是可以被&&引用(右值引用)!(注意:无法绑定左值)</p><p>左值引用能绑定左值,右值引用能绑定右值。常量左值引用能也绑定右值</p><p><strong><em>所有的引用(包括右值引用)本身都是左值</em></strong></p><blockquote><p><strong>使用右值引用作为参数的构造函数叫做移动构造函数。</strong></p><p>移动构造函数直接利用了原来临时对象中的堆内存,新的对象无需开辟内存,临时对象无需释放内存,从而大大提高计算效率。</p></blockquote><p>此处加一个PPT中的代码示例:</p><pre class="line-numbers language-c++" data-language="c++"><code class="language-c++">class Test {public:int * buf; //// only for demo.Test() {buf = new int[10]; //申请一块内存cout << "Test(): this->buf @ " << hex << buf << endl;}~Test() {cout << "~Test(): this->buf @ " << hex << buf << endl;if (buf) delete[] buf;}Test(const Test& t) : buf(new int[10]) {for(int i=0; i<10; i++) buf[i] = t.buf[i]; //拷贝数据cout << "Test(const Test&) called. this->buf @ "<< hex << buf << endl;}Test(Test&& t) : buf(t.buf) { //直接复制地址,避免拷贝cout << "Test(Test&&) called. this->buf @ "<< hex << buf << endl;t.buf = nullptr; //将t.buf改为nullptr,使其不再指向原来内存区域}};<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><blockquote><p>编译器自动进行返回值优化的条件:return 的值类型与函数签名的返回值类型相同;return的是一个局部对象。</p></blockquote><p>std::move函数:move函数本身不对对象做任何操作,仅做类型转换,即转换为右值。移动的具体操作在移动构造函数内实现。</p><blockquote><p>注意:函数返回类对象(类中显式定义移动构造函数,不进行返回值优化): {return Test(); or return tmp;}均调用移动构造</p></blockquote><p>有关拷贝赋值运算符的注意点:必须要是类的非静态成员函数,不能是友元函数。</p><h4 id="类型转换">6.6类型转换</h4><blockquote><p>当编译器发现表达式和函数调用所需的数据类型和实际类型不同时,便会进行<strong><em>自动类型转换</em></strong>。</p><p><strong>自动类型转换可通过定义特定的转换运算符和构造函数来完成。</strong></p></blockquote><ol type="1"><li><p>在源类中定义“目标类型转换运算符”:</p><pre class="line-numbers language-c++" data-language="c++"><code class="language-c++">class Src { //源类Sourcepublic: operator Dst() const { //目标类Dst()cout << "Src::operator Dst() called" << endl;return Dst(); }};<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></li><li><p>在目标类中定义“源类对象作参数的构造函数”</p></li></ol><pre class="line-numbers language-c++" data-language="c++"><code class="language-c++">class Dst {public: Dst() { cout << "Dst::Dst()" << endl; } Dst(const Src& s) { cout << "Dst::Dst(const Src&)" << endl; }};<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>注意:两种自动类型转换的方法不能同时使用,使用时请任选其中一种。</p><h5 id="禁止自动类型转换">禁止自动类型转换:</h5><p>用explicit修饰类型转换运算符或类型转换构造函数,则相应的类型转换必须显式地进行</p><h2 id="l7-组合与继承">L7-组合与继承</h2><h4 id="组合">7.1组合</h4><blockquote><p>组合:has-a、“整体-部分”关系</p><p>作为新类的公有数据成员,这样通过允许直接访问子对象而“提供”旧类接口;</p><p>作为新类的私有数据成员。新类可以调整旧类的对外接口,可以不使用旧类原有的接口(相当于对接口作了转换)</p></blockquote><h5 id="组合中的一些注意事项">组合中的一些注意事项:</h5><p>子对象构造时若需要参数,则应在当前类的构造函数的初始化列表中进行。若使用默认构造函数来构造子对象,则不用做任何处理。</p><h4 id="继承">7.2继承</h4><blockquote><p>继承:is-a:“一般-特殊”结构,也称“分类结构”,“一般-特殊”关系</p></blockquote><p>注意:不能被继承的有:构造函数、析构函数、赋值运算符、友元函数。</p><p>派生类的构造过程:</p><ol type="1"><li><p>基类中的数据成员需要在构造派生类对象的过程中调用基类构造函数来正确初始化(只能在派生类构造函数的初始化成员列表中进行)</p></li><li><p>先执行基类,再执行派生类。(析构过程与之相反)</p></li><li><p>无显式调用基类构造函数,则调用基类默认构造函数</p></li></ol><p>需要注意的一点是:如果派生类使用了继承构造函数,编译器就不会再为派生类生成隐式定义的默认构造函数。</p><p><strong><em>有关继承后的权限问题:</em></strong></p><ol type="1"><li><p>基类中的私有成员:不允许在派生类成员函数中访问,也不允许派生类的对象访问它们。真正体现“基类私有”,对派生类也不开放其权限!</p></li><li><p>基类中的公有成员:允许在派生类成员函数中被访问;</p><p>若是使用public继承方式,则成为派生类公有成员,可以被派生类的对象访问; 若是使用private/protected继承方式,则成为派生类私有/保护成员,不能被派生类的对象访问。若想让某成员能被派生类的对象访问,可在派生类public部分用关键字using声明它的名字。</p></li><li><p>基类中的保护成员: 保护成员允许在派生类成员函数中被访问,但不能被外部函数访问。</p></li></ol><h4 id="重写隐藏与重载">7.4重写隐藏与重载</h4><blockquote><p>重载:提供同名函数的不同实现,属于静态多态。</p><p>要求:函数名必须相同,函数参数必须不同,作用域相同</p></blockquote><blockquote><p>重写隐藏:在派生类中重新定义基类函数,实现派生类的特殊功能。屏蔽了基类的所有其它同名函数。</p><p>函数名必须相同,函数参数可以不同</p></blockquote><p>To be attention:重写隐藏发生时,基类中该成员函数的其他重载函数都将被屏蔽掉,不能提供给派生类对象使用</p><h5 id="多重继承的问题">多重继承的问题:</h5><p>数据存储的冗余与二义性</p><h2 id="l8-虚函数">L8-虚函数</h2><h4 id="向上类型转换">8.1向上类型转换</h4><blockquote><p>向上类型转换:只对public继承有效,派生类对象/引用/指针转换成基类对象/引用/指针,是一种隐式类型转换</p></blockquote><h4 id="对象切片">8.2对象切片</h4><blockquote><p>当派生类的对象(不是指针或引用)被转换为基类的对象时,派生类的对象被切片为对应基类的子对象。</p></blockquote><h4 id="虚函数">8.3虚函数</h4><blockquote><p>虚函数的晚捆绑:编译器将根据所指(或引用)对象的实际类型决定是调用基类中的函数,还是调用派生类重写的函数</p><p>注意:当派生类重写覆盖它时(同名,同参数函数) ,无论是否声明为虚函数,该成员函数都仍然是虚函数。</p></blockquote><p>构造函数不能也不必是虚函数(构造函数中调用的虚函数不起作用),析构函数常常是虚的</p><h5 id="重载重写隐藏与重写覆盖">重载、重写隐藏与重写覆盖</h5><table><thead><tr class="header"><th></th><th>重载(overload)</th><th>重写隐藏(redefining)</th><th>重写覆盖(override)</th></tr></thead><tbody><tr class="odd"><td>作用域</td><td>相同(同一个类中,或者均为全局函数)</td><td>不同(派生类和基类)</td><td>不同(派生类和基类)</td></tr><tr class="even"><td>函数名</td><td>相同</td><td>相同</td><td>相同</td></tr><tr class="odd"><td>函数参数</td><td>不同</td><td>相同/不同</td><td>相同</td></tr><tr class="even"><td>返回值</td><td>不能仅返回值不同</td><td>无要求</td><td>相同或协变的</td></tr><tr class="odd"><td>其他要求</td><td>—</td><td>如果函数参数相同,则基类函数不能为虚函数</td><td>基类函数为虚函数</td></tr></tbody></table><p><strong><em>重写覆盖同样会隐藏掉基类的同名函数!</em></strong></p><blockquote><p>override关键词:只是编译器的一个检查,正确实现override时,对编译结果没有影响。</p></blockquote><blockquote><p>final关键词:</p><p>在虚函数声明或定义中使用时,final确保函数为虚且不可被派生类重写。禁止后续派生类对指定虚函数重写。 在类定义中使用时,final指定此类不可被继承。</p></blockquote><h2 id="l9-多态与模版">L9-多态与模版</h2><h4 id="纯虚函数与抽象类">9.1纯虚函数与抽象类</h4><blockquote><p>纯虚函数:virtual 返回类型 函数名(形式参数) = 0;</p><p>含有纯虚函数的为抽象类,无法实例化对象。主要用途是为派生类规定共性“接口”。</p><p>避免对象切片:保证只有指针和引用能被向上类型转换。</p><p>当继承一个抽象类时,除纯虚析构函数外(后面解释),必须实现所有纯虚函数,否则继承出的类也是抽象类。(纯虚析构函数除外)</p></blockquote><h4 id="向下类型转换">9.2向下类型转换</h4><blockquote><p>基类指针/引用转换成派生类指针/引用,则称为向下类型转换。(类层次中向下移动)</p><p>使用dynamic_cast的对象必须有虚函数</p></blockquote><p>示例:</p><pre class="line-numbers language-c++" data-language="c++"><code class="language-c++">//obj_p,obj_r分别是T1类型的指针和引用T2* pObj = dynamic_cast<T2*>(obj_p);//转换为T2指针,运行时失败返回nullptrT2& refObj = dynamic_cast<T2&>(obj_r);//转换为T2引用,运行时失败抛出bad_cast异常<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre><blockquote><p>如果我们知道正在处理的是哪些类型,可以使用static_cast来避免这种开销</p><p>static_cast在编译时静态浏览类层次,只检查继承关系。没有继承关系的类之间,必须具有转换途径才能进行转换</p></blockquote><p>示例:</p><pre class="line-numbers language-c++" data-language="c++"><code class="language-c++">//obj_p,obj_r分别是T1类型的指针和引用T2* pObj = static_cast<T2*>(obj_p); //转换为T2指针T2& refObj = static_cast<T2&>(obj_r); //转换为T2引用<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre><details><summary>dynamic_cast与static_cast</summary>相同点:都可完成向下类型转换。 <br> 不同点: static_cast在编译时静态执行向下类型转换。 <br>dynamic_cast会在运行时检查被转换的对象是否确实是正确的派生类。额外的检查需要 RTTI (Run-Time Type Information),因此要比static_cast慢一些,但是更安全。</details><details><summary>向上与向下类型转换</summary>向上类型转换: <br>转换为基类指针或引用,则对应虚函数表仍为派生类的虚函数表(晚绑定)。 <br>转换为基类对象,产生对象切片,调用基类函数(早绑定)。 <br>向下类型转换: <br>dynamic_cast通过虚函数表来判断是否能进行向下类型转换。</details><h4 id="多重继承中的虚函数">9.3多重继承中的虚函数</h4><blockquote><p>作用:避免 多重继承的二义性;利用 一个对象可以实现多个接口</p></blockquote><h4 id="多态">9.4多态</h4><blockquote><p>当利用基类指针/引用调用函数时:</p><ol type="1"><li>虚函数在运行时确定执行哪个版本,取决于引用或指针对象的真实类型</li><li>非虚函数在编译时绑定</li></ol><p>当利用类的对象直接调用函数时:</p><ol type="1"><li>无论什么函数,均在编译时绑定</li></ol></blockquote><p>总之,是一种代码重用的基本技术,可以大大提高程序的可复用性,提高了程序可拓展性和可维护性。</p><h4 id="函数模版与类模版">9.5函数模版与类模版</h4><blockquote><p>有些算法实现与类型无关,所以可以将函数的参数类型也定义为一种特殊的“参数”,这样就得到了“函数模板”。</p><p>对模板的处理是在编译期进行的,函数模板在调用时,编译器能自动推导出实际参数的类型(这个过程叫做实例化)。</p></blockquote><p>如下:</p><pre class="line-numbers language-c++" data-language="c++"><code class="language-c++">template <typename T> ReturnType Func(Args);<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p><strong><em>模板库必须在头文件中实现,不可以分开编译</em></strong></p><blockquote><p>类模板:在定义类时将一些类型信息抽取出来,用模板参数来替换,从而使类更具通用性。</p></blockquote><p>注意:所有模板参数必须在编译期确定,不可以使用变量。</p><pre class="line-numbers language-c++" data-language="c++"><code class="language-c++">template<typename T, unsigned size>class array { T elems[size];}; <span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre><p>有关模版与多态:</p><blockquote><p>模板的关联是在编译期处理,称为静多态</p><p>基于继承和虚函数的多态在运行期处理,称为动多态</p></blockquote><h2 id="l10-模版与stl初步">L10-模版与STL初步</h2><h4 id="命名空间">10.1命名空间</h4><p>略。。。。</p><h4 id="stl初步">10.2 STL初步</h4><blockquote><p>基于模板编写,包含4个组件,分别为算法、容器、函数、迭代器。</p><p>关键理念:将“在数据上执行的操作”与“要执行操作的数据”分离。</p></blockquote><h5 id="容器">容器:</h5><blockquote><p>包括:简单容器(simple container)、序列容器(sequence container)、关系容器(associative container)</p></blockquote><ol type="1"><li><p>pair容器</p><pre class="line-numbers language-c++" data-language="c++"><code class="language-c++">template<class T1, class T2> struct pair{T1 first;T2 second;//若干其它函数};std::pair<int, int> t;t.first = 4; t.second = 5;auto t = std::make_pair(“abc”, 7.8);//创建//支持比较运算符重载//std::make_pair(1, 4) < std::make_pair(2, 3);//std::make_pair(1, 4) > std::make_pair(1, 2);<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></li><li><p>tuple容器</p><pre class="line-numbers language-c++" data-language="c++"><code class="language-c++">auto t = std::make_tuple(“abc”, 7.8, 123, ‘3’);//创建std::string x; double y; int z;std::tie(x, y, z) = std::make_tuple(“abc”, 7.8, 123);//同时获取三个值auto v0 = std::get<0>(t);//通过get获得数据,必须在编译时确定下标<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre></li><li><p>vector数组</p><pre class="line-numbers language-c++" data-language="c++"><code class="language-c++">std:vector<int> x;//创建x.size();//获取长度x.clear();//清空x.push_back(1); x.pop_back();//末尾增/删//迭代器中间删/增x.insert(x.begin()+1, 5);x.erase(x.begin()+1);for(auto & x : vec)//遍历<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p><strong><em>注意迭代器失效的情况:</em></strong></p><ol type="1"><li>调用insert/erase后,所修改位置之后的所有迭代器失效。(原先的内存空间存储的元素被改变)</li><li>调用push_back等修改vector大小的方法时,可能会使所有迭代器失效</li></ol></li><li><p>list链表</p><blockquote><ol type="1"><li>不支持下标等随机访问</li><li>支持在任意位置高速插入/删除数据</li><li>其访问主要依赖迭代器,插入和删除操作不会导致迭代器失效(除指向被删除的元素的迭代器外)</li></ol></blockquote></li><li><p>set集合</p><blockquote><ol type="1"><li><p>内部元素无重复</p></li><li><p>内部按大小顺序排列,比较器由函数对象Compare完成。</p></li></ol></blockquote></li><li><p>map容器</p><blockquote><p>其值类型为pair<Key, T>。元素key必须互不相同。可以通过下标访问。可使用insert函数进行插入。</p></blockquote></li></ol><h5 id="容器的相关总结">==容器的相关总结:==</h5><blockquote><p>序列容器:容器中的元素有顺序,可以按顺序访问</p><p>例如:vector、list等</p><p>关联容器:元素无顺序,可以按照数值(大小)访问</p><p>例如:set、map等</p><p>有关迭代器失效:vector中的插入删除操作使得其后所有的迭代器失效;其他只是当前迭代器失效</p></blockquote><h4 id="函数模版与类模版特化">10.3函数模版与类模版特化</h4><blockquote><p>有时,有些类型并不合适,则需要对模板在某种情况下的具体类型进行特殊处理,这称为“模板特化”。</p><p><strong><em>注意:特化时必须提供所有参数的特例类型(但可以用重载来替代部分特化。)</em></strong></p></blockquote><blockquote><p>函数模板重载解析顺序:</p><ol type="1"><li>如果有普通函数且类型匹配,则直接选中,重载解析结束</li><li>如果没有类型匹配的普通函数,则选择最合适的基础模板</li><li>如果选中的基础模板有全特化版本且类型匹配,则选择全特化版本,否则使用基础模板</li></ol></blockquote><h2 id="l12-stl和字符串处理">L12-STL和字符串处理</h2><h4 id="string类字符串">12.1 string类字符串</h4><p>一些容易忽略的基础知识</p><pre class="line-numbers language-c++" data-language="c++"><code class="language-c++">//构造方法string s3(“Another character sequence”, 12);//截取前12个字符string s4(10, 'x'); //复制字符:xxxxxxxxxxfor(char c : str) //迭代访问//读取方式getline(cin, fullname);//读一行getline(cin, fullnames, ‘#’);//读到指定分隔符为止(可以读入换行符)//数值类型字符串化的精度损失to_string(3.1415926)//"3.141593" 注意精度损失int b = stoi("50 cats", &sz) //b=50 sz=2 代表读入长度<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h4 id="iostream输入输出流">12.2 iostream输入输出流</h4><h5 id="ostream">12.2.1 ostream</h5><blockquote><p>是STL库中所有输出流的基类;统一了输出接口;cout是内建的一个ostream对象</p></blockquote><p>有关格式化输出:</p><pre class="line-numbers language-c++" data-language="c++"><code class="language-c++">cout << fixed << 2018.0 << " " << 0.0001 << endl;//浮点数 -> 2018.000000 0.000100cout << scientific << 2018.0 << endl;//科学计数法 -> 2.018000e+03cout << defaultfloat; //还原默认输出格式cout << setprecision(2) << 3.1415926 << endl; //输出精度设置为2 -> 3.2cout << oct << 12 << " " << hex << 12 << endl; //八进制输出 -> 14 十六进制输出 -> ccout << dec;//还原十进制cout << setw(3) << setfill('*') << 5 << endl;//设置对齐长度为3,对齐字符为* -> **5<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>一点相关说明:</p><blockquote><p>setprecision : 一个类的对象。流操纵算子:借助辅助类,设置成员变量</p><p>endl:是一个函数,等同于输出'',再清空缓冲区 os.flush(),同时也是流操纵算子</p><p>==有关cout的复制问题==:重载流运算符要返回引用是为了避免复制,只允许移动,仅使用cout一个全局对象</p><p>原因:减少复制开销;一个对象对应一个标准输出,符合OOP思想;多个对象之间无法同步输出状态</p></blockquote><h4 id="文件输入输出流">12.3 文件输入输出流</h4><blockquote><p>ifstream是istream的子类。</p><p>流输入取代scanf的原因:类型友好;安全性;可拓展性;</p><p>性能:scanf在运行期间需要对格式字符串进行解析;istream在编译期间已经解析完毕</p></blockquote><h4 id="字符串输入输出流">12.4 字符串输入输出流</h4><blockquote><p>stringstream是iostream的子类,实现了输入输出流双方的接口,一般用于程序内的字符串操作</p><p>具体实现:在对象内部维护了一个buffer,使用流输出函数可以将数据写入buffer,使用流输入函数可以从buffer中读出数据</p><p>有关buffer的获取:ss.str()返回一个string对象(即是buffer的内容,但并不是未读取的内容,buffer内含一个指针)</p></blockquote><h2 id="l13-函数对象与智能指针">L13 函数对象与智能指针</h2><h4 id="函数对象">13.1函数对象</h4><blockquote><p>用变量表示函数:</p><pre class="line-numbers language-c++" data-language="c++"><code class="language-c++">void (*func)(int&); //函数指针的声明auto func = flag==1?increase:decrease; //使用auto自动推断<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre></blockquote><p>函数可以作为变量,传入类模版参数(模版类型可以接受函数指针/函数对象):</p><blockquote><p>STL提供的预定义的比较函数:less<int>()与greater<int>()</int></int></p></blockquote><p>注意:</p><blockquote><p>实际上,greater<int>()是一个对象,greater是一个模板类,greater<int> 用int实例化的,greater<int>() 该类的一个对象</int></int></int></p><p><strong><em>这种对象被称为函数对象</em></strong></p></blockquote><p>函数对象的要求:</p><ol type="1"><li>需要重载operator()运算符</li><li>并且该函数需要是public访问权限</li></ol><p>在模版这一策略模式中,想要用数组储存选项:需要std::function类,例如:</p><pre class="line-numbers language-c++" data-language="c++"><code class="language-c++">function<string()> readArr[] = {readFromScreen, ReadFromFile()};<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><blockquote><p>function为函数指针与对象提供了统一的接口</p></blockquote><p>使用模版策略:编译期确定调用函数的地址(当T不为std::function时);运行时确定调用函数的地址(使用std::function时)</p><blockquote><p>function的意义:</p><ol type="1"><li>函数对象化:函数可以作为参数传递、函数可以作为变量储存</li></ol></blockquote><h4 id="智能指针与-引用计数">13.2 智能指针与引用计数</h4><blockquote><p>智能指针:shared_ptr 来自<memory>库</memory></p><p>注意,当指针p2和p3指向同一对象,当两者均出作用域才会被销毁(引用计数归0)</p></blockquote><p>有关shared_ptr的一些其他用法:</p><pre class="line-numbers language-c++" data-language="c++"><code class="language-c++">p.get()//获取裸指针p.reset()//清除指针并减少引用计数static_pointer_cast<int>(p) //转为int类型指针(和static_cast类似,无类型检查)dynamic_pointer_cast<Base>(p) //转为int类型指针(和dynamic_cast类似,动态类型检查)<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre><p>注意:</p><ol type="1"><li>不能用一个裸指针初始化多个智能指针(会产生多个辅助指针),不能直接用智能指针维护对象数组。</li><li>智能指针并不是总是智能,也会出现内存泄漏的情况(需要弱引用指针)</li></ol><blockquote><p>弱引用指针weak_ptr:指向对象,却不计数</p></blockquote><p>弱引用指针weak_ptr的一些用法:</p><pre class="line-numbers language-c++" data-language="c++"><code class="language-c++">wp.use_count()//获取引用计数wp.reset()//清除指针wp.expired()//检查对象是否无效sp = wp.lock()//从弱引用获得一个智能指针<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre><blockquote><p>unique_ptr:独享所有权,保证一个对象只被一个指针引用;可以移动,不能复制</p></blockquote><p>有关智能指针的总结:</p><blockquote><p><strong><em>优点:</em></strong></p><ol type="1"><li>智能指针可以帮助管理内存,避免内存泄露</li><li>区分unique_ptr和shared_ptr能够明确语义</li><li>在手动维护指针不可行,复制对象开销太大时,智能指针是唯一选择。</li></ol><p><strong><em>缺点:</em></strong></p><ol type="1"><li>引用计数会影响性能</li><li>智能指针不总是智能,需要了解内部原理</li><li>需要小心环状结构和数组指针</li></ol></blockquote><h2 id="l14-行为型模式">L14-行为型模式</h2><blockquote><p>设计模式:在长期实践中,开发人员总结的优秀架构与解决方案。</p><p>三大种类:行为型模式(Behavioral Patterns)、结构型模式(Structural Patterns)、创建型模式(Creational Patterns)</p><p><strong><em>各自的优势与特点:</em></strong></p><p>行为型模式:关注对象行为功能上的抽象,旨在提升对象在行为功能上的可拓展性,<strong><em>以最少的代码变动完成功能的增减。</em></strong></p><p>结构型模式:关注对象之间结构关系上的抽象,旨在<strong><em>提升对象结构的可维护性、代码健壮性</em></strong>,在结构层面上解耦合。</p><p>创建型模式:将对象创建与使用分离,旨在<strong><em>规避复杂对象创建带来的资源消耗</em></strong>,以简短代码完成对象的高效创建</p></blockquote><h4 id="行为型模式">行为型模式:</h4><h5 id="模版方法模式">14.1 模版方法模式:</h5><blockquote><ol type="1"><li>在接口的一个方法中定义算法的骨架(父类抽象类定义算法的骨架)</li><li>将一些步骤的实现延迟到子类中(算法的实现细节由子类实现类负责实现)</li><li>使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。</li></ol><p><strong><em>注意:当拓展一个新的实现类时,重新继承与实现即可,无需对已有的实现类进行修改</em></strong></p></blockquote><p>总结:</p><ol type="1"><li>模版方法针对接口编程,设计出描述“抽象概念”的接口类,接口类中有一系列的(纯)虚函数(简单稳定)</li><li>根据具体的需求,通过继承、实现虚函数,形成抽象基类的“实现类”(复杂多变)</li><li>用接口类引用实现类,方便大型程序的管理</li></ol><blockquote><p>模版方法的开放封闭原则:</p><ol type="1"><li>对扩展开放,有新需求或变化时,可以方便地现有代码进行扩展,而无需整体变动</li><li>对修改封闭,新的扩展类一旦设计完成,可以独立完成其工作,同样不需要整体变动</li></ol></blockquote><h5 id="策略模式">14.2 策略模式</h5><blockquote><p>定义一系列算法并加以封装,使得这些算法可以互相替换</p></blockquote><p>需要的实现:</p><p>1个AIFramework类、3个抽象策略类(接口)、n+m+k个策略实现类(实现),减少了实现类组合造成的大量代码冗余</p><blockquote><p>策略模式的单一责任原则:</p><ol type="1"><li>一个类(接口)只负责一项职责</li><li>不要存在多于一个导致类变更的原因</li></ol><p>单一职责原则的核心:在功能层面上解耦</p></blockquote><p>两种方式的比较:</p><p>从代码方面</p><pre class="line-numbers language-c++" data-language="c++"><code class="language-c++">//模版方法模式class AIFramework {public:virtual void readData(string path) = 0;virtual string processData(OneData data) = 0;virtual float evaluate(vector<int> results) = 0; //......protected: //用以存储信息的成员变量 ....};class SentimentAnalysis:public AIFramework { //实现具体的模版类public:void readData(string path);string processData(OneData data);void evaluate(); //.......};//其余具体实现.......//针对每一种特定的需求,继承产生各自的实现类,这种方式在组合的过程中,造成大量的代码冗余<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><pre class="line-numbers language-c++" data-language="c++"><code class="language-c++">//策略模式//读取策略基类class ReadStrategy {public:virtual vector<OneData> readData(string path) = 0;};class ReadStrategyTxt : public ReadStrategy {//读取算法一具体实现public:vector<OneData> readData(string path){};};//读取算法其余实现.....class ReadStrategyCsv : public ReadStrategy {…};//数据处理基类class ProcessStrategy {public:virtual string processData(OneData data) = 0;};class ProcessStrategyTokenize : public ProcessStrategy { //数据处理算法一具体实现public:string processData(OneData data) {....}};//数据处理算法二具体实现class ProcessStrategyStopWord : public ProcessStrategy {public:string processData(OneData data) {....}};class AIFramework {public://AIFramework就是各个策略类的组合AIFramework(ReadStrategy* rs, ProcessStrategy* ps, EvaluateStrategy* es, Model* model);void readData(string path);string processData(OneData data);float evaluate(vector<int> results);int predict(string input);protected://用来完成不同功能的策略类ReadStrategy* readStrategy;ProcessStrategy* processStrategy;EvaluateStrategy* evaluateStrategy; //其余存储数......};<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p><strong><em>小结:</em></strong></p><p>模板方法:侧重于<strong><em>逻辑复杂但结构稳定</em></strong>的场景,尤其是其中的某些步骤(部分功能)变化剧烈且没有相互关联。</p><p>策略模式:适用于<strong><em>算法(功能)本身灵活多变</em></strong>的场景,且多种算法之间需要协同工作。</p><h5 id="迭代器模式">14.3 迭代器模式:</h5><blockquote><p>实现与底层数据结构无关的统一算法接口,分离“存储”与“访问”</p><p>实现思想:用模板方法构建迭代器和数据存储基类,为每种单独的数据结构都实现其独有的迭代器和存储类</p><p>对于上层算法的执行,<strong><em>只依赖抽象的迭代器接口</em></strong></p></blockquote><pre class="line-numbers language-c++" data-language="c++"><code class="language-c++">//迭代器基类class Iterator {public:virtual ~Iterator() { }virtual Iterator& operator++() = 0;virtual OneData& operator++(int) = 0;virtual OneData& operator*() = 0;virtual OneData* operator->() = 0;virtual bool operator!=(const Iterator &other) const = 0;bool operator==(const Iterator &other) const {return !(*this != other);}};<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>一种基于数组的迭代器:</p><pre class="line-numbers language-c++" data-language="c++"><code class="language-c++">class ArrayCollection : public Collection { //底层为数组的存储结构类friend class ArrayIterator; //friend可以使得配套的迭代器类可以访问数据OneData* _data; //若需要实现float数组迭代器,可将OneData改为floatint _size;public: //存储数据,构造函数略.....Iterator* begin() const;Iterator* end() const;};Iterator* ArrayCollection::begin() const {//头迭代器,并放入相应数据return new ArrayIterator(_data, 0); //注意该迭代器应该由外部销毁}Iterator* ArrayCollection::end() const { //尾迭代器,并放入相应数据return new ArrayIterator(_data, _size); }//前缀++Iterator& ArrayIterator::operator++() {_index++; return *this; }//后缀++OneData& ArrayIterator::operator++(int) { _index++; return _data[_index - 1]; }<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p><strong><em>STL中的迭代器模式:</em></strong></p><p>与上述基于继承的操作不同,是基于模版实现的。</p><blockquote><p>区别:</p><p>继承:算法中需要使用迭代器的基类指针 模板:更加简洁,算法可以使用迭代器对象;对每一种迭代器类型都会生成相应代码,使编译速度变慢、可执行文件变大</p></blockquote><h2 id="l15-结构型模式">L15-结构型模式</h2><blockquote><p><strong><em>结构型模式:</em></strong>关心对象组成结构上的抽象,包括接口,层次,对象组合等,核心就在于<strong><em>==抽象结构层次上的不变量==</em></strong>,尽可能==减少类与类之间的联系与耦合==,从而能够以最小的代价支持新功能的增加。</p><ol type="1"><li>适配器模式:在类与类之间进行转接,提高了类的复用度与灵活性</li><li>代理/委托模式:减少了类与类层次间的耦合,使得类各自的职责清晰</li><li>装饰器模式:动态扩展被装饰类的功能,并留有接口进行持续扩展</li></ol></blockquote><h5 id="适配器adapater模式">15.1适配器(Adapater)模式:</h5><blockquote><p>核心:进行接口的“转换”,将一个类的接口转换成客户希望的另一个接口。</p><p>结构:目标、需要适配的类、适配器</p></blockquote><p>两种适配器模式://</p><ol type="1"><li>对象适配器模式:使用组合实现适配。</li><li>类适配器模式:使用继承实现适配。</li></ol><p>适配器的优点:统一接口、提高代码复用率、将目标类和适配者类解耦</p><pre class="line-numbers language-c++" data-language="c++"><code class="language-c++">//使用组合实现适配class NewModelAdapter : public Model{public: int predict(string input) { float result = newModel.predictResult(input); return result >= 0.5; } void load() { newModel.loadParameters(); };private:// 将NewModel组合进来实现相关功能 NewModel newModel;};//使用继承实现适配class NewModelAdapter : private NewModel, public Model {public: int predict(string input) { float res = predictResult(input); return res >= 0.5; } void load() { loadParameters(); }};<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h5 id="代理委托proxy">15.2代理/委托(Proxy)</h5><blockquote><p>代理/委托模式:提供被代理类所有接口的功能,另一方面可以同时进行额外的控制操作,如引用计数控制、权限控制、远程代理、延迟初始化等等</p><p>常见使用场景:</p><ol type="1"><li>远程代理:需要为一个存在于远程的对象在本地提供代表</li><li>智能引用:在访问对象时增加一些附加操作,例如引用计数</li><li>虚代理:一个对象的创建开销很大,需要延迟创建(即实际访问该对象内容时才申请资源创建对象)</li><li>保护代理:用代理对象控制对原始对象的访问权限</li></ol></blockquote><p>应用实例:AI预测模型的远程数据加载,使用代理模式实时加载数据,并不在本地保存所有数据,需要访问数据内容时先从远程逐条获取数据。</p><pre class="line-numbers language-c++" data-language="c++"><code class="language-c++">// 数据抽象类class AbstractData{public:virtual string getData() = 0;virtual int getLabel() = 0;};// 数据类class RealData: public AbstractData{public:string getData() {return text;}int getLabel() {return label;}private:string text; int label;};// 数据代理类class DataProxy: public AbstractData{public:string getData() {// 使用时加载数据RealData d = load();return d.getData();}int getLabel() {RealData d = load();return d.getLabel();}// 根据dataId从云端获取单条数据RealData load(){ … }private://数据id,根据id可逐条下载数据string dataId;};<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><blockquote><p>代理模式与适配模式的比较:</p><p>相同:在被访问对象之上进行封装、提供被封装对象的功能接口供外部使用</p><p>不同:代理不会改变接口,但适配器可能会、适配器不会增加控制,代理可能会。 适配器的核心要素是变换接口,、代理的核心要素是分割访问对象与被访问对象以减少耦合,并能在中间增加各种控制功能</p></blockquote><h5 id="装饰器decorator">15.3装饰器(Decorator)</h5><blockquote><p>装饰器:用装饰器类整体包裹改动之前的类,以保留原来的全部接口,在原来接口保留的基础上进行新功能扩充。</p><p>装饰类与被包装的类继承于同一基类,这样装饰之后的类可以被再次包装并赋予更多功能</p></blockquote><pre class="line-numbers language-c++" data-language="c++"><code class="language-c++">class ProcessDecorator : public ProcessStrategy {public:ProcessDecorator(ProcessStrategy* component) : component(component) {}//......virtual string extraProcess(string lastout) = 0;private://这里一个基类指针可以能够以递归的形式不断增加新功能ProcessStrategy* component;};//包裹原component并增加去除停用词处理class StopWordDecorator : public ProcessDecorator {public:StopWordDecorator(ProcessStrategy* component) : ProcessDecorator(component) {}string extraProcess(string lastout) { … } // 去除停用词};//包裹原component并增加前缀class PrefixDecorator : public ProcessDecorator {public:PrefixDecorator(ProcessStrategy* component) : ProcessDecorator(component) {}string extraProcess(string lastout) { … } // 增加前缀};<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><blockquote><p>装饰器与其他设计模式的比较:</p><ol type="1"><li><p>装饰器与策略模式相比:</p><p>相同点:通过组合修改对象的功能,更加灵活,减少冗余</p><p>不同点:策略修改对象功能的内核(行为),侧重于功能选择</p><p> 装饰器修改对象功能的外壳(结构),侧重于功能组装</p></li><li><p>装饰器与代理:</p><p>相同点:改变对象的行为,可以把“装饰”看成是一连串的“代理”</p><p>不同点:</p><p>装饰器:为被装饰对象增加额外的行为;不影响被装饰对象的原有功能;不创建被装饰对象(将新功能添加到已有对象上) 经常多重嵌套装饰</p><p>代理:常用来对被代理对象进行更精细的控制;被代理对象不存在时常创建被代理对象;少见多重嵌套</p></li></ol></blockquote><h3 id="设计模式总结">设计模式总结:</h3><ol type="1"><li><p>行为型模式:</p><p>提升对象在行为功能上的可拓展性,能以最少的代码变动完成功能的增减,常用于描述对类和对象的交互与职责分配。</p><p><strong><em>模板方法模式:</em></strong>定义算法骨架,将具体步骤的实现放到子类中实现。</p><p><strong><em>策略模式:</em></strong>定义一类算法,将每个算法分别封装,不同算法可以相互替换</p><p><strong><em>迭代器模式:</em></strong>解耦算法与数据访问。</p></li><li><p>结构型模式:</p><p>关注对象之间结构关系上的抽象,从而提升对象结构的可维护性、代码的健壮性,能在结构层面上尽可能的解耦合,常用于处理类和对象的组合关系。</p><p><strong><em>适配器模式:</em></strong>将不兼容的接口转换为可兼容的接口</p><p><strong><em>代理/委托模式:</em></strong>在不改变原始类接口的条件下,为原始类定义一个代理类,增加控制访问</p><p><strong><em>装饰模式:</em></strong>用组合来替代继承,给原始类添加增强功能</p></li></ol>]]></content>
<categories>
<category> CS </category>
<category> OOP </category>
</categories>
<tags>
<tag> OOP </tag>
</tags>
</entry>
</search>