-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
543 lines (277 loc) · 251 KB
/
atom.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
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>JaxRunboo's blog</title>
<subtitle>farmer</subtitle>
<link href="/atom.xml" rel="self"/>
<link href="https://www.smallapp.xyz/"/>
<updated>2020-04-07T09:54:46.558Z</updated>
<id>https://www.smallapp.xyz/</id>
<author>
<name>JaxRunboo</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>1102 Invert a Binary Tree</title>
<link href="https://www.smallapp.xyz/2020/04/07/1102InvertBinaryTree/"/>
<id>https://www.smallapp.xyz/2020/04/07/1102InvertBinaryTree/</id>
<published>2020-04-07T02:33:33.657Z</published>
<updated>2020-04-07T09:54:46.558Z</updated>
<content type="html"><![CDATA[<h3 id="分析-求反转二叉树的层序遍历和中序遍历,实际是改变二叉树节点的遍历输出顺序。层序遍历改为从右往左输出,"><a href="#分析-求反转二叉树的层序遍历和中序遍历,实际是改变二叉树节点的遍历输出顺序。层序遍历改为从右往左输出," class="headerlink" title="分析: 求反转二叉树的层序遍历和中序遍历,实际是改变二叉树节点的遍历输出顺序。层序遍历改为从右往左输出,"></a>分析: 求反转二叉树的层序遍历和中序遍历,实际是改变二叉树节点的遍历输出顺序。层序遍历改为从右往左输出,</h3><h3 id="中序遍历改为-右子树-root-左子树的顺序输出。"><a href="#中序遍历改为-右子树-root-左子树的顺序输出。" class="headerlink" title="中序遍历改为 右子树-root-左子树的顺序输出。"></a>中序遍历改为 右子树-root-左子树的顺序输出。</h3><h3 id="二维数组存储节点信息,层数遍历使用队列操作。中序遍历使用递归操作。"><a href="#二维数组存储节点信息,层数遍历使用队列操作。中序遍历使用递归操作。" class="headerlink" title="二维数组存储节点信息,层数遍历使用队列操作。中序遍历使用递归操作。"></a>二维数组存储节点信息,层数遍历使用队列操作。中序遍历使用递归操作。</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><iostream></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><vector></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><string></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><queue></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><cmath></span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">int</span> nodes[<span class="number">10</span>][<span class="number">2</span>];<span class="comment">//为0</span></span><br><span class="line"><span class="keyword">int</span> n;</span><br><span class="line"><span class="built_in">queue</span><<span class="keyword">int</span>> q,in;</span><br><span class="line"><span class="keyword">int</span> root = <span class="number">-1</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">LevelOrder</span><span class="params">(<span class="keyword">int</span> rootIndex)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> q.push(rootIndex);</span><br><span class="line"> <span class="keyword">while</span>(!q.empty())</span><br><span class="line"> {</span><br><span class="line"> rootIndex = q.front();</span><br><span class="line"> q.pop();</span><br><span class="line"> <span class="keyword">if</span>(nodes[rootIndex][<span class="number">1</span>]!=<span class="number">-1</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">" %d"</span>,nodes[rootIndex][<span class="number">1</span>]);</span><br><span class="line"> q.push(nodes[rootIndex][<span class="number">1</span>]);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span>(nodes[rootIndex][<span class="number">0</span>]!=<span class="number">-1</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">" %d"</span>,nodes[rootIndex][<span class="number">0</span>]);</span><br><span class="line"> q.push(nodes[rootIndex][<span class="number">0</span>]);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">InOrder</span><span class="params">(<span class="keyword">int</span> rootIndex)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="comment">//右root左</span></span><br><span class="line"> <span class="keyword">if</span>(nodes[rootIndex][<span class="number">1</span>]!=<span class="number">-1</span>)</span><br><span class="line"> {</span><br><span class="line"> InOrder(nodes[rootIndex][<span class="number">1</span>]);</span><br><span class="line"> }</span><br><span class="line"> in.push(rootIndex);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span>(nodes[rootIndex][<span class="number">0</span>]!=<span class="number">-1</span>)</span><br><span class="line"> {</span><br><span class="line"> InOrder(nodes[rootIndex][<span class="number">0</span>]);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d"</span>,&n);</span><br><span class="line"> <span class="keyword">int</span> hasvalue[n] = {<span class="number">0</span>};</span><br><span class="line"> <span class="built_in">string</span> left,right;</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>; i<n; i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">cin</span>>>left>>right;</span><br><span class="line"> <span class="keyword">if</span>(left==<span class="string">"-"</span>)</span><br><span class="line"> {</span><br><span class="line"> nodes[i][<span class="number">0</span>] = <span class="number">-1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> l = stoi(left);</span><br><span class="line"> hasvalue[l] =<span class="number">1</span>;</span><br><span class="line"> nodes[i][<span class="number">0</span>] =l;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span>(right==<span class="string">"-"</span>)</span><br><span class="line"> {</span><br><span class="line"> nodes[i][<span class="number">1</span>] = <span class="number">-1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> r = stoi(right);</span><br><span class="line"> hasvalue[r] =<span class="number">1</span>;</span><br><span class="line"> nodes[i][<span class="number">1</span>] = r;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>; i<n; i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span>(hasvalue[i]==<span class="number">0</span>)</span><br><span class="line"> {</span><br><span class="line"> root = i;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d"</span>,root);</span><br><span class="line"> LevelOrder(root);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"\n"</span>);</span><br><span class="line"> <span class="comment">//中序顺序进入队列后输出</span></span><br><span class="line"> InOrder(root);</span><br><span class="line"> <span class="keyword">while</span>(!in.empty())</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span>(in.<span class="built_in">size</span>()==<span class="number">1</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d"</span>,in.front());</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span>{</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d "</span>,in.front());</span><br><span class="line"> }</span><br><span class="line"> in.pop();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<h3 id="分析-求反转二叉树的层序遍历和中序遍历,实际是改变二叉树节点的遍历输出顺序。层序遍历改为从右往左输出,"><a href="#分析-求反转二叉树的层序遍历和中序遍历,实际是改变二叉树节点的遍历输出顺序。层序遍历改为从右往左输出," class="headerlin
</summary>
<category term="pta" scheme="https://www.smallapp.xyz/categories/pta/"/>
<category term="pta" scheme="https://www.smallapp.xyz/tags/pta/"/>
</entry>
<entry>
<title>日志</title>
<link href="https://www.smallapp.xyz/2020/04/07/2.4%E6%97%A5%E5%BF%97/"/>
<id>https://www.smallapp.xyz/2020/04/07/2.4%E6%97%A5%E5%BF%97/</id>
<published>2020-04-06T16:00:00.000Z</published>
<updated>2020-04-07T02:10:42.369Z</updated>
<content type="html"><![CDATA[<h2 id="服务器端"><a href="#服务器端" class="headerlink" title="服务器端"></a>服务器端</h2><p>ABP使用Castle Windsor的日志记录工具。它可以和不同的日志库一起工作:Log4Net, NLog, Serilog等等。Castle为所有的日志库提供了一个公共的接口。通过这种方式,你可以独立使用一个特殊的日志库,并且轻松的替换它。</p><p><a href="http://logging.apache.org/log4net/" target="_blank" rel="noopener">Log4Net</a>是最受欢迎的日志库之一。log4net的依赖只需要一行代码( 如配置部分所示),因此你可以轻松替换成你喜欢的库。</p><h2 id="获得Logger"><a href="#获得Logger" class="headerlink" title="获得Logger"></a>获得Logger</h2><p>不论你选用哪种日志库,写入日志的代码是相同的(感谢Castle的公共ILogger接口).</p><p>首先,我们需要取得一个Logger对象来记录日志。因为ABP热衷于使用依赖注入,我们可以使用属性注入(或者构造函数注入)方式,轻松地注入一个Logger对象。这是一个写日志的简单例子:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">using Castle.Core.Logging; //1: Import Logging namespace</span><br><span class="line"></span><br><span class="line">public class TaskAppService : ITaskAppService</span><br><span class="line">{ </span><br><span class="line"> //2: Getting a logger using property injection</span><br><span class="line"> public ILogger Logger { get; set; }</span><br><span class="line"></span><br><span class="line"> public TaskAppService()</span><br><span class="line"> {</span><br><span class="line"> //3: Do not write logs if no Logger supplied.</span><br><span class="line"> Logger = NullLogger.Instance;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> public void CreateTask(CreateTaskInput input)</span><br><span class="line"> {</span><br><span class="line"> //4: Write logs</span><br><span class="line"> Logger.Info("Creating a new task with description: " + input.Description);</span><br><span class="line"></span><br><span class="line"> //TODO: save task to database...</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>首先</strong>,引入Castle的Logger接口的命名空间。<br><strong>然后</strong>,定义一个public ILogger对象,命名为Logger。这是我们将用来写入日志的对象。依赖注入系统会在创建TaskAppService对象后注入这个属性。这是属性注入的方式。<br><strong>第三步</strong>,设置Logger为NullLogger.Instance。没有这一行,系统仍旧会正常工作,但是使用属性注入的方式是最佳实践。如果Logger没有设定值,Logger会是null,当我们想要使用他的时候,我们会获得一个”object reference…”的exception。这确保它不能为空。<br>如果没有日志库的内容给到Logger,它将会是NullLogger。这被成为空对象模式。NullLogger不做任何事。它不写入日志。采用这种方式,不论是否使用日志工具,我们都可以正常工作。<br><strong>最后</strong>,我们使用信息等级来写一个日志文本。有不同的等级(查看配置部分)。</p><p>如果我们调用CreateTask方法并查看日志文件,我们会看到一条日志行如下:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">INFO 2014-07-13 13:40:23,360 [8 ] SimpleTaskSystem.Tasks.TaskAppService - Creating a new task with description: Remember to drink milk before sleeping!</span><br></pre></td></tr></table></figure><h2 id="使用Logger的基类"><a href="#使用Logger的基类" class="headerlink" title="使用Logger的基类"></a>使用Logger的基类</h2><p>ABP为MVC controller、Web API controller,应用服务类及其他内容计通了基类。它声明了一个Logger属性。使用这种方式,你可以直接使用这个Logger来写日志,不需要注入。如:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">public class HomeController : SimpleTaskSystemControllerBase</span><br><span class="line">{</span><br><span class="line"> public ActionResult Index()</span><br><span class="line"> {</span><br><span class="line"> Logger.Debug("A sample log message...");</span><br><span class="line"> return View();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>注意SimpleTaskSystemControllerBase是我们的应用特定的基controller,继承了AbpController。用这种方式,它可以直接使用Logger。你可以为了其他的类写你自己的公共基类.之后你将不需要次次注入一个logger。</p><h2 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h2><p>当你使用ABP创建你的应用时,所有的Log4Net的配置都已经写好了。<br>默认的配置日志格式如下:</p><ul><li><strong>日志等级</strong>:DEBUG, INFO, WARN, ERROR or FATAL.</li><li><strong>Date and time</strong>: 日志写入时间.</li><li><strong>线程号</strong>:写入日支行的线程号.</li><li><strong>日志文本</strong>:你写入的实际日志文本.<br>在应用的log4net.config文件中定义如下:<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><?xml version="1.0" encoding="utf-8" ?></span><br><span class="line"><log4net></span><br><span class="line"> <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender" ></span><br><span class="line"> <file value="Logs/Logs.txt" /></span><br><span class="line"> <appendToFile value="true" /></span><br><span class="line"> <rollingStyle value="Size" /></span><br><span class="line"> <maxSizeRollBackups value="10" /></span><br><span class="line"> <maximumFileSize value="10000KB" /></span><br><span class="line"> <staticLogFileName value="true" /></span><br><span class="line"> <layout type="log4net.Layout.PatternLayout"></span><br><span class="line"> <conversionPattern value="%-5level %date [%-5.5thread] %-40.40logger - %message%newline" /></span><br><span class="line"> </layout></span><br><span class="line"> </appender></span><br><span class="line"> <root></span><br><span class="line"> <appender-ref ref="RollingFileAppender" /></span><br><span class="line"> <level value="DEBUG" /></span><br><span class="line"> </root></span><br><span class="line"> <logger name="NHibernate"></span><br><span class="line"> <level value="WARN" /></span><br><span class="line"> </logger></span><br><span class="line"></log4net></span><br></pre></td></tr></table></figure></li></ul><p>Log4Net是一个高度可配置的强大的日志库。你可以使用不同格式写入不同的目标(文本文件、数据库…)。你可以设置最小的日志等级(正如在这个为NHibernate的配置中)。你可以将不同的loggers写入不同的文件。当达到特定的大小(在这个RollingFileAppender配置中每个文件最多包含10000kb),它可以自动备份文件,创建新的日志文件等等。请阅读它自己的<a href="http://logging.apache.org/log4net/release/config-examples.html" target="_blank" rel="noopener">配置文档</a>以获得更多信息。</p><p>最后,在Global.asax文件中,我们声明我们使用Log4Net,它的配置文件为log4net.config:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">public class MvcApplication : AbpWebApplication</span><br><span class="line">{</span><br><span class="line"> protected override void Application_Start(object sender, EventArgs e)</span><br><span class="line"> {</span><br><span class="line"> IocManager.Instance.IocContainer.AddFacility<LoggingFacility>(f => f.UseLog4Net().WithConfig("log4net.config"));</span><br><span class="line"> base.Application_Start(sender, e);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这是我们依赖log4net的唯一的一行代码。只有web项目依赖log4net库的包。你也可以无需改动日志使用代码,轻松修改到其他库。</p><h2 id="Abp-Castle-Log4Net包"><a href="#Abp-Castle-Log4Net包" class="headerlink" title="Abp.Castle.Log4Net包"></a>Abp.Castle.Log4Net包</h2><p>ABP使用Castle日志记录工具,它不是直接依赖log4net,如上文声明。然而,Castle的Log4net集成存在一个问题,它不支持最新的log4net。我们创建了一个Nuget包,Abp.Castle.Log4Net,来解决这个问题。在添加这个包到我们的解决方案后,我们所做的内容仅仅是修改应用的start方法如下:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">public class MvcApplication : AbpWebApplication</span><br><span class="line">{</span><br><span class="line"> protected override void Application_Start(object sender, EventArgs e)</span><br><span class="line"> {</span><br><span class="line"> IocManager.Instance.IocContainer.AddFacility<LoggingFacility>(f => f.UseAbpLog4Net().WithConfig("log4net.config"));</span><br><span class="line"> base.Application_Start(sender, e);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>唯一的区别是我们使用”UseAbpLog4Net()”(defined in Abp.Castle.Logging.Log4Net namespace)来代替”UseLog4Net()”。当我们使用”Abp.Castle.Log4Net”包,你不需要使用Castle.Windsor-log4net和Castle.Core-log4net包。</p><p>如果你需要在运行时修改你的log4net配置文件,想要在未重启应用时立刻产生影响,你可以像下面这样使用:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">public class MvcApplication : AbpWebApplication</span><br><span class="line">{</span><br><span class="line"> protected override void Application_Start(object sender, EventArgs e)</span><br><span class="line"> {</span><br><span class="line"> options.IocManager.IocContainer.AddFacility<LoggingFacility>(</span><br><span class="line"> f => f.LogUsing(new Log4NetLoggerFactory("log4net.config", reloadOnChange:true))</span><br><span class="line"> );</span><br><span class="line"> base.Application_Start(sender, e);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="客户端"><a href="#客户端" class="headerlink" title="客户端"></a>客户端</h2><p>ABP为客户端定义了一个简单的JS日志API。它默认在浏览器的console中记录日志。这是一些写入日志的JS代码:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">abp.log.warn(<span class="string">'a sample log message...'</span>);</span><br></pre></td></tr></table></figure><p>有关更多信息,请参阅<a href="http://logging.apache.org/log4net/release/config-examples.html" target="_blank" rel="noopener">日志API文档</a>。</p>]]></content>
<summary type="html">
<h2 id="服务器端"><a href="#服务器端" class="headerlink" title="服务器端"></a>服务器端</h2><p>ABP使用Castle Windsor的日志记录工具。它可以和不同的日志库一起工作:Log4Net, NLog, Seril
</summary>
<category term="ABP" scheme="https://www.smallapp.xyz/categories/ABP/"/>
<category term="ABP" scheme="https://www.smallapp.xyz/tags/ABP/"/>
</entry>
<entry>
<title>1155 想要判断给出的binary tree是否是一个heap</title>
<link href="https://www.smallapp.xyz/2020/03/31/1155HeapPaths/"/>
<id>https://www.smallapp.xyz/2020/03/31/1155HeapPaths/</id>
<published>2020-03-31T02:55:32.734Z</published>
<updated>2020-04-02T03:47:24.388Z</updated>
<content type="html"><![CDATA[<a id="more"></a> <h5 id="自行分析:-根据root和第二个节点就可以假设tree是最大堆(最小堆),"><a href="#自行分析:-根据root和第二个节点就可以假设tree是最大堆(最小堆)," class="headerlink" title="自行分析: 根据root和第二个节点就可以假设tree是最大堆(最小堆),"></a>自行分析: 根据root和第二个节点就可以假设tree是最大堆(最小堆),</h5><h5 id="然后,采用递归的方式,父元素与子元素进行比较,父元素-gt-lt-子元素,可继续比较-直到子元素为空。"><a href="#然后,采用递归的方式,父元素与子元素进行比较,父元素-gt-lt-子元素,可继续比较-直到子元素为空。" class="headerlink" title="然后,采用递归的方式,父元素与子元素进行比较,父元素>=(<=)子元素,可继续比较,直到子元素为空。"></a>然后,采用递归的方式,父元素与子元素进行比较,父元素>=(<=)子元素,可继续比较,直到子元素为空。</h5><h5 id="若不满足情况,则认为非最大堆(最小堆)"><a href="#若不满足情况,则认为非最大堆(最小堆)" class="headerlink" title="若不满足情况,则认为非最大堆(最小堆)"></a>若不满足情况,则认为非最大堆(最小堆)</h5><h5 id="柳婼版分析:"><a href="#柳婼版分析:" class="headerlink" title="柳婼版分析:"></a>柳婼版分析:</h5><h5 id="1-数组存储堆,使用vector,深搜回溯,直接显示paths"><a href="#1-数组存储堆,使用vector,深搜回溯,直接显示paths" class="headerlink" title="1. 数组存储堆,使用vector,深搜回溯,直接显示paths"></a>1. 数组存储堆,使用vector,深搜回溯,直接显示paths</h5><h5 id="2-根据index,对数组数据循环判断堆的类型"><a href="#2-根据index,对数组数据循环判断堆的类型" class="headerlink" title="2. 根据index,对数组数据循环判断堆的类型"></a>2. 根据index,对数组数据循环判断堆的类型</h5><blockquote><p>自制版:</p></blockquote><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><iostream></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><stack></span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="keyword">int</span> Index;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">HeapNode</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"> <span class="keyword">int</span> value;</span><br><span class="line"> Index leftChildIndex;</span><br><span class="line"> Index rightChildIndex;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="comment">//结果1:与increase顺序相同 -1:表示不同</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">ChargeAndShowOnePath</span><span class="params">(Index index,HeapNode arr[],<span class="keyword">int</span> increase)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="comment">/*1.判断是否是叶子节点</span></span><br><span class="line"><span class="comment"> 2.向上查找父节点,同时将index入栈</span></span><br><span class="line"><span class="comment"> 3.出栈时比较大小,作为大小判断的结果*/</span></span><br><span class="line"> <span class="built_in">stack</span><<span class="keyword">int</span>> paths;</span><br><span class="line"> <span class="keyword">int</span> firstNum;</span><br><span class="line"> <span class="keyword">int</span> secondNum;</span><br><span class="line"> <span class="keyword">int</span> res =<span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">do</span></span><br><span class="line"> {</span><br><span class="line"> paths.push(index);</span><br><span class="line"> index/=<span class="number">2</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">while</span>(index><span class="number">0</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span>(!paths.empty())</span><br><span class="line"> {</span><br><span class="line"> firstNum = paths.top();</span><br><span class="line"> paths.pop();</span><br><span class="line"> <span class="built_in">cout</span><<arr[firstNum].value<<<span class="string">" "</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">while</span>(!paths.empty())</span><br><span class="line"> {</span><br><span class="line"> secondNum = paths.top();</span><br><span class="line"> paths.pop();</span><br><span class="line"> <span class="keyword">if</span>(increase==<span class="number">1</span>&& arr[secondNum].value>arr[firstNum].value)</span><br><span class="line"> {</span><br><span class="line"> res= <span class="number">-1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span>(increase==<span class="number">-1</span>&& arr[secondNum].value<arr[firstNum].value)</span><br><span class="line"> {</span><br><span class="line"> res= <span class="number">-1</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="built_in">cout</span><<arr[secondNum].value;</span><br><span class="line"> <span class="keyword">if</span>(!paths.empty())</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">cout</span><<<span class="string">" "</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">cout</span><<<span class="built_in">endl</span>;</span><br><span class="line"> }</span><br><span class="line"> firstNum = secondNum;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> res;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">FindTreeChild</span><span class="params">(<span class="built_in">stack</span><<span class="keyword">int</span>> &s,HeapNode arr[],<span class="keyword">int</span> index)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span>(arr[index].leftChildIndex==<span class="number">-1</span>&&arr[index].rightChildIndex==<span class="number">-1</span>)</span><br><span class="line"> {</span><br><span class="line"> s.push(index);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span>(arr[index].leftChildIndex!=<span class="number">-1</span>)</span><br><span class="line"> {</span><br><span class="line"> FindTreeChild(s,arr,index*<span class="number">2</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span>(arr[index].rightChildIndex!=<span class="number">-1</span>)</span><br><span class="line"> {</span><br><span class="line"> FindTreeChild(s,arr,index*<span class="number">2</span>+<span class="number">1</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">int</span> heapEleNum;</span><br><span class="line"> <span class="built_in">cin</span>>>heapEleNum;</span><br><span class="line"> HeapNode arr[heapEleNum+<span class="number">1</span>];</span><br><span class="line"> <span class="keyword">int</span> i=<span class="number">1</span>;</span><br><span class="line"> <span class="keyword">int</span> value;</span><br><span class="line"> <span class="keyword">int</span> increase;</span><br><span class="line"> <span class="keyword">int</span> obey =<span class="number">1</span> ;</span><br><span class="line"> <span class="built_in">stack</span><<span class="keyword">int</span>> indexS;</span><br><span class="line"> <span class="comment">//stack<int> &indexS1 = indexS;</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">while</span>(i<=heapEleNum)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">cin</span>>>value;</span><br><span class="line"> arr[i].value = value;</span><br><span class="line"> arr[i].leftChildIndex = <span class="number">2</span>*i>heapEleNum?<span class="number">-1</span>:<span class="number">2</span>*i;</span><br><span class="line"> arr[i].rightChildIndex = (<span class="number">2</span>*i+<span class="number">1</span>)>heapEleNum?<span class="number">-1</span>:(<span class="number">2</span>*i+<span class="number">1</span>);</span><br><span class="line"> i++;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> FindTreeChild(indexS,arr,<span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"> increase = arr[<span class="number">1</span>].value> arr[<span class="number">2</span>].value? <span class="number">1</span>:(arr[<span class="number">1</span>].value<arr[<span class="number">2</span>].value?<span class="number">-1</span>:<span class="number">1</span>) ;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">while</span>(!indexS.empty())</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> needindex = indexS.top();</span><br><span class="line"> indexS.pop();</span><br><span class="line"> <span class="keyword">int</span> result = ChargeAndShowOnePath(needindex,arr,increase);</span><br><span class="line"> <span class="keyword">if</span>(result==<span class="number">-1</span>)</span><br><span class="line"> {</span><br><span class="line"> obey = <span class="number">-1</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span>(obey==<span class="number">1</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span>(increase==<span class="number">1</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">cout</span><<<span class="string">"Max Heap"</span><<<span class="built_in">endl</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">cout</span><<<span class="string">"Min Heap"</span><<<span class="built_in">endl</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">cout</span><<<span class="string">"Not Heap"</span><<<span class="built_in">endl</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>柳婼版:</p></blockquote><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><iostream></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><vector></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"><span class="built_in">vector</span><<span class="keyword">int</span>> v;</span><br><span class="line"><span class="keyword">int</span> a[<span class="number">1009</span>], n, isMin = <span class="number">1</span>, isMax = <span class="number">1</span>;</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">dfs</span><span class="params">(<span class="keyword">int</span> index)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (index * <span class="number">2</span> > n && index * <span class="number">2</span> + <span class="number">1</span> > n)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (index <= n)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < v.<span class="built_in">size</span>(); i++)</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d%s"</span>, v[i], i != v.<span class="built_in">size</span>() - <span class="number">1</span> ? <span class="string">" "</span> : <span class="string">"\n"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> {</span><br><span class="line"> v.push_back(a[index * <span class="number">2</span> + <span class="number">1</span>]);</span><br><span class="line"> dfs(index * <span class="number">2</span> + <span class="number">1</span>);</span><br><span class="line"> v.pop_back();</span><br><span class="line"> v.push_back(a[index * <span class="number">2</span>]);</span><br><span class="line"> dfs(index * <span class="number">2</span>);</span><br><span class="line"> v.pop_back();</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="built_in">cin</span> >> n;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i <= n; i++)</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d"</span>, &a[i]);</span><br><span class="line"> v.push_back(a[<span class="number">1</span>]);</span><br><span class="line"> dfs(<span class="number">1</span>);</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">2</span>; i <= n; i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (a[i/<span class="number">2</span>] > a[i])</span><br><span class="line"> isMin = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">if</span> (a[i/<span class="number">2</span>] < a[i])</span><br><span class="line"> isMax = <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (isMin == <span class="number">1</span>)</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Min Heap"</span>);</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%s"</span>, isMax == <span class="number">1</span> ? <span class="string">"Max Heap"</span> : <span class="string">"Not Heap"</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<a id="more"></a>
<h5 id="自行分析:-根据root和第二个节点就可以假设tree是最大堆(最小堆),"><a href="#自行分析:-根据root和第二个节点就可以假设tree是最大堆(最小堆)," class="headerlink" title=
</summary>
<category term="pta" scheme="https://www.smallapp.xyz/categories/pta/"/>
<category term="pta" scheme="https://www.smallapp.xyz/tags/pta/"/>
</entry>
<entry>
<title>1151 LCA in Binray Tree</title>
<link href="https://www.smallapp.xyz/2020/03/31/1151lcaInBinaryTree/"/>
<id>https://www.smallapp.xyz/2020/03/31/1151lcaInBinaryTree/</id>
<published>2020-03-31T02:55:32.720Z</published>
<updated>2020-04-02T03:46:58.607Z</updated>
<content type="html"><![CDATA[<h5 id="分析:"><a href="#分析:" class="headerlink" title="分析:"></a>分析:</h5><h5 id="1-给定了前序和中序,得到唯一的二叉树结构"><a href="#1-给定了前序和中序,得到唯一的二叉树结构" class="headerlink" title="1.给定了前序和中序,得到唯一的二叉树结构"></a>1.给定了前序和中序,得到唯一的二叉树结构</h5><h5 id="2-获得的请求lca的数据,逐条执行"><a href="#2-获得的请求lca的数据,逐条执行" class="headerlink" title="2.获得的请求lca的数据,逐条执行"></a>2.获得的请求lca的数据,逐条执行</h5><h5 id="柳诺版本分析:"><a href="#柳诺版本分析:" class="headerlink" title="柳诺版本分析:"></a>柳诺版本分析:</h5><h5 id="lca方法:-无需得出二叉树,根据前序和中序可以得到二叉树的root节点,相对复杂的点是root节点位置的计算"><a href="#lca方法:-无需得出二叉树,根据前序和中序可以得到二叉树的root节点,相对复杂的点是root节点位置的计算" class="headerlink" title="lca方法: 无需得出二叉树,根据前序和中序可以得到二叉树的root节点,相对复杂的点是root节点位置的计算"></a>lca方法: 无需得出二叉树,根据前序和中序可以得到二叉树的root节点,相对复杂的点是root节点位置的计算</h5><h5 id="1-若u和v在root的左侧,获取左侧子二叉树的root节点,重新使用u、v进行比较"><a href="#1-若u和v在root的左侧,获取左侧子二叉树的root节点,重新使用u、v进行比较" class="headerlink" title="1.若u和v在root的左侧,获取左侧子二叉树的root节点,重新使用u、v进行比较"></a>1.若u和v在root的左侧,获取左侧子二叉树的root节点,重新使用u、v进行比较</h5><h5 id="2-若u和v在root的两侧,则u、v的lca为root"><a href="#2-若u和v在root的两侧,则u、v的lca为root" class="headerlink" title="2.若u和v在root的两侧,则u、v的lca为root"></a>2.若u和v在root的两侧,则u、v的lca为root</h5><h5 id="3-若u和v在root的右侧,获取右侧子二叉树的root节点,重新使用u、v进行比较"><a href="#3-若u和v在root的右侧,获取右侧子二叉树的root节点,重新使用u、v进行比较" class="headerlink" title="3.若u和v在root的右侧,获取右侧子二叉树的root节点,重新使用u、v进行比较"></a>3.若u和v在root的右侧,获取右侧子二叉树的root节点,重新使用u、v进行比较</h5><h5 id="4-若u或者v不存在,输出u、v不存在的结论"><a href="#4-若u或者v不存在,输出u、v不存在的结论" class="headerlink" title="4.若u或者v不存在,输出u、v不存在的结论"></a>4.若u或者v不存在,输出u、v不存在的结论</h5><h5 id="使用两个vector分别存储前序和中序,使用一个map-lt-value-index-gt-来存储前序的值在中序中对应的位置"><a href="#使用两个vector分别存储前序和中序,使用一个map-lt-value-index-gt-来存储前序的值在中序中对应的位置" class="headerlink" title="使用两个vector分别存储前序和中序,使用一个map<value,index>来存储前序的值在中序中对应的位置"></a>使用两个vector分别存储前序和中序,使用一个map<value,index>来存储前序的值在中序中对应的位置</h5><blockquote><p>柳神版代码:</p></blockquote><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><iostream></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><vector></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><map></span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"></span><br><span class="line"><span class="built_in">vector</span><<span class="keyword">int</span>> pre,in;</span><br><span class="line"><span class="built_in">map</span><<span class="keyword">int</span>,<span class="keyword">int</span>> pos;</span><br><span class="line"><span class="keyword">int</span> m,n,a,b;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">lca</span><span class="params">(<span class="keyword">int</span> inl,<span class="keyword">int</span> inr,<span class="keyword">int</span> preRoot,<span class="keyword">int</span> a,<span class="keyword">int</span> b)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span>(inl>inr)</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> <span class="keyword">int</span> rootIndex = pos[pre[preRoot]];</span><br><span class="line"> <span class="keyword">int</span> aIndex = pos[a];</span><br><span class="line"> <span class="keyword">int</span> bIndex =pos[b];</span><br><span class="line"> <span class="keyword">if</span>(aIndex<rootIndex&&bIndex< rootIndex)</span><br><span class="line"> lca(inl,rootIndex<span class="number">-1</span>,preRoot+<span class="number">1</span>,a,b);</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span>((aIndex<rootIndex&&bIndex>rootIndex)||(aIndex>rootIndex&&bIndex<rootIndex))</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"LCA of %d and %d is %d.\n"</span>,a,b,pre[preRoot]);</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span>(aIndex>rootIndex&&bIndex> rootIndex)</span><br><span class="line"> lca(rootIndex+<span class="number">1</span>,inr,preRoot+<span class="number">1</span>+(rootIndex-inl),a,b);</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span>(aIndex==rootIndex)</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d is an ancestor of %d.\n"</span>,a,b);</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span>(bIndex == rootIndex)</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d is an ancestor of %d.\n"</span>,b,a);</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="built_in">cin</span>>>m>>n;</span><br><span class="line"> pre.resize(n+<span class="number">1</span>);</span><br><span class="line"> in.resize(n+<span class="number">1</span>);</span><br><span class="line"> <span class="keyword">int</span> arr[m][<span class="number">2</span>];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>; i<=n; i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">cin</span>>>in[i];</span><br><span class="line"> pos[in[i]]=i;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>; i<=n; i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">cin</span>>>pre[i];</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>; i<m; i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">cin</span>>>arr[i][<span class="number">0</span>]>>arr[i][<span class="number">1</span>];</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>; i<m; i++)</span><br><span class="line"> {</span><br><span class="line"> a=arr[i][<span class="number">0</span>];</span><br><span class="line"> b=arr[i][<span class="number">1</span>];</span><br><span class="line"> <span class="keyword">if</span>(pos[a]==<span class="number">0</span>&&pos[b]==<span class="number">0</span>)</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"ERROR: %d and %d are not found.\n"</span>,a,b);</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span>(pos[a]==<span class="number">0</span>||pos[b]==<span class="number">0</span>)</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"ERROR: %d is not found.\n"</span>,pos[a]==<span class="number">0</span>?a:b);</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> lca(<span class="number">1</span>,n,<span class="number">1</span>,a,b);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<h5 id="分析:"><a href="#分析:" class="headerlink" title="分析:"></a>分析:</h5><h5 id="1-给定了前序和中序,得到唯一的二叉树结构"><a href="#1-给定了前序和中序,得到唯一的二叉树结构" class
</summary>
<category term="pta" scheme="https://www.smallapp.xyz/categories/pta/"/>
<category term="pta" scheme="https://www.smallapp.xyz/tags/pta/"/>
</entry>
<entry>
<title>1147 Heaps</title>
<link href="https://www.smallapp.xyz/2020/03/31/1147Heaps/"/>
<id>https://www.smallapp.xyz/2020/03/31/1147Heaps/</id>
<published>2020-03-31T02:55:32.712Z</published>
<updated>2020-04-02T03:46:37.950Z</updated>
<content type="html"><![CDATA[<h5 id="分析:"><a href="#分析:" class="headerlink" title="分析:"></a>分析:</h5><h5 id="给定了固定个数,固定元素数的完全二叉树,且按照层序遍历给出"><a href="#给定了固定个数,固定元素数的完全二叉树,且按照层序遍历给出" class="headerlink" title="给定了固定个数,固定元素数的完全二叉树,且按照层序遍历给出"></a>给定了固定个数,固定元素数的完全二叉树,且按照层序遍历给出</h5><h5 id="判断其是什么堆?且按照后续遍历给出"><a href="#判断其是什么堆?且按照后续遍历给出" class="headerlink" title="判断其是什么堆?且按照后续遍历给出"></a>判断其是什么堆?且按照后续遍历给出</h5><h5 id="数目固定,使用二维数组(初始化为0),不存在空间浪费,后续遍历输出即可"><a href="#数目固定,使用二维数组(初始化为0),不存在空间浪费,后续遍历输出即可" class="headerlink" title="数目固定,使用二维数组(初始化为0),不存在空间浪费,后续遍历输出即可"></a>数目固定,使用二维数组(初始化为0),不存在空间浪费,后续遍历输出即可</h5><h5 id="柳神版分析:思路大体相同,但相对而言,空间和时间利用率更佳"><a href="#柳神版分析:思路大体相同,但相对而言,空间和时间利用率更佳" class="headerlink" title="柳神版分析:思路大体相同,但相对而言,空间和时间利用率更佳"></a>柳神版分析:思路大体相同,但相对而言,空间和时间利用率更佳</h5><h5 id="1-判断堆类型时,采用n-2个循环计算"><a href="#1-判断堆类型时,采用n-2个循环计算" class="headerlink" title="1.判断堆类型时,采用n/2个循环计算"></a>1.判断堆类型时,采用n/2个循环计算</h5><h5 id="2-重复利用vector,不需要二维数组"><a href="#2-重复利用vector,不需要二维数组" class="headerlink" title="2.重复利用vector,不需要二维数组"></a>2.重复利用vector<int>,不需要二维数组</h5><blockquote><p>自制版:</p></blockquote><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><iostream></span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">int</span> m =<span class="number">0</span>;</span><br><span class="line"><span class="keyword">int</span> n=<span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">int</span> arr[<span class="number">100</span>][<span class="number">1001</span>];</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">PrintfArr</span><span class="params">(<span class="keyword">int</span> arrNew[],<span class="keyword">int</span> index)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span>(index>n)</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> PrintfArr(arrNew,index*<span class="number">2</span>);</span><br><span class="line"> PrintfArr(arrNew,index*<span class="number">2</span>+<span class="number">1</span>);</span><br><span class="line"> <span class="built_in">cout</span><<arrNew[index];</span><br><span class="line"> <span class="keyword">if</span>(index><span class="number">1</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">cout</span><<<span class="string">" "</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">cout</span><<<span class="built_in">endl</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//-1 min 1 max 0 not</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">Charge</span><span class="params">(<span class="keyword">int</span> arrNew[][<span class="number">1001</span>],<span class="keyword">int</span> findex)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">bool</span> isMin = <span class="literal">true</span>;</span><br><span class="line"> <span class="keyword">bool</span> isMax = <span class="literal">true</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">2</span>; i<n+<span class="number">1</span>; i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span>(arrNew[findex][i/<span class="number">2</span>]>arrNew[findex][i])</span><br><span class="line"> isMin = <span class="literal">false</span>;</span><br><span class="line"> <span class="keyword">if</span>(arrNew[findex][i/<span class="number">2</span>]<arrNew[findex][i])</span><br><span class="line"> isMax = <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span>(isMin&&!isMax)</span><br><span class="line"> <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span>(!isMin&&isMax)</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="built_in">cin</span>>>m>>n;</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>; i<m; i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> j=<span class="number">1</span>; j<n+<span class="number">1</span>; j++)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">cin</span>>>arr[i][j];</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>; i<m; i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> res = Charge(arr,i);</span><br><span class="line"> <span class="keyword">if</span>(res==<span class="number">1</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">cout</span><<<span class="string">"Max Heap"</span><<<span class="built_in">endl</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span>(res ==<span class="number">-1</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">cout</span><<<span class="string">"Min Heap"</span><<<span class="built_in">endl</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">cout</span><<<span class="string">"Not Heap"</span><<<span class="built_in">endl</span>;</span><br><span class="line"> }</span><br><span class="line"> PrintfArr(arr[i],<span class="number">1</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>柳神版:</p></blockquote><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><iostream></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><vector></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"><span class="keyword">int</span> m, n;</span><br><span class="line"><span class="built_in">vector</span><<span class="keyword">int</span>> v;</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">postOrder</span><span class="params">(<span class="keyword">int</span> index)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (index >= n)</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> postOrder(index * <span class="number">2</span> + <span class="number">1</span>);</span><br><span class="line"> postOrder(index * <span class="number">2</span> + <span class="number">2</span>);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d%s"</span>, v[index], index == <span class="number">0</span> ? <span class="string">"\n"</span> : <span class="string">" "</span>);</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d%d"</span>, &m, &n);</span><br><span class="line"> v.resize(n);</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < m; i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = <span class="number">0</span>; j < n; j++)</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d"</span>, &v[j]);</span><br><span class="line"> <span class="keyword">int</span> flag = v[<span class="number">0</span>] > v[<span class="number">1</span>] ? <span class="number">1</span> : <span class="number">-1</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = <span class="number">0</span>; j <= (n<span class="number">-1</span>) / <span class="number">2</span>; j++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> left = j * <span class="number">2</span> + <span class="number">1</span>, right = j * <span class="number">2</span> + <span class="number">2</span>;</span><br><span class="line"> <span class="keyword">if</span> (flag == <span class="number">1</span> && (v[j] < v[left] || (right < n && v[j] <</span><br><span class="line"> v[right])))</span><br><span class="line"> flag = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">if</span> (flag == <span class="number">-1</span> && (v[j] > v[left] || (right < n && v[j] ></span><br><span class="line"> v[right])))</span><br><span class="line"> flag = <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (flag == <span class="number">0</span>)</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Not Heap\n"</span>);</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%s Heap\n"</span>, flag == <span class="number">1</span> ? <span class="string">"Max"</span> : <span class="string">"Min"</span>);</span><br><span class="line"> postOrder(<span class="number">0</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<h5 id="分析:"><a href="#分析:" class="headerlink" title="分析:"></a>分析:</h5><h5 id="给定了固定个数,固定元素数的完全二叉树,且按照层序遍历给出"><a href="#给定了固定个数,固定元素数的完全二叉树,
</summary>
<category term="pta" scheme="https://www.smallapp.xyz/categories/pta/"/>
<category term="pta" scheme="https://www.smallapp.xyz/tags/pta/"/>
</entry>
<entry>
<title>1138PostOrderTraversal</title>
<link href="https://www.smallapp.xyz/2020/03/31/1138PostOrderTraversal/"/>
<id>https://www.smallapp.xyz/2020/03/31/1138PostOrderTraversal/</id>
<published>2020-03-31T02:55:32.698Z</published>
<updated>2020-04-02T03:46:22.444Z</updated>
<content type="html"><![CDATA[<h5 id="分析:已知前序和中序,求后序第一个应输出节点"><a href="#分析:已知前序和中序,求后序第一个应输出节点" class="headerlink" title="分析:已知前序和中序,求后序第一个应输出节点"></a>分析:已知前序和中序,求后序第一个应输出节点</h5><h5 id="1-无需先得到整体的二叉树,可递归求得最左侧-amp-amp-最底层的节点"><a href="#1-无需先得到整体的二叉树,可递归求得最左侧-amp-amp-最底层的节点" class="headerlink" title="1.无需先得到整体的二叉树,可递归求得最左侧&&最底层的节点"></a>1.无需先得到整体的二叉树,可递归求得最左侧&&最底层的节点</h5><h5 id="2-使用vector存储先序、中序,使用map-lt-int-int-gt-存储中序index和value"><a href="#2-使用vector存储先序、中序,使用map-lt-int-int-gt-存储中序index和value" class="headerlink" title="2.使用vector存储先序、中序,使用map<int,int>存储中序index和value"></a>2.使用vector<int>存储先序、中序,使用map<int,int>存储中序index和value</h5><h5 id="3-对先序的值逐个操作,与中序比对,对应处理"><a href="#3-对先序的值逐个操作,与中序比对,对应处理" class="headerlink" title="3.对先序的值逐个操作,与中序比对,对应处理"></a>3.对先序的值逐个操作,与中序比对,对应处理</h5><h5 id="柳神版分析:"><a href="#柳神版分析:" class="headerlink" title="柳神版分析:"></a>柳神版分析:</h5><h5 id="思路大致相同,关键点判断不同,其只采用两个vector存储先序中序,添加一个flag标签判断结束时机"><a href="#思路大致相同,关键点判断不同,其只采用两个vector存储先序中序,添加一个flag标签判断结束时机" class="headerlink" title="思路大致相同,关键点判断不同,其只采用两个vector存储先序中序,添加一个flag标签判断结束时机"></a>思路大致相同,关键点判断不同,其只采用两个vector存储先序中序,添加一个flag标签判断结束时机</h5><h5 id="自制版的思路来源是柳神的-1151LcaInBinaryTree-柳神版不使用map速度更快,空间占用小"><a href="#自制版的思路来源是柳神的-1151LcaInBinaryTree-柳神版不使用map速度更快,空间占用小" class="headerlink" title="自制版的思路来源是柳神的 1151LcaInBinaryTree,柳神版不使用map速度更快,空间占用小"></a>自制版的思路来源是柳神的 1151LcaInBinaryTree,柳神版不使用map速度更快,空间占用小</h5><blockquote><p>自制版</p></blockquote><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><iostream></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><vector></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><map></span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">int</span> n;<span class="comment">//n<=50000</span></span><br><span class="line"><span class="built_in">vector</span><<span class="keyword">int</span>> pre,in;</span><br><span class="line"><span class="built_in">map</span><<span class="keyword">int</span>,<span class="keyword">int</span>> pos;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">deal</span><span class="params">(<span class="keyword">int</span> preRootIndex,<span class="keyword">int</span> leftIndex,<span class="keyword">int</span> rightIndex )</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">int</span> inIndex = pos[pre[preRootIndex]] ;</span><br><span class="line"> <span class="keyword">if</span>(inIndex-leftIndex><span class="number">0</span>)</span><br><span class="line"> {</span><br><span class="line"> preRootIndex++;</span><br><span class="line"> rightIndex = inIndex<span class="number">-1</span>;</span><br><span class="line"> deal(preRootIndex,leftIndex,rightIndex);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span>(inIndex-rightIndex<<span class="number">0</span>)</span><br><span class="line"> {</span><br><span class="line"> preRootIndex++;</span><br><span class="line"> leftIndex = inIndex +<span class="number">1</span>;</span><br><span class="line"> deal(preRootIndex,leftIndex,rightIndex);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">cout</span><<pre[preRootIndex];</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="built_in">cin</span>>>n;</span><br><span class="line"> <span class="keyword">if</span>(n==<span class="number">0</span>) <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> pre.resize(n);</span><br><span class="line"> in.resize(n);</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>; i<n; i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">cin</span>>>pre[i];</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>; i<n; i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">cin</span>>>in[i];</span><br><span class="line"> pos[in[i]] = i;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> deal(<span class="number">0</span>,<span class="number">0</span>,n<span class="number">-1</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>柳神版:</p></blockquote><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><iostream></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><vector></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"><span class="built_in">vector</span><<span class="keyword">int</span>> pre, in;</span><br><span class="line"><span class="keyword">bool</span> flag = <span class="literal">false</span>;</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">postOrder</span><span class="params">(<span class="keyword">int</span> prel, <span class="keyword">int</span> inl, <span class="keyword">int</span> inr)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span> (inl > inr || flag == <span class="literal">true</span>)</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> <span class="keyword">int</span> i = inl;</span><br><span class="line"> <span class="keyword">while</span> (in[i] != pre[prel])</span><br><span class="line"> i++;</span><br><span class="line"> postOrder(prel+<span class="number">1</span>, inl, i<span class="number">-1</span>);</span><br><span class="line"> postOrder(prel+i-inl+<span class="number">1</span>, i+<span class="number">1</span>, inr);</span><br><span class="line"> <span class="keyword">if</span> (flag == <span class="literal">false</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d"</span>, in[i]);</span><br><span class="line"> flag = <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">int</span> n;</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d"</span>, &n);</span><br><span class="line"> pre.resize(n);</span><br><span class="line"> in.resize(n);</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < n; i++)</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d"</span>, &pre[i]);</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < n; i++)</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d"</span>, &in[i]);</span><br><span class="line"> postOrder(<span class="number">0</span>, <span class="number">0</span>, n<span class="number">-1</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<h5 id="分析:已知前序和中序,求后序第一个应输出节点"><a href="#分析:已知前序和中序,求后序第一个应输出节点" class="headerlink" title="分析:已知前序和中序,求后序第一个应输出节点"></a>分析:已知前序和中序,求后序第一个应输出
</summary>
<category term="pta" scheme="https://www.smallapp.xyz/categories/pta/"/>
<category term="pta" scheme="https://www.smallapp.xyz/tags/pta/"/>
</entry>
<entry>
<title>1135 1135RedBlackTree</title>
<link href="https://www.smallapp.xyz/2020/03/31/1135RedBlackTree/"/>
<id>https://www.smallapp.xyz/2020/03/31/1135RedBlackTree/</id>
<published>2020-03-31T02:55:32.696Z</published>
<updated>2020-04-02T03:46:10.604Z</updated>
<content type="html"><![CDATA[<h5 id="分析:判断给出的先序树是否是红黑树"><a href="#分析:判断给出的先序树是否是红黑树" class="headerlink" title="分析:判断给出的先序树是否是红黑树"></a>分析:判断给出的先序树是否是红黑树</h5><h5 id="这题好像有问题,为什么只给一个先序就可以直接对其进行判断了,连树的结构都没确定"><a href="#这题好像有问题,为什么只给一个先序就可以直接对其进行判断了,连树的结构都没确定" class="headerlink" title="这题好像有问题,为什么只给一个先序就可以直接对其进行判断了,连树的结构都没确定"></a>这题好像有问题,为什么只给一个先序就可以直接对其进行判断了,连树的结构都没确定</h5><h5 id="1-直接给出先序,采用链表存储"><a href="#1-直接给出先序,采用链表存储" class="headerlink" title="1.直接给出先序,采用链表存储"></a>1.直接给出先序,采用链表存储</h5><h5 id="2-考虑红黑树条件"><a href="#2-考虑红黑树条件" class="headerlink" title="2.考虑红黑树条件"></a>2.考虑红黑树条件</h5><h5 id="1-root为black,即-arr-0-gt-0"><a href="#1-root为black,即-arr-0-gt-0" class="headerlink" title="1) root为black,即 arr[0]>0"></a>1) root为black,即 arr[0]>0</h5><h5 id="2-arr-i-lt-0-则-arr-2i-1-和-arr-2i-都-gt-0"><a href="#2-arr-i-lt-0-则-arr-2i-1-和-arr-2i-都-gt-0" class="headerlink" title="2) arr[i]<0,则 arr[2i+1]和 arr[2i]都>0"></a>2) arr[i]<0,则 arr[2i+1]和 arr[2i]都>0</h5><h5 id="3-叶子节点(2i-gt-N)到root的路径,black-即-gt-0-的点要相等"><a href="#3-叶子节点(2i-gt-N)到root的路径,black-即-gt-0-的点要相等" class="headerlink" title="3) 叶子节点(2i>N)到root的路径,black(即>0)的点要相等"></a>3) 叶子节点(2i>N)到root的路径,black(即>0)的点要相等</h5><h2 id="懵了,不管"><a href="#懵了,不管" class="headerlink" title="懵了,不管"></a>懵了,不管</h2>]]></content>
<summary type="html">
<h5 id="分析:判断给出的先序树是否是红黑树"><a href="#分析:判断给出的先序树是否是红黑树" class="headerlink" title="分析:判断给出的先序树是否是红黑树"></a>分析:判断给出的先序树是否是红黑树</h5><h5 id="这题好像有
</summary>
<category term="pta" scheme="https://www.smallapp.xyz/categories/pta/"/>
<category term="pta" scheme="https://www.smallapp.xyz/tags/pta/"/>
</entry>
<entry>
<title>1127 ZigZagging on a Tree</title>
<link href="https://www.smallapp.xyz/2020/03/31/1127ZigZaggingTree/"/>
<id>https://www.smallapp.xyz/2020/03/31/1127ZigZaggingTree/</id>
<published>2020-03-31T02:55:32.686Z</published>
<updated>2020-04-02T03:45:18.239Z</updated>
<content type="html"><![CDATA[<h5 id="分析:已知中序和后序,可得一个唯一的二叉树-对其按照层次,之字形输出结果"><a href="#分析:已知中序和后序,可得一个唯一的二叉树-对其按照层次,之字形输出结果" class="headerlink" title="分析:已知中序和后序,可得一个唯一的二叉树,对其按照层次,之字形输出结果"></a>分析:已知中序和后序,可得一个唯一的二叉树,对其按照层次,之字形输出结果</h5><h5 id="1-根据中序和后序建树,保存在二维数组中"><a href="#1-根据中序和后序建树,保存在二维数组中" class="headerlink" title="1.根据中序和后序建树,保存在二维数组中"></a>1.根据中序和后序建树,保存在二维数组中</h5><h5 id="2-层序遍历要使用队列来实现"><a href="#2-层序遍历要使用队列来实现" class="headerlink" title="2.层序遍历要使用队列来实现"></a>2.层序遍历要使用队列来实现</h5><h5 id="3-还需要一个二维数组来存储每层的结果,用来实现zigzag"><a href="#3-还需要一个二维数组来存储每层的结果,用来实现zigzag" class="headerlink" title="3.还需要一个二维数组来存储每层的结果,用来实现zigzag"></a>3.还需要一个二维数组来存储每层的结果,用来实现zigzag</h5><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><iostream></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><vector></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><queue></span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"><span class="built_in">vector</span><<span class="keyword">int</span>> in,post,result[<span class="number">35</span>];</span><br><span class="line"><span class="keyword">int</span> tree[<span class="number">35</span>][<span class="number">2</span>],n,rootIndex;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">Node</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"> <span class="keyword">int</span> index;</span><br><span class="line"> <span class="keyword">int</span> depth;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">dfs</span><span class="params">(<span class="keyword">int</span> &index,<span class="keyword">int</span> inLeftIndex,<span class="keyword">int</span> inRightIndex,<span class="keyword">int</span> postLeftIndex,<span class="keyword">int</span> postRightIndex)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span>(inLeftIndex>inRightIndex)</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> index = postRightIndex;</span><br><span class="line"> <span class="comment">//inIndex</span></span><br><span class="line"> <span class="keyword">int</span> i=<span class="number">1</span>;</span><br><span class="line"> <span class="keyword">while</span>(in[i]!=post[postRightIndex])</span><br><span class="line"> i++;</span><br><span class="line"> dfs(tree[index][<span class="number">0</span>],inLeftIndex,i<span class="number">-1</span>,postLeftIndex,index-(inRightIndex - i)<span class="number">-1</span>);</span><br><span class="line"> dfs(tree[index][<span class="number">1</span>],i+<span class="number">1</span>,inRightIndex,index-(inRightIndex - i),postRightIndex<span class="number">-1</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">bfs</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="comment">//使用队列,进行层序遍历</span></span><br><span class="line"> <span class="comment">//当前数组还是一个post的顺序,将其变为层序,保存到result中</span></span><br><span class="line"> <span class="built_in">queue</span><Node> q ;</span><br><span class="line"> q.push(Node{rootIndex,<span class="number">0</span>});</span><br><span class="line"> <span class="keyword">while</span>(!q.empty())</span><br><span class="line"> {</span><br><span class="line"> Node node = q.front();</span><br><span class="line"> q.pop();</span><br><span class="line"> result[node.depth].push_back(post[node.index]);</span><br><span class="line"> <span class="keyword">if</span>(tree[node.index][<span class="number">0</span>]!=<span class="number">0</span>)</span><br><span class="line"> q.push(Node{tree[node.index][<span class="number">0</span>],node.depth+<span class="number">1</span>});</span><br><span class="line"> <span class="keyword">if</span>(tree[node.index][<span class="number">1</span>]!=<span class="number">0</span>)</span><br><span class="line"> q.push(Node{tree[node.index][<span class="number">1</span>],node.depth+<span class="number">1</span>});</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="built_in">cin</span>>>n;</span><br><span class="line"> in.resize(n+<span class="number">1</span>);</span><br><span class="line"> post.resize(n+<span class="number">1</span>);</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>; i<=n; i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">cin</span>>>in[i];</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>; i<=n; i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">cin</span>>>post[i];</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//深搜获取唯一二叉树</span></span><br><span class="line"> dfs(rootIndex,<span class="number">1</span>,n,<span class="number">1</span> ,n);</span><br><span class="line"> <span class="comment">//广搜得到层次结构</span></span><br><span class="line"> bfs();</span><br><span class="line"> <span class="comment">//按要求输出</span></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d"</span>,result[<span class="number">0</span>][<span class="number">0</span>]);</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>;i<<span class="number">35</span>;i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span>(i%<span class="number">2</span> ==<span class="number">1</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> j=<span class="number">0</span>;j<result[i].<span class="built_in">size</span>();j++)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">" %d"</span>,result[i][j]);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> j=result[i].<span class="built_in">size</span>()<span class="number">-1</span>;j>=<span class="number">0</span>;j--)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">" %d"</span>,result[i][j]);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<h5 id="分析:已知中序和后序,可得一个唯一的二叉树-对其按照层次,之字形输出结果"><a href="#分析:已知中序和后序,可得一个唯一的二叉树-对其按照层次,之字形输出结果" class="headerlink" title="分析:已知中序和后序,可得一个唯一的二叉
</summary>
<category term="pta" scheme="https://www.smallapp.xyz/categories/pta/"/>
<category term="pta" scheme="https://www.smallapp.xyz/tags/pta/"/>
</entry>
<entry>
<title>1119 Pre and Post-order Traversals</title>
<link href="https://www.smallapp.xyz/2020/03/31/1119PreAndPostorderTraversals/"/>
<id>https://www.smallapp.xyz/2020/03/31/1119PreAndPostorderTraversals/</id>
<published>2020-03-31T02:55:32.677Z</published>
<updated>2020-04-02T03:45:01.603Z</updated>
<content type="html"><![CDATA[<h5 id="分析:已知先序和后序,求中序"><a href="#分析:已知先序和后序,求中序" class="headerlink" title="分析:已知先序和后序,求中序"></a>分析:已知先序和后序,求中序</h5><h5 id="需要知道,如何判断这个中序是否不唯一-先序的首位和后序的末位相等,为根元素。之后先序后推一位,后序前推一位。当两值相等-此时便无法区分到底是左子树还是右子树"><a href="#需要知道,如何判断这个中序是否不唯一-先序的首位和后序的末位相等,为根元素。之后先序后推一位,后序前推一位。当两值相等-此时便无法区分到底是左子树还是右子树" class="headerlink" title="需要知道,如何判断这个中序是否不唯一.先序的首位和后序的末位相等,为根元素。之后先序后推一位,后序前推一位。当两值相等,此时便无法区分到底是左子树还是右子树"></a>需要知道,如何判断这个中序是否不唯一.先序的首位和后序的末位相等,为根元素。之后先序后推一位,后序前推一位。当两值相等,此时便无法区分到底是左子树还是右子树</h5><h5 id="即不能够唯一断定,某子节点是左节点还是右节点"><a href="#即不能够唯一断定,某子节点是左节点还是右节点" class="headerlink" title="即不能够唯一断定,某子节点是左节点还是右节点"></a>即不能够唯一断定,某子节点是左节点还是右节点</h5><h5 id="vector存储pre,post,in"><a href="#vector存储pre,post,in" class="headerlink" title="vector存储pre,post,in"></a>vector存储pre,post,in</h5><h5 id="算法中自定义出现不唯一时认定其为左子树"><a href="#算法中自定义出现不唯一时认定其为左子树" class="headerlink" title="算法中自定义出现不唯一时认定其为左子树"></a>算法中自定义出现不唯一时认定其为左子树</h5><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><iostream></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><vector></span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">int</span> n;</span><br><span class="line"><span class="built_in">vector</span><<span class="keyword">int</span>> pre,post,in;</span><br><span class="line"><span class="keyword">bool</span> uniqueT = <span class="literal">true</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Charge</span><span class="params">(<span class="keyword">int</span> preL,<span class="keyword">int</span> preR,<span class="keyword">int</span> postL,<span class="keyword">int</span> postR)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">if</span>(preL==preR)</span><br><span class="line"> {</span><br><span class="line"> in.push_back(pre[preL]);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">//两端相等也认定为左子树</span></span><br><span class="line"> <span class="keyword">if</span>(pre[preL]==post[postR])</span><br><span class="line"> {</span><br><span class="line"> <span class="comment">//根节点确定,考虑子树情况</span></span><br><span class="line"> <span class="keyword">if</span>(pre[preL+<span class="number">1</span>]== post[postR<span class="number">-1</span>])</span><br><span class="line"> {</span><br><span class="line"> uniqueT = <span class="literal">false</span>;</span><br><span class="line"> <span class="comment">//意味着剩下的全是左子树的内容</span></span><br><span class="line"> Charge(preL+<span class="number">1</span>,preR,postL,postR<span class="number">-1</span>);<span class="comment">//左</span></span><br><span class="line"> in.push_back(pre[preL]);<span class="comment">//根</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">int</span> i=<span class="number">0</span>;</span><br><span class="line"> <span class="keyword">while</span>(pre[preL+i]!=post[postR<span class="number">-1</span>])</span><br><span class="line"> {</span><br><span class="line"> i++;</span><br><span class="line"> }</span><br><span class="line"> i=i<span class="number">-1</span>;</span><br><span class="line"> Charge(preL+<span class="number">1</span>,preL+i,postL,postL+i<span class="number">-1</span>);<span class="comment">//左子树</span></span><br><span class="line"> in.push_back(pre[preL]);<span class="comment">//根节点</span></span><br><span class="line"> Charge(preL+i+<span class="number">1</span>,preR,postL+i,postR<span class="number">-1</span>);<span class="comment">//右子树</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="built_in">cin</span>>>n;</span><br><span class="line"> pre.resize(n+ <span class="number">1</span>);</span><br><span class="line"> post.resize(n+<span class="number">1</span>);</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>; i<=n; i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">cin</span>>>pre[i];</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>; i<=n; i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">cin</span>>>post[i];</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//判断并存储</span></span><br><span class="line"> Charge(<span class="number">1</span>,n,<span class="number">1</span>,n);</span><br><span class="line"> <span class="comment">//输出</span></span><br><span class="line"> <span class="keyword">if</span>(uniqueT)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">cout</span><<<span class="string">"Yes"</span><<<span class="built_in">endl</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">cout</span><<<span class="string">"No"</span><<<span class="built_in">endl</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">cout</span><<in[<span class="number">0</span>];</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>; i<in.<span class="built_in">size</span>(); i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">cout</span><<<span class="string">" "</span><<in[i];</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">cout</span><<<span class="built_in">endl</span>;</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<h5 id="分析:已知先序和后序,求中序"><a href="#分析:已知先序和后序,求中序" class="headerlink" title="分析:已知先序和后序,求中序"></a>分析:已知先序和后序,求中序</h5><h5 id="需要知道,如何判断这个中序是否不唯
</summary>
<category term="pta" scheme="https://www.smallapp.xyz/categories/pta/"/>
<category term="pta" scheme="https://www.smallapp.xyz/tags/pta/"/>
</entry>
<entry>
<title>1115 Counting Nodes in a BST</title>
<link href="https://www.smallapp.xyz/2020/03/31/1115CountingNodesInBST/"/>
<id>https://www.smallapp.xyz/2020/03/31/1115CountingNodesInBST/</id>
<published>2020-03-31T02:55:32.667Z</published>
<updated>2020-04-02T08:39:48.591Z</updated>
<content type="html"><![CDATA[<h5 id="分析:左子树小于父节点,右子树大于父节点"><a href="#分析:左子树小于父节点,右子树大于父节点" class="headerlink" title="分析:左子树小于父节点,右子树大于父节点"></a>分析:左子树小于父节点,右子树大于父节点</h5><h5 id="链表存储自定义节点,存储bst,递归构建"><a href="#链表存储自定义节点,存储bst,递归构建" class="headerlink" title="链表存储自定义节点,存储bst,递归构建"></a>链表存储自定义节点,存储bst,递归构建</h5><h5 id="由根节点开始,dfs节点,并累计不同深度的系欸但数量"><a href="#由根节点开始,dfs节点,并累计不同深度的系欸但数量" class="headerlink" title="由根节点开始,dfs节点,并累计不同深度的系欸但数量"></a>由根节点开始,dfs节点,并累计不同深度的系欸但数量</h5><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br></pre></td><td class="code"><pre><span class="line">#include <iostream></span><br><span class="line">#include <vector></span><br><span class="line"></span><br><span class="line">using namespace std;</span><br><span class="line">int n;//<=1000</span><br><span class="line">struct Node</span><br><span class="line">{</span><br><span class="line"> int value;</span><br><span class="line"> struct Node *left,*right;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">Node* Build(struct Node *root,int value)</span><br><span class="line">{</span><br><span class="line"> if(root==NULL)</span><br><span class="line"> {</span><br><span class="line"> root = new Node();</span><br><span class="line"> root->value = value;</span><br><span class="line"> root->left = NULL;</span><br><span class="line"> root->right = NULL;</span><br><span class="line"> }</span><br><span class="line"> else if(value <= root->value)</span><br><span class="line"> {</span><br><span class="line"> root->left= Build(root->left,value);</span><br><span class="line"> }</span><br><span class="line"> else</span><br><span class="line"> {</span><br><span class="line"> root->right = Build(root->right,value);</span><br><span class="line"> }</span><br><span class="line"> return root;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">vector<int> arr(1001);</span><br><span class="line">int maxDepth = 0;</span><br><span class="line"></span><br><span class="line">void DFS(struct Node *root,int depth)</span><br><span class="line">{</span><br><span class="line"> if(root==NULL)</span><br><span class="line"> {</span><br><span class="line"> maxDepth = max(maxDepth,depth);</span><br><span class="line"> return ;</span><br><span class="line"> }</span><br><span class="line"> arr[depth]++;</span><br><span class="line"> DFS(root->left,depth+1);</span><br><span class="line"> DFS(root->right,depth+1);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">int main()</span><br><span class="line">{</span><br><span class="line"> cin>>n;</span><br><span class="line"> int t;</span><br><span class="line"> Node *root = NULL;</span><br><span class="line"> for(int i=1; i<=n; i++)</span><br><span class="line"> {</span><br><span class="line"> cin>>t;</span><br><span class="line"> root = Build(root,t);</span><br><span class="line"> }</span><br><span class="line"> DFS(root,1);</span><br><span class="line"> int b = arr[maxDepth-1];</span><br><span class="line"> int a = arr[maxDepth-2];</span><br><span class="line"></span><br><span class="line"> for(int i=0;i<arr.size();i++)</span><br><span class="line"> {</span><br><span class="line"> cout<<arr[i]<<endl;</span><br><span class="line"> }</span><br><span class="line"> printf("%d + %d = %d",b,a,a+b);</span><br><span class="line"></span><br><span class="line"> return 0;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<h5 id="分析:左子树小于父节点,右子树大于父节点"><a href="#分析:左子树小于父节点,右子树大于父节点" class="headerlink" title="分析:左子树小于父节点,右子树大于父节点"></a>分析:左子树小于父节点,右子树大于父节点</h5><
</summary>
<category term="pta" scheme="https://www.smallapp.xyz/categories/pta/"/>
<category term="pta" scheme="https://www.smallapp.xyz/tags/pta/"/>
</entry>
<entry>
<title>1110 Complete Binary Tree</title>
<link href="https://www.smallapp.xyz/2020/03/31/1110CompleteBinaryTree/"/>
<id>https://www.smallapp.xyz/2020/03/31/1110CompleteBinaryTree/</id>
<published>2020-03-31T02:55:32.650Z</published>
<updated>2020-04-02T08:39:43.667Z</updated>
<content type="html"><![CDATA[<h5 id="分析:每次可以获得一个-坐标-和左子树坐标和右子树坐标"><a href="#分析:每次可以获得一个-坐标-和左子树坐标和右子树坐标" class="headerlink" title="分析:每次可以获得一个 坐标 和左子树坐标和右子树坐标"></a>分析:每次可以获得一个 坐标 和左子树坐标和右子树坐标</h5><h5 id="判断是否是完全二叉树-是-返回树的最后一个节点坐标"><a href="#判断是否是完全二叉树-是-返回树的最后一个节点坐标" class="headerlink" title="判断是否是完全二叉树 是:返回树的最后一个节点坐标"></a>判断是否是完全二叉树 是:返回树的最后一个节点坐标</h5><h5 id="否-返回root坐标"><a href="#否-返回root坐标" class="headerlink" title="否:返回root坐标"></a>否:返回root坐标</h5><h5 id="gt-如何根据给定的数据,把数据构建成树"><a href="#gt-如何根据给定的数据,把数据构建成树" class="headerlink" title="=> 如何根据给定的数据,把数据构建成树"></a>=> 如何根据给定的数据,把数据构建成树</h5><h5 id="一个数组hasvalue-n-,根据输入结果判断是否是1,若1-n某一点不为1,即为根节点"><a href="#一个数组hasvalue-n-,根据输入结果判断是否是1,若1-n某一点不为1,即为根节点" class="headerlink" title="一个数组hasvalue[n],根据输入结果判断是否是1,若1-n某一点不为1,即为根节点"></a>一个数组hasvalue[n],根据输入结果判断是否是1,若1-n某一点不为1,即为根节点</h5><h5 id="一个二维数组存储输入值"><a href="#一个二维数组存储输入值" class="headerlink" title="一个二维数组存储输入值"></a>一个二维数组存储输入值</h5><h5 id="若为完全二叉树,dfs后得的最大元素index会比节点总数大"><a href="#若为完全二叉树,dfs后得的最大元素index会比节点总数大" class="headerlink" title="若为完全二叉树,dfs后得的最大元素index会比节点总数大"></a>若为完全二叉树,dfs后得的最大元素index会比节点总数大</h5><h5 id=""><a href="#" class="headerlink" title=""></a></h5><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br></pre></td><td class="code"><pre><span class="line">#include <iostream></span><br><span class="line"></span><br><span class="line">using namespace std;</span><br><span class="line">int n;</span><br><span class="line">int arr[100][2];</span><br><span class="line">int maxn = 0;//最大index</span><br><span class="line">int ans;//最大节点值在数组的index</span><br><span class="line"></span><br><span class="line">void DFS(int root,int index)</span><br><span class="line">{</span><br><span class="line"> if(index>maxn)</span><br><span class="line"> {</span><br><span class="line"> maxn = index;</span><br><span class="line"> ans = root;</span><br><span class="line"> }</span><br><span class="line"> if(arr[root][0]!= -1)</span><br><span class="line"> DFS(arr[root][0],index *2);</span><br><span class="line"> if(arr[root][1]!= -1)</span><br><span class="line"> DFS(arr[root][1],index *2+1);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">int main()</span><br><span class="line">{</span><br><span class="line"> cin>>n;</span><br><span class="line"> int root = 0;</span><br><span class="line"> int hasvalue[100] = {0};</span><br><span class="line"></span><br><span class="line"> string left,right;</span><br><span class="line"> for(int i=0; i<n; i++)</span><br><span class="line"> {</span><br><span class="line"> cin>>left>>right;</span><br><span class="line"> if(left=="-")</span><br><span class="line"> {</span><br><span class="line"> arr[i][0]=-1;</span><br><span class="line"> }</span><br><span class="line"> else</span><br><span class="line"> {</span><br><span class="line"> arr[i][0] = stoi(left);</span><br><span class="line"> hasvalue[arr[i][0]] = 1;</span><br><span class="line"> }</span><br><span class="line"> if(right=="-")</span><br><span class="line"> {</span><br><span class="line"> arr[i][1]=-1;</span><br><span class="line"> }</span><br><span class="line"> else</span><br><span class="line"> {</span><br><span class="line"> arr[i][1] = stoi(right);</span><br><span class="line"> hasvalue[arr[i][1]] = 1;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> while(hasvalue[root]!=0)</span><br><span class="line"> root++;</span><br><span class="line"> DFS(root,1);</span><br><span class="line"></span><br><span class="line"> if(maxn==n)</span><br><span class="line"> {</span><br><span class="line"> printf("YES %d",ans);</span><br><span class="line"> }</span><br><span class="line"> else</span><br><span class="line"> {</span><br><span class="line"> printf("NO %d",root);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> return 0;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<h5 id="分析:每次可以获得一个-坐标-和左子树坐标和右子树坐标"><a href="#分析:每次可以获得一个-坐标-和左子树坐标和右子树坐标" class="headerlink" title="分析:每次可以获得一个 坐标 和左子树坐标和右子树坐标"></a>分析:每次
</summary>
<category term="pta" scheme="https://www.smallapp.xyz/categories/pta/"/>
<category term="pta" scheme="https://www.smallapp.xyz/tags/pta/"/>
</entry>
<entry>
<title>1106 Lowest Price in Supply Chain</title>
<link href="https://www.smallapp.xyz/2020/03/31/1106LowestPriceInSupplyChain/"/>
<id>https://www.smallapp.xyz/2020/03/31/1106LowestPriceInSupplyChain/</id>
<published>2020-03-31T02:55:32.648Z</published>
<updated>2020-04-02T08:39:46.540Z</updated>
<content type="html"><![CDATA[<h5 id="N-lt-10-10,可以使用vector二维数组存储数据"><a href="#N-lt-10-10,可以使用vector二维数组存储数据" class="headerlink" title="N<10^10,可以使用vector二维数组存储数据"></a>N<10^10,可以使用vector二维数组存储数据</h5><h5 id="万一末尾节点没有零售商?没有在考虑范围内,按照结果来看,零售商应该是叶子节点"><a href="#万一末尾节点没有零售商?没有在考虑范围内,按照结果来看,零售商应该是叶子节点" class="headerlink" title="万一末尾节点没有零售商?没有在考虑范围内,按照结果来看,零售商应该是叶子节点"></a>万一末尾节点没有零售商?没有在考虑范围内,按照结果来看,零售商应该是叶子节点</h5><h5 id="mindep表示层数-num表示叶节点个数"><a href="#mindep表示层数-num表示叶节点个数" class="headerlink" title="mindep表示层数 num表示叶节点个数"></a>mindep表示层数 num表示叶节点个数</h5><h5 id="需要注意结果精确位数"><a href="#需要注意结果精确位数" class="headerlink" title="需要注意结果精确位数"></a>需要注意结果精确位数</h5><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></td><td class="code"><pre><span class="line">#include <cstdio></span><br><span class="line">#include <vector></span><br><span class="line">#include <cmath></span><br><span class="line"></span><br><span class="line">using namespace std;</span><br><span class="line"></span><br><span class="line">int n;//节点数</span><br><span class="line">vector<int> arr[100000];</span><br><span class="line">int mindep = 99999999;</span><br><span class="line">int num=1;</span><br><span class="line"></span><br><span class="line">void DFS(int root,int depth)</span><br><span class="line">{</span><br><span class="line"> if(mindep<depth)</span><br><span class="line"> return;</span><br><span class="line"> if(arr[root].size() == 0)</span><br><span class="line"> {</span><br><span class="line"> if(mindep>depth)</span><br><span class="line"> {</span><br><span class="line"> mindep = depth;</span><br><span class="line"> num =1;</span><br><span class="line"> }</span><br><span class="line"> else if(mindep== depth)</span><br><span class="line"> {</span><br><span class="line"> num++;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> for(int i=0; i<arr[root].size(); i++)</span><br><span class="line"> {</span><br><span class="line"> DFS(arr[root][i],depth+1);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">int main()</span><br><span class="line">{</span><br><span class="line"> int n;</span><br><span class="line"> double p,r;</span><br><span class="line"> scanf("%d %lf %lf",&n,&p,&r);</span><br><span class="line"> for(int i=0; i<n; i++)</span><br><span class="line"> {</span><br><span class="line"> int ln;</span><br><span class="line"> scanf("%d",&ln);</span><br><span class="line"></span><br><span class="line"> for(int j=0; j<ln; j++)</span><br><span class="line"> {</span><br><span class="line"> int index;</span><br><span class="line"> scanf("%d",&index);</span><br><span class="line"> arr[i].push_back(index);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> DFS(0,0);//获取树</span><br><span class="line"></span><br><span class="line"> printf("%.4f %d",p*pow((1+r/100),mindep),num);</span><br><span class="line"></span><br><span class="line"> return 0;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<h5 id="N-lt-10-10,可以使用vector二维数组存储数据"><a href="#N-lt-10-10,可以使用vector二维数组存储数据" class="headerlink" title="N&lt;10^10,可以使用vector二维数组存储数据"></a
</summary>
<category term="pta" scheme="https://www.smallapp.xyz/categories/pta/"/>
<category term="pta" scheme="https://www.smallapp.xyz/tags/pta/"/>
</entry>
<entry>
<title>pta相关词汇</title>
<link href="https://www.smallapp.xyz/2020/03/31/vocabulary/"/>
<id>https://www.smallapp.xyz/2020/03/31/vocabulary/</id>
<published>2020-03-31T02:55:32.645Z</published>
<updated>2020-04-07T05:41:28.973Z</updated>
<content type="html"><![CDATA[<blockquote><p>vocabulary 词汇<br>positive 正的;积极的<br>traversal 遍历<br>sequence 序列<br>occupy 占领、占用<br>argument 实参<br>parameter 形参<br>ancestor 祖先<br>descendant 后裔、子孙<br>respectively 分别的、各自的<br>postorder traversal sequence 后序遍历序列<br>corresponding 对应的,相应的;一致的<br>recursively 递归的<br>indices 标志,标记;迹象,征象,征候;指数,指标,率<br>invert 使…反转<br>adjacent 临近的</p></blockquote>]]></content>
<summary type="html">
<blockquote>
<p>vocabulary 词汇<br>positive 正的;积极的<br>traversal 遍历<br>sequence 序列<br>occupy 占领、占用<br>argument 实参<br>parameter 形参<br>ancestor 祖
</summary>
<category term="pta" scheme="https://www.smallapp.xyz/categories/pta/"/>
<category term="pta" scheme="https://www.smallapp.xyz/tags/pta/"/>
</entry>
<entry>
<title>模块系统</title>
<link href="https://www.smallapp.xyz/2020/03/21/1.3%E6%A8%A1%E5%9D%97%E7%B3%BB%E7%BB%9F/"/>
<id>https://www.smallapp.xyz/2020/03/21/1.3%E6%A8%A1%E5%9D%97%E7%B3%BB%E7%BB%9F/</id>
<published>2020-03-20T16:00:00.000Z</published>
<updated>2020-04-02T05:46:37.912Z</updated>
<content type="html"><![CDATA[<h2 id="介绍"><a href="#介绍" class="headerlink" title="介绍"></a>介绍</h2><p>ABP提供用于构建模块并将其组合以创建应用程序的基础设施。一个模块可基于另一个模块。通常,一个集合被当做一个模块,如果你创建了一个有多个集合的应用,这就需要为每个集合创建模块定义。<br>模块系统目前主要集中在服务器端,而不是客户端。</p><h2 id="模块定义"><a href="#模块定义" class="headerlink" title="模块定义"></a>模块定义</h2><p>模块是使用派生自ABP包中的AbpModule的类定义的。假设我们正在开发一个可以用于不同应用程序的博客模块。最简单的模块定义可以像下面的例子一样:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">public class MyBlogApplicationModule : AbpModule</span><br><span class="line">{</span><br><span class="line"> public override void Initialize()</span><br><span class="line"> {</span><br><span class="line"> IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>模块定义类通过依赖注入注册需要的模块。也可以配置应用程序和其他模块,增加新功能等。</p><h2 id="生命周期方法"><a href="#生命周期方法" class="headerlink" title="生命周期方法"></a>生命周期方法</h2><p>ABP在启动和关闭时调用一些特殊的方法。可以重写这些方法在执行一些特殊任务。ABP调用这些按照依赖排序的方法。<br>如果模块A依赖模块B,模块B会在模块A之前初始化。<br>准确的启动方法顺序:PreInitialize-B, PreInitialize-A, Initialize-B, Initialize-A, PostInitialize-B and PostInitialize-A。对于所有依赖关系图都是如此。关闭方法也类似,但顺序相反。</p><h2 id="PreInitialize(预初始化)"><a href="#PreInitialize(预初始化)" class="headerlink" title="PreInitialize(预初始化)"></a>PreInitialize(预初始化)</h2><p>这个方法在应用启动时首先调用。这是在框架和其他模块初始化之前配置他们的首选方法。<br>可以在此写一些特殊code,在依赖项注入注册之前运行。例如,可以创建一个常规的注册类,在这里使用<strong>IocManager.AddConventionalRegisterer</strong>方法注册。</p><h2 id="Initialize(初始化)"><a href="#Initialize(初始化)" class="headerlink" title="Initialize(初始化)"></a>Initialize(初始化)</h2><p>这是依赖项注入注册的位置。通常使用<strong>IocManager.AddConventionalRegisterer</strong>方法。如果想要自定义依赖项注册,查看<a href="https://aspnetboilerplate.com/Pages/Documents/Dependency-Injection" target="_blank" rel="noopener">依赖注入</a>说明文档。</p><h2 id="PostInitialize(初始化后)"><a href="#PostInitialize(初始化后)" class="headerlink" title="PostInitialize(初始化后)"></a>PostInitialize(初始化后)</h2><p>这个方法在启动过程中最后调用。在这里解决依赖项是安全的。</p><h2 id="Shutdown"><a href="#Shutdown" class="headerlink" title="Shutdown"></a>Shutdown</h2><p>这个方法在应用关闭的时候调用。</p><h2 id="模块依赖"><a href="#模块依赖" class="headerlink" title="模块依赖"></a>模块依赖</h2><p>一个模块可以依赖于另一个模块。需要使用DependsOn属性显式声明依赖关系,如下:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">[DependsOn(typeof(MyBlogCoreModule))]</span><br><span class="line">public class MyBlogApplicationModule : AbpModule</span><br><span class="line">{</span><br><span class="line"> public override void Initialize()</span><br><span class="line"> {</span><br><span class="line"> IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>MyBlogApplicationModule依赖于MyBlogCoreModule,应该在MyBlogApplicationModule之前初始化MyBlogCoreModule。<br>ABP可以从启动模块开始递归地解析依赖项,并相应地初始化它们。启动模块初始化为最后一个模块。</p><h2 id="插件模块"><a href="#插件模块" class="headerlink" title="插件模块"></a>插件模块</h2><p>虽然从启动模块开始研究模块并遍历依赖项,ABP还可以动态加载模块。AbpBootstrapper类定义了PlugInSources属性,该属性可用于将源代码添加到动态加载的插件模块中。插件源可以是实现IPlugInSource接口的任何类。PlugInFolderSource类实现它来从位于文件夹中的程序集获取插件模块。</p><h2 id="ASP-NET-Core"><a href="#ASP-NET-Core" class="headerlink" title="ASP.NET Core"></a>ASP.NET Core</h2><p>ABP ASP.NET Core模块在AddAbp扩展方法中定义了在Startup类中添加插件源的选项:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">services.AddAbp<MyStartupModule>(options =></span><br><span class="line">{</span><br><span class="line"> options.PlugInSources.Add(new FolderPlugInSource(@"C:\MyPlugIns"));</span><br><span class="line">});</span><br></pre></td></tr></table></figure><p>我们可以使用一个更简单的语法AddFolder扩展方法:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">services.AddAbp<MyStartupModule>(options =></span><br><span class="line">{</span><br><span class="line"> options.PlugInSources.AddFolder(@"C:\MyPlugIns");</span><br><span class="line">});</span><br></pre></td></tr></table></figure><p><a href="https://aspnetboilerplate.com/Pages/Documents/AspNet-Core" target="_blank" rel="noopener">有关启动类的更多关于ASP.NET Core的信息</a></p><h2 id="ASP-NET-MVC-Web-API"><a href="#ASP-NET-MVC-Web-API" class="headerlink" title="ASP.NET MVC, Web API"></a>ASP.NET MVC, Web API</h2><p>传统ASP.NET MVC应用,可以通过在global.asax中覆盖Application_Start来添加插件文件夹。如下图所示:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">public class MvcApplication : AbpWebApplication<MyStartupModule></span><br><span class="line">{</span><br><span class="line"> protected override void Application_Start(object sender, EventArgs e)</span><br><span class="line"> {</span><br><span class="line"> AbpBootstrapper.PlugInSources.AddFolder(@"C:\MyPlugIns");</span><br><span class="line"> //...</span><br><span class="line"> base.Application_Start(sender, e);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="插件中的Controllers"><a href="#插件中的Controllers" class="headerlink" title="插件中的Controllers"></a>插件中的Controllers</h2><p>如果你的模块包括MVC或Web API控制器,ASP.NET无法调查您的控制器。为了克服这个问题,你可以改变global.asax文件如下:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">using System.Web;</span><br><span class="line">using Abp.PlugIns;</span><br><span class="line">using Abp.Web;</span><br><span class="line">using MyDemoApp.Web;</span><br><span class="line"></span><br><span class="line">[assembly: PreApplicationStartMethod(typeof(PreStarter), "Start")]</span><br><span class="line"></span><br><span class="line">namespace MyDemoApp.Web</span><br><span class="line">{</span><br><span class="line"> public class MvcApplication : AbpWebApplication<MyStartupModule></span><br><span class="line"> {</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> public static class PreStarter</span><br><span class="line"> {</span><br><span class="line"> public static void Start()</span><br><span class="line"> {</span><br><span class="line"> //...</span><br><span class="line"> MvcApplication.AbpBootstrapper.PlugInSources.AddFolder(@"C:\MyPlugIns\");</span><br><span class="line"> MvcApplication.AbpBootstrapper.PlugInSources.AddToBuildManager();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="附加组件"><a href="#附加组件" class="headerlink" title="附加组件"></a>附加组件</h2><p>IAssemblyFinder and ITypeFinder 的默认实现(ABP使用它们来研究应用程序中的特定类)只查找这些程序集中的模块程序集和类型。我们可以在模块中覆盖GetAdditionalAssemblies方法来包含额外的程序集。</p><h2 id="定制模块方法"><a href="#定制模块方法" class="headerlink" title="定制模块方法"></a>定制模块方法</h2><p>您的模块还可以具有其他依赖于此模块的模块可以使用的自定义方法。假设MyModule2依赖于MyModule1,并且希望在PreInitialize方法中调用MyModule1的方法。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line">public class MyModule1 : AbpModule</span><br><span class="line">{</span><br><span class="line"> public override void Initialize()</span><br><span class="line"> {</span><br><span class="line"> IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> public void MyModuleMethod1()</span><br><span class="line"> {</span><br><span class="line"> //this is a custom method of this module</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">[DependsOn(typeof(MyModule1))]</span><br><span class="line">public class MyModule2 : AbpModule</span><br><span class="line">{</span><br><span class="line"> private readonly MyModule1 _myModule1;</span><br><span class="line"></span><br><span class="line"> public MyModule2(MyModule1 myModule1)</span><br><span class="line"> {</span><br><span class="line"> _myModule1 = myModule1;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> public override void PreInitialize()</span><br><span class="line"> {</span><br><span class="line"> _myModule1.MyModuleMethod1(); //Call MyModule1's method</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> public override void Initialize()</span><br><span class="line"> {</span><br><span class="line"> IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>在这里,我们将构造函数注入到MyModule2中,因此MyModule2可以调用MyModule1的定制方法。这只有在Module2依赖于Module1时才有可能。</p><h2 id="模块配置"><a href="#模块配置" class="headerlink" title="模块配置"></a>模块配置</h2><p>虽然可以使用自定义模块方法来配置模块,但我们建议您使用启动配置系统来定义和设置模块的配置。</p><h2 id="模块生命周期"><a href="#模块生命周期" class="headerlink" title="模块生命周期"></a>模块生命周期</h2><p>模块类被自动注册为单例。</p>]]></content>
<summary type="html">
<h2 id="介绍"><a href="#介绍" class="headerlink" title="介绍"></a>介绍</h2><p>ABP提供用于构建模块并将其组合以创建应用程序的基础设施。一个模块可基于另一个模块。通常,一个集合被当做一个模块,如果你创建了一个有多个集合
</summary>
<category term="ABP" scheme="https://www.smallapp.xyz/categories/ABP/"/>
<category term="ABP" scheme="https://www.smallapp.xyz/tags/ABP/"/>
</entry>
<entry>
<title>Session</title>
<link href="https://www.smallapp.xyz/2020/03/21/2.2session/"/>
<id>https://www.smallapp.xyz/2020/03/21/2.2session/</id>
<published>2020-03-20T16:00:00.000Z</published>
<updated>2020-04-02T05:47:12.588Z</updated>
<content type="html"><![CDATA[<h2 id="说明"><a href="#说明" class="headerlink" title="说明"></a>说明</h2><p>ABP提供了IAbpSession接口来获取当前用户和租户,而不需要使用ASP.NET的会话。在ABP中,IAbpSession也被其他结构完全集成和使用,如<a href="https://aspnetboilerplate.com/Pages/Documents/Setting-Management" target="_blank" rel="noopener">设置</a>和<a href="https://aspnetboilerplate.com/Pages/Documents/Authorization" target="_blank" rel="noopener">授权系统</a>。</p><h2 id="注入会话"><a href="#注入会话" class="headerlink" title="注入会话"></a>注入会话</h2><p>IAbpSession通常是注入到需要的类中的属性,除非没有会话信息就无法工作。如果我们使用属性注入,我们可以使用NullAbpSession.Instance作为默认值,如下:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">public class MyClass : ITransientDependency</span><br><span class="line">{</span><br><span class="line"> public IAbpSession AbpSession { get; set; }</span><br><span class="line"></span><br><span class="line"> public MyClass()</span><br><span class="line"> {</span><br><span class="line"> AbpSession = NullAbpSession.Instance;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> public void MyMethod()</span><br><span class="line"> {</span><br><span class="line"> var currentUserId = AbpSession.UserId;</span><br><span class="line"> //...</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>由于身份验证/授权是一个应用层任务,在应用层和上层使用IAbpSession是明智之举。这通常不是在域层中完成的。ApplicationService、AbpController、AbpApiController和其他一些基类已经注入了AbpSession,因此,例如,您可以直接在应用程序服务方法中使用AbpSession属性。</p><h2 id="会话属性"><a href="#会话属性" class="headerlink" title="会话属性"></a>会话属性</h2><p>AbpSession定义了几个关键属性:</p><ul><li><strong>UserId</strong>: 当前用户的Id,如果没有当前用户则为null。如果需要调用授权代码,则不能为空。</li><li><strong>TenantId</strong>: 当前租户的Id,如果没有当前租户,则为null(如果用户没有登录或他是主机用户)。</li><li><strong>ImpersonatorUserId</strong>: 如果当前会话由另一个用户模拟,则为该模拟用户的Id。如果这不是模拟登录,则为空。</li><li><strong>ImpersonatorTenantId</strong>: 如果当前会话由另一个用户模拟,则该模拟用户的租户的Id。如果这不是模拟登录,则为空。</li><li><strong>MultiTenancySide</strong>: 它可以是主机或租户。</li></ul><p><strong>UserId</strong>和<strong>TenantId</strong>是可空的。还有不可空的<strong>GetUserId()</strong>和<strong>GetTenantId()</strong>方法。如果确定有当前用户,可以调用<strong>GetUserId()</strong>。如果当前用户为空,则此方法将引发异常。<strong>GetTenantId()</strong>也以这种方式工作。</p><p>模拟程序属性不像其他属性那样常见,通常用于审计日志记录。</p><h3 id="ClaimsAbpSession"><a href="#ClaimsAbpSession" class="headerlink" title="ClaimsAbpSession"></a>ClaimsAbpSession</h3><p>ClaimsAbpSession是IAbpSession接口的默认实现。它从当前用户的主体声明中获取会话属性(MultiTenancySide除外,it’s calculated)。对于基于cookie的表单身份验证,它从cookie获取值。因此,它完全集成到 ASP.NET’s的身份验证机制。</p><h2 id="覆盖当前会话值"><a href="#覆盖当前会话值" class="headerlink" title="覆盖当前会话值"></a>覆盖当前会话值</h2><p>在某些特定情况下,您可能需要更改/覆盖有限范围内的会话值。在这种情况下,您可以使用IAbpSession.Use方法:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">public class MyService</span><br><span class="line">{</span><br><span class="line"> private readonly IAbpSession _session;</span><br><span class="line"></span><br><span class="line"> public MyService(IAbpSession session)</span><br><span class="line"> {</span><br><span class="line"> _session = session;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> public void Test()</span><br><span class="line"> {</span><br><span class="line"> using (_session.Use(42, null))</span><br><span class="line"> {</span><br><span class="line"> var tenantId = _session.TenantId; //42</span><br><span class="line"> var userId = _session.UserId; //null</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>Use方法返回一个IDisposable,它必须被释放。一旦返回值被释放,会话值将自动恢复到以前的值。</p><h2 id="Warning"><a href="#Warning" class="headerlink" title="Warning!"></a>Warning!</h2><p>始终在using块中使用use方法,如上所示。否则,您可能会得到意外的会话值。您可以嵌套使用块,它们将如您所期望的那样工作。</p><h2 id="用户识别"><a href="#用户识别" class="headerlink" title="用户识别"></a>用户识别</h2><p>您可以使用 .touseridentifier()扩展方法从IAbpSession创建一个UserIdentifier对象。由于UserIdentifier在许多api中都被使用,这将简化当前用户UserIdentifier对象的创建。</p>]]></content>
<summary type="html">
<h2 id="说明"><a href="#说明" class="headerlink" title="说明"></a>说明</h2><p>ABP提供了IAbpSession接口来获取当前用户和租户,而不需要使用ASP.NET的会话。在ABP中,IAbpSession也被其他结构
</summary>
<category term="ABP" scheme="https://www.smallapp.xyz/categories/ABP/"/>
<category term="ABP" scheme="https://www.smallapp.xyz/tags/ABP/"/>
</entry>
<entry>
<title>多租户</title>
<link href="https://www.smallapp.xyz/2020/03/21/1.5%E5%A4%9A%E7%A7%9F%E6%88%B7/"/>
<id>https://www.smallapp.xyz/2020/03/21/1.5%E5%A4%9A%E7%A7%9F%E6%88%B7/</id>
<published>2020-03-20T16:00:00.000Z</published>
<updated>2020-04-02T05:46:51.146Z</updated>
<content type="html"><![CDATA[<h2 id="什么是多租户"><a href="#什么是多租户" class="headerlink" title="什么是多租户"></a>什么是多租户</h2><p>软件多租户指的是一种软件架构,其中一个软件实例运行在服务器上,为多个租户服务。租户是一组用户,他们共享对软件实例具有特定特权的公共访问。使用多租户体系结构,软件应用程序被设计为为每个租户提供一个专用的实例共享,包括其数据、配置、用户管理、租户个人功能和非功能性属性。多租户与多实例体系结构形成对比,在多实例体系结构中,独立的软件实例代表不同的租户进行操作。<br>简而言之,多租户是一项创建SAAS(Software as-a Service)应用的服务。</p><h2 id="数据库和部署架构"><a href="#数据库和部署架构" class="headerlink" title="数据库和部署架构"></a>数据库和部署架构</h2><p>有一些不同的多租户数据库和部署方法:</p><h3 id="多个部署——多个数据库"><a href="#多个部署——多个数据库" class="headerlink" title="多个部署——多个数据库"></a>多个部署——多个数据库</h3><p>这实际上不是多租户,但是如果我们使用一个独立的数据库为每个客户(租户)运行一个应用程序实例,我们可以在一个服务器上为多个租户提供服务。我们只需确保应用程序的多个实例在相同的服务器环境中不会相互冲突。<br>对于设计为非多租户的现有应用程序,这也是可能的。创建这样的应用程序比较容易,因为应用程序不知道多租户。但是,这种方法存在设置、使用和维护问题。</p><h3 id="单一部署—多个数据库"><a href="#单一部署—多个数据库" class="headerlink" title="单一部署—多个数据库"></a>单一部署—多个数据库</h3><p>在这种方法中,我们在服务器上运行应用程序的单个实例。我们有一个主(主机)数据库来存储租户元数据(如租户名称和子域),并为每个租户提供一个单独的数据库。一旦我们确定了当前的租户(例如,从子域或从用户登录表单),然后,我们可以切换到该租户的数据库来执行操作。<br>我们为每个租户创建和维护一个单独的数据库,这包括数据库迁移。如果我们有许多使用专用数据库的客户,那么在应用程序更新期间迁移数据库模式可能需要很长时间。由于每个承租者都有一个单独的数据库,所以可以将其数据库与其他承租者分开备份。如果租户需要,我们还可以将租户数据库移动到更强大的服务器上。</p><h3 id="单一部署——单一数据库"><a href="#单一部署——单一数据库" class="headerlink" title="单一部署——单一数据库"></a>单一部署——单一数据库</h3><p>这是最理想的多租户体系结构:我们只将应用程序的单个实例与单个数据库部署到单个服务器上。每个表(对于RDBMS)中都有一个TenantId(或类似的)字段,用于将租户的数据与其他数据隔离。<br>这种类型的应用程序易于设置和维护,但难于创建。这是因为我们必须防止租户读取或写入其他租户数据。我们可以为每个数据库读(选择)操作添加一个TenantId过滤器。我们也可以在每次写入时检查它,看看这个实体是否与当前租户相关。这很乏味,而且容易出错。然而,ASP。NET Boilerplate通过使用自动数据过滤来帮助我们。<br>如果有许多租户使用大型数据集,则此方法可能会出现性能问题。我们可以使用表分区或其他数据库特性来克服这个问题。</p><h3 id="单一部署——混合数据库"><a href="#单一部署——混合数据库" class="headerlink" title="单一部署——混合数据库"></a>单一部署——混合数据库</h3><p>通常,我们可能希望将租户存储在单个数据库中,但是可能希望为所需的租户创建一个单独的数据库。例如,我们可以将拥有大数据的租户存储在他们自己的数据库中,而将所有其他租户存储在一个数据库中。</p><h3 id="多部署——单个-多个-混合数据库"><a href="#多部署——单个-多个-混合数据库" class="headerlink" title="多部署——单个/多个/混合数据库"></a>多部署——单个/多个/混合数据库</h3><p>最后,我们可能希望将应用程序部署到多个服务器(如web farm),以获得更好的应用程序性能、高可用性和/或可伸缩性。这与数据库方法无关。</p><h2 id="ABP中的多租户"><a href="#ABP中的多租户" class="headerlink" title="ABP中的多租户"></a>ABP中的多租户</h2><p>ABP可以处理上面描述的所有场景。</p><h3 id="启用多租户"><a href="#启用多租户" class="headerlink" title="启用多租户"></a>启用多租户</h3><p>框架级别默认禁用多租户。我们可以在模块的PreInitialize method中启用它,如下图所示</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Configuration.MultiTenancy.IsEnabled = true;</span><br></pre></td></tr></table></figure><h3 id="忽略主机用户的特性检查"><a href="#忽略主机用户的特性检查" class="headerlink" title="忽略主机用户的特性检查"></a>忽略主机用户的特性检查</h3><p>还有一种配置可以忽略主机用户的特性检查。我们可以在模块的PreInitialize method中启用它,如下图所示:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Configuration.MultiTenancy.IgnoreFeatureCheckForHostUsers = true;</span><br></pre></td></tr></table></figure><h2 id="主机vs租户"><a href="#主机vs租户" class="headerlink" title="主机vs租户"></a>主机vs租户</h2><p>我们定义了在多租户系统中使用的两个术语:</p><ul><li>Tenant:有自己的用户、角色、权限、设置……并使用与其他租户完全隔离的应用程序。多租户应用程序将有一个或多个租户。如果这是一个CRM应用程序,不同的租户也有自己的帐户、联系人、产品和订单。所以当我们说“承租者用户”时,我们指的是承租者拥有的用户。</li><li>Host: 主机是单例的(只有一个主机)。主机负责创建和管理租户。“主机用户”位于更高的级别,独立于所有租户,可以控制它们。<h2 id="Session-会话"><a href="#Session-会话" class="headerlink" title="Session(会话)"></a>Session(会话)</h2>ABP定义了IAbpSession接口来获取当前用户和租户id。默认情况下,此接口用于多租户以获取当前租户的id。因此,它可以根据当前租户的id过滤数据。</li><li>如果UserId和TenantId都为空,则当前用户没有登录到系统。我们无法知道它是主机用户还是租户用户。在这种情况下,用户不能访问授权的内容。</li><li>如果UserId不为空,TenantId为空,那么我们知道当前用户是主机用户。</li><li>如果UserId不为空,TenantId也不为空,我们就知道当前用户是租户用户。</li><li>如果UserId为null,但TenantId不为null,这意味着我们知道当前租户,但当前请求未被授权(用户未登录)。请参阅下一节以了解如何确定当前租户。</li></ul><p>有关<a href="https://aspnetboilerplate.com/Pages/Documents/Abp-Session" target="_blank" rel="noopener">更多信息</a>,请参见会话文档。</p><h2 id="确定当前租户"><a href="#确定当前租户" class="headerlink" title="确定当前租户"></a>确定当前租户</h2><p>由于所有租户用户都使用相同的应用程序,所以我们应该有一种方法来区分当前请求的租户。默认的会话实现(ClaimsAbpSession)使用不同的方法来找到与当前请求相关的租户,顺序如下:</p><ol><li>如果用户已登录,它将从当前声明(claim)中获取TenantId。声明(claim)名称是<a href="http://www.aspnetboilerplate.com/identity/claims/tenantId,应该包含一个整数值。如果在声明中没有找到该用户,则假定该用户是主机用户。" target="_blank" rel="noopener">http://www.aspnetboilerplate.com/identity/claims/tenantId,应该包含一个整数值。如果在声明中没有找到该用户,则假定该用户是主机用户。</a></li><li>如果用户尚未登录,则它将尝试从tenant resolve contributors解析TenantId。有3个预定义的租户贡献者,并以一个给定的顺序(第一个成功解析器’wins ‘)运行:<ol><li>DomainTenantResolveContributor: 尝试从url解析租赁名称,通常是从域或子域解析。您可以在模块的PreInitialize方法中配置域格式(如Configuration.Modules.AbpWebCommon().MultiTenancy.DomainFormat = “{0}.mydomain.com”;)。如果域格式是“{0}.mydomain.com”,而请求的当前主机是acme.mydomain.com,则租赁权名称解析为“acme”。下一步是查询ITenantStore,根据给定的租户名称查找TenantId。如果找到租户,则将其解析为当前租户。<ol start="2"><li>HttpHeaderTenantResolveContributor: 如果存在,尝试从“Abp.TenantId”header值解析TenantId。这是在Abp.MultiTenancy.MultiTenancyConsts.TenantIdResolveKey中定义的一个常数。</li><li>HttpCookieTenantResolveContributor: 如果存在,尝试从“Abp.TenantId”cookie值解析TenantId。这里使用的是与上面介绍的相同的常数。<br>默认情况下,ABP使用“Abp.TenantId”来从Cookie或请求头文件中查找TenantId。你可以使用多租户配置来更改:<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Configuration.MultiTenancy.TenantIdResolveKey = "Abp-TenantId";</span><br></pre></td></tr></table></figure>你还需要在客户端配置它:<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">abp.multiTenancy.tenantIdCookieName = 'Abp-TenantId';</span><br></pre></td></tr></table></figure>如果这些尝试都不能解析TenantId,则认为当前请求者是主机。租户解析器是可扩展的。您可以向Configuration.MultiTenancy.Resolvers集合添加解析器,或删除现有的解析器。<br>关于解析器的最后一件事:出于性能原因,在同一请求期间缓存已解析的租户id。解析器在请求中执行一次,并且仅在当前用户尚未登录时执行。</li></ol></li></ol></li></ol><h2 id="租户存储"><a href="#租户存储" class="headerlink" title="租户存储"></a>租户存储</h2><p>DomainTenantResolveContributor使用ITenantStore根据租户名称查找租户id。ITenantStore的默认实现是NullTenantStore,它不包含任何租户,查询时返回null。您可以实现并替换它来从任何数据源查询租户。模块Zero通过从它的租户管理器获得它,从而正确地实现了它。因此,如果使用模块Zero,就不必担心租户存储。</p><h2 id="数据过滤"><a href="#数据过滤" class="headerlink" title="数据过滤"></a>数据过滤</h2><p>对于多租户单数据库方法,我们必须添加TenantId过滤器,以便在从数据库检索实体时仅获取当前租户的实体。当您为您的实体实现两个接口之一:IMustHaveTenant和IMayHaveTenant时,ABP将自动执行此操作。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">public class Product : Entity, IMustHaveTenant</span><br><span class="line">{</span><br><span class="line"> public int TenantId { get; set; }</span><br><span class="line"></span><br><span class="line"> public string Name { get; set; }</span><br><span class="line"></span><br><span class="line"> //...other properties</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这种方式,ABP知道这是一个特定于租户的实体,并自动将租户的实体与其他租户隔离开来。</p><h2 id="IMayHaveTenant接口"><a href="#IMayHaveTenant接口" class="headerlink" title="IMayHaveTenant接口"></a>IMayHaveTenant接口</h2><p>我们可能需要在主机和租户之间共享一个实体类型。因此,一个实体可以由租户或主机拥有。IMayHaveTenant接口也定义了TenantId(类似于IMustHaveTenant),但是在本例中它是可空的。实现IMayHaveTenant的示例实体:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">public class Role : Entity, IMayHaveTenant</span><br><span class="line">{</span><br><span class="line"> public int? TenantId { get; set; }</span><br><span class="line"></span><br><span class="line"> public string RoleName { get; set; }</span><br><span class="line"></span><br><span class="line"> //...other properties</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>我们可以使用相同的角色类来存储主机角色和租户角色。在本例中,TenantId属性表示这是主机实体还是租户实体。空值意味着这是一个主机实体,非空值意味着这个实体由租户所有,而Id是TenantId。</p><h2 id="补充说明"><a href="#补充说明" class="headerlink" title="补充说明"></a>补充说明</h2><p>IMayHaveTenant并不像IMustHaveTenant一样常见。例如,产品类不能是IMayHaveTenant,因为产品与实际的应用程序功能相关,而与管理承租者无关。所以要小心使用IMayHaveTenant接口,因为维护主机和租户共享的代码比较困难。<br>当你定义一个实体类型为IMustHaveTenant或IMayHaveTenant时,要在你创建一个新的实体时设置TenantId(然而ABP试图从当前TenantId设置它,在某些情况下可能不可能,特别是对于IMayHaveTenant实体)。大多数情况下,这是你处理TenantId属性的唯一时刻。在编写LINQ时,不需要在条件中显式地编写TenantId过滤器,因为它是自动过滤的。</p><h2 id="在主机和租户之间切换"><a href="#在主机和租户之间切换" class="headerlink" title="在主机和租户之间切换"></a>在主机和租户之间切换</h2><p>在处理多租户应用程序数据库时,我们可以获得当前租户。默认情况下,它是从IAbpSession中获得的(如前所述)。我们可以更改此行为并切换到另一个租户的数据库。例子:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">public class ProductService : ITransientDependency</span><br><span class="line">{</span><br><span class="line"> private readonly IRepository<Product> _productRepository;</span><br><span class="line"> private readonly IUnitOfWorkManager _unitOfWorkManager;</span><br><span class="line"></span><br><span class="line"> public ProductService(IRepository<Product> productRepository, IUnitOfWorkManager unitOfWorkManager)</span><br><span class="line"> {</span><br><span class="line"> _productRepository = productRepository;</span><br><span class="line"> _unitOfWorkManager = unitOfWorkManager;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> [UnitOfWork]</span><br><span class="line"> public virtual List<Product> GetProducts(int tenantId)</span><br><span class="line"> {</span><br><span class="line"> using (_unitOfWorkManager.Current.SetTenantId(tenantId))</span><br><span class="line"> {</span><br><span class="line"> return _productRepository.GetAllList();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>SetTenantId确保我们处理的是给定租户的数据,独立于数据库架构:</p><ul><li>如果给定的租户有一个专用的数据库,它将切换到该数据库并从中获取产品。</li><li>如果给定的租户没有专用的数据库(例如,单一数据库方法),则添加自动TenantId筛选器来只查询该租户的产品。<br>如果我们不使用SetTenantId,它会从session获取tenantId。这里有一些指导方针和最佳实践:</li><li>使用SetTenantId(null)切换到主机。</li><li>如果没有特殊情况,请在using块中使用SetTenantId(如本例中所示)。通过这种方式,它会在using块的末尾自动恢复tenantId,并且调用GetProducts方法的代码与前面一样工作。</li><li>如果需要,可以在嵌套块中使用SetTenantId。</li><li>因为_unitOfWorkManager.Current仅在工作单元中可用,请确保您的代码在UOW中运行。</li></ul>]]></content>
<summary type="html">
<h2 id="什么是多租户"><a href="#什么是多租户" class="headerlink" title="什么是多租户"></a>什么是多租户</h2><p>软件多租户指的是一种软件架构,其中一个软件实例运行在服务器上,为多个租户服务。租户是一组用户,他们共享对软件
</summary>
<category term="ABP" scheme="https://www.smallapp.xyz/categories/ABP/"/>
<category term="ABP" scheme="https://www.smallapp.xyz/tags/ABP/"/>
</entry>
<entry>
<title>缓存</title>
<link href="https://www.smallapp.xyz/2020/03/21/2.3%E7%BC%93%E5%AD%98/"/>
<id>https://www.smallapp.xyz/2020/03/21/2.3%E7%BC%93%E5%AD%98/</id>
<published>2020-03-20T16:00:00.000Z</published>
<updated>2020-04-02T05:47:22.705Z</updated>
<content type="html"><![CDATA[<h2 id="说明"><a href="#说明" class="headerlink" title="说明"></a>说明</h2><p>ABP提供了缓存的抽象。它在内部使用这个缓存抽象。虽然默认实现使用了MemoryCache,但它可以被实现并与任何其他缓存提供程序交换。例如,Abp.RedisCache包使用Redis实现缓存(参见下面的“Redis缓存集成”一节)。</p><h2 id="ICacheManager"><a href="#ICacheManager" class="headerlink" title="ICacheManager"></a>ICacheManager</h2><p>缓存的主要接口是ICacheManager。我们可以注入它并使用它来获得缓存。例子:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">public class TestAppService : ApplicationService</span><br><span class="line">{</span><br><span class="line"> private readonly ICacheManager _cacheManager;</span><br><span class="line"></span><br><span class="line"> public TestAppService(ICacheManager cacheManager)</span><br><span class="line"> {</span><br><span class="line"> _cacheManager = cacheManager;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> public Item GetItem(int id)</span><br><span class="line"> {</span><br><span class="line"> //Try to get from cache</span><br><span class="line"> return _cacheManager</span><br><span class="line"> .GetCache("MyCache")</span><br><span class="line"> .Get(id.ToString(), () => GetFromDatabase(id)) as Item;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> public Item GetFromDatabase(int id)</span><br><span class="line"> {</span><br><span class="line"> //... retrieve item from database</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>在本例中,我们将注入ICacheManager并获得一个名为MyCache的缓存。缓存名是大小写敏感的,这意味着“MyCache”和“MyCache”是两个不同的缓存</p><h2 id="ICache"><a href="#ICache" class="headerlink" title="ICache"></a>ICache</h2><p>ICacheManager.GetCache方法返回一个ICache。缓存是单例的(每个缓存名)。它是在第一次请求时创建的,然后总是返回相同的缓存对象。通过这种方式,我们可以在不同的类(客户端)中使用相同的名称共享相同的缓存。</p><p>在示例代码中,我们看到了ICache的一个简单用法ICache.Get方法。它有两个参数:</p><ul><li>key: 缓存中一项的唯一键(字符串).</li><li>factory: 如果没有具有给定键的项,则调用该操作。工厂方法应该创建并返回实际的项目。如果给定的键存在于缓存中,则不调用它。</li></ul><p>ICache接口还有GetOrDefault、Set、Remove和Clear等方法。所有方法都有异步版本。</p><h2 id="ITypedCache"><a href="#ITypedCache" class="headerlink" title="ITypedCache"></a>ITypedCache</h2><p>ICache接口使用一个字符串作为键,一个对象作为值。ITypedCache是ICache的一个包装器,提供了一个类型安全的通用缓存。我们可以使用通用的GetCache扩展方法来获得一个ITypedCache:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ITypedCache<int, Item> myCache = _cacheManager.GetCache<int, Item>("MyCache");</span><br></pre></td></tr></table></figure><p>我们还可以使用AsTyped扩展方法将现有的ICache实例转换为ITypedCache。</p><h2 id="Configuration"><a href="#Configuration" class="headerlink" title="Configuration"></a>Configuration</h2><p>默认的缓存过期时间是60分钟。它在滑动,所以如果你不在缓存中使用一个项目60分钟,它会自动从缓存中删除。您可以为所有缓存或特定的缓存配置它。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">//Configuration for all caches</span><br><span class="line">Configuration.Caching.ConfigureAll(cache =></span><br><span class="line">{</span><br><span class="line"> cache.DefaultSlidingExpireTime = TimeSpan.FromHours(2);</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line">//Configuration for a specific cache</span><br><span class="line">Configuration.Caching.Configure("MyCache", cache =></span><br><span class="line">{</span><br><span class="line"> cache.DefaultSlidingExpireTime = TimeSpan.FromHours(8);</span><br><span class="line">});</span><br></pre></td></tr></table></figure><p>这段代码应该放在模块的PreInitialize方法中。使用此代码,“MyCache”将在8小时内过期,而所有其他缓存项将在2小时内过期。</p><p>一旦缓存首次创建(在第一次请求时),就会调用配置操作。配置不局限于DefaultSlidingExpireTime,因为缓存对象是一个ICacheOptions,您可以使用它的属性自由地配置和初始化它。</p><h2 id="Entity-Caching"><a href="#Entity-Caching" class="headerlink" title="Entity Caching"></a>Entity Caching</h2><p>虽然ABP的缓存系统是为一般用途。但如果你想缓存实体,有一个EntityCache基类,可以帮助你。如果我们通过实体的Id来获取实体,并且我们希望通过Id来缓存它们,那么我们可以使用这个基类,这样就不会重复查询数据库。假设我们有一个这样的Person实体:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">public class Person : Entity</span><br><span class="line">{</span><br><span class="line"> public string Name { get; set; }</span><br><span class="line"></span><br><span class="line"> public int Age { get; set; }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>假设当我们知道他们的Id,我们经常想要获得人名。首先,我们创建一个类来存储缓存项:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">[AutoMapFrom(typeof(Person))]</span><br><span class="line">public class PersonCacheItem</span><br><span class="line">{</span><br><span class="line"> public string Name { get; set; }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>不要直接在缓存中存储实体,因为缓存可能需要序列化缓存的对象。实体可能不会被序列化,特别是当它们具有导航属性时。这就是为什么我们定义了一个简单的(DTO)类来在缓存中存储数据。我们添加了AutoMapFrom属性,因为我们希望使用AutoMapper将Person实体自动转换为PersonCacheItem对象。如果我们不使用AutoMapper,我们应该覆盖EntityCache类的MapToCacheItem方法来手动转换/映射它。<br>虽然这不是必需的,我们可能想要为我们的缓存类定义一个接口:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">public interface IPersonCache : IEntityCache<PersonCacheItem></span><br><span class="line">{</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>最后,我们可以创建cache类来缓存Person实体:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">public class PersonCache : EntityCache<Person, PersonCacheItem>, IPersonCache, ITransientDependency</span><br><span class="line">{</span><br><span class="line"> public PersonCache(ICacheManager cacheManager, IRepository<Person> repository)</span><br><span class="line"> : base(cacheManager, repository)</span><br><span class="line"> {</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>就是这样。我们的人员缓存准备使用! 缓存类可以是瞬态的(如本例所示),也可以是单例的。这并不意味着缓存的数据是暂时的。它总是全局缓存,并在应用程序中以线程安全的方式访问。<br>无论何时我们需要一个人的名字,我们都可以通过使用这个人的Id从缓存中获得它。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">public class MyPersonService : ITransientDependency</span><br><span class="line">{</span><br><span class="line"> private readonly IPersonCache _personCache;</span><br><span class="line"></span><br><span class="line"> public MyPersonService(IPersonCache personCache)</span><br><span class="line"> {</span><br><span class="line"> _personCache = personCache;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> public string GetPersonNameById(int id)</span><br><span class="line"> {</span><br><span class="line"> return _personCache[id].Name; //alternative: _personCache.Get(id).Name;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>我们只需注入IPersonCache,获取缓存项,然后获取Name属性。</p><h2 id="How-EntityCache-Works"><a href="#How-EntityCache-Works" class="headerlink" title="How EntityCache Works"></a>How EntityCache Works</h2><ul><li>它在第一次调用时从存储库(数据库)获取实体。然后在后续调用中从缓存中获取。</li><li>如果更新或删除缓存的实体,它将自动使其无效。因此,它将在下一个调用中从数据库中检索。</li><li>它使用IObjectMapper将实体映射到缓存项。IObjectMapper是由AutoMapper模块实现的。如果您正在使用AutoMapper模块,则需要它。您可以覆盖MapToCacheItem方法来手动将实体映射到缓存项。</li><li>它使用cache类的FullName作为缓存名。您可以通过将缓存名传递给基本构造函数来更改它。</li><li>它是线程安全的。<br>如果需要更复杂的缓存需求,可以扩展EntityCache或创建自己的解决方案。</li></ul><h2 id="Multi-Tenancy-Entity-Caching"><a href="#Multi-Tenancy-Entity-Caching" class="headerlink" title="Multi-Tenancy Entity Caching"></a>Multi-Tenancy Entity Caching</h2><p>虽然EntityCache可以帮助您缓存实体,但它不是多租户安全的。例如,由承租者A检索和缓存的实体不应该被承租者b缓存。为了正确缓存多租户实体,我们引入了MustHaveTenantEntityCache和MayHaveTenantEntityCache,它们接受实现IMustHaveTenant或IMayHaveTenant接口的实体类<br>类似于实体缓存,我们可以有IMayHaveTenant实体和这样的缓存项:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">public class Phone : Entity, IMayHaveTenant</span><br><span class="line">{</span><br><span class="line"> public int? TenantId { get; set; }</span><br><span class="line"></span><br><span class="line"> public string Number { get; set; }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">[AutoMapFrom(typeof(Phone))]</span><br><span class="line">public class PhoneCacheItem</span><br><span class="line">{</span><br><span class="line"> public string Number { get; set; }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>与实体缓存类似,为缓存类定义一个接口是可选的:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">public interface IPhoneCache : IMultiTenancyEntityCache<PhoneCacheItem></span><br><span class="line">{</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>然后,创建缓存类来缓存Phone实体:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">public class PhoneCache : MayHaveTenantEntityCache<Phone, PhoneCacheItem>, IPhoneCache, ITransientDependency</span><br><span class="line">{</span><br><span class="line"> public PhoneCache(ICacheManager cacheManager, IUnitOfWorkManager unitOfWorkManager, IRepository<Phone> repository)</span><br><span class="line"> : base(cacheManager, unitOfWorkManager, repository)</span><br><span class="line"> {</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>现在我们可以在您的应用程序中以多租户安全的方式访问Phone实体缓存。它还具有EntityCache的所有优点,例如全局缓存,缓存类可以是瞬态/单态的。</p><h2 id="How-MustHaveTenantEntityCache-MayHaveTenantEntityCache-Works"><a href="#How-MustHaveTenantEntityCache-MayHaveTenantEntityCache-Works" class="headerlink" title="How MustHaveTenantEntityCache/MayHaveTenantEntityCache Works"></a>How MustHaveTenantEntityCache/MayHaveTenantEntityCache Works</h2><p>它的工作方式与EntityCache类似,但有一些区别。</p><ul><li>它在构造缓存键时使用TenantId。“{EntityId}@{TenantId}”。</li><li>这是多租户安全的。<br>如果需要更复杂的多租户缓存需求,可以扩展MultiTenancyEntityCache并添加自己的解决方案</li></ul><h2 id="Redis缓存集成"><a href="#Redis缓存集成" class="headerlink" title="Redis缓存集成"></a>Redis缓存集成</h2><p>默认的缓存管理器使用内存缓存。如果您有多个并发web服务器运行相同的应用程序,就会出现问题。在这种情况下,您可能需要一个分布式/中央缓存服务器。您可以轻松地使用Redis作为您的缓存服务器。<br>首先,您需要将Abp.RedisCache NuGet包安装到您的应用程序中(例如,您可以将它安装到您的Web项目中)。然后,您需要为AbpRedisCacheModule添加一个DependsOn属性,并在模块的PreInitialize方法中调用UseRedis扩展方法,如下:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">//...other namespaces</span><br><span class="line">using Abp.Runtime.Caching.Redis;</span><br><span class="line"></span><br><span class="line">namespace MyProject.AbpZeroTemplate.Web</span><br><span class="line">{</span><br><span class="line"> [DependsOn(</span><br><span class="line"> //...other module dependencies</span><br><span class="line"> typeof(AbpRedisCacheModule))]</span><br><span class="line"> public class MyProjectWebModule : AbpModule</span><br><span class="line"> {</span><br><span class="line"> public override void PreInitialize()</span><br><span class="line"> {</span><br><span class="line"> //...other configurations</span><br><span class="line"></span><br><span class="line"> Configuration.Caching.UseRedis();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> //...other code</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>Abp.RedisCache package 默认使用”localhost” 作为链接字符串.您可以向配置文件中添加一个连接字符串来覆盖它。例子:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><add name="Abp.Redis.Cache" connectionString="localhost"/></span><br></pre></td></tr></table></figure><p>此外,您还可以向appSettings添加一个设置来设置Redis的数据库id。例子:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><add key="Abp.Redis.Cache.DatabaseId" value="2"/></span><br></pre></td></tr></table></figure><p>在ASP.NET Core中, 您可以使用UseRedis的委托参数覆盖它。例子:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Configuration.Caching.UseRedis(options =></span><br><span class="line">{</span><br><span class="line"> options.ConnectionString = _appConfiguration["RedisCache:ConnectionString"];</span><br><span class="line"> options.DatabaseId = _appConfiguration.GetValue<int>("RedisCache:DatabaseId");</span><br><span class="line">});</span><br></pre></td></tr></table></figure><p>不同的数据库id对于在同一服务器中创建不同的键空间(隔离的缓存)很有用。</p><p>UseRedis方法还有一个重载,它采取一个动作来直接设置选项值(这个动作覆盖了配置文件中的值)。</p><p>有关Redis及其配置的更多信息,请参阅<a href="http://redis.io/documentation" target="_blank" rel="noopener">Redis文档</a>。</p><p>注意:应该安装并运行Redis服务器来使用ABP中的Redis缓存。</p>]]></content>
<summary type="html">
<h2 id="说明"><a href="#说明" class="headerlink" title="说明"></a>说明</h2><p>ABP提供了缓存的抽象。它在内部使用这个缓存抽象。虽然默认实现使用了MemoryCache,但它可以被实现并与任何其他缓存提供程序交换。例如
</summary>
<category term="ABP" scheme="https://www.smallapp.xyz/categories/ABP/"/>
<category term="ABP" scheme="https://www.smallapp.xyz/tags/ABP/"/>
</entry>
<entry>
<title>依赖注入</title>
<link href="https://www.smallapp.xyz/2020/03/21/2.1%E4%BE%9D%E8%B5%96%E6%B3%A8%E5%85%A5/"/>
<id>https://www.smallapp.xyz/2020/03/21/2.1%E4%BE%9D%E8%B5%96%E6%B3%A8%E5%85%A5/</id>
<published>2020-03-20T16:00:00.000Z</published>
<updated>2020-04-02T05:47:07.236Z</updated>
<content type="html"><![CDATA[<h2 id="什么是依赖注入"><a href="#什么是依赖注入" class="headerlink" title="什么是依赖注入"></a>什么是依赖注入</h2><p>如果您已经了解了依赖项注入、构造函数和属性注入模式的概念,您可以跳到下一节。</p><p>Wikipedia称:依赖项注入是一种软件设计模式,在这种模式中,一个或多个依赖项(或服务)被注入或通过引用传递到一个依赖对象(或客户端),并成为客户端状态的一部分。该模式将客户机依赖项的创建与它自己的行为分离开来,后者允许程序设计松散耦合,并遵循依赖项倒置和单一职责原则。它直接对比了服务定位器模式,该模式允许客户了解他们用来查找依赖项的系统。</p><p>如果不使用依赖项注入技术,就很难管理依赖项和开发模块化的、结构良好的应用程序。</p><h2 id="传统方式的问题"><a href="#传统方式的问题" class="headerlink" title="传统方式的问题"></a>传统方式的问题</h2><p>在应用程序中,类相互依赖。假设我们有一个应用程序服务,它使用存储库将实体插入到数据库中。在这种情况下,应用程序服务类依赖于存储库类。请看下面的例子:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">public class PersonAppService</span><br><span class="line">{</span><br><span class="line"> private IPersonRepository _personRepository;</span><br><span class="line"></span><br><span class="line"> public PersonAppService()</span><br><span class="line"> {</span><br><span class="line"> _personRepository = new PersonRepository(); </span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> public void CreatePerson(string name, int age)</span><br><span class="line"> {</span><br><span class="line"> var person = new Person { Name = name, Age = age };</span><br><span class="line"> _personRepository.Insert(person);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>PersonAppService使用PersonRepository将一个人插入到数据库中。虽然这看起来是无害的,但这段代码有一些问题:</p><ul><li>PersonAppService将IPersonRepository引用用于CreatePerson方法。该方法依赖于IPersonRepository接口,而不是PersonRepository具体类。但是,在构造函数中,PersonAppService依赖于PersonRepository而不是接口。组件应该依赖于接口而不是具体的实现。这就是所谓的依赖倒置原理。</li><li>如果PersonAppService本身创建了PersonRepository,它就会依赖于IPersonRepository接口的特定实现。这不能与其他实现一起工作。因此,将接口与实现分离变得毫无意义。硬依赖使代码库紧密耦合,从而忽略了可重用性。</li><li>将来我们可能需要更改PersonRepository的创建。假设我们想让它成为一个单例(单个共享实例,而不是为每个使用创建一个对象)。或者,我们可能希望创建多个实现IPersonRepository的类,并希望有条件地创建其中一个。在这种情况下,我们必须更改所有依赖于IPersonRepository的类。</li><li>有了这样的依赖,就很难(或者不可能)对PersonAppService进行单元测试。<br>为了克服这些问题,可以使用工厂模式。因此,对repository类的创建进行了抽象。参见下面的代码:<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">public class PersonAppService</span><br><span class="line">{</span><br><span class="line"> private IPersonRepository _personRepository;</span><br><span class="line"></span><br><span class="line"> public PersonAppService()</span><br><span class="line"> {</span><br><span class="line"> _personRepository = PersonRepositoryFactory.Create(); </span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> public void CreatePerson(string name, int age)</span><br><span class="line"> {</span><br><span class="line"> var person = new Person { Name = name, Age = age };</span><br><span class="line"> _personRepository.Insert(person);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>PersonRepositoryFactory是一个静态类,它创建并返回一个IPersonRepository。这称为服务定位器模式。创建问题得到了解决,因为PersonAppService不知道如何创建IPersonRepository的实现,而且它独立于PersonRepository实现。仍然存在一些问题:</li><li>此时,PersonAppService依赖于PersonRepositoryFactory。这是可以接受的,但是仍然存在硬依赖。</li><li>为每个存储库或每个依赖项编写工厂类/方法是冗长乏味的。</li><li>同样,测试也不容易,因为很难让PersonAppService使用IPersonRepository的模拟实现。</li></ul><h2 id="解决方案"><a href="#解决方案" class="headerlink" title="解决方案"></a>解决方案</h2><p>有一些最佳实践(模式)可以帮助我们依赖于其他类。</p><h3 id="构造函数注入模式"><a href="#构造函数注入模式" class="headerlink" title="构造函数注入模式"></a>构造函数注入模式</h3><p>上面的例子可以重写如下:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">public class PersonAppService</span><br><span class="line">{</span><br><span class="line"> private IPersonRepository _personRepository;</span><br><span class="line"></span><br><span class="line"> public PersonAppService(IPersonRepository personRepository)</span><br><span class="line"> {</span><br><span class="line"> _personRepository = personRepository;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> public void CreatePerson(string name, int age)</span><br><span class="line"> {</span><br><span class="line"> var person = new Person { Name = name, Age = age };</span><br><span class="line"> _personRepository.Insert(person);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这就是所谓的构造函数注入。PersonAppService不知道哪个类实现了IPersonRepository或者它是如何创建的。当需要PersonAppService时,我们首先创建一个IPersonRepository,并将其传递给PersonAppService的构造函数:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">var repository = new PersonRepository();</span><br><span class="line">var personService = new PersonAppService(repository);</span><br><span class="line">personService.CreatePerson("John Doe", 32);</span><br></pre></td></tr></table></figure><p>构造函数注入是使类独立于依赖对象创建的好方法,但是上面的代码有一些问题:</p><ul><li>创建一个PersonAppService变得更加困难。它有4个依赖项。我们必须创建这4个依赖对象,并将它们传递到PersonAppService的构造函数中。</li><li>从属类可能有其他依赖项(这里,PersonRepository有依赖项)。我们必须创建PersonAppService的所有依赖项,这些依赖项的所有依赖项等等。我们甚至可能无法创建单个对象,因为依赖关系图太复杂了!</li></ul><p>幸运的是,有<a href="https://aspnetboilerplate.com/Pages/Documents/Dependency-Injection#dIFrameworks" target="_blank" rel="noopener">依赖项注入框架</a>,可以自动管理依赖项。</p><h2 id="属性注入模式"><a href="#属性注入模式" class="headerlink" title="属性注入模式"></a>属性注入模式</h2><p>构造函数注入模式是提供类依赖项的好方法。通过这种方式,您不能在不提供依赖项的情况下创建类的实例。这也是显式声明类的需求的一种强有力的方式,这样它才能正常工作。<br>在某些情况下,这个类可能依赖于另一个类,但是没有它也可以工作。这通常适用于横切关注点,比如日志记录。一个类可以在没有日志记录的情况下工作,但是如果您为它提供了一个日志记录器,它也可以写日志。在这种情况下,可以将依赖项定义为公共属性,而不是在构造函数中获取它们。考虑一下我们如何在PersonAppService中写入日志。我们可以这样重写类:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">public class PersonAppService</span><br><span class="line">{</span><br><span class="line"> public ILogger Logger { get; set; }</span><br><span class="line"></span><br><span class="line"> private IPersonRepository _personRepository;</span><br><span class="line"></span><br><span class="line"> public PersonAppService(IPersonRepository personRepository)</span><br><span class="line"> {</span><br><span class="line"> _personRepository = personRepository;</span><br><span class="line"> Logger = NullLogger.Instance;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> public void CreatePerson(string name, int age)</span><br><span class="line"> {</span><br><span class="line"> Logger.Debug("Inserting a new person to database with name = " + name);</span><br><span class="line"> var person = new Person { Name = name, Age = age };</span><br><span class="line"> _personRepository.Insert(person);</span><br><span class="line"> Logger.Debug("Successfully inserted!");</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>NullLogger.Instance 是一个实现ILogger的单例对象,但它不做任何事情。它不写日志。它用空的方法体实现了ILogger。如果你在创建PersonAppService对象之后设置了Logger属性,PersonAppService就可以写日志了:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">var personService = new PersonAppService(new PersonRepository());</span><br><span class="line">personService.Logger = new Log4NetLogger();</span><br><span class="line">personService.CreatePerson("John Doe", 32);</span><br></pre></td></tr></table></figure><p>假设Log4NetLogger实现了ILogger,它使用Log4Net库写入日志,因此PersonAppService实际上可以写入日志。如果我们不设置日志记录器,它就不会写入日志。可以说ILogger是PersonAppService的一个可选的依赖项。<br>几乎所有依赖项注入框架都支持属性注入模式。</p><h2 id="依赖注入框架"><a href="#依赖注入框架" class="headerlink" title="依赖注入框架"></a>依赖注入框架</h2><p>有许多依赖项注入框架可以自动解决依赖项。他们可以递归地创建具有所有依赖项和依赖项的依赖项的对象。只需使用构造函数和属性注入模式编写类,DI框架将处理其余部分! 在一个好的应用程序中,您的类甚至独立于DI框架。在整个应用程序中,只有几行代码或类显式地与DI框架交互。</p><p>ASP。NET样本文件使用<a href="https://github.com/castleproject/Windsor/blob/master/docs/README.md" target="_blank" rel="noopener">Castle Windsor</a>框架进行依赖注入。它是最成熟的DI框架之一。还有许多其他框架,如Unity、Ninject、StructureMap和Autofac。<br>在依赖注入框架中,您首先将接口/类注册到依赖注入框架中,然后解析(创建)一个对象。在Castle Windsor,是这样的:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">var container = new WindsorContainer();</span><br><span class="line"></span><br><span class="line">container.Register(</span><br><span class="line"> Component.For<IPersonRepository>().ImplementedBy<PersonRepository>().LifestyleTransient(),</span><br><span class="line"> Component.For<IPersonAppService>().ImplementedBy<PersonAppService>().LifestyleTransient()</span><br><span class="line"> );</span><br><span class="line"></span><br><span class="line">var personService = container.Resolve<IPersonAppService>();</span><br><span class="line">personService.CreatePerson("John Doe", 32);</span><br></pre></td></tr></table></figure><p>首先,我们创建了WindsorContainer并使用它们的接口注册了PersonRepository和PersonAppService。然后,我们使用容器创建IPersonAppService。它用它的依赖项创建了具体的类PersonAppService,然后返回它。在这个简单的示例中,可能不清楚使用DI框架的优势是什么。但是,在实际的企业应用程序中有许多类和依赖项。依赖项的注册与对象的创建和使用是分离的,并且在应用程序启动期间只进行一次。<br>注意,我们还将对象的生命周期设置为transient。这意味着每当我们解析这些类型的对象时,都会创建一个新实例。有许多不同的生命周期,例如单例。</p><h2 id="ABP依赖注入基础架构"><a href="#ABP依赖注入基础架构" class="headerlink" title="ABP依赖注入基础架构"></a>ABP依赖注入基础架构</h2><p>ABP使得依赖注入框架的使用几乎是不可见的。它还通过遵循最佳实践和惯例帮助您编写应用程序。</p><h3 id="注册依赖"><a href="#注册依赖" class="headerlink" title="注册依赖"></a>注册依赖</h3><p>在ABP中,有不同的方法可以将你的类注册到依赖注入系统中。净样板。大多数情况下,常规注册就足够了</p><h3 id="常规注册"><a href="#常规注册" class="headerlink" title="常规注册"></a>常规注册</h3><p>ABP会根据约定自动注册所有存储库、域服务、应用程序服务、MVC控制器和Web API控制器。例如,您可能有一个IPersonAppService接口和一个实现它的PersonAppService类:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">public interface IPersonAppService : IApplicationService</span><br><span class="line">{</span><br><span class="line"> //...</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">public class PersonAppService : IPersonAppService</span><br><span class="line">{</span><br><span class="line"> //...</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>ABP自动注册它,因为它实现了IApplicationService接口(它只是一个空接口)。它被注册为transient,这意味着每次使用都要创建它。当您将IPersonAppService接口(使用构造函数注入)注入到类中时,PersonAppService对象将被创建并自动传递到构造函数中。</p><p><strong>命名约定</strong>(Naming conventions)非常重要。例如,您可以将PersonAppService的名称更改为MyPersonAppService或包含“PersonAppService”后缀的另一个名称。这将它注册到IPersonAppService,因为它有相同的后缀。但是,如果没有后缀,比如“PeopleService”,就不能为服务命名。如果这样做,它不会自动注册到IPersonAppService。相反,它是使用自注册(而不是接口)注册到DI框架的。在这种情况下,您可以手动注册它。<br>ABP可以按约定注册程序集。它很简单:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());</span><br></pre></td></tr></table></figure><p>Assembly.GetExecutingAssembly()获取对包含此代码的程序集的引用。您可以将其他程序集传递给RegisterAssemblyByConvention方法。这通常是在模块初始化时完成的。查看ABP的模块系统,以获取更多信息。</p><p>你可以通过实现IConventionalRegisterer接口,然后调用IocManager来编写你自己的常规注册类。在您的类中添加常规的alregisterer方法。您应该将其添加到模块的预初始化方法中。</p><h2 id="辅助接口"><a href="#辅助接口" class="headerlink" title="辅助接口"></a>辅助接口</h2><p>您可能希望注册一个不符合常规注册规则的特定类。ABP提供了<strong>ITransientDependency</strong>、<strong>IPerWebRequestDependency</strong>和<strong>ISingletonDependency</strong>接口作为快捷方式。例如:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">public interface IPersonManager</span><br><span class="line">{</span><br><span class="line"> //...</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">public class MyPersonManager : IPersonManager, ISingletonDependency</span><br><span class="line">{</span><br><span class="line"> //...</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>通过这种方式,您可以轻松地注册MyPersonManager。当您需要注入IPersonManager时,将使用MyPersonManager类。请注意,依赖项声明为单例。创建MyPersonManager的单个实例,并将相同的对象传递给所有需要的类。它在第一次使用时实例化,然后在应用程序的整个生命周期中使用。<br><strong>NOTE</strong>: <strong>IPerWebRequestDependency</strong>只能在web层使用。</p><h2 id="自定义-直接注册"><a href="#自定义-直接注册" class="headerlink" title="自定义/直接注册"></a>自定义/直接注册</h2><p>如果传统的注册方式不能满足您的需要,您可以使用IocManager或Castle Windsor来注册您的类和依赖项。</p><h3 id="Using-IocManager"><a href="#Using-IocManager" class="headerlink" title="Using IocManager"></a>Using IocManager</h3><p>你可以使用IocManager来注册依赖项(通常在你的模块定义类的PreInitialize方法中):</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">IocManager.Register<IMyService, MyService>(DependencyLifeStyle.Transient);</span><br></pre></td></tr></table></figure><p>使用Castle Windsor的API<br>您可以使用IIocManager.IocContainer属性来访问Castle Windsor容器并注册依赖项。例子:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">IocManager.IocContainer.Register(Classes.FromThisAssembly().BasedOn<IMySpecialInterface>().LifestylePerThread().WithServiceSelf());</span><br></pre></td></tr></table></figure><p>For more information, read <a href="https://github.com/castleproject/Home/blob/master/README.md" target="_blank" rel="noopener">Windsor’s documentation</a>.</p><h2 id="解决依赖关系"><a href="#解决依赖关系" class="headerlink" title="解决依赖关系"></a>解决依赖关系</h2><p>注册通知IOC(控制反转)容器(又称DI框架)有关您的类、它们的依赖项和生存期。在应用程序的某个地方,您需要使用IOC容器创建对象。ASP。NET提供了一些解决依赖项的选项。</p><h2 id="构造函数和属性注入"><a href="#构造函数和属性注入" class="headerlink" title="构造函数和属性注入"></a>构造函数和属性注入</h2><p>作为最佳实践,您应该使用构造函数和属性注入来获得类的依赖项。只要有可能,你就应该这样做。例子:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">public class PersonAppService</span><br><span class="line">{</span><br><span class="line"> public ILogger Logger { get; set; }</span><br><span class="line"></span><br><span class="line"> private IPersonRepository _personRepository;</span><br><span class="line"></span><br><span class="line"> public PersonAppService(IPersonRepository personRepository)</span><br><span class="line"> {</span><br><span class="line"> _personRepository = personRepository;</span><br><span class="line"> Logger = NullLogger.Instance;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> public void CreatePerson(string name, int age)</span><br><span class="line"> {</span><br><span class="line"> Logger.Debug("Inserting a new person to database with name = " + name);</span><br><span class="line"> var person = new Person { Name = name, Age = age };</span><br><span class="line"> _personRepository.Insert(person);</span><br><span class="line"> Logger.Debug("Successfully inserted!");</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>IPersonRepository从构造函数注入,ILogger注入一个公共属性。这样,您的代码将完全不知道依赖项注入系统。这是使用DI系统最合适的方式。</p><h2 id="IIocResolver-IIocManager-and-IScopedIocResolver"><a href="#IIocResolver-IIocManager-and-IScopedIocResolver" class="headerlink" title="IIocResolver, IIocManager and IScopedIocResolver"></a>IIocResolver, IIocManager and IScopedIocResolver</h2><p>您可能必须直接解析依赖项,而不是使用构造函数和属性注入。这应该尽可能避免,但也可能是不可能的。ABP提供了一些可以轻松注入和使用的服务。例子:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">public class MySampleClass : ITransientDependency</span><br><span class="line">{</span><br><span class="line"> private readonly IIocResolver _iocResolver;</span><br><span class="line"></span><br><span class="line"> public MySampleClass(IIocResolver iocResolver)</span><br><span class="line"> {</span><br><span class="line"> _iocResolver = iocResolver;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> public void DoIt()</span><br><span class="line"> {</span><br><span class="line"> //Resolving, using and releasing manually</span><br><span class="line"> var personService1 = _iocResolver.Resolve<PersonAppService>();</span><br><span class="line"> personService1.CreatePerson(new CreatePersonInput { Name = "John", Surname = "Doe" });</span><br><span class="line"> _iocResolver.Release(personService1);</span><br><span class="line"></span><br><span class="line"> //Resolving and using in a safe way</span><br><span class="line"> using (var personService2 = _iocResolver.ResolveAsDisposable<PersonAppService>())</span><br><span class="line"> {</span><br><span class="line"> personService2.Object.CreatePerson(new CreatePersonInput { Name = "John", Surname = "Doe" });</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>在应用程序的示例类中使用MySampleClass。它是构造注入的IIocResolver,并使用它来解析和释放对象。有一些解析方法的重载可以在需要时使用。发布方法用于发布组件(对象)。如果你手动解析一个对象,调用Release是很重要的。否则,您的应用程序可能存在内存泄漏。为了确保释放对象,尽可能使用ResolveAsDisposable(如上面的示例所示)。Release在using块的末尾被自动调用。<br>IIocResolver(和IIocManager)还具有CreateScope扩展方法(在app . dependency名称空间中定义)来安全地释放所有解析的依赖项。例子:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">using (var scope = _iocResolver.CreateScope())</span><br><span class="line">{</span><br><span class="line"> var simpleObj1 = scope.Resolve<SimpleService1>();</span><br><span class="line"> var simpleObj2 = scope.Resolve<SimpleService2>();</span><br><span class="line"> //...</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>在使用块结束时,所有解析的依赖项将自动删除。还可以使用IScopedIocResolver注入范围。您可以注入这个接口并解析依赖项。在释放类时,所有解析的依赖项都将被释放。使用这个仔细!如果你的类有一个很长的生命周期(假设它是一个单例),并且你解析了太多的对象,那么所有的对象都将保留在内存中,直到你的类被释放。<br>如果希望直接访问IOC容器(Castle Windsor)来解决依赖项,可以构造-注入IIocManager并使用IIocManager.IocContainer属性。如果您是在静态上下文中,或者不能注入IIocManager,最后的办法是使用单例对象IocManager。实例无处不在。但是,在这种情况下,您的代码不容易测试。</p><h2 id="额外内容"><a href="#额外内容" class="headerlink" title="额外内容"></a>额外内容</h2><h3 id="IShouldInitialize接口"><a href="#IShouldInitialize接口" class="headerlink" title="IShouldInitialize接口"></a>IShouldInitialize接口</h3><p>有些类在第一次使用之前需要初始化。IShouldInitialize有一个Initialize()方法。如果实现了它,那么在创建对象之后(在使用对象之前)会自动调用Initialize()方法。为了使用这个特性,您需要注入/解析对象。</p><h3 id="ASP-NET-MVC-amp-ASP-NET-Web-API-集成"><a href="#ASP-NET-MVC-amp-ASP-NET-Web-API-集成" class="headerlink" title="ASP.NET MVC & ASP.NET Web API 集成"></a>ASP.NET MVC & ASP.NET Web API 集成</h3><p>我们必须调用依赖项注入系统来解析依赖项图中的根对象。在一个ASP。它通常是一个控制器类。我们还可以在控制器中使用构造器和属性注入模式。当请求到达我们的应用程序时,将使用IOC容器创建控制器,并递归地解析所有依赖项。这是怎么发生的?这一切都是由ABP自动完成的,通过扩展 ASP.NET MVC的默认控制器工厂。ASP.NET Web API亦是如此。您不必担心创建和释放对象。</p><h3 id="ASP-NET-Core-集成"><a href="#ASP-NET-Core-集成" class="headerlink" title="ASP.NET Core 集成"></a>ASP.NET Core 集成</h3><p>ASP.NET Core已经有一个内置的依赖注入系统,带有Microsoft.Extensions.DependencyInjection包。ABP 使用 Castle.Windsor.MsDependencyInjection 包来集成它的依赖注入系统和 ASP.NET Core 的,所以你不需要考虑它。</p><h3 id="最后指出"><a href="#最后指出" class="headerlink" title="最后指出"></a>最后指出</h3><p>只要您遵循规则并使用上面的结构,ABP就可以简化和自动化依赖项注入。大多数时候你不需要更多。如果您确实需要更多,您可以直接使用Castle Windsor的原始功能来执行许多任务,比如自定义注册、注入挂钩、拦截器等等。</p>]]></content>
<summary type="html">
<h2 id="什么是依赖注入"><a href="#什么是依赖注入" class="headerlink" title="什么是依赖注入"></a>什么是依赖注入</h2><p>如果您已经了解了依赖项注入、构造函数和属性注入模式的概念,您可以跳到下一节。</p>
<p>Wiki
</summary>
<category term="ABP" scheme="https://www.smallapp.xyz/categories/ABP/"/>
<category term="ABP" scheme="https://www.smallapp.xyz/tags/ABP/"/>
</entry>
<entry>
<title>调试</title>
<link href="https://www.smallapp.xyz/2020/03/21/1.7%E8%B0%83%E8%AF%95/"/>
<id>https://www.smallapp.xyz/2020/03/21/1.7%E8%B0%83%E8%AF%95/</id>
<published>2020-03-20T16:00:00.000Z</published>
<updated>2020-04-02T05:47:02.745Z</updated>
<content type="html"><![CDATA[<p>虽然通常不需要这样做,但是在调试项目时,您可能希望进入ABP的源代码。<br>所有官方的ABP NuGet包是Sourcelink启用。这意味着您可以轻松地调试项目中的Abp.* NuGet包。要启用它,请更改Visual Studio(2017+)调试选项如下:<br><img src="https://raw.githubusercontent.com/aspnetboilerplate/aspnetboilerplate/master/doc/WebSite/images/enable-sourcelink.png" alt="调试"></p><p>一旦启用了它,就可以进入(F11) ABP源代码。</p>]]></content>
<summary type="html">
<p>虽然通常不需要这样做,但是在调试项目时,您可能希望进入ABP的源代码。<br>所有官方的ABP NuGet包是Sourcelink启用。这意味着您可以轻松地调试项目中的Abp.* NuGet包。要启用它,请更改Visual Studio(2017+)调试选项如下:<br><
</summary>
<category term="ABP" scheme="https://www.smallapp.xyz/categories/ABP/"/>
<category term="ABP" scheme="https://www.smallapp.xyz/tags/ABP/"/>
</entry>
<entry>
<title>OWIN集成</title>
<link href="https://www.smallapp.xyz/2020/03/21/1.6owin%E9%9B%86%E6%88%90/"/>
<id>https://www.smallapp.xyz/2020/03/21/1.6owin%E9%9B%86%E6%88%90/</id>
<published>2020-03-20T16:00:00.000Z</published>
<updated>2020-04-02T05:46:57.585Z</updated>
<content type="html"><![CDATA[<p>如果你同时使用ASP.NET MVC和ASP.NET Web API在您的应用程序中,您需要将Abp.Owin NuGet包添加到您的项目中。</p><h2 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h2><p>将Abp.Owin NuGet包添加到您的主机项目(通常是Web项目)。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Install-Package Abp.Owin</span><br></pre></td></tr></table></figure><h2 id="用法"><a href="#用法" class="headerlink" title="用法"></a>用法</h2><p>然后在你的OWIN启动文件中调用UseAbp()扩展方法,如下图所示:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">[assembly: OwinStartup(typeof(Startup))]</span><br><span class="line">public class Startup</span><br><span class="line">{</span><br><span class="line"> public void Configuration(IAppBuilder app)</span><br><span class="line"> {</span><br><span class="line"> app.UseAbp();</span><br><span class="line"></span><br><span class="line"> //your other configuration...</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>如果您只使用OWIN(例如,在一个自托管的Web API项目中),那么您可以使用UseAbp的覆盖,它使用一个启动模块来初始化ABP框架。注意,只有在ABP没有以另一种方式初始化的情况下才应该这样做。</p>]]></content>
<summary type="html">
<p>如果你同时使用ASP.NET MVC和ASP.NET Web API在您的应用程序中,您需要将Abp.Owin NuGet包添加到您的项目中。</p>
<h2 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安
</summary>
<category term="ABP" scheme="https://www.smallapp.xyz/categories/ABP/"/>
<category term="ABP" scheme="https://www.smallapp.xyz/tags/ABP/"/>
</entry>
</feed>