<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>ZRainy</title>
  
  
  <link href="/atom.xml" rel="self"/>
  
  <link href="http://yoursite.com/"/>
  <updated>2020-07-01T16:15:51.895Z</updated>
  <id>http://yoursite.com/</id>
  
  <author>
    <name>ZRainy</name>
    
  </author>
  
  <generator uri="http://hexo.io/">Hexo</generator>
  
  <entry>
    <title>TARS学习笔记（二）</title>
    <link href="http://yoursite.com/2020/07/02/TARS%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%88%E4%BA%8C%EF%BC%89/"/>
    <id>http://yoursite.com/2020/07/02/TARS学习笔记（二）/</id>
    <published>2020-07-01T16:15:20.000Z</published>
    <updated>2020-07-01T16:15:51.895Z</updated>
    
    <content type="html"><![CDATA[<h1 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h1><p>一直说Tars是使用epoll模型的，而且之前校招面试的时候也老会被问到epoll，所以这次打算先把epoll看一下，看看tars是怎么做epoll的，但由于对网络编程没有什么了解，所以会先看一些基础的其他类。</p><p>在网上找了一个系列博客，感觉还挺多的，可以看看。</p><p><a href="https://blog.csdn.net/stpeace/category_7554860.html" target="_blank" rel="noopener">https://blog.csdn.net/stpeace/category_7554860.html</a></p><p>大概会照着他这个目录看一看。</p><p>他的目录中第二篇看的是一个<code>tc_loki.h</code>，但我看了下和epoll暂时没有什么关系，所以先跳过这个文件，从<code>tc_commom.h</code>开始看。</p><a id="more"></a><h2 id="tc-commom"><a href="#tc-commom" class="headerlink" title="tc_commom"></a>tc_commom</h2><p>这个文件是基础工具类，主要是tars提供的一些common函数，能够在开发中直接使用的，能节省很多时间，都是一些有用的小函数，而且都是static的，可以直接用，工作中使用过很多。</p><p>大致扫了一眼头文件，发现原来提供了这么多基础函数啊，以后类似在C++中遇到分割字符串等基础工作再也不用手动造轮子了，用这里面的基础函数既省事也放心，函数类型大致可以分为以下几类：</p><ul><li>sleep函数</li><li>浮点数比较</li><li>字符串相关操作</li><li>时间相关</li><li>数值和字符串或者时间转换</li><li>其他</li></ul><p>针对其中一些函数，还使用了模板特化</p><h2 id="tc-exception"><a href="#tc-exception" class="headerlink" title="tc_exception"></a>tc_exception</h2><p>tars中的异常类，主要包装了一个buffer和一个错误码code，并且针对不同平台做了一些兼容处理。</p><h2 id="tc-socket"><a href="#tc-socket" class="headerlink" title="tc_socket"></a>tc_socket</h2><p>封装了socket编程，看源码里注释都很清晰了，这里挑几个函数看一看。<br><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></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * 这里面用到了几个没见过的值，简单说明一下</span></span><br><span class="line"><span class="comment"> * SOCK_STREAM表示基于TCP，SOCK_DGRAM则是基于UDP，表示tars是支持这两种协议的，而且默认是SOCK_STREAM</span></span><br><span class="line"><span class="comment"> * iDomain的默认值是AF_INET，查了下就理解成基于ipv4的地址就行，就是我们常用的那种host:port</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="keyword">void</span> TC_Socket::createSocket(<span class="keyword">int</span> iSocketType, <span class="keyword">int</span> iDomain)</span><br><span class="line">&#123;</span><br><span class="line">    assert(iSocketType == SOCK_STREAM || iSocketType == SOCK_DGRAM);</span><br><span class="line">    close();</span><br><span class="line"></span><br><span class="line">    _iDomain    = iDomain;</span><br><span class="line">    _sock       = socket(iDomain, iSocketType, <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span>(_sock &lt; <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        _sock = INVALID_SOCKET;</span><br><span class="line">        THROW_EXCEPTION_SYSCODE(TC_Socket_Exception, <span class="string">"[TC_Socket::createSocket] create socket error"</span>);</span><br><span class="line">        <span class="comment">// throw TC_Socket_Exception("[TC_Socket::createSocket] create socket error! :" + string(strerror(errno)));</span></span><br><span class="line">    &#125; </span><br><span class="line"><span class="keyword">else</span> </span><br><span class="line">&#123;</span><br><span class="line">        ignoreSigPipe();<span class="comment">//这个是用来忽视什么信号的，系列2里有</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p><p>对socket编程完全不了解呀，看下来云里雾里，但感觉就是把socket抽象封装了一层，以后再看。</p><h2 id="tc-epoll"><a href="#tc-epoll" class="headerlink" title="tc_epoll"></a>tc_epoll</h2><p>epoll操作封装类。</p><p>首先有一个平平无奇的TC_Epoller_Exception类。</p><p>TC_Epoller默认采用了ET方式触发，epoll初始化不是线程安全的，需要在一开始全局设置一下。</p><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></pre></td><td class="code"><pre><span class="line"><span class="comment">//创建epoll，可以看到这个size其实最终并没有赋值给_max_connections，</span></span><br><span class="line"><span class="comment">//这里和博文里的代码不一样，想必是tars源码做过改动，size要大于零</span></span><br><span class="line"><span class="keyword">void</span> TC_Epoller::create(<span class="keyword">int</span> size)</span><br><span class="line">&#123;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> TARGET_PLATFORM_IOS</span></span><br><span class="line">    _iEpollfd = kqueue();</span><br><span class="line"><span class="meta">#<span class="meta-keyword">else</span></span></span><br><span class="line">_iEpollfd = epoll_create(size);</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line">    <span class="keyword">if</span> (<span class="literal">nullptr</span> != _pevs)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">delete</span>[] _pevs;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    _max_connections = <span class="number">1024</span>;</span><br><span class="line"></span><br><span class="line">    _pevs = <span class="keyword">new</span> epoll_event[_max_connections];</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//这个方法再往底层都加了锁，不管是add、mod还是del</span></span><br><span class="line"><span class="keyword">void</span> TC_Epoller::ctrl(SOCKET_TYPE fd, <span class="keyword">uint64_t</span> data, <span class="keyword">uint32_t</span> events, <span class="keyword">int</span> op)</span><br><span class="line">&#123;</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">epoll_event</span> <span class="title">ev</span>;</span></span><br><span class="line">ev.data.u64 = data;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> TARGET_PLATFORM_WINDOWS</span></span><br><span class="line">ev.events = events;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">else</span></span></span><br><span class="line">    ev.events   = events | EPOLLET;<span class="comment">//可以看到linux下默认都会加上ET的，所以默认是ET模式</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"></span><br><span class="line">epoll_ctl(_iEpollfd, op, fd, &amp;ev);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="tc-autoptr-h"><a href="#tc-autoptr-h" class="headerlink" title="tc_autoptr.h"></a>tc_autoptr.h</h2><p>这是tars里自己实现的自动指针类，底层利用atomic实现了引用计数，所有需要智能指针的类都需要从TC_HandleBase类继承。</p><p>除了atomic引用计数外，该类还有一个表示是否删除的标志位，看起来是为了防止del多次。<br><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">UTIL_DLL_API</span> <span class="title">TC_HandleBase</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * @brief 复制.</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * @return TC_HandleBase&amp;</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    TC_HandleBase&amp; <span class="keyword">operator</span>=(<span class="keyword">const</span> TC_HandleBase&amp;)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span> *<span class="keyword">this</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * @brief 增加计数</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">incRef</span><span class="params">()</span> </span>&#123; ++_atomic; &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * @brief 减少计数, 当计数==0时, 且需要删除数据时, 释放对象</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">decRef</span><span class="params">()</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>((--_atomic) == <span class="number">0</span> &amp;&amp; !_bNoDelete)</span><br><span class="line">        &#123;</span><br><span class="line">            _bNoDelete = <span class="literal">true</span>;</span><br><span class="line">            <span class="keyword">delete</span> <span class="keyword">this</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * @brief 获取计数.</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * @return int 计数值</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">getRef</span><span class="params">()</span> <span class="keyword">const</span>        </span>&#123; <span class="keyword">return</span> _atomic; &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief 设置不自动释放. </span></span><br><span class="line"><span class="comment"> *  </span></span><br><span class="line"><span class="comment">     * @param b 是否自动删除,true or false</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">setNoDelete</span><span class="params">(<span class="keyword">bool</span> b)</span>  </span>&#123; _bNoDelete = b; &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * @brief 构造函数</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    TC_HandleBase() : _atomic(<span class="number">0</span>), _bNoDelete(<span class="literal">false</span>)</span><br><span class="line">    &#123;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * @brief 拷贝构造</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    TC_HandleBase(<span class="keyword">const</span> TC_HandleBase&amp;) : _atomic(<span class="number">0</span>), _bNoDelete(<span class="literal">false</span>)</span><br><span class="line">    &#123;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * @brief 析够</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">virtual</span> ~TC_HandleBase()</span><br><span class="line">    &#123;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 计数</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="built_in">std</span>::atomic&lt;<span class="keyword">int</span>&gt;  _atomic;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 是否自动删除</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">bool</span>        _bNoDelete;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></p><p>接下来是一个智能指针模板类<code>TC_AutoPtr</code>，方法没什么好说的，只是要注意模板参数T必须继承于<code>TC_HandleBase</code>。</p><p>还有个要注意点的点是这些智能指针类之间的等于、不等于、小于比较全都是直接比较指针本身，而不是比较指针指向的值。</p><h2 id="tc-config"><a href="#tc-config" class="headerlink" title="tc_config"></a>tc_config</h2><p>配置文件读取类。</p><p>配置文件能实现配置参数和代码逻辑的分离，如果需要修改配置参数，仅仅修改配置即可。</p><p>配置文件说白了，就是把数据从外存导到内存来使用（我觉得这个理解挺好的）。</p><p>tars的配置文件在我使用过程中就是类似于读取<code>/a/b/c&lt;d&gt;</code>这种格式，就能从第一层a开始取到最后一层d所指的数据，对应下面这种格式的配置文件：<br><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">&lt;a&gt;</span><br><span class="line">    &lt;b&gt;</span><br><span class="line">        &lt;c&gt;</span><br><span class="line">            d=hello</span><br><span class="line">        &lt;/c&gt;</span><br><span class="line">    &lt;/b&gt;</span><br><span class="line">&lt;/a&gt;</span><br></pre></td></tr></table></figure></p><p>tars的配置文件就长这样，所以这个tc_config类主要就是用来解析这种格式的文件，知道了作用，接下来开始看源码。</p><p>Tars读取配置文件是线程安全的，将整个配置文件分为了域和参数两部分，其中kv键值对的k是参数，而&lt;&gt;表示的是域，用以下宏定义的字符来分割。<br><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></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">* 域分隔符</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="keyword">const</span> <span class="keyword">char</span> TC_CONFIG_DOMAIN_SEP = <span class="string">'/'</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">* 参数开始符</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="keyword">const</span> <span class="keyword">char</span> TC_CONFIG_PARAM_BEGIN = <span class="string">'&lt;'</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">* 参数结束符</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="keyword">const</span> <span class="keyword">char</span> TC_CONFIG_PARAM_END = <span class="string">'&gt;'</span>;</span><br></pre></td></tr></table></figure></p><p>有几个类：</p><ol><li>定义了两个异常类</li><li>TC_ConfigDomain类，定义配置文件中域的类。上层的TC_Config类就包含一个 TC_ConfigDomain类的成员变量，域类里会有子域，感觉实现上面像个广度优先的树，TC_Config类就是root节点。这种用树的结构来实现的例子也要记住。</li></ol><p>看几个函数吧：<br><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></pre></td><td class="code"><pre><span class="line">    <span class="comment">//tc_config.h</span></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * @brief 解析一个domain </span></span><br><span class="line"><span class="comment">     * 对形如"/Main/Domain&lt;Name&gt;"的path进行解析，解析的结果为一个 </span></span><br><span class="line"><span class="comment">     * DomainPath 类型，包括路径_domains和路径中对应的配置项_param.</span></span><br><span class="line"><span class="comment">     *  </span></span><br><span class="line"><span class="comment">     * @param path       一个经过处理的字符串，必须符合一定的要求</span></span><br><span class="line"><span class="comment">     * @param bWithParam "/Main/Domain&lt;Name&gt;"时bWithParam为ture </span></span><br><span class="line"><span class="comment">     *                   "/Main/Domain"时bWithParam为false</span></span><br><span class="line"><span class="comment">     * @return DomainPath 一个DomainPath对象，解析出域中的域名和参数</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">static</span> DomainPath <span class="title">parseDomainName</span><span class="params">(<span class="keyword">const</span> <span class="built_in">string</span>&amp; path, <span class="keyword">bool</span> bWithParam)</span></span>;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//定义</span></span><br><span class="line">    <span class="comment">//tc_config.cpp</span></span><br><span class="line">    TC_ConfigDomain::DomainPath TC_ConfigDomain::parseDomainName(<span class="keyword">const</span> <span class="built_in">string</span>&amp; path, <span class="keyword">bool</span> bWithParam)</span><br><span class="line">&#123;</span><br><span class="line">    TC_ConfigDomain::DomainPath dp;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span>(bWithParam)</span><br><span class="line">    &#123;</span><br><span class="line">    <span class="built_in">string</span>::size_type pos1 = path.find_first_of(TC_CONFIG_PARAM_BEGIN);</span><br><span class="line">    <span class="keyword">if</span>(pos1 == <span class="built_in">string</span>::npos)</span><br><span class="line">    &#123;</span><br><span class="line">    <span class="keyword">throw</span> TC_Config_Exception(<span class="string">"[TC_Config::parseDomainName] : param path '"</span> + path + <span class="string">"' is invalid!"</span> );</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span>(path[<span class="number">0</span>] != TC_CONFIG_DOMAIN_SEP)</span><br><span class="line">    &#123;</span><br><span class="line">    <span class="keyword">throw</span> TC_Config_Exception(<span class="string">"[TC_Config::parseDomainName] : param path '"</span> + path + <span class="string">"' must start with '/'!"</span> );</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">string</span>::size_type pos2 = path.find_first_of(TC_CONFIG_PARAM_END);</span><br><span class="line">    <span class="keyword">if</span>(pos2 == <span class="built_in">string</span>::npos)</span><br><span class="line">    &#123;</span><br><span class="line">    <span class="keyword">throw</span> TC_Config_Exception(<span class="string">"[TC_Config::parseDomainName] : param path '"</span> + path + <span class="string">"' is invalid!"</span> );</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">        dp._domains = TC_Common::sepstr&lt;<span class="built_in">string</span>&gt;(path.substr(<span class="number">1</span>, pos1<span class="number">-1</span>), TC_Common::tostr(TC_CONFIG_DOMAIN_SEP));</span><br><span class="line">dp._param = path.substr(pos1 + <span class="number">1</span>, pos2 - pos1 - <span class="number">1</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">    &#123;</span><br><span class="line"><span class="comment">//    if(path.length() &lt;= 1 || path[0] != TC_CONFIG_DOMAIN_SEP)</span></span><br><span class="line">        <span class="keyword">if</span>(path[<span class="number">0</span>] != TC_CONFIG_DOMAIN_SEP)</span><br><span class="line">    &#123;</span><br><span class="line">    <span class="keyword">throw</span> TC_Config_Exception(<span class="string">"[TC_Config::parseDomainName] : param path '"</span> + path + <span class="string">"' must start with '/'!"</span> );</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">        dp._domains = TC_Common::sepstr&lt;<span class="built_in">string</span>&gt;(path.substr(<span class="number">1</span>), TC_Common::tostr(TC_CONFIG_DOMAIN_SEP));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> dp;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//之所以要看这个方法，是因为我想了一下，</span></span><br><span class="line"><span class="comment">//这个简答的字符串处理如果换成是我来写，那我肯定是for循环来处理了，</span></span><br><span class="line"><span class="comment">//所以看到这个实现的时候有种恍然大悟的感觉，啥叫优雅的写法，这就是呀……</span></span><br><span class="line"><span class="comment">//但是在setParamValue方法里不知道为啥就用了for循环，感觉代码不是一个人写的呀。</span></span><br></pre></td></tr></table></figure></p><p>递归搜索子域的方法<code>getSubTcConfigDomain</code>怎么感觉没明白呢？它搜了个寂寞？既然是搜索，但参数里没有个要搜索的目标啊，就给了两个迭代器？好奇怪。后需要再看下。</p><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></pre></td><td class="code"><pre><span class="line"><span class="comment">//20200701联合tc_config::operator[]再看，感觉理解了一些，</span></span><br><span class="line"><span class="comment">//TC_ConfigDomain::getSubTcConfigDomain这个方法搜的其实并不是别的，就是`itEnd`对应的*TC_ConfigDomain</span></span><br><span class="line"><span class="keyword">const</span> TC_ConfigDomain *TC_ConfigDomain::getSubTcConfigDomain(<span class="built_in">vector</span>&lt;<span class="built_in">string</span>&gt;::const_iterator itBegin, <span class="built_in">vector</span>&lt;<span class="built_in">string</span>&gt;::const_iterator itEnd) <span class="keyword">const</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="comment">//递归结束条件，我是理解了上面注释里说的这个方法所要搜索的就是iEnd对应的域之后才看明白了这个递归条件</span></span><br><span class="line">    <span class="comment">//但其实我感觉看到递归条件就应该明白要搜索的是啥了，还是太菜了，没看懂一开始。</span></span><br><span class="line">    <span class="keyword">if</span>(itBegin == itEnd)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">map</span>&lt;<span class="built_in">string</span>, TC_ConfigDomain*&gt;::const_iterator it = _subdomain.find(*itBegin);</span><br><span class="line"></span><br><span class="line"><span class="comment">//根据匹配规则找不到匹配的子域</span></span><br><span class="line"><span class="keyword">if</span>(it == _subdomain.end())</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//继续在子域下搜索</span></span><br><span class="line"><span class="keyword">return</span> it-&gt;second-&gt;getSubTcConfigDomain(itBegin + <span class="number">1</span>, itEnd);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>tars的配置里配置项如果没写<code>=</code>，看起来是会把整行当做一个key，然后对应值是空。</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><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></pre></td><td class="code"><pre><span class="line">    /**</span><br><span class="line">    * @brief 转换成配置文件的字符串格式. </span><br><span class="line">    *  </span><br><span class="line">    * @param i  tab的层数</span><br><span class="line">    * @return   string类型配置字符串</span><br><span class="line">    */</span><br><span class="line">    string tostr(int i) const;</span><br><span class="line">    </span><br><span class="line">    //该方法将整个类转换成配置文件格式的字符串输出，同样适用了递归方法，好好看，好好学</span><br><span class="line">    string TC_ConfigDomain::tostr(int i) const</span><br><span class="line">&#123;</span><br><span class="line">    string sTab;</span><br><span class="line">    for(int k = 0; k &lt; i; ++k)</span><br><span class="line">    &#123;</span><br><span class="line">        sTab += &quot;  &quot;;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    ostringstream buf;</span><br><span class="line"></span><br><span class="line">    buf &lt;&lt; sTab &lt;&lt; &quot;&lt;&quot; &lt;&lt; reverse_parse(_name) &lt;&lt; &quot;&gt;&quot; &lt;&lt; endl;;</span><br><span class="line"></span><br><span class="line">    for(size_t n = 0; n &lt; _key.size(); n++)</span><br><span class="line">    &#123;</span><br><span class="line">        map&lt;string, string&gt;::const_iterator it = _param.find(_key[n]);</span><br><span class="line"></span><br><span class="line">        assert(it != _param.end());</span><br><span class="line"></span><br><span class="line">        //值为空, 则不打印出=</span><br><span class="line">        if(it-&gt;second.empty())</span><br><span class="line">        &#123;</span><br><span class="line">            buf &lt;&lt; &quot;  &quot; &lt;&lt; sTab &lt;&lt; reverse_parse(_key[n]) &lt;&lt; endl;</span><br><span class="line">        &#125;</span><br><span class="line">        else</span><br><span class="line">        &#123;</span><br><span class="line">            buf &lt;&lt; &quot;  &quot; &lt;&lt; sTab &lt;&lt; reverse_parse(_key[n]) &lt;&lt; &quot;=&quot; &lt;&lt; reverse_parse(it-&gt;second) &lt;&lt; endl;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    ++i;</span><br><span class="line"></span><br><span class="line">    for(size_t n = 0; n &lt; _domain.size(); n++)</span><br><span class="line">    &#123;</span><br><span class="line">        map&lt;string, TC_ConfigDomain*&gt;::const_iterator itm = _subdomain.find(_domain[n]);</span><br><span class="line"></span><br><span class="line">        assert(itm != _subdomain.end());</span><br><span class="line"></span><br><span class="line">        buf &lt;&lt; itm-&gt;second-&gt;tostr(i);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">buf &lt;&lt; sTab &lt;&lt; &quot;&lt;/&quot; &lt;&lt; reverse_parse(_name) &lt;&lt; &quot;&gt;&quot; &lt;&lt; endl;</span><br><span class="line"></span><br><span class="line">return buf.str();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>tc_config的operator[]方法：<br><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></pre></td><td class="code"><pre><span class="line"><span class="built_in">string</span> TC_Config::<span class="keyword">operator</span>[](<span class="keyword">const</span> <span class="built_in">string</span> &amp;path) <span class="keyword">const</span></span><br><span class="line">&#123;</span><br><span class="line">    TC_ConfigDomain::DomainPath dp = TC_ConfigDomain::parseDomainName(path, <span class="literal">true</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">//这里所搜索的域其实就是dp._domains的最后一个元素对应的域</span></span><br><span class="line">    <span class="comment">//和上面的getSubTcConfigDomain结合起来看更好理解</span></span><br><span class="line"><span class="keyword">const</span> TC_ConfigDomain *pTcConfigDomain = searchTcConfigDomain(dp._domains);</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>(pTcConfigDomain == <span class="literal">NULL</span>)</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">throw</span> TC_ConfigNoParam_Exception(<span class="string">"[TC_Config::operator[]] path '"</span> + path + <span class="string">"' not exits!"</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> pTcConfigDomain-&gt;getParamValue(dp._param);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p><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="comment">/**</span></span><br><span class="line"><span class="comment">     * @brief 合并配置文件到当前配置文件. </span></span><br><span class="line"><span class="comment">     *  </span></span><br><span class="line"><span class="comment">     * @param cf</span></span><br><span class="line"><span class="comment">     * @param bUpdate true-冲突项更新本配置, false-冲突项不更新</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">joinConfig</span><span class="params">(<span class="keyword">const</span> TC_Config &amp;cf, <span class="keyword">bool</span> bUpdate)</span></span>;</span><br><span class="line">    </span><br><span class="line">    </span><br><span class="line">    <span class="comment">//上述方法内部实现调用了parse方法，parse方法里会把字符串解析成配置</span></span><br><span class="line">    <span class="comment">//parse核心代码，主要靠一个栈实现，这种字符串解析代码看上去还是很优雅呀：</span></span><br><span class="line">    <span class="keyword">void</span> TC_Config::parse(istream &amp;is)</span><br><span class="line">&#123;</span><br><span class="line">    _root.destroy();</span><br><span class="line"></span><br><span class="line">    <span class="built_in">stack</span>&lt;TC_ConfigDomain*&gt; stkTcCnfDomain;</span><br><span class="line">    stkTcCnfDomain.push(&amp;_root);</span><br><span class="line"></span><br><span class="line">    <span class="built_in">string</span> line;</span><br><span class="line">    <span class="keyword">while</span>(getline(is, line))</span><br><span class="line">&#123;</span><br><span class="line">line = TC_Common::trim(line, <span class="string">" \r\n\t"</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>(line.length() == <span class="number">0</span>)</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">continue</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>(line[<span class="number">0</span>] == <span class="string">'#'</span>)<span class="comment">//以#开头的是注释，忽略</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">continue</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span>(line[<span class="number">0</span>] == <span class="string">'&lt;'</span>)</span><br><span class="line">&#123;</span><br><span class="line"><span class="built_in">string</span>::size_type posl = line.find_first_of(<span class="string">'&gt;'</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>(posl == <span class="built_in">string</span>::npos)</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">throw</span> TC_Config_Exception(<span class="string">"[TC_Config::parse]:parse error! line : "</span> + line);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>(line[<span class="number">1</span>] == <span class="string">'/'</span>)</span><br><span class="line">&#123;</span><br><span class="line"><span class="function"><span class="built_in">string</span> <span class="title">sName</span><span class="params">(line.substr(<span class="number">2</span>, (posl - <span class="number">2</span>)))</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>(stkTcCnfDomain.size() &lt;= <span class="number">0</span>)</span><br><span class="line">                &#123;</span><br><span class="line">                    <span class="keyword">throw</span> TC_Config_Exception(<span class="string">"[TC_Config::parse]:parse error! &lt;"</span> + sName + <span class="string">"&gt; hasn't matched domain."</span>);</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">if</span>(stkTcCnfDomain.top()-&gt;getName() != sName)</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">throw</span> TC_Config_Exception(<span class="string">"[TC_Config::parse]:parse error! &lt;"</span> + stkTcCnfDomain.top()-&gt;getName() + <span class="string">"&gt; hasn't match &lt;"</span> + sName +<span class="string">"&gt;."</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">                <span class="comment">//弹出</span></span><br><span class="line">stkTcCnfDomain.pop();</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="built_in">string</span> name(line.substr(<span class="number">1</span>, posl - <span class="number">1</span>));</span><br><span class="line"></span><br><span class="line">                stkTcCnfDomain.push(stkTcCnfDomain.top()-&gt;addSubDomain(name));</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">&#123;</span><br><span class="line">            stkTcCnfDomain.top()-&gt;setParamValue(line);</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>(stkTcCnfDomain.size() != <span class="number">1</span>)</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">throw</span> TC_Config_Exception(<span class="string">"[TC_Config::parse]:parse error : hasn't match"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      &lt;h1 id=&quot;背景&quot;&gt;&lt;a href=&quot;#背景&quot; class=&quot;headerlink&quot; title=&quot;背景&quot;&gt;&lt;/a&gt;背景&lt;/h1&gt;&lt;p&gt;一直说Tars是使用epoll模型的，而且之前校招面试的时候也老会被问到epoll，所以这次打算先把epoll看一下，看看tars是怎么做epoll的，但由于对网络编程没有什么了解，所以会先看一些基础的其他类。&lt;/p&gt;
&lt;p&gt;在网上找了一个系列博客，感觉还挺多的，可以看看。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.csdn.net/stpeace/category_7554860.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://blog.csdn.net/stpeace/category_7554860.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;大概会照着他这个目录看一看。&lt;/p&gt;
&lt;p&gt;他的目录中第二篇看的是一个&lt;code&gt;tc_loki.h&lt;/code&gt;，但我看了下和epoll暂时没有什么关系，所以先跳过这个文件，从&lt;code&gt;tc_commom.h&lt;/code&gt;开始看。&lt;/p&gt;
    
    </summary>
    
      <category term="职业学习" scheme="http://yoursite.com/categories/%E8%81%8C%E4%B8%9A%E5%AD%A6%E4%B9%A0/"/>
    
    
      <category term="Tars" scheme="http://yoursite.com/tags/Tars/"/>
    
  </entry>
  
  <entry>
    <title>TARS学习笔记（一）</title>
    <link href="http://yoursite.com/2020/06/22/TARS%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%EF%BC%88%E4%B8%80%EF%BC%89/"/>
    <id>http://yoursite.com/2020/06/22/TARS学习笔记（一）/</id>
    <published>2020-06-22T15:56:20.000Z</published>
    <updated>2020-06-22T15:57:27.710Z</updated>
    
    <content type="html"><![CDATA[<h1 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h1><p>工作中一直使用TAF，但对底层原理缺少了解，感觉以后工作中不理解原理不太好，但又一直懒着不想看。最近有了契机，就看看吧，希望能坚持下去，之前的levelDB暂时放一边。</p><p>官方简介文档：<a href="https://tarscloud.gitbook.io/tarsdocs/rumen/tars-intro" target="_blank" rel="noopener">https://tarscloud.gitbook.io/tarsdocs/rumen/tars-intro</a></p><p>文档里有的就不再赘述了，本系列学习主要是为了看源码，框架概念方面的知识官方文档才是最好的。</p><a id="more"></a><h1 id="基础概念"><a href="#基础概念" class="headerlink" title="基础概念"></a>基础概念</h1><h2 id="APP"><a href="#APP" class="headerlink" title="APP"></a>APP</h2><p>APP是应用名，是一组服务的集合，通常可以表示实现某个业务的系统名称。</p><p>在Tars系统中APP名必须唯一。</p><h2 id="Server"><a href="#Server" class="headerlink" title="Server"></a>Server</h2><p>Server是服务名，是提供服务的进程名称。</p><p>一个Server必须属于某个APP，一个APP下的所有Server名都应具备唯一性。</p><p>一个Server代表一个独立的程序，绑定至少一个ip，实现一组相关的接口。</p><h2 id="Servant"><a href="#Servant" class="headerlink" title="Servant"></a>Servant</h2><p>Servant是服务提供者，提供了一个或多个具体接口给客户端调用。</p><p>Servant对应代码中的一个类，继承于tars文件中的interface。</p><p>一个Servant必须属于某个Server，一个Server下的所有Servant名都应具备唯一性。</p><p>也就是说，一个tars协议文件对应的其实是一个Servant，而不是我之前理解的一个Server！</p><p>一个Server下可以有多个Servant，可以在Server的initialize方法下使用addServant添加！具体可以看手上的YUDS代码！</p><p>终于分清Server和Servant的区别了……</p><h2 id="获取配置"><a href="#获取配置" class="headerlink" title="获取配置"></a>获取配置</h2><p>发布之后登陆机器，运行<code>ps -efww | grep ${your server name}</code>命令可以看到服务运行的命令行，可以看到配置文件。</p><h2 id="client创建通信器"><a href="#client创建通信器" class="headerlink" title="client创建通信器"></a>client创建通信器</h2><p>之前就在代码里见过两种方式，但没有深究，现在看来原来一种是自己直接指定ip和端口，也是我比较常用的，另一种就是将通信器指定到框架主控中，由主控来帮忙寻址，就不用自己指定ip和port了，但是这种方式没有上报信息，如果需要上报信息的话也需要向指定主控一样指定其他相关属性。<br><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 第一种</span></span><br><span class="line">Communicator *communicator = <span class="keyword">new</span> Communicator();</span><br><span class="line">HelloPrx helloPrx = communicator-&gt;stringToProxy&lt;HelloPrx&gt;(<span class="string">"Test.HelloServer.HelloObj@tcp -h xxx -p yyy:tcp -h www -p zzz"</span>);</span><br><span class="line">helloPrx-&gt;call();</span><br><span class="line"></span><br><span class="line"><span class="comment">// 第二种</span></span><br><span class="line">Communicator *communicator = <span class="keyword">new</span> Communicator();</span><br><span class="line">communicator-&gt;setProperty(<span class="string">"locator"</span>, <span class="string">"tars.tarsregistry.QueryObj@tcp -h xxxx -p 17890"</span>);</span><br><span class="line">communicator-&gt;setProperty(<span class="string">"stat"</span>, <span class="string">"tars.tarsstat.StatObj"</span>);<span class="comment">//指定stat状态信息</span></span><br><span class="line">communicator-&gt;setProperty(<span class="string">"property"</span>, <span class="string">"tars.tarspropery.PropertyObj"</span>);<span class="comment">//指定自定义属性信息</span></span><br><span class="line">HelloPrx helloPrx = communicator-&gt;stringToProxy&lt;HelloPrx&gt;(<span class="string">"Test.HelloServer.HelloObj"</span>);</span><br><span class="line">helloPrx-&gt;call();</span><br></pre></td></tr></table></figure></p><h2 id="模板配置"><a href="#模板配置" class="headerlink" title="模板配置"></a>模板配置</h2><p>tarsnode会从平台拉取服务对应的模板（服务部署时配好的），然后根据模板生成服务对应的配置，并用这个配置启动服务。</p><p>模板配置里，就会有比如这个服务的端口、启动的线程数之类的东西。</p><h2 id="入门"><a href="#入门" class="headerlink" title="入门"></a>入门</h2><p>每个Servant（Obj）对象对应一个业务处理线程，所以如果是Imp的成员变量，且只被当前的Imp对象处理，就不需要加锁。</p><p>枚举类是有stoe和etos两个方法的。</p><p>tars文件中还有key这个关键字，可以用来定义小于比较符号。</p><p>数据编码是由头信息和实际数据组成的。</p><p>TUP是Tars统一协议，最早就用来方便各语言客户端调用Tars服务，只提供编解码，并不提供网络通讯。当然如果Tars已经提供了某种语言的客户端，那么就不再需要使用TUP来调用Tars服务了。</p><h2 id="使用指南（c-）"><a href="#使用指南（c-）" class="headerlink" title="使用指南（c++）"></a>使用指南（c++）</h2><p>所有接口函数中的最后一个参数都是TarsCurrentPtr，通过这个结构体可以获取请求包的所有原始内容。</p><p>对于同一个Obj名称，多次调用stringToProxy返回的是proxy其实是同一个，多线程调用是安全的，且不会影响性能。</p><p>原来还可以针对接口设置超时时间。</p><h2 id="调用"><a href="#调用" class="headerlink" title="调用"></a>调用</h2><p>寻址方式按照是否在主控注册可以分为两类，不在主控注册就是直接按照ip寻址，在主控注册的服务的寻址方式是基于服务名进行的，由主控去帮忙寻址，但是需要在生成通信器的时候指定register的地址。</p><p>还可以指定set调用。</p><p>还有hash调用，会使同一个请求落在同一个机器上。</p><h2 id="染色"><a href="#染色" class="headerlink" title="染色"></a>染色</h2><p>染色的功能主要是可以在某服务某接口中对特定用户号码的消息进行染色，方便实时察看该用户引起后续所有相关调用信息流的日志。</p><p>染色日志有主动打开和被动打开两种方法。</p><p>主动打开是指在请求的客户端打开框架中的染色日志开关，被动打开是指在请求的服务端预先设定染色条件，判断收到的key值，由服务端打开染色开关。</p><p>被动打开中就会在jce文件中用到routekey关键字定义key。</p><h2 id="tars协议数据包大小"><a href="#tars协议数据包大小" class="headerlink" title="tars协议数据包大小"></a>tars协议数据包大小</h2><p>客户端对发出去的包大小没有限制，但是收到的回包默认不能超过10000000字节，差不多10M。</p><p>服务端也一样，对发出去的包没有限制，收到的包默认不能超过100000000字节，差不多100M。</p><h2 id="服务管理"><a href="#服务管理" class="headerlink" title="服务管理"></a>服务管理</h2><p>Tars还可以支持动态接收命令，来处理相关的业务逻辑。</p><p>有两个宏：<code>TARS_ADD_ADMIN_CMD_PREFIX</code>和<code>TARS_ADD_ADMIN_CMD_NORMAL</code>。</p><p>通常注册的接口处理有两种：全局的接口处理和基于对象的接口处理。</p><p>感觉全局的接口处理就是taf平台上用的发送自定义命令呀！</p><h2 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h2><p>Tars还支持一些其他操作，比如统计上报、异常上报、属性统计和查看tars调用链。</p><h2 id="服务线程"><a href="#服务线程" class="headerlink" title="服务线程"></a>服务线程</h2><p>Tars C++框架服务是单进程多线程RPC系统。</p><p>有7个固定线程，然后加上服务端网络线程数、业务处理线程数、客户端网络线程数以及每个客户端的异步回调线程数。</p><p>7个固定线程：主线程、端口业务逻辑线程、时间辅助线程、滚动日志线程、本地日志线程、远程日志线程、统计属性上报线程。</p><h2 id="protobuf协议"><a href="#protobuf协议" class="headerlink" title="protobuf协议"></a>protobuf协议</h2><p>现在tars已经支持proto文件了，能够从proto生成rpc相关代码。</p><p>注意，要在proto文件中加上<code>option cc_generic_services=false;</code></p><p>tars会生成tars.h文件</p><h2 id="协议解析器"><a href="#协议解析器" class="headerlink" title="协议解析器"></a>协议解析器</h2><p>协议解析器使得TarsCpp实现的Server几乎能支持任何协议，包括我们自定义的网络协议。</p>]]></content>
    
    <summary type="html">
    
      &lt;h1 id=&quot;背景&quot;&gt;&lt;a href=&quot;#背景&quot; class=&quot;headerlink&quot; title=&quot;背景&quot;&gt;&lt;/a&gt;背景&lt;/h1&gt;&lt;p&gt;工作中一直使用TAF，但对底层原理缺少了解，感觉以后工作中不理解原理不太好，但又一直懒着不想看。最近有了契机，就看看吧，希望能坚持下去，之前的levelDB暂时放一边。&lt;/p&gt;
&lt;p&gt;官方简介文档：&lt;a href=&quot;https://tarscloud.gitbook.io/tarsdocs/rumen/tars-intro&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://tarscloud.gitbook.io/tarsdocs/rumen/tars-intro&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;文档里有的就不再赘述了，本系列学习主要是为了看源码，框架概念方面的知识官方文档才是最好的。&lt;/p&gt;
    
    </summary>
    
      <category term="职业学习" scheme="http://yoursite.com/categories/%E8%81%8C%E4%B8%9A%E5%AD%A6%E4%B9%A0/"/>
    
    
      <category term="Tars" scheme="http://yoursite.com/tags/Tars/"/>
    
  </entry>
  
  <entry>
    <title>保险学习</title>
    <link href="http://yoursite.com/2020/05/06/%E4%BF%9D%E9%99%A9%E5%AD%A6%E4%B9%A0/"/>
    <id>http://yoursite.com/2020/05/06/保险学习/</id>
    <published>2020-05-06T13:35:14.000Z</published>
    <updated>2020-05-24T11:35:37.982Z</updated>
    
    <content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>保险学习，准备早买。</p><a id="more"></a><h1 id="1-你需要买保险吗？"><a href="#1-你需要买保险吗？" class="headerlink" title="1 你需要买保险吗？"></a>1 你需要买保险吗？</h1><h2 id="什么是保险"><a href="#什么是保险" class="headerlink" title="什么是保险"></a>什么是保险</h2><p>保险是指投保人根据合同约定，向保险人支付保险费，保险人对于合同约定的可能发生的事故因其发生所造成的财产损失承担赔偿保险金责任，或者当被保险人死亡、伤残、疾病或者达到合同约定的年龄、期限等条件时承担给付保险金责任的商业保险行为。</p><p>简单来说——买保险就是通过杠杆作用，用小额的保费获得高额的保障 。</p><p>保险的主要作用：规避风险，用小钱得到大保障，确保发生风险时，我们积累的财富尽可能不受影响。</p><p>而基金和股票等投资品的作用主要在于实现资金的保值增值，让小钱生大钱。</p><p>学到的要用起来。</p><h1 id="社保和商业保险，怎么取舍"><a href="#社保和商业保险，怎么取舍" class="headerlink" title="社保和商业保险，怎么取舍"></a>社保和商业保险，怎么取舍</h1><p>大病一场，社保根本不够用。</p><p>社保包括五险一金，是一种较低水平的基础保障，作用其实非常有限，如果生了大病，很多特效药社保都是不能报销的。</p><p>社保的特点：强制性、广覆盖和保障水平低。</p><p>社保虽然不够，但是能解决我们基本的医疗需求，是必须要有的，而且社保和很多城市办理户口、买房买车都有关。</p><p>社保的医疗部分是终身无条件续保的。</p><p>所以商业保险是社保的扩充，不能全部替代社保。</p><p>社保四不管：1免赔额不管；2封顶金额以上不管；3自费部分不管；4自付部分不管。</p><p>社保允许报销的药品在已知药品目录中大概只占了1.4%，其中甲类报销100%，乙类报销90%。</p><p>想要得到更充分的保障，就需要商业保险。</p><h2 id="商保"><a href="#商保" class="headerlink" title="商保"></a>商保</h2><p>商业保险是指按照商业原则经营，以营利为目的的保全形式，由专门的保险企业经营。所谓的商业原则，就是保险公司的经济补偿以投保人交付保险费为前提，保障被保险人享受最大程度的经济保障。</p><p>死亡、意外、疾病。</p><p>保险需要好好规划，要综合考虑自身和家庭的需要、财务状况等因素。</p><p>如果能预知未来知道自己不会遇到风险的话，那保险确实没必要，可惜没有人能预知未来。</p><h1 id="一定要懂的保险基础知识"><a href="#一定要懂的保险基础知识" class="headerlink" title="一定要懂的保险基础知识"></a>一定要懂的保险基础知识</h1><h2 id="保险有哪些分类"><a href="#保险有哪些分类" class="headerlink" title="保险有哪些分类"></a>保险有哪些分类</h2><p>保险主要分为人身保险和财产保险，人身保险又分为人寿保险、健康险和意外险。人身保险的保险标的是人身安全，财产保险的保险标的就是物品。</p><h2 id="意外险"><a href="#意外险" class="headerlink" title="意外险"></a>意外险</h2><p>全称是人身意外伤害保险。分为普通意外险和特殊意外险，大多数意外伤害保险属于普通意外险，比如公共交通意外险就属于特殊意外险。</p><p>综合意外险是一种打包产品，将普通意外和特定意外以及一些其他险种进行了捆绑。</p><h2 id="健康险"><a href="#健康险" class="headerlink" title="健康险"></a>健康险</h2><p>健康险是以人的健康作为保障对象的保险，它和我们的生活密切相关，健康险又分为医疗险和重疾险两大类。</p><p>重疾险：定额赔付，如果投保人发生了重症，一旦理赔，保险公司就会按照合同给付保险金。</p><p>医疗险：医疗险和社保比较像，是报销型。</p><h2 id="寿险"><a href="#寿险" class="headerlink" title="寿险"></a>寿险</h2><p>寿险是针对人的生死提供保障的一种保险。</p><p>寿险主要分为风险保障型寿险和投资理财型寿险。</p><p>风险保障型寿险又分为定期寿险、终身寿险和两全保险。</p><p>投资理财型寿险又分为年金险、分红险、万能险和投资连结险。</p><h1 id="直面死亡，寿险"><a href="#直面死亡，寿险" class="headerlink" title="直面死亡，寿险"></a>直面死亡，寿险</h1><p>寿险以被保险人的生命为保险对象，是被保险人在保险责任期内生存或者身故，由保险公司根据契约规定给付保险金的一种保险。</p><p>应对死亡风险而设计的，保障死亡、保障生存、甚至投资理财。</p><p>买寿险之前，明确三件事：1需求是什么？2应该先给谁买？3买多少保额？</p><p>家庭需求法：寿险保额 = 未来10年的支出 + 未来10年总负债 + 父母赡养费用 + 子女教育费用 - 现有流动资产</p><h2 id="如何挑选能够提供足够保障的寿险产品？"><a href="#如何挑选能够提供足够保障的寿险产品？" class="headerlink" title="如何挑选能够提供足够保障的寿险产品？"></a>如何挑选能够提供足够保障的寿险产品？</h2><p>定期寿险和终身寿险，最大的差别就是保障时间不同。</p><p>在考虑购买定期寿险还是终身寿险的时候，我们应该考量的不是经济承受能力，而是保险需求。定期寿险的使命是保障特定的时间内发生死亡所造成的的经济损失，而终身寿险承担的是资产传承。</p><p>两全型保险的设计是既保生存也保死亡，和终身寿险的保险责任也不同，也两全型保险能够帮助强制储蓄。</p><h2 id="投资理财型寿险"><a href="#投资理财型寿险" class="headerlink" title="投资理财型寿险"></a>投资理财型寿险</h2><p>在买保障的同时实现资金的保值增值。</p><p>优点：1同时拥有保障和理财两种属性；2强制储蓄</p><p>但是保障和理财都不突出，毕竟这是折中的。</p><p>比较适合攒不下钱，投资理财意识薄弱，想要通过买保险给自己一份保障，同时还想有一些收益的。</p><h3 id="年金保险"><a href="#年金保险" class="headerlink" title="年金保险"></a>年金保险</h3><p>是指被保险人活着的时候，保险公司会按照合同约定的时间，定期定额给付保险金的人寿保险。子女教育金保险就属于定期年金保险。</p><p>终身年金保险则是在被保险人死亡后，保险公司才会停止给付保险金，可以作为养老保险的补充。</p><p>主要用于子女教育或者养老。</p><h3 id="分红保险"><a href="#分红保险" class="headerlink" title="分红保险"></a>分红保险</h3><p>保险公司保险业业务分红，风险小，收益也小。</p><h3 id="投资连结保险"><a href="#投资连结保险" class="headerlink" title="投资连结保险"></a>投资连结保险</h3><p>投资账户的投资收益，投资风险由自己承担。</p><h3 id="万能人寿保险"><a href="#万能人寿保险" class="headerlink" title="万能人寿保险"></a>万能人寿保险</h3><p>投资账户的投资收益，投资风险由保险公司和用户共同承担。</p><h2 id="挑选投资理财保险"><a href="#挑选投资理财保险" class="headerlink" title="挑选投资理财保险"></a>挑选投资理财保险</h2><ol><li>确定自己的需求</li><li>看想要的收益，确定收益+不确定收益，确定收益是承诺的，不确定的是预估的。</li></ol><h1 id="实操，寿险产品分析"><a href="#实操，寿险产品分析" class="headerlink" title="实操，寿险产品分析"></a>实操，寿险产品分析</h1><p>要去官方渠道查看这款保险的详细资料。</p><p>能不能买？</p><p>保额够不够？</p><p>保障什么？先看免责条款，就是保险不保的情况，寿险的免责条款越少越好。还要看宽限期。</p><h1 id="关于重疾险"><a href="#关于重疾险" class="headerlink" title="关于重疾险"></a>关于重疾险</h1><p>人一生患重疾的概率是72.18%。</p><p>重疾险是指由保险公司经办的，以特定重大疾病为保险对象，当被保人确诊疾病并符合保险条款时，由保险公司直接赔付保额的商业保险行为。</p><p>25种，其中有6种更高，这6种也是必保项。</p><h2 id="买重疾险之前的三个问题"><a href="#买重疾险之前的三个问题" class="headerlink" title="买重疾险之前的三个问题"></a>买重疾险之前的三个问题</h2><ol><li>重疾险保障的疾病种类是不是越多越好？一般来说，选择重疾险时考察其条款中是否能完全包含25种重疾。</li><li>重疾险先给谁买？优先给家庭经济支柱买。</li><li>重疾险保额买多少？保额 = 重疾治疗花费 + 5年生活费用 + 5年家庭负债 - 流动资产 （感觉我得整一两百万，艰难……）</li></ol><h2 id="如何挑选"><a href="#如何挑选" class="headerlink" title="如何挑选"></a>如何挑选</h2><p>定期、终身。有条件选终身。</p><p>单次赔付、多次赔付。有条件选多次，因为得过大病的人在未来得病的可能性更高，而且重疾的治疗费用特别贵。</p><p>是否返还本金，消费型、返还型。返还型就是到期没得病还能返钱，能强制储蓄一些，但保费高一些，而且买保险主要是看保障，追求收益投资其他的呗。</p><h1 id="重疾险实操"><a href="#重疾险实操" class="headerlink" title="重疾险实操"></a>重疾险实操</h1><p>三步走：</p><ol><li>能不能买？</li><li>保额够不够？</li><li>具体的保障内容。</li></ol><p>保障的具体内容：</p><ol><li>看等待期，越短越好。</li><li>看重疾险的覆盖的病种，要看看有没有轻症豁免和重疾豁免。</li><li>看赔付次数</li><li>看责任免除条款</li></ol><h1 id="医疗险"><a href="#医疗险" class="headerlink" title="医疗险"></a>医疗险</h1><p>医疗险指的是以保险合同约定的医疗行为的发生为给付保险金条件，为被保险人接受诊疗期间的医疗费用支出提供保障的保险。</p><p>医疗险是报销型的，当被保险人因为各种各样的原因发生了相关的医疗费用，只要是符合佩服标准的，都可以按照爆款条款中的规定进行报销。</p><p>医疗险不像重疾险一样直接给钱，但有它，看大病能省下不少钱。</p><p>有的重疾险不是确诊后就赔付，有的疾病是要手术之后或者疾病达到约定的状态，保险公司才赔。</p><h2 id="缺陷"><a href="#缺陷" class="headerlink" title="缺陷"></a>缺陷</h2><p>大多为一年期产品。</p><p>得了重疾，要花钱的可不只是医疗费用。</p><p>所以，重疾险和医疗险互为补充，都很重要，一定要把保障买足买全。</p><h2 id="分类"><a href="#分类" class="headerlink" title="分类"></a>分类</h2><p>普通医疗险，有的只保社保，保额低。</p><p>百万医疗险</p><p>中端医疗险</p><p>高端医疗险，会有vip待遇，但普通人没有必要，保费较高。</p><p>普通人一般选择百万医疗险或者中端医疗险，或者两者搭配。</p><h2 id="产品分析"><a href="#产品分析" class="headerlink" title="产品分析"></a>产品分析</h2><ol><li>看投保须知，看能不能续保，续保有没有什么限制</li><li>看保障内容，重点看报销范围以及承保医院的范围</li><li>看保障条件，重点看医疗保险金怎么算，免赔额、最高给付金额、赔付比例分别是多少</li></ol><h1 id="意外险-1"><a href="#意外险-1" class="headerlink" title="意外险"></a>意外险</h1><p>杠杆率比较高。</p><p>意外险的全称是人身意外伤害保险。理赔的前提是遭受意外伤害导致死亡或者残疾。</p><h2 id="两个基本点"><a href="#两个基本点" class="headerlink" title="两个基本点"></a>两个基本点</h2><ol><li>时间界定：合同有效期内发生的，自伤害之日起保险责任期内认定。</li><li>责任界定：外来的，突发的，非本意的，非疾病的。猝死不属于。</li></ol><h2 id="意外险分类"><a href="#意外险分类" class="headerlink" title="意外险分类"></a>意外险分类</h2><p>普通意外险和特定意外险。</p><p>还有一种综合意外险，将普通意外和特定意外以及其他险种进行了捆绑，提高了保障范围和保障额度。虽然覆盖面广，但有些项目可能并不需要。</p><h2 id="怎么选"><a href="#怎么选" class="headerlink" title="怎么选"></a>怎么选</h2><p>普通意外险最重要，但特定意外险也要根据实际情况去补充。</p><p>一般人更需要的是普通意外的保障。</p><p>特定意外险可以通过便宜的保额帮我们轻松提高保额，一般只有特定意外的保额才会很高，普通意外的保额一般只有几万或几十万。</p><p>特定意外险还能弥补某些特殊情况下普通意外险不适用的场景，比如旅行意外险。</p><p>意外险选长期还是短期？短期比长期好。</p><p>购买时要如实选择自己的职业。</p><p>对于家庭来说意外险保额 = 未来20年的生活费用 + 未来20年总负债 + 父母赡养费 + 子女教育费用- 流动资产</p><p>个人保额 = 意外险家庭保额 * 个人收入比例，一般不要少于50万</p><h2 id="这些情况意外险不赔"><a href="#这些情况意外险不赔" class="headerlink" title="这些情况意外险不赔"></a>这些情况意外险不赔</h2><ul><li>中暑</li><li>猝死</li><li>医疗事故</li><li>高风险运动</li><li>伤残等级不足</li></ul><h2 id="意外险实操"><a href="#意外险实操" class="headerlink" title="意外险实操"></a>意外险实操</h2><p>在官网查询特定保险的详细信息。</p><ul><li>自己能不能买？</li><li>具体的保障内容是什么？保障类型、保障额度、保障期限和保费。</li><li>保险责任期有多长？就是买了保险以后，多长时间之内可以享受赔付。一般是180天。</li><li>如果分析的意外险产品涉及到意外医疗，则还需要看免赔额和赔付比例，免赔额越低越好，赔付比例越高越好。</li></ul><p>一般对年轻人而言，优先考虑意外身故的保障额度，而对老人和小孩则是意外医疗更重要。</p><h1 id="规划靠谱的人身保险方案"><a href="#规划靠谱的人身保险方案" class="headerlink" title="规划靠谱的人身保险方案"></a>规划靠谱的人身保险方案</h1><ul><li>少年期：意外险和医疗险</li><li>单神器：意外险、重疾险、医疗险要买，寿险可以按需选择</li><li>家庭形成成长期：意外险、重疾险、寿险和医疗险。</li><li>退休期：意外险和医疗险。</li></ul><h2 id="误区"><a href="#误区" class="headerlink" title="误区"></a>误区</h2><ul><li>关注产品多于需求</li><li>关注孩子多于家庭经济支柱</li><li>不做财务分析</li></ul><h2 id="实操"><a href="#实操" class="headerlink" title="实操"></a>实操</h2><p>一般情况下，建议拿收入的5%左右，最多15%，来作为保险规划的预算。</p><h1 id="买保险要知道的知识"><a href="#买保险要知道的知识" class="headerlink" title="买保险要知道的知识"></a>买保险要知道的知识</h1><p>医生说的小毛病可能会影响投保，保险公司核保结束后，一般会根据我们的身体情况，把我们分为标准体和非标准体。</p><p>标准体就可以正常投保，非标准体则会做出加费、责任除外、延期承保与拒保这种情况。</p><h2 id="听说保险有道霸王餐"><a href="#听说保险有道霸王餐" class="headerlink" title="听说保险有道霸王餐"></a>听说保险有道霸王餐</h2><p>保费豁免，指的就是，在保险合同期内，投保人或被保人达到某些特定的情况，保险公司同意投保人不再缴纳后续保费，保险合同仍然有效。</p><h2 id="保险买多了，是不是都能被赔付？"><a href="#保险买多了，是不是都能被赔付？" class="headerlink" title="保险买多了，是不是都能被赔付？"></a>保险买多了，是不是都能被赔付？</h2><ul><li>给付型保险，可以获得多重赔付，多投多保，寿险、重疾险。</li><li>报销型保险，是以保险人的实际花销为赔付金额，不能多获得，比如医疗险。</li></ul><p>【END】</p>]]></content>
    
    <summary type="html">
    
      &lt;h1 id=&quot;前言&quot;&gt;&lt;a href=&quot;#前言&quot; class=&quot;headerlink&quot; title=&quot;前言&quot;&gt;&lt;/a&gt;前言&lt;/h1&gt;&lt;p&gt;保险学习，准备早买。&lt;/p&gt;
    
    </summary>
    
      <category term="大杂烩" scheme="http://yoursite.com/categories/%E5%A4%A7%E6%9D%82%E7%83%A9/"/>
    
    
      <category term="理财投资" scheme="http://yoursite.com/tags/%E7%90%86%E8%B4%A2%E6%8A%95%E8%B5%84/"/>
    
  </entry>
  
  <entry>
    <title>网文学习</title>
    <link href="http://yoursite.com/2020/04/09/%E7%BD%91%E6%96%87%E5%AD%A6%E4%B9%A0/"/>
    <id>http://yoursite.com/2020/04/09/网文学习/</id>
    <published>2020-04-09T14:31:51.000Z</published>
    <updated>2020-04-26T16:01:51.442Z</updated>
    
    <content type="html"><![CDATA[<p>还是不甘心，下决心再给自己一个机会，好好学习总结。</p><p>多看多写多想，才是王道。</p><a id="more"></a><h1 id="36讲之《风青阳访谈》"><a href="#36讲之《风青阳访谈》" class="headerlink" title="36讲之《风青阳访谈》"></a>36讲之《风青阳访谈》</h1><p>爆更，对我来说不太现实。</p><ul><li>构思的时候，一场战斗，招式、过程、结尾都想好。</li><li>写手只有两件事：写书，经营粉丝。</li><li>要写长，节奏和布局很重要。</li><li>主线是脊椎，支线是骨架，节奏是心脏，细节是浑身血肉，立意是灵魂。去掉细节，就应该是大纲。主线是贯穿全文的，主角到底要干嘛？是什么让他不停地战斗。</li><li>节奏，大概三十万字会出一卷，形成两个小高潮，一个大高潮，而小高潮也是为大高潮准备的。10万字升一级，30万字一个大高潮，牵扯下一卷。</li><li>《龙血》写了三四十万字的细纲（我特么，人家活该成功）。</li><li>在一个最容易火的模式下，写出和别人不一样的东西，这才是真的懂了套路。</li><li>以作者的角度去看书，比如我看到这个进度，停一下，思考到底是后续的什么，还是前面的什么坑在吸引自己。想明白之后，就是运用。</li><li>玄幻文，第一章最重要的是代入感。人类对弱势群体的心理代入，对正能量的代入是天然的。所谓装逼就是同情之后的巅峰倒转。</li><li>学情绪看土豆。</li><li>玄幻升级小白文，关键的不是等级叫什么，而是等级要森严，等级差距、优越感和危机感都要有。突然觉得优越感确实很重要，想起之前看过的一些书，主角没达到一个等级之前，一定写的是朝思暮想，达到了会怎么怎么样，达不到又会怎么怎么样……构成期待！</li><li>力量对比不需要太严格，主要靠作者营造的氛围，但大概感觉不能错，比如武圣能飞，武者就不能飞。</li><li>很多都可以重复，但剧情不能。</li><li>要在套路的框架上，成功的经验里，把自己擅长的，读者又喜欢的东西写出来。</li><li>大局观，主线，节奏照着主线走，细节技巧靠自己活用。</li><li>玄幻中力量体系和金手指要通达，不是说你懂了1~9级，而是要怎么展示出1~9级，展示得好不好，读者读了有没有情绪，期不期待主角升级。任何玄幻书的本质都是这个，体系不通达不可能火，要写出剧情，融入等级，让读者自己看出来谁牛逼。</li></ul><h1 id="36讲之《管平潮访谈》"><a href="#36讲之《管平潮访谈》" class="headerlink" title="36讲之《管平潮访谈》"></a>36讲之《管平潮访谈》</h1><p>读者，本来以为管平潮搞实体出版的，可能说的更多会偏实体，结果……跪了……</p><ul><li>自己是为读者服务的。</li><li>在写具体故事甚至局部段落时，要先问自己：读者喜欢看吗？感觉就是在说不要自嗨。</li><li>甚至写法读者喜不喜欢看，都要考虑一下。</li><li>开头，写一个很爽或者很有悬念或者很狗血或者很暧昧的事件，而且关键在于这一定要是个最多一千五百字以内就能完结的小事。简单来说，一定要在最开头，用相对少的字数，呈现一个很爽的完整的事件！（感觉我悟了！）</li><li>一开始要有非常剧烈的矛盾冲突，或者非常剧烈浩大的奇观。</li><li>微创新，比如穿越，可以考虑在什么人穿越、带什么穿越、穿越到哪里等方面进行微创新。感觉微创新就是把一件事的某个细节方面抠一下，想一下，创新一下。</li><li>时刻要记住写的是哪种类型，清晰定位你的读者是什么群体。</li><li>一定要注意自己写文编故事的节奏，两点描述，一是能让读者爽的良好节奏，就是读者希望看到某情节时，情节就出现了。二是网文中，不要太多长线，一两条就行了，网文是碎片化阅读的，尽量多短线、不要让仇人过夜，最多一万字之内，要有进展！</li><li>不要让读者总是猜到，但也不能让读者一直猜不到。</li></ul><h1 id="36讲之《滚开访谈》"><a href="#36讲之《滚开访谈》" class="headerlink" title="36讲之《滚开访谈》"></a>36讲之《滚开访谈》</h1><p>分享，感觉滚开是个兴趣写手，他说为了挣钱写书是很累的……天赋吧唉，看了更多是一些羡慕，也让自己多一些坚持吧。</p><ul><li>写书就是分享，分享你自己的感动，无论是正面的还是负面的，只要分享成功了就行。</li><li>所有讲课的大神们都有个共同点，那就是分析，研究其他成功书的成功之处（害没有捷径可走……）。</li><li>积累功底最快的方法就是模仿，但是一炮而红是要新意和读者没见过的东西的。</li><li>不去研究自己的错漏，是不行的。</li><li>节奏才是重点。代入感第一，节奏第二。</li><li>功力不足，创新也没用。</li></ul><h1 id="36讲之《吴半仙灵异写作》"><a href="#36讲之《吴半仙灵异写作》" class="headerlink" title="36讲之《吴半仙灵异写作》"></a>36讲之《吴半仙灵异写作》</h1><p>不写灵异，权当见识。</p><ul><li>第三人称更像小说，第一人称更像经历。</li><li>灵异小说里面主角的存在感甚至可以比较低，这是和其他类型的主要区别，玄幻都市是要读者代入到人物，灵异则是代入到环境氛围。</li><li>灵异是故事本身，悬疑是写作手法。</li><li>开篇要动些脑筋。</li><li>分了三个等级的开头，第一小白，第二正统一点的，就是讲故事，第三就是经典了，可以当情怀的。</li><li>灵异小说切忌灌水，读者是来找刺激的。</li><li>好书要有血有肉有骨，玄幻的骨就是主线脉络设定，骨就是一本书要阐述的东西、主题、道理。</li><li>故事和剧情，是两码事。（这个还有点理解不到，只能说有一点感觉。）</li></ul><h1 id="36讲之《残剑不传秘籍》"><a href="#36讲之《残剑不传秘籍》" class="headerlink" title="36讲之《残剑不传秘籍》"></a>36讲之《残剑不传秘籍》</h1><ul><li>先压抑拉住读者的心，然后再写主角的金手指，但可以不交代全部的金手指，这就可以留下一定悬念，甚至连作者都可以不知道金手指还有什么用，以后根据剧情需要再添加金手指的能力，然后到了两三百万字的时候再考虑金手指的来历。</li><li>主角可以强大，可以无敌，但是一定不能顺心。一旦主角万事如意，那一本书就没有了吸引力。</li><li>每隔一段时间，都要给主角加一个目标，一个短期内可以实现的目标。</li><li>写网文，无非就是打怪、升级、装逼、被虐、升级、踩脸、夺宝、抢女人。</li><li>功法，围绕功法可以写功法怎么牛逼，什么来历，怎么争斗。</li><li>女人可以无视主角，但主角一定要慢慢展示自己的能力。</li><li>该考虑的都有大体的考虑之后，就可以设伏笔，伏笔不能太深让人看不懂，也不能太弱智。</li><li>每一件事，都自己找一些可以设置疑惑和悬念的地方记录下来，一点点套。</li><li>每一件事，不能让主角全部地顺心顺意，要留一点余地，让读者期待下去。</li><li>不要一味地打怪升级，要加一点点缀，就是开始引出一点新剧情的意思。</li></ul><h1 id="36讲之蚕茧里的牛"><a href="#36讲之蚕茧里的牛" class="headerlink" title="36讲之蚕茧里的牛"></a>36讲之蚕茧里的牛</h1><ul><li>出彩的第二男主角可以吸引腐女。</li><li>高潮一定要长，否则就白费了。</li><li>让读者跟着追，然后层层递进，读者本来以为明天就要高潮了，结果发现又是一次转折，层层递进，最终爆发。而且高潮一定要有观众，并且最好是与主角有一些关系的人。</li><li>换地图之前要铺垫一下，不要一下子就换。</li></ul><h1 id="36讲之辰机唐红豆爽文的核心"><a href="#36讲之辰机唐红豆爽文的核心" class="headerlink" title="36讲之辰机唐红豆爽文的核心"></a>36讲之辰机唐红豆爽文的核心</h1><ul><li>爽文的真正核心：你敢叫主角不爽，读者就敢叫你不爽。</li><li>网文的核心，应该是谁爽，谁才是爽点的中心？是主角，不是作者。</li><li>比如10章一个小循环，龙套嘲讽拉仇恨1~2章，主角被压1章，反踩1章，打脸2~3章，剩下的是收获。记得要有收获，收获才是核心，不然单纯地打脸爽感会很弱。</li><li>还有一点，好处必须要用出去。比如法宝之类的可消耗品，就不要积压太多，读者会记不住，尽快用出去。</li><li>结构节奏看番茄。</li><li>开书，要想好创意能坚持多少字，创意快写完换世界换宇宙的时候，之前一定要有伏笔。</li><li>主角目标可以依靠情节来引导，就是说，如果主角XXXX，就能XXXX。</li><li>拉仇恨中，嘲讽一般只是第一次需要。第一次主角被嘲讽，然后反踩打脸，然后被打脸的龙套自己去找下一个仇恨目标，换句话说他就自己去作死了，我们的视角得定在主角身上。</li><li>大仇恨目标，就设置一个场面。</li><li>主角可以吃小亏，但不能吃大亏，一个事件一定要以收获为结尾！</li></ul><h1 id="36讲之冬雪晚晴"><a href="#36讲之冬雪晚晴" class="headerlink" title="36讲之冬雪晚晴"></a>36讲之冬雪晚晴</h1><p>女白金作家，看看。</p><ul><li>悬念设置，就是勾引读者想要向下看的欲望，举个例子就是天天在面前晃的东西换个位置，就不普通了，比如狗尾巴在狗身上很正常，但如果在人身上那就有悬念了。悬念就是某些常规的东西一下子不常规了。</li><li>如果一开始做长文打算，进展不要太快。</li><li>写自己最擅长的东西，就是最好的。</li><li>人设不要太全能，全能了就没得展开了</li></ul><h1 id="36讲之愤怒的香蕉yy核心，掌控读者情绪"><a href="#36讲之愤怒的香蕉yy核心，掌控读者情绪" class="headerlink" title="36讲之愤怒的香蕉yy核心，掌控读者情绪"></a>36讲之愤怒的香蕉yy核心，掌控读者情绪</h1><ul><li>感动作者的感动，跟感动读者的感动，是不同的。</li><li>爽点要从心出发，而不是从分析和结构出发。</li><li>当你轻视小白文的时候，你还写小白文，那你当然会扑街。</li><li>爽点不是连升两级，而是升完级之后能干什么，成就感、满足感，摆脱危机后的轻松感。</li><li>他写书的核心，就是找到情绪，然后用任何不同的手段来复制这种情绪，传递到别人心里。</li><li>很多可以写，但是重点在于合理性，作者要给读者以理由，发生这种事情，理由是不是充分。</li><li>他研究一切文学的手法，都是为了操作读者的情绪而已。诸般繁琐，皆是人心。</li></ul><h1 id="36讲之红娘子"><a href="#36讲之红娘子" class="headerlink" title="36讲之红娘子"></a>36讲之红娘子</h1><ul><li>大众读者群体要看的小说主题，是废柴推倒白富美打到高富帅。</li><li>一个情节走完之后，主角实际上所得到的，比起在这个情节中损失掉的，要多两倍以上。相反，用在反派身上，也可以搞出很好的情节。</li><li>赢缩输冲，赌徒们在赢的时候只想着小富即安，保住胜利果实，下注越来越少；而输的时候就会不计风险，只想回本，下注越来越大。但是到了输冲的最后关头，赌徒只剩下最后的筹码时，他们却又会变得想要无论如何保住这最后的筹码。这就是非理性决策理论。</li><li>如何让读者进入非理性阶段？</li><li>框架效应，在写主角得到什么的时候，尽量用严肃、死板、生硬的词句；而在写主角损失什么的时候，尽量用欢快、幽默、搞笑的词句。</li><li>沉默等于铺垫，吐币等于小高潮，大奖等于大高潮。</li><li>差一点点就赢了，和赢了的胜利兴奋度差不多，前提是得要所有人都觉得你差一点点就赢了，觉得你差不多，但其实你还差很多。</li><li>主角有实际收货的时候，尽可能以实物的形式出现，哪怕这种实物和现金完全不成比例；而主角在必须所有损失的时候，以现金的形式出现。</li></ul><h1 id="36讲之狐王列那"><a href="#36讲之狐王列那" class="headerlink" title="36讲之狐王列那"></a>36讲之狐王列那</h1><ul><li>选定你自己喜欢的或者擅长的题材类型，然后再研究你的作品对应哪些用户群体，琢磨他们的口味。</li><li>最重要的是故事。</li></ul><h1 id="36讲之华表"><a href="#36讲之华表" class="headerlink" title="36讲之华表"></a>36讲之华表</h1><ul><li>开头应该有小高潮和期待感，转折只是其中的一种，先扔出来的应该是爽点的暗示和期待。</li><li>写作的整体结构应该是：词汇+风格+精气神+文笔+布局+节奏+伏笔+高潮。</li><li>支线没有后续没有伏笔的话，六千字就可以结束，如果涉及到主线推进的伏笔，可以延长到三万字。</li><li>高潮中要同时埋伏笔或者坑，一个不够，两三个最好。</li><li>写一本，准备第二本，构思第三本。</li><li>先写好结尾，无论你怎么加长，都不会脱离主线。</li></ul><h1 id="36讲之孑与2"><a href="#36讲之孑与2" class="headerlink" title="36讲之孑与2"></a>36讲之孑与2</h1><ul><li>写书其实就是写自己的生活，简单的生活夸大、扩写、拔高，就是小说。</li><li>简单的故事戏剧化，冲突达到顶点就是爽点，这样很自然。</li><li>生活里的矛盾不多，写出来就像是故意编的，那就要靠文笔，文笔差就用激情填补，先感动自己。</li><li>只管主角怎么想，喜恶厌憎都围着主角走。</li><li>细纲必须有。人物的出现，消失，事件的开始、结束，都要事先安排好。</li><li>讲述每一件事情都要有跟脚，一件事一次细纲。</li><li>故事写到了极点，就会有高潮，故事开始之前就要铺设伏笔，这是一定要做到的。</li></ul><h1 id="36讲之九穗禾"><a href="#36讲之九穗禾" class="headerlink" title="36讲之九穗禾"></a>36讲之九穗禾</h1><p>简体出版的一些情况，先当了解。</p><ul><li>腐女是萌人物的，尤其是一些有明显的个性特征，能够独立于书存在的人物。</li><li>虐文是写一件很美好的东西，然后在它最美好的时候撕碎它。</li><li>虐是需要一定反差的，一个很悲壮的场面下做了一件很温馨的小事。</li><li>读者喜欢看矛盾的人物。</li><li>女读者比男读者更讲究人物，男读者总是议论哪段写的爽，女读者总是说我好喜欢哪个角色，在女频文里，男主的塑造比女主更重要。</li><li>对于出版书来说，人物塑造要到位，有别于网文的剧情流。</li></ul><h1 id="36讲之孔令旗《打怪升级流》"><a href="#36讲之孔令旗《打怪升级流》" class="headerlink" title="36讲之孔令旗《打怪升级流》"></a>36讲之孔令旗《打怪升级流》</h1><ul><li>越级打怪方式可以多种多样：打比自己高级的、打两个同级的、打地位比自己高的、打有环境优势的……</li><li>九线法升升级，错开写。</li><li>要区分升级和进阶，也就是小段位简单写写，大段位要慎重一些。</li><li>原则是可以越级但不可以越阶战斗。</li></ul><h1 id="36讲之犁天谈地图"><a href="#36讲之犁天谈地图" class="headerlink" title="36讲之犁天谈地图"></a>36讲之犁天谈地图</h1><ul><li>玄幻和仙侠，设定比较重要。</li><li>做一个没有填的坑的笔记，不然挖了坑最后自己都忘了。</li><li>换地图，一开始不要告诉读者太多，一层一层来。</li><li>换地图后必须让主角在短时间内有一点表现的机会，让读者有期待感。</li><li>大高潮之后，是个灌水的好机会，可以把以前的坑拿出来找几个填上，勾起读者新的关注，度过平淡期。</li><li>主线一直要在，但大多数情节只要不把主线丢掉就行了，并一定都要围绕主线。</li><li>作者情绪低落的时候就可以找点不长眼的角色杀一下、把前面读者感兴趣的坑填一下、写一些人物互动，装逼都是在人物互动中完成的，红花需要绿叶配。</li><li>高潮堆积，总觉得高潮不够爽，比如杀反派，一下就杀了没意思，重点不是杀他，而是杀他之前，他的恐惧和绝望。</li><li>装逼的高潮始终都要靠周围路人来烘托的，逼是装给别人看的。</li><li>小说好不好看，就看能不能带动读者情绪，符不符合正常人的人情世故、行为心理。</li></ul><h1 id="36讲之梁老师《新书前的准备》"><a href="#36讲之梁老师《新书前的准备》" class="headerlink" title="36讲之梁老师《新书前的准备》"></a>36讲之梁老师《新书前的准备》</h1><ul><li>立志。</li><li>在给人讲故事时都是按照时间顺序在讲，但写小说时，无论哪种叙事手法，都是按照逻辑在讲。</li></ul><h1 id="36讲之貌似高手"><a href="#36讲之貌似高手" class="headerlink" title="36讲之貌似高手"></a>36讲之貌似高手</h1><p>这笔名不错。</p><ul><li>主角升级飞快，这六个字，说尽了玄幻小说的精髓。</li><li>要开辟多条路线升级。</li><li>玄幻小说有很多要点，无论是金手指、节奏、代入感、期待感还是各种技巧，但是这些都有一个前提，就是要流畅。</li><li>不断升级，不断虐人，想要流畅很简单，就是给主角安排好对手，这样节奏感就出来了。</li><li>期待感的重要意义之一就是打开读者想象空间。</li><li>想要读者觉得主角牛逼，就得虐天才。</li><li>流畅的情节需要方方面面，而升级也不能一味地升。</li><li>要流畅，主角就不要同时做多件事，单线程专注地做。不要一件事做一半就去做另一件事。</li><li>小白文的精髓就是，不关键的地方用说明文，关键但复杂需要大段过程的地方，牺牲一点质量，也用说明文。因为这样可以快速突进。</li><li>金手指的用处：1是作弊，2是装逼，或者说因为做了弊所以能装逼。3给读者建立期待感和代入感。对读者影响最大的是期待感，金手指一定要是未来非常牛逼的。</li><li>卧龙凤雏，要么在金手指上做文章，要么从开头就流畅，用节奏来带动读者。</li></ul><h1 id="36讲之梦入洪荒《不扑街的基础技术》"><a href="#36讲之梦入洪荒《不扑街的基础技术》" class="headerlink" title="36讲之梦入洪荒《不扑街的基础技术》"></a>36讲之梦入洪荒《不扑街的基础技术》</h1><ul><li>从整体上看，网络小说有两个关键要素，主题和主线。</li><li>把小说的每一卷都看成是一部独立的小说，然后设定好这一卷主角所有行为的驱动力。</li><li>每一卷的小主题可以戏剧领域的三十六种戏剧模式（word附录有），设立好小主题之后就围绕主题设定若干个事件，每章做一个冲突和悬念。</li><li>他遇到的六次瓶颈：1不知道小说怎么写，写什么内容？2如何突破套路化写作？3如何形成自己的写作风格？4字数较长的情况下如何保证质量？5字数更多之后素材都用的差不多了怎么办？6如何收尾？</li><li>小说矛盾冲突的四个主要类型——情感冲突、利益冲突、性格冲突和观念冲突。</li><li>高潮的种类——情感高潮、命运高潮、主题思想高潮、性格高潮、打斗高潮，主题高潮可以看《仙魔变》。</li><li>突转：把小说情节推向高潮的主要推手。</li><li>情节五步：1主角和反角发生矛盾冲突；2主角略微占优或者站劣；3反转优劣势，加剧矛盾冲突；4高潮，要跌宕起伏；5铺设伏笔，进入新的小情节。</li><li>悬念：1事件的悬念；2命运的悬念；3主题的悬念。</li></ul><h1 id="36讲之齐橙《专业知识的魅力与运用》"><a href="#36讲之齐橙《专业知识的魅力与运用》" class="headerlink" title="36讲之齐橙《专业知识的魅力与运用》"></a>36讲之齐橙《专业知识的魅力与运用》</h1><ul><li>接受知识是人类的本能，人都有好奇心呀，前提是能听懂。</li><li>能产生新鲜感的：创意、文字、思想、专业知识。</li><li>专业知识的作用：1作为推动剧情的主要金手指；2作为小说的卖点；3提高小说逼格</li><li>专业纹不太重（zhong），专业知识是用来点缀故事的。不需要多，只要读者意识到主角牛逼就行了。</li></ul><h1 id="36讲之千幻冰云"><a href="#36讲之千幻冰云" class="headerlink" title="36讲之千幻冰云"></a>36讲之千幻冰云</h1><p>出版影视版权拓展</p><ul><li>台湾连载是6~7万字一集，所以这么多字梳理就要有一个不错的中期目标被完成，20万字左右有一个大目标被完成。</li><li>影视要考虑成本问题，都市和清宫剧比较成本低，但清宫剧也被打了。</li></ul><h1 id="36讲之唐家三少"><a href="#36讲之唐家三少" class="headerlink" title="36讲之唐家三少"></a>36讲之唐家三少</h1><ul><li>坚持就是胜利（牛逼~~破音的那种）</li><li>想要提升写作水平最简单的方法，就是修改，但修改是枯燥的，很多人不愿意做。</li><li>先知先觉者经营，后者后觉者跟随，不知不觉者消费。</li></ul><h1 id="36讲之天堂羽"><a href="#36讲之天堂羽" class="headerlink" title="36讲之天堂羽"></a>36讲之天堂羽</h1><ul><li>题材风格自身能力方面，要扬长避短。</li></ul><h1 id="36讲之魏文成《人物和冲突》"><a href="#36讲之魏文成《人物和冲突》" class="headerlink" title="36讲之魏文成《人物和冲突》"></a>36讲之魏文成《人物和冲突》</h1><ul><li>人物特征靠故事表现，故事冲突要依附于人物塑造。</li><li>故事的主要内容是什么？是行为和互动。</li><li>不用太考虑人物性格局部的违和，通常这种小细节读者不会在意的，但整体大方向要把握好，主要性格要贯穿，偶尔反弹一下都不是事。</li><li>人物有三个维度的特征：1目标；2能力；3性格。</li><li>设置冲突的时候要注意，冲突最好能体现主角的能力。</li><li>性格通过对比产生，感情通过共同经历产生。</li></ul><h1 id="36讲之小米《开新书指导》"><a href="#36讲之小米《开新书指导》" class="headerlink" title="36讲之小米《开新书指导》"></a>36讲之小米《开新书指导》</h1><ul><li>开书时得给自己定位。</li><li>多看书。违禁不能写。重中之重，金手指要新颖。避免套路化。</li><li>玄幻，最重要的是金手指和升级体系。在没有想出金手指并基于金手指做好升级体系之前，不要一个劲想剧情，用处不大。</li><li>仙侠的骨头一般由两部分组成：1修仙主线2修炼体系。结合传统仙侠文套路，并有着全新金手指或幽默文风的新派仙侠，更容易出成绩。</li><li>都市，可以理解为现代世界背景下的玄幻。但是接地气是都市小说非常重要的一点。</li></ul><h1 id="36讲之心在流浪"><a href="#36讲之心在流浪" class="headerlink" title="36讲之心在流浪"></a>36讲之心在流浪</h1><ul><li>先找到自己适合并且也喜欢的风格。</li><li>可以看太监的书，撷取桥段，完善提高。</li></ul><h1 id="36讲之血红《细节刻画和代入感》"><a href="#36讲之血红《细节刻画和代入感》" class="headerlink" title="36讲之血红《细节刻画和代入感》"></a>36讲之血红《细节刻画和代入感》</h1><ul><li>小场面的描绘，仔细地刻画每一个人的细节、动作，乃至作息习惯，包括喜欢吃的喝的用的。</li><li>想象力有极限，读者代入也有极限。</li><li>一本书是否能代入，在于细节刻画的好坏，在于能否形成画面感。</li><li>什么是装逼，装逼就是用极其对立的行为，演绎主角的精神分裂。</li><li>其实我觉得他说的细节就是真实感了，人物真不真、世界真不真、组织形式真不真。</li></ul><h1 id="36讲之妖夜"><a href="#36讲之妖夜" class="headerlink" title="36讲之妖夜"></a>36讲之妖夜</h1><ul><li>代入感，读者代入主角，作者要代入整本书。</li><li>布局，也就是悬念，可以和高潮一样用反推法，，多误导读者，多次叠加悬念或者冲突。</li><li>玄幻小说要有完整的设定、世界观、力量体系、功法设定、宝物设定、地图设定，升级是主线。</li><li>副本其实是作者灌水的地方，可以让几个反派进去，虐一虐。</li><li>玄幻中，换地图一般会掉订阅，所以要提前铺垫。</li></ul><h1 id="36讲之月关"><a href="#36讲之月关" class="headerlink" title="36讲之月关"></a>36讲之月关</h1><ul><li>网络写手最重要的是讲故事的能力。</li><li>女性角色要塑造好，从一开始就要有所打算，需要一个什么样的女性角色，要达到什么目的或者说起到什么作用。女性角色有不依附于男主的一面，才能有特性，有灵魂。</li><li>男主三观要正，优柔寡断、当断不断、或者为了大义让自己女人牺牲的，都是很招人烦的。</li><li>配角不要脸谱化。</li><li>开头要么悬念，要么是出彩的故事。</li></ul><h1 id="36讲之庄毕凡"><a href="#36讲之庄毕凡" class="headerlink" title="36讲之庄毕凡"></a>36讲之庄毕凡</h1><p>​         异界全职业大师、万古至尊。</p><ul><li>他理解的装逼，其实就是制造反差。最简单的就是颠覆别人对主角的看法。</li><li>装逼得注意度，一个主角永远无敌的书读者是不太爱看的。</li></ul><h1 id="36讲之净无痕"><a href="#36讲之净无痕" class="headerlink" title="36讲之净无痕"></a>36讲之净无痕</h1><p>绝世武神，这些都是无线风的书，我感觉可能不适合我。</p><ul><li>当作者塑造了一个读者喜欢的女人后，读者会希望推倒，这是一种期待感，但是推完之后期待感就没了，所以轻易不能推。</li><li>仇恨也很容易塑造期待感，要报仇。一路热血就是一路期待感铺垫出来的，没有铺垫，就没有高潮和热血。拉仇恨很容易，一个很牛逼的人和主角发生了一点冲突，他说点蔑视的话就是拉仇恨了，当然有美女在会更好。</li><li>唐三的书会给主角提供一个舞台，舞台的期待感非常重要，就理解成玄幻里常见的各种比赛。可以在特定的时候点出舞台的存在，暗示读者，将来主角会登上这个舞台。击败对手的时候也一定要写出层次感、震撼感。</li><li>登上舞台之前要做好铺垫。</li><li>高潮，就是解决已经铺垫好的期待感。高潮一定要慢慢来，不要怕被读者说拖，要从多条线去拉足期待感。</li><li>一定要会掌控情绪。</li><li>要用反差，虐也要注意写好，用反差写。</li><li>可以尝试重叠高潮，如果觉得主角击败一个反派后还不够，可以立刻再出来一个反派背后的长老啥的在揍一顿</li></ul><h1 id="36讲之weid"><a href="#36讲之weid" class="headerlink" title="36讲之weid"></a>36讲之weid</h1><p>龙空创始人之一……</p><ul><li>类型化，要知道不同类型小说读者想看到什么。类型文学就是搭建起一个固定的舞台，作家要在程式化的表演中展现文学的独创性。</li><li>1成长2战斗3成就4情感，期待感要多重维度。</li><li>相较于玄幻，仙侠的期待感之一就是法宝，法宝要出彩。</li><li>打脸的本质是反击、获胜、得到赞美，构思人物和矛盾冲突时别太重复。</li><li>创新、风格、细节到位、高潮爽度处理得好，四点有一个好，就应该会不错。</li><li>大部分读者是靠作者的暗示来得到期待的。</li><li>遇到瓶颈低谷期的时候，可以写一些小副本的独立故事，牵扯别太多。</li></ul><h1 id="36讲之断桥残雪《现代修真和都市生活装逼》"><a href="#36讲之断桥残雪《现代修真和都市生活装逼》" class="headerlink" title="36讲之断桥残雪《现代修真和都市生活装逼》"></a>36讲之断桥残雪《现代修真和都市生活装逼》</h1><ul><li>现代修真一般走的是大隐隐于世的路线，走的时候低调装逼路线，所以主角职业选择最好是普通职业，或者作者自己熟悉或从事的职业。</li><li>装逼肯定要装，问题在于如何装好。</li><li>飞升后会写的很少，而且要提前铺垫。</li><li>期待感可以使用陪衬和对比。</li><li>打脸的时候，配角的反应要详细写（这个也算是学到了，很多大神都说过这点，没人赞叹就不爽了啊！）</li><li>装逼时要分人群装，就是不要一下子在所有熟人面前都装了……得把配角们留着，一个一个装给他们看。</li></ul><h1 id="36讲之傅啸尘《节奏》"><a href="#36讲之傅啸尘《节奏》" class="headerlink" title="36讲之傅啸尘《节奏》"></a>36讲之傅啸尘《节奏》</h1><ul><li>他的理解，节奏就是各个部分剧情的多寡。</li><li>升级不是目的，出风头才是王道。</li></ul><h1 id="36讲之格子里的夜晚《作者的自我训练历程》"><a href="#36讲之格子里的夜晚《作者的自我训练历程》" class="headerlink" title="36讲之格子里的夜晚《作者的自我训练历程》"></a>36讲之格子里的夜晚《作者的自我训练历程》</h1><p>啊，这个作者是之前那个猝死的……白金啊白金啊……这章比较高深感觉……</p><ul><li>要磨炼语感。</li><li>可以找一个作者的作品，截取一段，看明白内容，然后自己仿写，然后比较。</li><li>内容组织，要轻重缓急。</li><li>《异人傲世录》，大场面战斗的典范。</li><li>有书单，可以看。</li></ul><h1 id="36讲之虎神本尊《七情六欲之贪》"><a href="#36讲之虎神本尊《七情六欲之贪》" class="headerlink" title="36讲之虎神本尊《七情六欲之贪》"></a>36讲之虎神本尊《七情六欲之贪》</h1><ul><li>有句话说，贪婪是推进社会进步的一切动力。</li><li>贪按照佛家说法，包含七个方面，第一个方面叫做财，其实就是身外之物。</li><li>钱字的体现：1钱可通神；2钱权名三位一体；3取之有道；4木秀于林。</li><li>色，分为外在和内在，主要是讲怎么写女性的……外在分为本身和衣物配饰，内在一般网文里写三种：1伴侣、女神、知己，我理解后面讲的四种手段可以想成就是怎么让女性爱上主角呗：1布施，给她喜欢的；2爱语，说她喜欢听的；3利行，她关注的主角做到最棒，她遇到的困难主角帮忙漂亮解决；4同事，有相同的目标和事业，哪怕是一起逛街。</li></ul><h1 id="36讲之寂无《悟》"><a href="#36讲之寂无《悟》" class="headerlink" title="36讲之寂无《悟》"></a>36讲之寂无《悟》</h1><ul><li>写作最重要的是意境，要让自己身临其境。</li><li>文笔的灵魂也很重要。</li><li>制胜法宝：1封面图；2简介；3第一章的第一个字，第一个字我觉得夸张了，但是第一句话还是要领悟的。</li><li>第四点，就是悟，千万不要让其他人影响了你的意志、思想。</li><li>书最重要的是前面的一百万字。</li><li>一本书，主角的一个仇恨目标，写3~5w最多了。</li><li>一个超长篇，前期靠新意，中期靠情节，后期靠人物。越到后面人物越重要。——云中仙客</li></ul><h1 id="36讲之林海听涛《打脸与节奏》"><a href="#36讲之林海听涛《打脸与节奏》" class="headerlink" title="36讲之林海听涛《打脸与节奏》"></a>36讲之林海听涛《打脸与节奏》</h1><ul><li>打脸是一切网络小说的精髓和本质，没有打脸，就不是网文。</li><li>打脸是推动剧情的重要方式之一，在主角一遍遍的打脸中，等级提升了、剧情推动了、地图更换了……</li><li>主角太平淡、太中庸、太和善的话，天生会失去很多期待感。</li><li>读者们在看书的时候，并一定只是代入主角，他们会代入主角这一方的任何人。不同身份可以演变出不同的打脸剧情。比如主角团的一个配角和一个反派撕逼打赌，赌主角能不能怎么怎么样，那这时候再写主角做到了，也是一种打脸。《冠军之光》第一卷</li><li>打脸套路很简单，先压主角，调动读者的情绪和期待感，但压得不能太长，而且在压的同时还要暗示读者主角肯定会反击，这就是安全感。然后等大家恨不得主角马上把对方抽死的时候，设计一段打脸剧情，打脸就是高潮，高潮一定不能很快就过去，要拉长，要有人围观，要有人品头论足。</li><li>压抑主角不能太长，比起主角被欺负，读者更厌恶的是主角自暴自弃。</li><li>如果前期压抑得凶，那么后面打脸一定要更爽快，甚至不能用险胜这样的方式，要大胜，这时可以牺牲合理性。</li><li>空虚期可以用升级和爽点来交替，高潮和高潮之间，给读者一个期盼的点。</li><li>故事性也很重要，完全装逼打脸却没有故事，那是段子手。</li></ul><h1 id="36讲之南征《如何迎合读者》"><a href="#36讲之南征《如何迎合读者》" class="headerlink" title="36讲之南征《如何迎合读者》"></a>36讲之南征《如何迎合读者》</h1><ul><li>能迎合读者口味的作品，才更容易出头。</li><li>对学生党来说，最重要的是证明自己，喜欢热血。对上班族来说，更喜欢不需要努力就唾手可得的财富、权势、美色等，同时有了这些之后套门要纸醉金迷，然后施展抱负，上班族最爱的就是都市暧昧爽文。</li><li>节奏、亮点。</li><li>主角越惨，读者期待值就越高，当然这个惨是为了打脸准备的。惨是为了让读者同情主角，渴望主角变强，然后作者用最快的节奏完成升级，再打脸，就是在读者的渴望达到顶点时候让爽点爆发，让读者爽！相反，做不好就是虐主。</li><li>要充满正能量，这个正能量是指保护家人，保护兄弟，保护朋友！</li><li>爽、正能量、亮点、快节奏、金手指高、主角标签多，就是无限热文的典型特点。</li><li>坏人得寸进尺，好人一忍再忍，忍无可忍，无需再忍。</li><li>反派标签：自以为是、颠倒黑白、伪善、徇私枉法。</li><li>反派级别：1炮灰级，自以为是目中无人；2精英级，有实力自命不凡；3小BOSS，颠倒黑白，徇私枉法；4大Boss，邪恶的化身，幕后的黑手。</li></ul><h1 id="36讲之上山打老虎《以历史文谈网文剧情的处理》"><a href="#36讲之上山打老虎《以历史文谈网文剧情的处理》" class="headerlink" title="36讲之上山打老虎《以历史文谈网文剧情的处理》"></a>36讲之上山打老虎《以历史文谈网文剧情的处理》</h1><ul><li>面对的敌人要比自己高一点，但也不能高太多。</li><li>小说喜欢的就是反转，扮猪吃老虎。</li><li>大人物要留一点神秘感。</li></ul><h1 id="36讲之太一生水《如何写出玄幻的爽》"><a href="#36讲之太一生水《如何写出玄幻的爽》" class="headerlink" title="36讲之太一生水《如何写出玄幻的爽》"></a>36讲之太一生水《如何写出玄幻的爽》</h1><ul><li>要边写边学</li><li>高武类（就是玄幻修真）的爽点：1装逼打脸；2升级；3装备法宝功法等周边。</li><li>开篇要爽，爽法有很多，不一定要打脸的其实。比如万古至尊开头是装逼，不死武尊开头是打脸。装逼和打脸不一样。</li><li>写文也是写自己的文才好，让自己能够畅快的才是最好的。</li><li>网文也讲究笔力，比如武动的前几十章，一直在练级，但还有期待感。</li><li>开新书前要把老书重读一遍，知道哪里爽哪里不爽。</li><li>换地图要有大纲。</li><li>网文其实只有三种开篇，废柴，平庸，天才。</li><li>废柴的设定是为了成长为了期待，天才就是为了装逼。</li><li>没大纲，换地图后不知道干啥，只能用技巧上的东西拖延，比如冒出逗比反派来校长，然后主角打打打，就在打的过程中慢慢打开自己的思路。但这些都是小道。</li></ul><h1 id="36讲之霞飞双颊"><a href="#36讲之霞飞双颊" class="headerlink" title="36讲之霞飞双颊"></a>36讲之霞飞双颊</h1><ul><li>女配角的存在是为了衬托女主的，女配不能压过女主。</li><li>网文一句话：让看书的觉得这本书很屌，自己看了很爽，值得浪费时间去追，就成功了。</li></ul><h1 id="36讲之新杰《小白文套路写法》"><a href="#36讲之新杰《小白文套路写法》" class="headerlink" title="36讲之新杰《小白文套路写法》"></a>36讲之新杰《小白文套路写法》</h1><ul><li>无限小白文最大比例的人群：外出务工人员和学生群体。</li><li>章节末尾，不一定要有悬念，但尽量不要是完成态。</li><li>上架前卡点。</li><li>越级打架，小境界可以，大境界的话前期不要。</li><li>无线的都市，开篇给主角一个任务，但不要复仇、阴谋什么的，那太复杂了，要简单直白的，要一看就知道怎么发展的套路。</li><li>都市文的优劣，就是暧昧尺度的把握。</li><li>玄幻中其实并不需要太多的暧昧，玄幻的期待值不是暧昧。</li></ul><h1 id="36讲之妖月夜《略谈商业玄幻文的写法》"><a href="#36讲之妖月夜《略谈商业玄幻文的写法》" class="headerlink" title="36讲之妖月夜《略谈商业玄幻文的写法》"></a>36讲之妖月夜《略谈商业玄幻文的写法》</h1><p>不死武神，打脸。</p><ul><li>在开书时给自己定位</li><li>选择适合自己的开局</li><li>代入感</li><li>节奏</li><li>金手指开启后，实力的提升需要一个过程，这时候就可以写可爱的女孩子了。（像番茄就是专心写修炼，看哪种适合自己）</li><li>大冲突，需要好好架构。</li><li>拉冲突，写拉仇恨——升级——打脸的时候最好要写细纲。</li><li>写每个情节时，写好大纲方向：1这个情节主角有什么目标？要踩谁？2完成目标时，主角提升到什么实力，得到什么东西，在哪里得到？3在这个情节时和谁发生什么冲突？4什么时候爆发？主角凭借什么爆发？5这个情节又留下了什么伏笔给下个情节？这些都想好后，再想剧情情节。</li><li>目标引出情节，情节引出目标，不断循环衔接下去。</li></ul><h1 id="36讲之幽瞑摆渡者《一只活的运营谈选书》"><a href="#36讲之幽瞑摆渡者《一只活的运营谈选书》" class="headerlink" title="36讲之幽瞑摆渡者《一只活的运营谈选书》"></a>36讲之幽瞑摆渡者《一只活的运营谈选书》</h1><ul><li>第三方就是除去你签约网站以外所有能给你带来收益的网站合作方。</li><li>引入读者后再说读者留存率与付费转化率的问题。</li><li>字数多容易赚钱啊……字数多推荐成本小。</li><li>有创意，且开篇要点题。</li><li>全渠道还是都市占优势。</li><li>在本身网站60万字就知道能不能混出来，100万字可以在其他平台试验数据。</li></ul><h1 id="36讲之鱼人二代"><a href="#36讲之鱼人二代" class="headerlink" title="36讲之鱼人二代"></a>36讲之鱼人二代</h1><ul><li>读者黏度。</li><li>默默付出的女主比较讨喜。</li><li>都市文总结起来，就是亲戚出事、小弟出事、女主出事、兄弟出事，主角去一一解决，然后在解决中时不时点一下主线。</li></ul><h1 id="记录自己的经验"><a href="#记录自己的经验" class="headerlink" title="记录自己的经验"></a>记录自己的经验</h1><ul><li>开篇要单刀直入，少切换视角，把视角定格在主角身上，尽快进入获得金手指之后的变化和爽感。</li></ul>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;还是不甘心，下决心再给自己一个机会，好好学习总结。&lt;/p&gt;
&lt;p&gt;多看多写多想，才是王道。&lt;/p&gt;
    
    </summary>
    
      <category term="大杂烩" scheme="http://yoursite.com/categories/%E5%A4%A7%E6%9D%82%E7%83%A9/"/>
    
    
      <category term="小说教程" scheme="http://yoursite.com/tags/%E5%B0%8F%E8%AF%B4%E6%95%99%E7%A8%8B/"/>
    
  </entry>
  
  <entry>
    <title>未完待续-肆</title>
    <link href="http://yoursite.com/2020/01/24/%E6%9C%AA%E5%AE%8C%E5%BE%85%E7%BB%AD-%E8%82%86/"/>
    <id>http://yoursite.com/2020/01/24/未完待续-肆/</id>
    <published>2020-01-24T10:06:08.000Z</published>
    <updated>2020-01-24T10:09:16.519Z</updated>
    
    <content type="html"><![CDATA[<p>（生活之余，闲暇记录，禁止粘贴复制转载，谢谢配合。本文写于2017年1月21日，2018年5月31日上传保存。）</p><p>姑娘她撑伞走过，红墙与白瓦蹉跎。</p><p>这一秒纷纷扰扰，看起来像你像我。</p><p>明明心事良多。</p><p>却，从不说。</p><a id="more"></a><p>……</p><p>时间过得真快，此刻我站在2020春节的门槛上，回望过去，从考研考场出来坐在地铁上对身旁女友说“迎接新开始”的画面还历历在目，转眼竟然已经离开那座百年学府半年了。</p><p>但这次不谈时间，这次要发发牢骚。</p><p>翻了翻过去一年的朋友圈，有些是看的电影，有些是玩的游戏，有些是发的照片，还有一些，是我的不开心。</p><p>所有的加起来，便是我的生活。</p><p>2月24日，能与人言者无二三；</p><p>5月20日，死一会儿；</p><p>5月30日，现实比小说更狗血；</p><p>6月14日，唉；</p><p>11月13日，（比较长，不贴了）；</p><p>12月11日，要少说话哦，因为说了也没人鸟你哦；</p><p>1月19日，唉……</p><p>……</p><p>不开心的具体缘由已经有些记不清，但应该大体不差，除了5月20日的不开心是因为毕业论文暂缓，其余的，大概都是同一件事。</p><p>但其实也没什么好提的，说多了便是矫情，XS会说“你怎么娘们唧唧”的。</p><p>ZY说“痛苦和快乐其实都不能共享，成年人就是要戛然而止”。</p><p>我说“行吧，反正我也不是很在意”。</p><p>好吧，那就戛然而止。</p><p>……</p><p>女朋友说“你是假的不在意，你是真的不开心”。</p><p>……</p><p>2019年上半年的主题是“毕业”，却差点没能毕业，5月20日的不开心便来自于毕业答辩的暂缓决议。</p><p>说起来那天还是校庆，花团锦簇里我要暂缓，可能这就是学校对我的依依不舍？</p><p>好在后来还是顺利毕业了，和室友大佬们拍了不少或正经或不正经的照片，发在朋友圈里呼朋引赞，那是517离别前最后的高潮。</p><p>离校的那天，父母来接我，站在校门口红色泼墨大字下合影，大学的六年时光如影过脑，终是抓不住回不去。</p><p>阳光正好，适合出发。</p><p>2013年的夏天，这里是我午后梦里最青葱的向往；</p><p>2019年的夏天，这里是我收拾行囊要告别的地方。</p><p>幸好，也甚好。</p><p>……</p><p>上半年的时候被JXD带着重新入了阴阳师的坑，直到今天，距离全图还是遥遥无期，却乐此不疲。</p><p>写这话的时候，刚刚在新年概率up活动里抽到了新SSR式神鬼童丸，这是第一次在式神的专属活动里抽到新式神，兴许是2020年的好兆头。</p><p>CX大佬入坑晚，但大佬毕竟是大佬，加上欧皇体质加成，全图鉴进度已经远超本菜鸡，希望新的一年里能早日全图，继续带我躺着刷魂十魂土魂王……</p><p>新的一年，希望大家都能圆圆满满。</p><p>……</p><p>后来我便去了上海，坐在呼啸的高铁上时，我怀里抱着新买的双肩包，看着窗外飞速后退的风景。列车上的人们在低声交谈着，我侧耳轻听，想听些别人的故事，想写些自己的新故事。</p><p>工作的新鲜感来得快，去得也快，好在团队里多有逗比，欢声笑语不断，成长中依旧收获良多。</p><p>工作刚开始的时候，和517大佬们时不时会开视频分享工作初期的感受。</p><p>讲究生活质量的WKS的背景是豪华公寓，似乎还有敞亮的落地窗（管他呢反正我觉得有），他掐着时间，依然雷打不动地按点和家里打电话，按点拉屎；</p><p>公司安排住宿的WJY的背景是酒店标间，下班很晚，窗外却依旧灯火通明，隔壁床的大哥似乎老是没下班回来；</p><p>能活就行的ZSK的背景……好吧他没什么背景，一间房不知道有没有十平米，开了视频就让我们帮看看他两边额头上的头发是不是没了。</p><p>WKS说一看见你们就好像还在宿舍，你们还是那么憨批……</p><p>我们说你才是憨批，你全家都憨批。</p><p>他没有反驳，因为已经回头给女神回消息了。</p><p>哦对，他这一年舔到了……不，追到了女神，于是在拉屎和打电话之后又多了项活动。</p><p>真是应有尽有，不愧人生赢家。</p><p>还有JXD，人帅能力强，gay气不可挡，一切都很棒，只是说好的找我玩，不要再放我鸽子了！还有回消息的时候请快点。</p><p>新的一年，希望大家都赚更多钱。</p><p>……</p><p>下半年的时候，陆续和在同在上海的老友们聚了一波，面对面的时候我才感觉好像时间也没走太多。</p><p>今年出国求学的SYY和CSB回来了，准备搞金融的他们在陆家嘴找了工作，以后就是投资界的大鳄，走上人生巅峰不是梦，赚钱记得带上我呀……</p><p>不过当我看着坐在对面吃起东西和以前毫无变化的SYY时，上面的话到了嘴边又有些犹豫，要不还是等她先吃饱再说吧！</p><p>XS也有了女朋友！</p><p>真真不可思议，震惊朋友圈！</p><p>那可是能问出妹子“你喜欢什么小动物？冰原狼吗？”的24K纯男。</p><p>到底是什么样的妹子能接下这样的攻势……</p><p>我百思不得其解。</p><p>不说了，XS已经扛着刀来了。</p><p>……</p><p>二公子时不时半夜发个骚，发个消息说声“想我雨哥了”。</p><p>我觉得他一点也不想。</p><p>要不怎么为什么我回他之后就没有下文了？</p><p>男人都是大猪蹄子。</p><p>……</p><p>某追星女孩FXT千里迢迢从北京来到上海看演唱会，在昆山的TM和我自然要给她个面子，出来恰了一顿饭，看了一场《误杀》。</p><p>好像和她们也很久没见了，还记得几年前在南理工超市货架前霸气请我吃薯片的FXT，以及坐在湖边一起聊天时的TM。</p><p>现在FXT在北京，明年也要毕业了；TM已经在昆山工作了好些年。</p><p>“这次的活动打了吗？”TM摊开手机，画面上正在挂机打阴阳师，那时正好有个活动，平安京沦陷，大岳丸得意洋洋。</p><p>“没有啊。”我说，“太肝了，想弃了。”</p><p>“要弃坑？那有没有什么碎片可以薅？”她眼里发光。</p><p>“……”我掏出手机，“那我还是继续肝吧！”</p><p>“这次活动很好打的，我帮你，分分钟给你领个SSR！”</p><p>“真的假的？”我来了兴致，凑了过去。</p><p>一旁的FXT眨了眨眼睛，吸了口奶茶，一脸懵逼：“你俩在说啥？”</p><p>新的一年，都要开心。</p><p>……</p><p>没想到ZY也来了上海，更没想到的是差一点她也要来阅文实习，HR晚通知了一天，于是她去了头条。</p><p>想想若是她来了阅文做产品实习生，而且她要去的海外产品线和我们还有不少业务对接，不禁不寒而栗……还好还好。</p><p>本来她刚来上海的第一天就要约饭的，但一直有事一直错过，真正约上饭已经过了一个月，一个月里……这小姑娘还分了手。</p><p>没办法，该她请的客这次自然得换成我请，更何况她还愿意坐一个半小时地铁来浦东！我请！随便吃！</p><p>不管是杭州还是上海，好像都喜欢下雨，这次约饭也是下雨。</p><p>下雨便不好辨认方向，何况我平日里也不爱出门，于是在饶了一丢丢路之后，她的暴脾气上来了……</p><p>“雨哥你真的是路痴。”她突然站住，很不满，很笃定。</p><p>“我……我真不是啊！我不得先从商场里出来走到马路边才能找到路吗！”</p><p>“可刚刚明明直走就到了，你非要绕一大圈到后面的马路上！”她瞪我，“你这个傻逼。”</p><p>“……”</p><p>听听，这是女孩子说的话吗？</p><p>“我……我只是想先找到马路再辨认方向……”</p><p>“别说了，气得我胃疼。”</p><p>“……”</p><p>行吧没法讲道理，但说好给我的生日礼物是不是年后该送过来了。</p><p>新的一年，希望你继续前进。</p><p>……</p><p>TY生日的时候约了一波海底捞，也有段时间没和小胖子见面了，她现在也忙了，也不再是之前那个有事没事会发疯找我乱扯的人了。</p><p>过年回家，她年初二就要回去了。</p><p>她说“要赚钱诶，要生活诶”。</p><p>是的，要赚钱生活呀。</p><p>但我还是会偶尔怀念以前的时光。</p><p>那时候小胖子风一样从天桥上奔下来，把什么烦恼忧愁都抛在身后。</p><p>新的一年，要减肥呀哈哈。</p><p>……</p><p>后来还和去年一起在阅文实习的QZJ约了次饭，她因为一些原因刚刚毕业，租了房子，是个一室户。</p><p>朝南的阳台上阳光很好，让我这个住了半年朝北卧室没晒到太阳的人很是羡慕，明年我也想换个朝南的房间，想迎着太阳坐在桌前，写些什么。</p><p>她要去华为了，听说加班很严重，要注意身体。</p><p>……</p><p>FJY也要毕业了，但她有些迷糊，不知道未来想做什么，感情上出了问题，回消息也很慢。</p><p>昨天整理照片时看到当初考研时她截的图，我发给她，她说“这不都考上了吗？”</p><p>是啊，现在的路都是以前的自己拼命努力走出来的，那就好好走下去。</p><p>回家前和她吃了次烧烤，等座的时候下了几局五子棋，想起当初高中在作文本上画线下棋的时光，慨从中来，便不留情地赢了她几局。谁让她老不回我消息？</p><p>于是她不玩了，又聊了些电影，回家可以补补，看看别人的路，有时候对自己也有帮助。</p><p>新的一年，要做好选择。</p><p>……</p><p>一直想约一直加班的BLY也很久没见了，来年有空再约，要少加班呀。</p><p>……</p><p>今年是工作的第一年，却是我和她在一起的很多年。</p><p>这些年里她陪我从本科到硕士，也走过了江浙沪。</p><p>这些年老是惹她生气，想想我真是没什么出息。</p><p>但好在她没离开我，她养的猫也不再对我大喊大叫。</p><p>给她买了些过年的礼物，希望她能够开心。</p><p>但……她还想要个包！</p><p>哇，我都买了那么多东西啦，你竟然还想要包！</p><p>我抠抠索索的神经瞬间就反抗起来了！</p><p>“要不要呢？”她眨巴着眼睛，仰着头看我，一脸可怜。</p><p>我……</p><p>好挣扎啊……</p><p>好痛苦啊……</p><p>你不要对我卖萌，没有用的！</p><p>哇，不行了……</p><p>但尊严还是要有的……</p><p>“这样，你扔骰子！扔三次！三次里有两次大于等于五点，我就买！”</p><p>这是我最后的倔强！</p><p>“好！”她竟然答应了，不过我觉得她可能算不清这里面的概率……</p><p>“二”</p><p>“五”</p><p>“五”</p><p>……</p><p>“冲鸭！”</p><p>好吧好吧，天意如此，买咯。</p><p>反正就算你扔不出来，我也会买的。</p><p>……</p><p>“才不信。”你大概会这么说。</p><p>但这个是真的，信我呀。</p><p>……</p><p>每年过年回家本来都该聚一聚玩一玩的，但今年新型冠状病毒肺炎疫情严重，口罩供不应求，估计是难了。</p><p>只希望大家都能平安过年，愿祖国早日渡过这劫。</p><p>……</p><p>事情很多，很多时候我都想说。</p><p>但好像没人想听，或者是我永远不知道说着说着哪一句就没有了回应。</p><p>那会让我很不开心。</p><p>去年我在《叁》里面说有愿意跟你分享的人是幸福的，但今年可能没那么幸福。</p><p>这也让我很不开心。</p><p>而且疫情严重，不要和我呆在一起太久。</p><p>所以这一篇便这样吧，系列里最短的一篇，我也克制自己几乎没写感慨。</p><p>WYZ说：“你说了没人理，你不说也没人理啊（摊手）。”</p><p>好吧好像很有道理，我的感觉，她还是很懂。</p><p>新的一年，希望自己少说话。</p><p>希望明年还有新故事可以写。</p><p>【END】</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;（生活之余，闲暇记录，禁止粘贴复制转载，谢谢配合。本文写于2017年1月21日，2018年5月31日上传保存。）&lt;/p&gt;
&lt;p&gt;姑娘她撑伞走过，红墙与白瓦蹉跎。&lt;/p&gt;
&lt;p&gt;这一秒纷纷扰扰，看起来像你像我。&lt;/p&gt;
&lt;p&gt;明明心事良多。&lt;/p&gt;
&lt;p&gt;却，从不说。&lt;/p&gt;
    
    </summary>
    
      <category term="余记" scheme="http://yoursite.com/categories/%E4%BD%99%E8%AE%B0/"/>
    
    
      <category term="日志" scheme="http://yoursite.com/tags/%E6%97%A5%E5%BF%97/"/>
    
  </entry>
  
  <entry>
    <title>leveldb源码学习5-dbformat和comparator</title>
    <link href="http://yoursite.com/2019/12/11/leveldb%E6%BA%90%E7%A0%81%E5%AD%A6%E4%B9%A05-dbformat%E5%92%8Ccomparator/"/>
    <id>http://yoursite.com/2019/12/11/leveldb源码学习5-dbformat和comparator/</id>
    <published>2019-12-11T13:55:37.000Z</published>
    <updated>2019-12-11T13:56:23.383Z</updated>
    
    <content type="html"><![CDATA[<h1 id="简述"><a href="#简述" class="headerlink" title="简述"></a>简述</h1><p>LevelDB第五篇笔记，主要解析dbformat.h/cc两个文件，这两个文件主要是定义了一些数据库在存储方面使用到的一些结构。</p><p>依旧采取先注释再分析重点的方式。</p><a id="more"></a><h1 id="dbformat"><a href="#dbformat" class="headerlink" title="dbformat"></a>dbformat</h1><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><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">ifndef</span> STORAGE_LEVELDB_DB_DBFORMAT_H_</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> STORAGE_LEVELDB_DB_DBFORMAT_H_</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"leveldb/comparator.h"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"leveldb/db.h"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"leveldb/filter_policy.h"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"leveldb/slice.h"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"leveldb/table_builder.h"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"util/coding.h"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"util/logging.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> leveldb &#123;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// config域名里定义了一组常量，用户可能希望通过选项设置这些参数。</span></span><br><span class="line"><span class="keyword">namespace</span> config &#123;</span><br><span class="line"><span class="comment">// LevelDB的级数</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">const</span> <span class="keyword">int</span> kNumLevels = <span class="number">7</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 当命中这么多文件时，Level-0开始压缩</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">const</span> <span class="keyword">int</span> kL0_CompactionTrigger = <span class="number">4</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Level-0文件个数的软限制，到达这个限制时LevelDB会降低写速度。</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">const</span> <span class="keyword">int</span> kL0_SlowdownWritesTrigger = <span class="number">8</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Level-0文件个数的最大限制，到达这个限制时会停止写。</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">const</span> <span class="keyword">int</span> kL0_StopWritesTrigger = <span class="number">12</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 如果一个新压缩的memtable没有产生重叠，就将其推到的最大级别。</span></span><br><span class="line"><span class="comment">// 我们尝试将级别提升到2来避免相对昂贵的level 0 =&gt; level 1压缩，并避免一些昂贵的manifile操作。</span></span><br><span class="line"><span class="comment">// 我们并不会一直推到最大级别，因为如果相同的key空间被覆盖的话，就会产生大量的磁盘空间浪费。</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">const</span> <span class="keyword">int</span> kMaxMemCompactLevel = <span class="number">2</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 在迭代期间读取的数据样本之间的字节数的近似差距，1MB</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">const</span> <span class="keyword">int</span> kReadBytesPeriod = <span class="number">1048576</span>;</span><br><span class="line"></span><br><span class="line">&#125;  <span class="comment">// namespace config</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">InternalKey</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 该枚举类被编码成InternalKey的最后组成部分。</span></span><br><span class="line"><span class="comment">// 不要改变该枚举类的值，它们被嵌入到磁盘上的数据结构中。</span></span><br><span class="line"><span class="keyword">enum</span> ValueType &#123; kTypeDeletion = <span class="number">0x0</span>, kTypeValue = <span class="number">0x1</span> &#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// kValueTypeForSeek定义了当构建一个ParsedInternalKey对象时应该被传入用来寻找一个特定sequence number的ValueType值。</span></span><br><span class="line"><span class="comment">// 因为我们会递增排列sequence number，并且ValueType会被嵌入到intervalkey中的sequence number的低8位中，所以我们需要最高编号的ValueType，而不是最低的。</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">const</span> ValueType kValueTypeForSeek = kTypeValue;</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="keyword">uint64_t</span> SequenceNumber;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 我们留出了低位8bit为空，以便sequence和valuetype能够包装在一起成为一个64bits。</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">const</span> SequenceNumber kMaxSequenceNumber = ((<span class="number">0x1</span>ull &lt;&lt; <span class="number">56</span>) - <span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">//解析过的InternalKey，即包含user_key、SequenceNumber和ValueType三个字段</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">ParsedInternalKey</span> &#123;</span></span><br><span class="line">  Slice user_key;</span><br><span class="line">  SequenceNumber sequence;</span><br><span class="line">  ValueType type;</span><br><span class="line"></span><br><span class="line">  ParsedInternalKey() &#123;&#125;  <span class="comment">// 出于速率考虑，故意没有初始化</span></span><br><span class="line">  ParsedInternalKey(<span class="keyword">const</span> Slice&amp; u, <span class="keyword">const</span> SequenceNumber&amp; seq, ValueType t)</span><br><span class="line">      : user_key(u), sequence(seq), type(t) &#123;&#125;</span><br><span class="line">  <span class="built_in">std</span>::<span class="function"><span class="built_in">string</span> <span class="title">DebugString</span><span class="params">()</span> <span class="keyword">const</span></span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 返回key编码后的长度，就是user_key的长度加上8个bytes（sequence和ValuType一共64bits）</span></span><br><span class="line"><span class="function"><span class="keyword">inline</span> size_t <span class="title">InternalKeyEncodingLength</span><span class="params">(<span class="keyword">const</span> ParsedInternalKey&amp; key)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> key.user_key.size() + <span class="number">8</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 将“key”的序列化结果附加到*result。</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">AppendInternalKey</span><span class="params">(<span class="built_in">std</span>::<span class="built_in">string</span>* result, <span class="keyword">const</span> ParsedInternalKey&amp; key)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 尝试将internal_key转成ParsedInternalKey，成功返回true，并将结果存在result中。</span></span><br><span class="line"><span class="comment">// 若失败，返回false，result处于未定义状态。</span></span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">ParseInternalKey</span><span class="params">(<span class="keyword">const</span> Slice&amp; internal_key, ParsedInternalKey* result)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 返回InternalKey中的user_key部分</span></span><br><span class="line"><span class="comment">// 一个InternalKey其实就是user_key+sequence+valtype，后两者一共占8个byte</span></span><br><span class="line"><span class="function"><span class="keyword">inline</span> Slice <span class="title">ExtractUserKey</span><span class="params">(<span class="keyword">const</span> Slice&amp; internal_key)</span> </span>&#123;</span><br><span class="line">  assert(internal_key.size() &gt;= <span class="number">8</span>);</span><br><span class="line">  <span class="keyword">return</span> Slice(internal_key.data(), internal_key.size() - <span class="number">8</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 一个供InternalKey使用的比较器，该比较器使用一个特定的比较器来比较userkey部分并通过减少序sequenceNumber来断开连接。</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">InternalKeyComparator</span> :</span> <span class="keyword">public</span> Comparator &#123;</span><br><span class="line"> <span class="keyword">private</span>:</span><br><span class="line">  <span class="keyword">const</span> Comparator* user_comparator_;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span>:</span><br><span class="line">  explicit InternalKeyComparator(const Comparator* c) : user_comparator_(c) &#123;&#125;</span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> <span class="keyword">const</span> <span class="keyword">char</span>* <span class="title">Name</span><span class="params">()</span> <span class="keyword">const</span></span>;</span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> <span class="keyword">int</span> <span class="title">Compare</span><span class="params">(<span class="keyword">const</span> Slice&amp; a, <span class="keyword">const</span> Slice&amp; b)</span> <span class="keyword">const</span></span>;</span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">FindShortestSeparator</span><span class="params">(<span class="built_in">std</span>::<span class="built_in">string</span>* start,</span></span></span><br><span class="line"><span class="function"><span class="params">                                     <span class="keyword">const</span> Slice&amp; limit)</span> <span class="keyword">const</span></span>;</span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">FindShortSuccessor</span><span class="params">(<span class="built_in">std</span>::<span class="built_in">string</span>* key)</span> <span class="keyword">const</span></span>;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">const</span> Comparator* <span class="title">user_comparator</span><span class="params">()</span> <span class="keyword">const</span> </span>&#123; <span class="keyword">return</span> user_comparator_; &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">int</span> <span class="title">Compare</span><span class="params">(<span class="keyword">const</span> InternalKey&amp; a, <span class="keyword">const</span> InternalKey&amp; b)</span> <span class="keyword">const</span></span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 将InternalKey转换成Userkeys的过滤策略包装器</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">InternalFilterPolicy</span> :</span> <span class="keyword">public</span> FilterPolicy &#123;</span><br><span class="line"> <span class="keyword">private</span>:</span><br><span class="line">  <span class="keyword">const</span> FilterPolicy* <span class="keyword">const</span> user_policy_;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span>:</span><br><span class="line">  explicit InternalFilterPolicy(const FilterPolicy* p) : user_policy_(p) &#123;&#125;</span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> <span class="keyword">const</span> <span class="keyword">char</span>* <span class="title">Name</span><span class="params">()</span> <span class="keyword">const</span></span>;</span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">CreateFilter</span><span class="params">(<span class="keyword">const</span> Slice* keys, <span class="keyword">int</span> n, <span class="built_in">std</span>::<span class="built_in">string</span>* dst)</span> <span class="keyword">const</span></span>;</span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> <span class="keyword">bool</span> <span class="title">KeyMayMatch</span><span class="params">(<span class="keyword">const</span> Slice&amp; key, <span class="keyword">const</span> Slice&amp; filter)</span> <span class="keyword">const</span></span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// LevelDB应该将internal-key封装在InternalKey中而不是原生的string中，这样我们才不至于错误地使用字符串比较而不是InternalKeyComparator。</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">InternalKey</span> &#123;</span></span><br><span class="line"> <span class="keyword">private</span>:</span><br><span class="line">  <span class="built_in">std</span>::<span class="built_in">string</span> rep_;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span>:</span><br><span class="line">  InternalKey() &#123;&#125;  <span class="comment">// rep_留空来表示无效</span></span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 构造InternalKey，最终rep_的结构为 user_key + ( s&lt;&lt;8 | t)</span></span><br><span class="line">  InternalKey(<span class="keyword">const</span> Slice&amp; user_key, SequenceNumber s, ValueType t) &#123;</span><br><span class="line">    AppendInternalKey(&amp;rep_, ParsedInternalKey(user_key, s, t));</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 把s赋值给rep_</span></span><br><span class="line">  <span class="function"><span class="keyword">void</span> <span class="title">DecodeFrom</span><span class="params">(<span class="keyword">const</span> Slice&amp; s)</span> </span>&#123; rep_.assign(s.data(), s.size()); &#125;</span><br><span class="line">  <span class="comment">//就是返回rep_</span></span><br><span class="line">  <span class="function">Slice <span class="title">Encode</span><span class="params">()</span> <span class="keyword">const</span> </span>&#123;</span><br><span class="line">    assert(!rep_.empty());</span><br><span class="line">    <span class="keyword">return</span> rep_;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 调用ExtractUserKey方法提取rep_中的userkey部分，其实就是抛弃后面8个bye</span></span><br><span class="line">  <span class="function">Slice <span class="title">user_key</span><span class="params">()</span> <span class="keyword">const</span> </span>&#123; <span class="keyword">return</span> ExtractUserKey(rep_); &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 其实就是reset方法吧</span></span><br><span class="line">  <span class="function"><span class="keyword">void</span> <span class="title">SetFrom</span><span class="params">(<span class="keyword">const</span> ParsedInternalKey&amp; p)</span> </span>&#123;</span><br><span class="line">    rep_.clear();</span><br><span class="line">    AppendInternalKey(&amp;rep_, p);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">void</span> <span class="title">Clear</span><span class="params">()</span> </span>&#123; rep_.clear(); &#125;</span><br><span class="line"></span><br><span class="line">  <span class="built_in">std</span>::<span class="function"><span class="built_in">string</span> <span class="title">DebugString</span><span class="params">()</span> <span class="keyword">const</span></span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 其实就是比较两个string</span></span><br><span class="line"><span class="keyword">inline</span> <span class="keyword">int</span> InternalKeyComparator::Compare(<span class="keyword">const</span> InternalKey&amp; a,</span><br><span class="line">                                          <span class="keyword">const</span> InternalKey&amp; b) <span class="keyword">const</span> &#123;</span><br><span class="line">  <span class="keyword">return</span> Compare(a.Encode(), b.Encode());</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 尝试把InternalKey转换成ParsedInternalKey，感觉就是InternalKey类构造函数的逆操作</span></span><br><span class="line"><span class="function"><span class="keyword">inline</span> <span class="keyword">bool</span> <span class="title">ParseInternalKey</span><span class="params">(<span class="keyword">const</span> Slice&amp; internal_key,</span></span></span><br><span class="line"><span class="function"><span class="params">                             ParsedInternalKey* result)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">const</span> <span class="keyword">size_t</span> n = internal_key.size();</span><br><span class="line">  <span class="keyword">if</span> (n &lt; <span class="number">8</span>) <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">  <span class="keyword">uint64_t</span> num = DecodeFixed64(internal_key.data() + n - <span class="number">8</span>);</span><br><span class="line">  <span class="keyword">unsigned</span> <span class="keyword">char</span> c = num &amp; <span class="number">0xff</span>;</span><br><span class="line">  result-&gt;sequence = num &gt;&gt; <span class="number">8</span>;</span><br><span class="line">  result-&gt;type = <span class="keyword">static_cast</span>&lt;ValueType&gt;(c);</span><br><span class="line">  result-&gt;user_key = Slice(internal_key.data(), n - <span class="number">8</span>);</span><br><span class="line">  <span class="keyword">return</span> (c &lt;= <span class="keyword">static_cast</span>&lt;<span class="keyword">unsigned</span> <span class="keyword">char</span>&gt;(kTypeValue));</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// A helper class useful for DBImpl::Get()</span></span><br><span class="line"><span class="comment">// db内部在为查找memtable/sstable方便，包装使用的key结构，保存有userkey与SequnceNumber/ValueType dump在内存的数据。</span></span><br><span class="line"><span class="comment">// 对memtable 进行lookup时使用 [start,end], 对sstable lookup时使用[kstart, end]。</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">LookupKey</span> &#123;</span></span><br><span class="line"> <span class="keyword">public</span>:</span><br><span class="line">  <span class="comment">// 初始化this指针用来查找和某个特定sequence相关的快照中的user_key。</span></span><br><span class="line">  LookupKey(<span class="keyword">const</span> Slice&amp; user_key, SequenceNumber sequence);</span><br><span class="line"></span><br><span class="line">  LookupKey(<span class="keyword">const</span> LookupKey&amp;) = <span class="keyword">delete</span>;</span><br><span class="line">  LookupKey&amp; <span class="keyword">operator</span>=(<span class="keyword">const</span> LookupKey&amp;) = <span class="keyword">delete</span>;</span><br><span class="line"></span><br><span class="line">  ~LookupKey();</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 返回一个MemTable中适合用来lookup的key</span></span><br><span class="line">  <span class="function">Slice <span class="title">memtable_key</span><span class="params">()</span> <span class="keyword">const</span> </span>&#123; <span class="keyword">return</span> Slice(start_, end_ - start_); &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// Return an internal key (suitable for passing to an internal iterator)</span></span><br><span class="line">  <span class="function">Slice <span class="title">internal_key</span><span class="params">()</span> <span class="keyword">const</span> </span>&#123; <span class="keyword">return</span> Slice(kstart_, end_ - kstart_); &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// Return the user key</span></span><br><span class="line">  <span class="function">Slice <span class="title">user_key</span><span class="params">()</span> <span class="keyword">const</span> </span>&#123; <span class="keyword">return</span> Slice(kstart_, end_ - kstart_ - <span class="number">8</span>); &#125;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span>:</span><br><span class="line">  <span class="comment">// 以以下格式构建数组：</span></span><br><span class="line">  <span class="comment">//    klength  varint32               &lt;-- start_</span></span><br><span class="line">  <span class="comment">//    userkey  char[klength]          &lt;-- kstart_</span></span><br><span class="line">  <span class="comment">//    tag      uint64</span></span><br><span class="line">  <span class="comment">//                                    &lt;-- end_</span></span><br><span class="line">  <span class="comment">// 该数组是一个MemTable key.</span></span><br><span class="line">  <span class="comment">// 以“userkey”开头的后缀可以用作InternalKey.</span></span><br><span class="line">  <span class="keyword">const</span> <span class="keyword">char</span>* start_;</span><br><span class="line">  <span class="keyword">const</span> <span class="keyword">char</span>* kstart_;</span><br><span class="line">  <span class="keyword">const</span> <span class="keyword">char</span>* end_;</span><br><span class="line">  <span class="keyword">char</span> space_[<span class="number">200</span>];  <span class="comment">// 避免为短key分配</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">inline</span> LookupKey::~LookupKey() &#123;</span><br><span class="line">  <span class="keyword">if</span> (start_ != space_) <span class="keyword">delete</span>[] start_;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">&#125;  <span class="comment">// namespace leveldb</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span>  <span class="comment">// STORAGE_LEVELDB_DB_DBFORMAT_H_</span></span></span><br></pre></td></tr></table></figure><p>头文件中一些方法的实现都在对应的源文件中，如下：<br><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><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// dbformat.cc</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"db/dbformat.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"port/port.h"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"util/coding.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> leveldb &#123;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 将sequence和ValueType整合到一个无符号64位整型中</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> uint64_t <span class="title">PackSequenceAndType</span><span class="params">(<span class="keyword">uint64_t</span> seq, ValueType t)</span> </span>&#123;</span><br><span class="line">  assert(seq &lt;= kMaxSequenceNumber);</span><br><span class="line">  assert(t &lt;= kValueTypeForSeek);</span><br><span class="line">  <span class="keyword">return</span> (seq &lt;&lt; <span class="number">8</span>) | t;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 将key追加到result中</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">AppendInternalKey</span><span class="params">(<span class="built_in">std</span>::<span class="built_in">string</span>* result, <span class="keyword">const</span> ParsedInternalKey&amp; key)</span> </span>&#123;</span><br><span class="line">  result-&gt;append(key.user_key.data(), key.user_key.size());</span><br><span class="line">  PutFixed64(result, PackSequenceAndType(key.sequence, key.type));</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 该方法就是把ParsedInternalKey打印一下，用来debug</span></span><br><span class="line"><span class="built_in">std</span>::<span class="built_in">string</span> ParsedInternalKey::DebugString() <span class="keyword">const</span> &#123;</span><br><span class="line">  <span class="keyword">char</span> buf[<span class="number">50</span>];</span><br><span class="line">  <span class="built_in">snprintf</span>(buf, <span class="keyword">sizeof</span>(buf), <span class="string">"' @ %llu : %d"</span>, (<span class="keyword">unsigned</span> <span class="keyword">long</span> <span class="keyword">long</span>)sequence,</span><br><span class="line">           <span class="keyword">int</span>(type));</span><br><span class="line">  <span class="built_in">std</span>::<span class="built_in">string</span> result = <span class="string">"'"</span>;</span><br><span class="line">  <span class="comment">// EscapeString方法将返回一个便于人阅读的格式的string</span></span><br><span class="line">  result += EscapeString(user_key.ToString());</span><br><span class="line">  result += buf;</span><br><span class="line">  <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 尝试把InternalKey转成ParsedInternalKey再调输出debug信息</span></span><br><span class="line"><span class="comment">// 转换失败的时候，则会在result里添加bad信息，并直接调用EscapeString方法</span></span><br><span class="line"><span class="built_in">std</span>::<span class="built_in">string</span> InternalKey::DebugString() <span class="keyword">const</span> &#123;</span><br><span class="line">  <span class="built_in">std</span>::<span class="built_in">string</span> result;</span><br><span class="line">  ParsedInternalKey parsed;</span><br><span class="line">  <span class="keyword">if</span> (ParseInternalKey(rep_, &amp;parsed)) &#123;</span><br><span class="line">    result = parsed.DebugString();</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    result = <span class="string">"(bad)"</span>;</span><br><span class="line">    result.append(EscapeString(rep_));</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> <span class="keyword">char</span>* InternalKeyComparator::Name() <span class="keyword">const</span> &#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="string">"leveldb.InternalKeyComparator"</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">int</span> InternalKeyComparator::Compare(<span class="keyword">const</span> Slice&amp; akey, <span class="keyword">const</span> Slice&amp; bkey) <span class="keyword">const</span> &#123;</span><br><span class="line">  <span class="comment">// 按照user_key升序，sequence_number和value_type降序，其中user_key升序使用用户提供的比较器</span></span><br><span class="line">  <span class="keyword">int</span> r = user_comparator_-&gt;Compare(ExtractUserKey(akey), ExtractUserKey(bkey));</span><br><span class="line">  <span class="keyword">if</span> (r == <span class="number">0</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> <span class="keyword">uint64_t</span> anum = DecodeFixed64(akey.data() + akey.size() - <span class="number">8</span>);</span><br><span class="line">    <span class="keyword">const</span> <span class="keyword">uint64_t</span> bnum = DecodeFixed64(bkey.data() + bkey.size() - <span class="number">8</span>);</span><br><span class="line">    <span class="keyword">if</span> (anum &gt; bnum) &#123;</span><br><span class="line">      r = <span class="number">-1</span>;</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (anum &lt; bnum) &#123;</span><br><span class="line">      r = +<span class="number">1</span>;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> r;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 接下来两个方法到用到的地方再看下</span></span><br><span class="line"><span class="keyword">void</span> InternalKeyComparator::FindShortestSeparator(<span class="built_in">std</span>::<span class="built_in">string</span>* start,</span><br><span class="line">                                                  <span class="keyword">const</span> Slice&amp; limit) <span class="keyword">const</span> &#123;</span><br><span class="line">  <span class="comment">// 尝试缩短key的用户部分</span></span><br><span class="line">  Slice user_start = ExtractUserKey(*start);</span><br><span class="line">  Slice user_limit = ExtractUserKey(limit);</span><br><span class="line">  <span class="built_in">std</span>::<span class="function"><span class="built_in">string</span> <span class="title">tmp</span><span class="params">(user_start.data(), user_start.size())</span></span>;</span><br><span class="line">  user_comparator_-&gt;FindShortestSeparator(&amp;tmp, user_limit);</span><br><span class="line">  <span class="keyword">if</span> (tmp.size() &lt; user_start.size() &amp;&amp;</span><br><span class="line">      user_comparator_-&gt;Compare(user_start, tmp) &lt; <span class="number">0</span>) &#123;</span><br><span class="line">    <span class="comment">// User key has become shorter physically, but larger logically.</span></span><br><span class="line">    <span class="comment">// Tack on the earliest possible number to the shortened user key.</span></span><br><span class="line">    PutFixed64(&amp;tmp,</span><br><span class="line">               PackSequenceAndType(kMaxSequenceNumber, kValueTypeForSeek));</span><br><span class="line">    assert(<span class="keyword">this</span>-&gt;Compare(*start, tmp) &lt; <span class="number">0</span>);</span><br><span class="line">    assert(<span class="keyword">this</span>-&gt;Compare(tmp, limit) &lt; <span class="number">0</span>);</span><br><span class="line">    start-&gt;swap(tmp);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">void</span> InternalKeyComparator::FindShortSuccessor(<span class="built_in">std</span>::<span class="built_in">string</span>* key) <span class="keyword">const</span> &#123;</span><br><span class="line">  Slice user_key = ExtractUserKey(*key);</span><br><span class="line">  <span class="built_in">std</span>::<span class="function"><span class="built_in">string</span> <span class="title">tmp</span><span class="params">(user_key.data(), user_key.size())</span></span>;</span><br><span class="line">  user_comparator_-&gt;FindShortSuccessor(&amp;tmp);</span><br><span class="line">  <span class="keyword">if</span> (tmp.size() &lt; user_key.size() &amp;&amp;</span><br><span class="line">      user_comparator_-&gt;Compare(user_key, tmp) &lt; <span class="number">0</span>) &#123;</span><br><span class="line">    <span class="comment">// user_key逻辑上变大而实际上变小了。</span></span><br><span class="line">    <span class="comment">// 将尽可能早的数字添加到缩短的user_key上。【TODO】</span></span><br><span class="line">    PutFixed64(&amp;tmp,</span><br><span class="line">               PackSequenceAndType(kMaxSequenceNumber, kValueTypeForSeek));</span><br><span class="line">    assert(<span class="keyword">this</span>-&gt;Compare(*key, tmp) &lt; <span class="number">0</span>);</span><br><span class="line">    key-&gt;swap(tmp);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> <span class="keyword">char</span>* InternalFilterPolicy::Name() <span class="keyword">const</span> &#123; <span class="keyword">return</span> user_policy_-&gt;Name(); &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">void</span> InternalFilterPolicy::CreateFilter(<span class="keyword">const</span> Slice* keys, <span class="keyword">int</span> n,</span><br><span class="line">                                        <span class="built_in">std</span>::<span class="built_in">string</span>* dst) <span class="keyword">const</span> &#123;</span><br><span class="line">  <span class="comment">// 我们依赖table.cc中的代码不会在意我们修改keys[]这样的一个实时。【TODO】</span></span><br><span class="line">  Slice* mkey = <span class="keyword">const_cast</span>&lt;Slice*&gt;(keys);</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; n; i++) &#123;</span><br><span class="line">    mkey[i] = ExtractUserKey(keys[i]);</span><br><span class="line">    <span class="comment">// TODO(sanjay): Suppress dups?</span></span><br><span class="line">  &#125;</span><br><span class="line">  user_policy_-&gt;CreateFilter(keys, n, dst);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">bool</span> InternalFilterPolicy::KeyMayMatch(<span class="keyword">const</span> Slice&amp; key, <span class="keyword">const</span> Slice&amp; f) <span class="keyword">const</span> &#123;</span><br><span class="line">  <span class="keyword">return</span> user_policy_-&gt;KeyMayMatch(ExtractUserKey(key), f);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 根据user_key和sequence_number构造出LookupKey</span></span><br><span class="line">LookupKey::LookupKey(<span class="keyword">const</span> Slice&amp; user_key, SequenceNumber s) &#123;</span><br><span class="line">  <span class="keyword">size_t</span> usize = user_key.size();</span><br><span class="line">  <span class="keyword">size_t</span> needed = usize + <span class="number">13</span>;  <span class="comment">// 一个保守估计</span></span><br><span class="line">  <span class="keyword">char</span>* dst;</span><br><span class="line">  <span class="keyword">if</span> (needed &lt;= <span class="keyword">sizeof</span>(space_)) &#123;</span><br><span class="line">    dst = space_;</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    dst = <span class="keyword">new</span> <span class="keyword">char</span>[needed];</span><br><span class="line">  &#125;</span><br><span class="line">  start_ = dst;</span><br><span class="line">  dst = EncodeVarint32(dst, usize + <span class="number">8</span>);</span><br><span class="line">  kstart_ = dst;</span><br><span class="line">  <span class="built_in">memcpy</span>(dst, user_key.data(), usize);</span><br><span class="line">  dst += usize;</span><br><span class="line">  EncodeFixed64(dst, PackSequenceAndType(s, kValueTypeForSeek));</span><br><span class="line">  dst += <span class="number">8</span>;</span><br><span class="line">  end_ = dst;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">&#125;  <span class="comment">// namespace leveldb</span></span><br></pre></td></tr></table></figure></p><h1 id="Comparator"><a href="#Comparator" class="headerlink" title="Comparator"></a>Comparator</h1><p>简单看一下比较器的头文件和实现文件。<br><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></pre></td><td class="code"><pre><span class="line"><span class="comment">//comparator.h</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">ifndef</span> STORAGE_LEVELDB_INCLUDE_COMPARATOR_H_</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> STORAGE_LEVELDB_INCLUDE_COMPARATOR_H_</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;string&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"leveldb/export.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> leveldb &#123;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Slice</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 比较器提供sstable或者database中key的排序方法。</span></span><br><span class="line"><span class="comment">// 一个比较器的实现必须是线程安全的，因为leveldb可能会同时从多个线程调用比较器的方法。</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">LEVELDB_EXPORT</span> <span class="title">Comparator</span> &#123;</span></span><br><span class="line">  <span class="keyword">public</span>:</span><br><span class="line">  <span class="keyword">virtual</span> ~Comparator();</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 三种比较结果:</span></span><br><span class="line">  <span class="comment">//   &lt; 0 iff "a" &lt; "b",</span></span><br><span class="line">  <span class="comment">//   == 0 iff "a" == "b",</span></span><br><span class="line">  <span class="comment">//   &gt; 0 iff "a" &gt; "b"</span></span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> <span class="keyword">int</span> <span class="title">Compare</span><span class="params">(<span class="keyword">const</span> Slice&amp; a, <span class="keyword">const</span> Slice&amp; b)</span> <span class="keyword">const</span> </span>= <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 比较器的名字，用来检查比较器能不能match上（比如数据库创建时使用的名字和后来使用的不一致）</span></span><br><span class="line">  <span class="comment">//</span></span><br><span class="line">  <span class="comment">// 如果比较器实的实现改变了并且会造成任何多个key的相关顺序改变，那客户端就应该换一个新名字。</span></span><br><span class="line">  <span class="comment">//</span></span><br><span class="line">  <span class="comment">// 以'level.'开头的名字被保留，客户端不要使用</span></span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> <span class="keyword">const</span> <span class="keyword">char</span>* <span class="title">Name</span><span class="params">()</span> <span class="keyword">const</span> </span>= <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 高级方法：它们用于减少索引块等内部数据结构的空间需求。</span></span><br><span class="line">  <span class="comment">// 如果*start &lt; limit，改变*start变成一个短字符串[start,limit)</span></span><br><span class="line">  <span class="comment">// 简单的比较器实现可能不会改变*start并直接返回</span></span><br><span class="line">  <span class="comment">// 比如，一个什么也不做的实现也是可以的</span></span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">FindShortestSeparator</span><span class="params">(<span class="built_in">std</span>::<span class="built_in">string</span>* start,</span></span></span><br><span class="line"><span class="function"><span class="params">                                     <span class="keyword">const</span> Slice&amp; limit)</span> <span class="keyword">const</span> </span>= <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 改变*key变成一个更短但&gt;=*key的短字符串</span></span><br><span class="line">  <span class="comment">// 简单的比较器实现可能不会改变*key并直接返回</span></span><br><span class="line">  <span class="comment">// 比如，一个什么也不做的实现也是可以的</span></span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">FindShortSuccessor</span><span class="params">(<span class="built_in">std</span>::<span class="built_in">string</span>* key)</span> <span class="keyword">const</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 返回一个内置的使用字典序的比较器</span></span><br><span class="line"><span class="comment">// 返回结果仍然是这个模块的属性，不能删除。</span></span><br><span class="line"><span class="function">LEVELDB_EXPORT <span class="keyword">const</span> Comparator* <span class="title">BytewiseComparator</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line">&#125;  <span class="comment">// namespace leveldb</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span>  <span class="comment">// STORAGE_LEVELDB_INCLUDE_COMPARATOR_H_</span></span></span><br></pre></td></tr></table></figure></p><p>其中几个方法的实现如下，其实实现文件是Comparator类的一个内置子类，就是上面头文件最后出现的BytewiseComparator：<br><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;algorithm&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;cstdint&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;string&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"leveldb/comparator.h"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"leveldb/slice.h"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"util/logging.h"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"util/no_destructor.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> leveldb &#123;</span><br><span class="line"></span><br><span class="line">Comparator::~Comparator() &#123;&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> &#123;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">BytewiseComparatorImpl</span> :</span> <span class="keyword">public</span> Comparator &#123;</span><br><span class="line"> <span class="keyword">public</span>:</span><br><span class="line">  BytewiseComparatorImpl() &#123;&#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">//比较器名字，可见果然用了level.做前缀</span></span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> <span class="keyword">const</span> <span class="keyword">char</span>* <span class="title">Name</span><span class="params">()</span> <span class="keyword">const</span> </span>&#123; <span class="keyword">return</span> <span class="string">"leveldb.BytewiseComparator"</span>; &#125;</span><br><span class="line">  <span class="comment">//比较</span></span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> <span class="keyword">int</span> <span class="title">Compare</span><span class="params">(<span class="keyword">const</span> Slice&amp; a, <span class="keyword">const</span> Slice&amp; b)</span> <span class="keyword">const</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> a.compare(b);</span><br><span class="line">  &#125;</span><br><span class="line">    </span><br><span class="line">  <span class="comment">//获得大于start但小于limit的最小值</span></span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">FindShortestSeparator</span><span class="params">(<span class="built_in">std</span>::<span class="built_in">string</span>* start,</span></span></span><br><span class="line"><span class="function"><span class="params">                                     <span class="keyword">const</span> Slice&amp; limit)</span> <span class="keyword">const</span> </span>&#123;</span><br><span class="line">    <span class="comment">// 找到公共前缀的长度</span></span><br><span class="line">    <span class="keyword">size_t</span> min_length = <span class="built_in">std</span>::min(start-&gt;size(), limit.size());</span><br><span class="line">    <span class="keyword">size_t</span> diff_index = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">while</span> ((diff_index &lt; min_length) &amp;&amp;</span><br><span class="line">           ((*start)[diff_index] == limit[diff_index])) &#123;</span><br><span class="line">      diff_index++;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (diff_index &gt;= min_length) &#123;</span><br><span class="line">      <span class="comment">// 如果一个字符串是另一个字符串的前缀，则不做改变</span></span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      <span class="comment">//很奇特的一段逻辑，将较小的字符串的最后一位+1，并去掉后面的字符</span></span><br><span class="line">      <span class="comment">//这时才回头看上面dbformat.cc文件中的那句注释“user_key逻辑上变大而实际上变小了。”，就理解意思了。</span></span><br><span class="line">      <span class="comment">//逻辑上变大：因为字符串最后的字母+1了，比如'b'变成了'a'，那么在字典序中就靠前了一些，变大了一些</span></span><br><span class="line">      <span class="comment">//实际上变小：字符串长度变短了</span></span><br><span class="line">      <span class="comment">//比如传入的参数是"abcg"和"abe"，那运行后"abe"还是"abe"，但"abcd"已经变成了"abd"</span></span><br><span class="line">      <span class="keyword">uint8_t</span> diff_byte = <span class="keyword">static_cast</span>&lt;<span class="keyword">uint8_t</span>&gt;((*start)[diff_index]);</span><br><span class="line">      <span class="keyword">if</span> (diff_byte &lt; <span class="keyword">static_cast</span>&lt;<span class="keyword">uint8_t</span>&gt;(<span class="number">0xff</span>) &amp;&amp;</span><br><span class="line">          diff_byte + <span class="number">1</span> &lt; <span class="keyword">static_cast</span>&lt;<span class="keyword">uint8_t</span>&gt;(limit[diff_index])) &#123;</span><br><span class="line">        (*start)[diff_index]++;</span><br><span class="line">        start-&gt;resize(diff_index + <span class="number">1</span>);</span><br><span class="line">        assert(Compare(*start, limit) &lt; <span class="number">0</span>);</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 找到第一个可以递增的字符，递增它，然后去掉后面的字符</span></span><br><span class="line">  <span class="comment">// 获得比start大的最小值</span></span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">FindShortSuccessor</span><span class="params">(<span class="built_in">std</span>::<span class="built_in">string</span>* key)</span> <span class="keyword">const</span> </span>&#123;</span><br><span class="line">    <span class="comment">// 找到第一个可以递增的字符</span></span><br><span class="line">    <span class="keyword">size_t</span> n = key-&gt;size();</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">size_t</span> i = <span class="number">0</span>; i &lt; n; i++) &#123;</span><br><span class="line">      <span class="keyword">const</span> <span class="keyword">uint8_t</span> byte = (*key)[i];</span><br><span class="line">      <span class="keyword">if</span> (byte != <span class="keyword">static_cast</span>&lt;<span class="keyword">uint8_t</span>&gt;(<span class="number">0xff</span>)) &#123;</span><br><span class="line">        (*key)[i] = byte + <span class="number">1</span>;</span><br><span class="line">        key-&gt;resize(i + <span class="number">1</span>);</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// *key 是0xff，保留。</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;;</span><br><span class="line">&#125;  <span class="comment">// namespace</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//static单例</span></span><br><span class="line"><span class="function"><span class="keyword">const</span> Comparator* <span class="title">BytewiseComparator</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  <span class="keyword">static</span> NoDestructor&lt;BytewiseComparatorImpl&gt; singleton;</span><br><span class="line">  <span class="keyword">return</span> singleton.get();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">&#125;  <span class="comment">// namespace leveldb</span></span><br></pre></td></tr></table></figure></p>]]></content>
    
    <summary type="html">
    
      &lt;h1 id=&quot;简述&quot;&gt;&lt;a href=&quot;#简述&quot; class=&quot;headerlink&quot; title=&quot;简述&quot;&gt;&lt;/a&gt;简述&lt;/h1&gt;&lt;p&gt;LevelDB第五篇笔记，主要解析dbformat.h/cc两个文件，这两个文件主要是定义了一些数据库在存储方面使用到的一些结构。&lt;/p&gt;
&lt;p&gt;依旧采取先注释再分析重点的方式。&lt;/p&gt;
    
    </summary>
    
      <category term="职业学习" scheme="http://yoursite.com/categories/%E8%81%8C%E4%B8%9A%E5%AD%A6%E4%B9%A0/"/>
    
    
      <category term="leveldb" scheme="http://yoursite.com/tags/leveldb/"/>
    
  </entry>
  
  <entry>
    <title>基金进阶笔记</title>
    <link href="http://yoursite.com/2019/12/09/%E5%9F%BA%E9%87%91%E8%BF%9B%E9%98%B6%E7%AC%94%E8%AE%B0/"/>
    <id>http://yoursite.com/2019/12/09/基金进阶笔记/</id>
    <published>2019-12-09T13:15:16.000Z</published>
    <updated>2020-01-20T14:34:12.742Z</updated>
    
    <content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>本篇笔记也是记录关于基金的一些学习笔记。</p><a id="more"></a><h1 id="2012-12-09"><a href="#2012-12-09" class="headerlink" title="2012/12/09"></a>2012/12/09</h1><p>单一资产的风险和收益一般是正相关的。</p><p>马考维茨投资组合有效边界模型。</p><h2 id="非系统性风险"><a href="#非系统性风险" class="headerlink" title="非系统性风险"></a>非系统性风险</h2><ul><li>企业经营风险，经营不善。</li><li>企业财务风险，无力偿还到期债务。</li><li>行业风险，比如三聚氰胺。</li></ul><h2 id="系统性风险"><a href="#系统性风险" class="headerlink" title="系统性风险"></a>系统性风险</h2><ul><li>市场风险</li><li>利率风险</li></ul><p>通过正确的资产配置，才能获取与风险相匹配的更高回报。</p><h2 id="组合"><a href="#组合" class="headerlink" title="组合"></a>组合</h2><p>可以利用投资品的“相关性”来做组合，两个投资标的的关系有正相关、负相关和不相关三种。</p><p>可以利用同一市场不同投资品之间一定程度的负相关性，来降低风险，提高收益。也可以通过找到与中国相关性低的市场，来实现有效的资产配置。</p><h2 id="全球资产配置"><a href="#全球资产配置" class="headerlink" title="全球资产配置"></a>全球资产配置</h2><p>一万块实现全球资产配置。</p><p>四招，也就是接下来的学习：</p><ol><li>全球股票配置法</li><li>升级版股债平衡法</li><li>网络策略投资法，赚到股价波动的利润，赚取中短期收益。</li><li>进阶投资者的心态</li></ol><h2 id="如何成为一名进阶的投资者"><a href="#如何成为一名进阶的投资者" class="headerlink" title="如何成为一名进阶的投资者"></a>如何成为一名进阶的投资者</h2><ol><li>学会接受风险</li><li>没有完美的投资方法，只有不断进步的思考</li></ol><h1 id="2019-12-10"><a href="#2019-12-10" class="headerlink" title="2019/12/10"></a>2019/12/10</h1><p>宽基指数：代表整个市场的走势</p><p>行业指数：帮助我们投资优秀行业</p><p>策略指数：帮助我们挑出市场上的优秀股票</p><p>QDII指数：代表各类海外市场</p><p>随着股市的发展，指数的种类越来越多，挑选股票的方法也越来越复杂。</p><p>三步认清一只指数</p><ol><li>确认指数的样本空间，就是范围</li><li>确认选样方法，就是筛选方法</li><li>确认加权方式</li></ol><h1 id="2019-12-11"><a href="#2019-12-11" class="headerlink" title="2019/12/11"></a>2019/12/11</h1><p>宽基指数是在整个是场内进行选股，投资他们可以获得市场的平均收益。</p><p>超越市场平均收益——策略指数。</p><p>在宽基指数的基础上，再加上策略因子，就成了策略指数。</p><h2 id="有效的策略因子"><a href="#有效的策略因子" class="headerlink" title="有效的策略因子"></a>有效的策略因子</h2><ol><li>规模，小盘股长期来看比大盘股回报高。</li><li>价值，价格低于价值的股票长期来看比贵的股票收益高。</li><li>低波动，总体波动较小的股票长期表现会更好。</li><li>红利，分红多的股票长期回报更高。</li><li>质量，质地好的、优秀公司的股票，长期回报更好。</li><li>动量，这个因子认为过去涨的股票将来还会继续涨。</li></ol><p>上证红利指数、中证红利指数、深圳红利指数三个比较是红利指数中比较重要的，基本代表了A股中红利指数的走势情况。</p><p>全收益指数包括股票的价格上涨和分红收益。</p><h2 id="红利指数的高收益"><a href="#红利指数的高收益" class="headerlink" title="红利指数的高收益"></a>红利指数的高收益</h2><p>好价格买好公司。</p><p>中证红利指数会在每年的12月份根据股息率做一次调仓。</p><h1 id="2015-12-16"><a href="#2015-12-16" class="headerlink" title="2015/12/16"></a>2015/12/16</h1><p>选对行业更赚钱——行业指数</p><p>行业指数就是在某一个特定行业内挑选成份股，指数内公司全都出自同一个行业。</p><p>一级行业分类：</p><ol><li>能源行业</li><li>材料行业</li><li>工业行业</li><li>可选消费行业</li><li>必需消费行业</li><li>医药行业</li><li>金融行业</li><li>信息行业</li><li>电信行业</li><li>公共事业</li></ol><p>这十个行业都有对应的中证指数。</p><p>两个方法判断一个行业未来能不能持续赚钱：</p><ol><li>人们的需求是否稳定，只有需求稳定，才能够促进行业不断挣到钱。</li><li>参考国外成熟市场的经验，比如美股。</li></ol><p>强周期行业一般包括金融、地产、煤炭、钢铁等，但并不是所有的强周期性行业都适合投资，因为很难判断他们的周期。</p><p>金融行业下面的证券行业周期性明显且容易判断，周期性体现在牛熊交替的时候。</p><p>熊市：新开户的人数很少，成交量也很少，证券行业的收入自然而然就少。</p><p>牛市：大量的人涌进股市，开户的人数和成交量飙升，收入自然水涨船高。</p><p>所以只要会给证券行业估值，能判断股票市场的牛熊，就能获取可观的收益。</p><h1 id="2019-12-17"><a href="#2019-12-17" class="headerlink" title="2019/12/17"></a>2019/12/17</h1><p>QDII基金，是专门投资国外市场的。</p><p>海外市场</p><p>海外市场可以分为两大类，一类是新兴市场，一类是成熟市场。（A股也算是新兴市场）</p><p>要找和A股相关性低的，要选成熟市场。</p><p>原因：</p><ol><li>因为新兴市场的国家和成熟市场的国家，他们的经济基础不一样，所以发展速度也不同步；</li><li>新兴市场和成熟市场的经济周期不同，投资者对两类市场的预期不一样，这就会导致股市出现不同的涨跌情况。</li></ol><p>成熟市场还有波动性更小、风险相对更小的优势，因为成熟市场成立时间长，专业投资者占比高。</p><p>换手率：指在一定时间内市场中股票转手买卖的频率，换手率越高，说明买卖越频繁，股价也就越容易波动。</p><p>QDII基金是指在一国境内设立，经该国有关部门批准从事境外证券市场的股票、债券等有价证券业务的证券投资基金。</p><h1 id="2019-12-24"><a href="#2019-12-24" class="headerlink" title="2019/12/24"></a>2019/12/24</h1><p>预测投资收益率——博格公式估值法</p><p>约翰博格，指数基金之父。</p><p>股市长期回报率 = 投资回报率 + 投机回报率 = 初始投资时刻的股息率 + 投资期内的盈利增长率 + 投资期内的市盈率变化率</p><p>博格认为，投资一组股票的收益有两个重要的来源，一个是经济，一个是情绪。</p><p>经济就是指一家公司实实在在的盈利，可以把它称为投资回报。</p><p>情绪是指投资者的买卖交易，可以称为投机回报。</p><p>投资回报 = 初始投资时刻的股息率 + 投资期内的盈利增长率</p><p>投机回报率 = 投资期内的市盈率变化率</p><p>投资一只指数基金的收益率大约等于博格公式的计算结果。</p><p>理杏仁。</p><h1 id="2019-12-29"><a href="#2019-12-29" class="headerlink" title="2019/12/29"></a>2019/12/29</h1><p>指数基金那么多，怎么没买才好？</p><p>指数基金配置方法</p><p>目标：实现稳健的高收益。</p><p>后卫：主要起防守作用，保证我们稳健地获取市场的平均收益。比如宽基指数。50%。</p><p>中锋：既防守又进攻，在后卫的基础上获取一定的超额收益。比如策略指数和海外指数。30%</p><p>前锋：主要负责获取超额收益，比如行业指数。20%</p><p>但在我们实际的投资过程中，并不是三种都需要。</p><h2 id="后卫"><a href="#后卫" class="headerlink" title="后卫"></a>后卫</h2><p>在选择后卫队员时，可以把A股市场的大小盘指数都配齐全。宽基指数配置大原则：一半大盘股+一半小盘股。</p><h2 id="中锋"><a href="#中锋" class="headerlink" title="中锋"></a>中锋</h2><p>大部分策略指数很难界定它的风格是大盘还是中小盘。</p><p>策略指数投15%，看长投温度估值，处于低估区域中的指数选1~2只。</p><p>海外指数选低估的一只就好了。</p><h2 id="前锋"><a href="#前锋" class="headerlink" title="前锋"></a>前锋</h2><p>行业指数。</p><p>消费、医药、证券以及互联网。</p><p>也是看估值，选低估的一个就好。</p><h1 id="2020-1-1"><a href="#2020-1-1" class="headerlink" title="2020/1/1"></a>2020/1/1</h1><p>一次性搞定所有债券基金</p><p>债券的本质：是机构公开向大家借钱并承诺还本付息的一种凭证。</p><ol><li>政府债券：政府像我们借钱的凭证，国债和地方债（市政债券），风险低收益也比较低。</li><li>金融机构债券，风险居中，收益居中。</li><li>企业债券，指企业向我们借钱的凭证，风险较高收益也较高。</li></ol><p>债券基金分类：</p><ol><li>纯债基金，全部投资债券</li><li>偏债基金，至少80%的资金投资债券</li></ol><h2 id="纯债基金"><a href="#纯债基金" class="headerlink" title="纯债基金"></a>纯债基金</h2><p>要看四个方面：</p><ol><li>历史综合评价，晨星网的晨星评级</li><li>成立时间，要大于5年</li><li>基金规模，不要小于5亿</li><li>分析纯债基金持有的债券类型和每种类型的债券占比，挑选风险更低的。建议优先选择持有国债和金融机构债券占比在20%以上的。</li></ol><h2 id="偏债基金"><a href="#偏债基金" class="headerlink" title="偏债基金"></a>偏债基金</h2><p>优点</p><ol><li>相对于纯债基金，偏债基金可以在牛市中博取更大的收益</li><li>相对于股票基金，偏债基金在熊市中往往可以有更小的下跌幅度，属于进可攻退可守的基金</li></ol><p>偏债基金最关键的一步要看基金经理，要大于等于5年。</p><p>长期持有该基金的话，买后缀是A的会比B更划算。</p><h2 id="选择时机"><a href="#选择时机" class="headerlink" title="选择时机"></a>选择时机</h2><p>在市场利率的高的时候买入债券基金，再在市场利率低的时候卖出，就能实现低买高卖。</p><p>市场利率可以参考10年期的国债利率。</p><p>当前市场利率大于3.5%时，就买入，小于3%时，就卖出。</p><p>英为财情网站可以查10年期国债收益率。</p><h1 id="2020-1-2"><a href="#2020-1-2" class="headerlink" title="2020/1/2"></a>2020/1/2</h1><p>攻守兼备的投资利器——可转债基金</p><p>可转债投资占比比较高，一般在40%以上，有些甚至达到80%、90%以上。</p><p>有价值的投资品——经历过一个完整的牛熊市还表现优秀。</p><h2 id="什么是可转债"><a href="#什么是可转债" class="headerlink" title="什么是可转债"></a>什么是可转债</h2><p>全称是可转换公司债券，是上市公司发型的，在一定条件下可以被转换为公司股票的债券，它具有债性和股性的双重属性。</p><h2 id="可转债基金挑选"><a href="#可转债基金挑选" class="headerlink" title="可转债基金挑选"></a>可转债基金挑选</h2><ol><li>历史综合评价，看晨星网的晨星评级</li><li>历史回报率，可转债基金，更看重它保底的属性，最好选择历史收益大于0的</li><li>成立时间大于五年</li><li>规模不要小于5亿</li></ol><h2 id="什么时候买什么时候卖"><a href="#什么时候买什么时候卖" class="headerlink" title="什么时候买什么时候卖"></a>什么时候买什么时候卖</h2><p>市面上所有可转债的平均价格低于100元，可以买。</p><p>市面上所有可转债的平均价格高于130元，可以卖。</p><p>富投网。</p><h1 id="2020-1-7"><a href="#2020-1-7" class="headerlink" title="2020/1/7"></a>2020/1/7</h1><p>升级版股债平衡</p><p>稳定获得高收益的秘密：市场上的资金量是一定的，股票市场和债券市场通常是此消彼长的状态。</p><p>50:50股债平衡的配置方法也有缺点，会导致我们在估值较高的时候买入相对过多的股票类资产，在下跌时造成损失，而在估值低的时候又少买了股票类资产，上涨时收益又不够高。</p><p>升级版的股债平衡就是借助简投法的思想，根据市场估值确认资产的配比。</p><p>根据长投温度，中证全指的长投温度。</p><h1 id="2020-1-13"><a href="#2020-1-13" class="headerlink" title="2020/1/13"></a>2020/1/13</h1><p>波动的市场，网格祝你锁定收益</p><p>定投：坚持等到牛市到来，一定会收获颇丰。但即使知道，也很难做到。</p><p>客观来说，想要通过短线操作获取一些收益，这种想法无可厚非，因为这是天性。关键在于要正确的引导，如果可以正确引导及时满足天性，可以帮助我们更好地长期投资。</p><h2 id="网格策略"><a href="#网格策略" class="headerlink" title="网格策略"></a>网格策略</h2><p>网格策略就是在股市波动的情况下，将资金分成若干份，在交易之前设定好每份资金的买入卖出价，再严格执行，以获取收益的策略。</p><p>在设定买卖 价格时，每一分资金的买入价，是上一份资金的卖出价，首尾相连，不管价格如何波动，每份资金都能获取利润，所以称为网格策略。</p><p>对于单纯的上涨和下跌，网格策略都不太适用，一定要把它和定投策略相结合来降低风险。</p><p>一定要记住，网格策略是用来赚点小钱的，定投才是赚大钱的，定投为主，网格为辅。</p><p>网格策略上分配的资金一定不要超过股权类资产总投资金额的10%。</p><h2 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h2><p>首先得找到一个适合网格策略的交易品种，这要具备两个条件：</p><ol><li>交易品种不能死，最好选指数基金</li><li>品种的价格最好有较高波动，价格波动越强，触及买入卖出线的可能就越大、次数就越多，利润也就越多。通过看指数的波动率就可以判断了，120日波动率就可以。</li></ol><p>网格策略适合用场内基金，交易更方便，手续费也更低。</p><h1 id="2020-1-16"><a href="#2020-1-16" class="headerlink" title="2020/1/16"></a>2020/1/16</h1><p>网格策略</p><h2 id="找到网格最佳的投资时机"><a href="#找到网格最佳的投资时机" class="headerlink" title="找到网格最佳的投资时机"></a>找到网格最佳的投资时机</h2><p>就是交易品种的价格刚刚低于价值的时候，估值的方式有很多，简单的话可以用长投投温度衡量，当长投温度处于25~30度之间时就可以开始建立网格。</p><h2 id="模拟交易品种的最大跌幅"><a href="#模拟交易品种的最大跌幅" class="headerlink" title="模拟交易品种的最大跌幅"></a>模拟交易品种的最大跌幅</h2><p>最大跌幅的预估，能够了解自己对于亏损的承受能力。这样就可以根据自己对跌幅的容忍度，来设计网格的下限。</p><p>不同的交易品种会有不同的下跌幅度，一般来说，进入低估区域后的指数基金再往下跌的最大幅度会在40%左右，可以根据自己的风险偏好来定最后一格的买入价。</p><p>在投入相同资金的情况下，网格的数量越小，每格分到的资金就越多，每一网收割的收益也就越多。</p><p>跌破网格怎么办？</p><ol><li>如果还有富余的资金，再往下简历一个网格</li><li>加大长线策略的定投比例。</li></ol><p>网格大小在4%~10%之间比较合适，对于宽基指数，网格大小在4%~5%就可以，对于行业指数，则可以在7%~10%。</p><p>网格策略不是一个无风险获取高收益的策略，它的目的是安抚大家无处安放的交易欲望，为长期投资做辅助。</p><h1 id="2020-1-20"><a href="#2020-1-20" class="headerlink" title="2020/1/20"></a>2020/1/20</h1><p>进阶投资者的心态</p><h2 id="心理误区一"><a href="#心理误区一" class="headerlink" title="心理误区一"></a>心理误区一</h2><p>在接触到更多的策略之后，我们总会下意识地觉得，越复杂的策略越精准、越高级，能给我们带来更多的收益。</p><h3 id="正确想法"><a href="#正确想法" class="headerlink" title="正确想法"></a>正确想法</h3><p>世界上没有完美的投资策略，每个策略都有自己的优势和局限。</p><h2 id="心理误区二"><a href="#心理误区二" class="headerlink" title="心理误区二"></a>心理误区二</h2><p>在资产配置的时候，存在多个心理账户。</p><h2 id="正确想法-1"><a href="#正确想法-1" class="headerlink" title="正确想法"></a>正确想法</h2><p>单只基金或者单个投资品的盈利和亏损不重要，要关注的是整体资产的收益变化。投资组合赚钱才是最终目的。</p><h2 id="心理误区三"><a href="#心理误区三" class="headerlink" title="心理误区三"></a>心理误区三</h2><p>在投资这件充满不确定的事情中寻求确定的答案。</p><h3 id="正确想法-2"><a href="#正确想法-2" class="headerlink" title="正确想法"></a>正确想法</h3><p>不要纠结于短期的波动，不要计较短期的得失。接受投资的艺术性，接受市场的不稳定性，理解策略的原理，经过独立思考，找到适合自己的策略，坚定执行，耐心地等待，直到赢取最后的财富。</p><p>【END】</p>]]></content>
    
    <summary type="html">
    
      &lt;h1 id=&quot;前言&quot;&gt;&lt;a href=&quot;#前言&quot; class=&quot;headerlink&quot; title=&quot;前言&quot;&gt;&lt;/a&gt;前言&lt;/h1&gt;&lt;p&gt;本篇笔记也是记录关于基金的一些学习笔记。&lt;/p&gt;
    
    </summary>
    
      <category term="大杂烩" scheme="http://yoursite.com/categories/%E5%A4%A7%E6%9D%82%E7%83%A9/"/>
    
    
      <category term="理财投资" scheme="http://yoursite.com/tags/%E7%90%86%E8%B4%A2%E6%8A%95%E8%B5%84/"/>
    
  </entry>
  
  <entry>
    <title>leveldb源码学习4-varint</title>
    <link href="http://yoursite.com/2019/10/29/leveldb%E6%BA%90%E7%A0%81%E5%AD%A6%E4%B9%A04-varint/"/>
    <id>http://yoursite.com/2019/10/29/leveldb源码学习4-varint/</id>
    <published>2019-10-29T13:48:43.000Z</published>
    <updated>2019-12-11T13:56:24.439Z</updated>
    
    <content type="html"><![CDATA[<h1 id="简述"><a href="#简述" class="headerlink" title="简述"></a>简述</h1><p>这篇文章学习源码中util/coding.h和util/coding.cc文件，这两个文件主要介绍了leveldb中使用的编码方式，包括变长和不变长两种。</p><p>leveldb默认采用小端字节序存储，即低位字节排放在内存的低地址中。</p><p>这篇文章不能简单靠注释了，其中有一些编码算法可以仔细看一下。</p><a id="more"></a><h1 id="coding-h"><a href="#coding-h" class="headerlink" title="coding.h"></a>coding.h</h1><p>先简单看下头文件，添加些注释。<br><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></pre></td><td class="code"><pre><span class="line"><span class="comment">//</span></span><br><span class="line"><span class="comment">// Endian-neutral encoding（直译：尾数中和编码）:</span></span><br><span class="line"><span class="comment">// 首先，固定长度的数字用最低有效位编码</span></span><br><span class="line"><span class="comment">// 其次，leveldb支持可变长度的varint编码</span></span><br><span class="line"><span class="comment">// 字符串以varint格式的长度作为前缀进行编码</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">ifndef</span> STORAGE_LEVELDB_UTIL_CODING_H_</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> STORAGE_LEVELDB_UTIL_CODING_H_</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdint.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;string.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;string&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"leveldb/slice.h"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"port/port.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> leveldb &#123;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 以下Put...方法将value加到string中。</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">PutFixed32</span><span class="params">(<span class="built_in">std</span>::<span class="built_in">string</span>* dst, <span class="keyword">uint32_t</span> value)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">PutFixed64</span><span class="params">(<span class="built_in">std</span>::<span class="built_in">string</span>* dst, <span class="keyword">uint64_t</span> value)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">PutVarint32</span><span class="params">(<span class="built_in">std</span>::<span class="built_in">string</span>* dst, <span class="keyword">uint32_t</span> value)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">PutVarint64</span><span class="params">(<span class="built_in">std</span>::<span class="built_in">string</span>* dst, <span class="keyword">uint64_t</span> value)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">PutLengthPrefixedSlice</span><span class="params">(<span class="built_in">std</span>::<span class="built_in">string</span>* dst, <span class="keyword">const</span> Slice&amp; value)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 以下Get...从一个Slice的开头开始解析一个值，并且将input移动到解析之后的位置</span></span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">GetVarint32</span><span class="params">(Slice* input, <span class="keyword">uint32_t</span>* value)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">GetVarint64</span><span class="params">(Slice* input, <span class="keyword">uint64_t</span>* value)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">GetLengthPrefixedSlice</span><span class="params">(Slice* input, Slice* result)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 基于指针的变种GetVarint...</span></span><br><span class="line"><span class="comment">// 它们要么在*v中存储一个值并返回一个刚刚经过解析的值的指针，要么在出现错误时返回nullptr。这些例程只查看范围[p..limit-1]内的字节。</span></span><br><span class="line"><span class="function"><span class="keyword">const</span> <span class="keyword">char</span>* <span class="title">GetVarint32Ptr</span><span class="params">(<span class="keyword">const</span> <span class="keyword">char</span>* p, <span class="keyword">const</span> <span class="keyword">char</span>* limit, <span class="keyword">uint32_t</span>* v)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">const</span> <span class="keyword">char</span>* <span class="title">GetVarint64Ptr</span><span class="params">(<span class="keyword">const</span> <span class="keyword">char</span>* p, <span class="keyword">const</span> <span class="keyword">char</span>* limit, <span class="keyword">uint64_t</span>* v)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 返回v的varint32/varint64后的编码长度</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">VarintLength</span><span class="params">(<span class="keyword">uint64_t</span> v)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 低级的put方法，会把value字节写入字符缓冲区</span></span><br><span class="line"><span class="comment">// 要求：dst有足够的空间给value写。</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">EncodeFixed32</span><span class="params">(<span class="keyword">char</span>* dst, <span class="keyword">uint32_t</span> value)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">EncodeFixed64</span><span class="params">(<span class="keyword">char</span>* dst, <span class="keyword">uint64_t</span> value)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 低级的put方法，会把value字节写入字符缓冲区并且返回一个指向最后写入字符之后位置的指针。</span></span><br><span class="line"><span class="comment">// 要求：dst有足够的空间给value写。</span></span><br><span class="line"><span class="function"><span class="keyword">char</span>* <span class="title">EncodeVarint32</span><span class="params">(<span class="keyword">char</span>* dst, <span class="keyword">uint32_t</span> value)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">char</span>* <span class="title">EncodeVarint64</span><span class="params">(<span class="keyword">char</span>* dst, <span class="keyword">uint64_t</span> value)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 低级的get方法，直接从字符缓冲区中读取数据。没有任何边界检查。</span></span><br><span class="line"><span class="function"><span class="keyword">inline</span> uint32_t <span class="title">DecodeFixed32</span><span class="params">(<span class="keyword">const</span> <span class="keyword">char</span>* ptr)</span> </span>&#123;</span><br><span class="line">  <span class="comment">//小端存储</span></span><br><span class="line">  <span class="keyword">if</span> (port::kLittleEndian) &#123;</span><br><span class="line">    <span class="comment">// 加载原始字节</span></span><br><span class="line">    <span class="keyword">uint32_t</span> result;</span><br><span class="line">    <span class="built_in">memcpy</span>(&amp;result, ptr, <span class="keyword">sizeof</span>(result));  <span class="comment">// gcc将此优化成普通加载</span></span><br><span class="line">    <span class="keyword">return</span> result;</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> ((<span class="keyword">static_cast</span>&lt;<span class="keyword">uint32_t</span>&gt;(<span class="keyword">static_cast</span>&lt;<span class="keyword">unsigned</span> <span class="keyword">char</span>&gt;(ptr[<span class="number">0</span>]))) |</span><br><span class="line">            (<span class="keyword">static_cast</span>&lt;<span class="keyword">uint32_t</span>&gt;(<span class="keyword">static_cast</span>&lt;<span class="keyword">unsigned</span> <span class="keyword">char</span>&gt;(ptr[<span class="number">1</span>])) &lt;&lt; <span class="number">8</span>) |</span><br><span class="line">            (<span class="keyword">static_cast</span>&lt;<span class="keyword">uint32_t</span>&gt;(<span class="keyword">static_cast</span>&lt;<span class="keyword">unsigned</span> <span class="keyword">char</span>&gt;(ptr[<span class="number">2</span>])) &lt;&lt; <span class="number">16</span>) |</span><br><span class="line">            (<span class="keyword">static_cast</span>&lt;<span class="keyword">uint32_t</span>&gt;(<span class="keyword">static_cast</span>&lt;<span class="keyword">unsigned</span> <span class="keyword">char</span>&gt;(ptr[<span class="number">3</span>])) &lt;&lt; <span class="number">24</span>));</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 同上，不过是64位的</span></span><br><span class="line"><span class="function"><span class="keyword">inline</span> uint64_t <span class="title">DecodeFixed64</span><span class="params">(<span class="keyword">const</span> <span class="keyword">char</span>* ptr)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (port::kLittleEndian) &#123;</span><br><span class="line">    <span class="comment">// Load the raw bytes</span></span><br><span class="line">    <span class="keyword">uint64_t</span> result;</span><br><span class="line">    <span class="built_in">memcpy</span>(&amp;result, ptr, <span class="keyword">sizeof</span>(result));  <span class="comment">// gcc optimizes this to a plain load</span></span><br><span class="line">    <span class="keyword">return</span> result;</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    <span class="keyword">uint64_t</span> lo = DecodeFixed32(ptr);</span><br><span class="line">    <span class="keyword">uint64_t</span> hi = DecodeFixed32(ptr + <span class="number">4</span>);</span><br><span class="line">    <span class="keyword">return</span> (hi &lt;&lt; <span class="number">32</span>) | lo;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Internal routine for use by fallback path of GetVarint32Ptr</span></span><br><span class="line"><span class="comment">// 内部例程，用于GetVarint32Ptr方法的回退</span></span><br><span class="line"><span class="function"><span class="keyword">const</span> <span class="keyword">char</span>* <span class="title">GetVarint32PtrFallback</span><span class="params">(<span class="keyword">const</span> <span class="keyword">char</span>* p, <span class="keyword">const</span> <span class="keyword">char</span>* limit,</span></span></span><br><span class="line"><span class="function"><span class="params">                                   <span class="keyword">uint32_t</span>* value)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">inline</span> <span class="keyword">const</span> <span class="keyword">char</span>* <span class="title">GetVarint32Ptr</span><span class="params">(<span class="keyword">const</span> <span class="keyword">char</span>* p, <span class="keyword">const</span> <span class="keyword">char</span>* limit,</span></span></span><br><span class="line"><span class="function"><span class="params">                                  <span class="keyword">uint32_t</span>* value)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (p &lt; limit) &#123;</span><br><span class="line">    <span class="keyword">uint32_t</span> result = *(<span class="keyword">reinterpret_cast</span>&lt;<span class="keyword">const</span> <span class="keyword">unsigned</span> <span class="keyword">char</span>*&gt;(p));</span><br><span class="line">    <span class="keyword">if</span> ((result &amp; <span class="number">128</span>) == <span class="number">0</span>) &#123;</span><br><span class="line">      *value = result;</span><br><span class="line">      <span class="keyword">return</span> p + <span class="number">1</span>;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> GetVarint32PtrFallback(p, limit, value);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">&#125;  <span class="comment">// namespace leveldb</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span>  <span class="comment">// STORAGE_LEVELDB_UTIL_CODING_H_</span></span></span><br></pre></td></tr></table></figure></p><h1 id="Fixint编码"><a href="#Fixint编码" class="headerlink" title="Fixint编码"></a>Fixint编码</h1><p>Fixint是固定编码，比较简单，主要是根据小端还是大端存储来将字节放入缓冲区中，编码代码如下：<br><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></pre></td><td class="code"><pre><span class="line"><span class="comment">//coding.cc</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">EncodeFixed32</span><span class="params">(<span class="keyword">char</span>* dst, <span class="keyword">uint32_t</span> value)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (port::kLittleEndian) &#123;</span><br><span class="line">  <span class="comment">//如果是小端存储模式，则直接用memcpy将value拷贝到dst缓冲区中</span></span><br><span class="line">    <span class="built_in">memcpy</span>(dst, &amp;value, <span class="keyword">sizeof</span>(value));</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">  <span class="comment">//如果不是小端存储模式，则利用位运算手动处理成小端模式存储到dst中</span></span><br><span class="line">    dst[<span class="number">0</span>] = value &amp; <span class="number">0xff</span>;</span><br><span class="line">    dst[<span class="number">1</span>] = (value &gt;&gt; <span class="number">8</span>) &amp; <span class="number">0xff</span>;</span><br><span class="line">    dst[<span class="number">2</span>] = (value &gt;&gt; <span class="number">16</span>) &amp; <span class="number">0xff</span>;</span><br><span class="line">    dst[<span class="number">3</span>] = (value &gt;&gt; <span class="number">24</span>) &amp; <span class="number">0xff</span>;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 64位整数处理方式和32位大体相似，只不过64位要使用8个byte</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">EncodeFixed64</span><span class="params">(<span class="keyword">char</span>* dst, <span class="keyword">uint64_t</span> value)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (port::kLittleEndian) &#123;</span><br><span class="line">    <span class="built_in">memcpy</span>(dst, &amp;value, <span class="keyword">sizeof</span>(value));</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    dst[<span class="number">0</span>] = value &amp; <span class="number">0xff</span>;</span><br><span class="line">    dst[<span class="number">1</span>] = (value &gt;&gt; <span class="number">8</span>) &amp; <span class="number">0xff</span>;</span><br><span class="line">    dst[<span class="number">2</span>] = (value &gt;&gt; <span class="number">16</span>) &amp; <span class="number">0xff</span>;</span><br><span class="line">    dst[<span class="number">3</span>] = (value &gt;&gt; <span class="number">24</span>) &amp; <span class="number">0xff</span>;</span><br><span class="line">    dst[<span class="number">4</span>] = (value &gt;&gt; <span class="number">32</span>) &amp; <span class="number">0xff</span>;</span><br><span class="line">    dst[<span class="number">5</span>] = (value &gt;&gt; <span class="number">40</span>) &amp; <span class="number">0xff</span>;</span><br><span class="line">    dst[<span class="number">6</span>] = (value &gt;&gt; <span class="number">48</span>) &amp; <span class="number">0xff</span>;</span><br><span class="line">    dst[<span class="number">7</span>] = (value &gt;&gt; <span class="number">56</span>) &amp; <span class="number">0xff</span>;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p><p>知道了编码方式，解码方式即是逆操作，解码实现代码在coding.h中，第一节已经里已经列出，可以看出同样是一开始先判断是否是小端存储，若是小端存储则直接用memcpy方法复制；如果不是小端存储，则利用位运算和或运算对每个byte进行整合得到最终结果。</p><p>值得注意的是，64位的解码方法DecodeFixed64没有像编码方法EncodeFixed64一样写完8个字节的处理，而是调用了两次DecodeFixed32方法分别处理了高4位和低4位，最后或了一下。</p><p>一般来说，能复用的代码都不会重复写，那为什么64位的编码方法EncodeFixed64没有选择复用EncodeFixed32而是自己写了8个byte的处理呢？</p><p>比如，写成下面这样：<br><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">EncodeFixed64</span><span class="params">(<span class="keyword">char</span>* dst, <span class="keyword">uint64_t</span> value)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (port::kLittleEndian) &#123;</span><br><span class="line">    <span class="built_in">memcpy</span>(dst, &amp;value, <span class="keyword">sizeof</span>(value));</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    EncodeFixed32(dst, value);</span><br><span class="line">    EncodeFixed32(dst + <span class="number">4</span>, value &gt;&gt; <span class="number">32</span>);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p><p>我在vs2017上测了下好像和源码里提供的方法并没有什么区别，所以为什么源码里没有使用复用的方式呢？有点好奇，但问题不大，暂且忽略。【突然想到是不是大端机器上使用复用的方法会有点问题？但应该没有才对呀。。。】</p><h1 id="Varint编码"><a href="#Varint编码" class="headerlink" title="Varint编码"></a>Varint编码</h1><p>Varint是一种紧凑的表示数字的方法，它用一个字节或多个字节来表示一个数字。它是一种使用一个或多个字节序列化整数的方法，会把整数编码为变长字节。对于32位整型数字而言，varint编码会将它编码成1~5个字节，小的数字只占用1个字节，大的则会占用5个字节，而根据统计学来说，小数字使用频率大于大数字，所以利用varint编码能够起到压缩空间的作用。</p><p>接下来详细看一下它的编解码过程。</p><p>另外说一句，最近发现varint编码方式应用似乎还是很广泛的，除了LevelDB外，项目中使用到的另一个开源工具Protobuf中也使用了这种编码，所以还是很有必要学习一下呀~</p><h2 id="编码原理与实现"><a href="#编码原理与实现" class="headerlink" title="编码原理与实现"></a>编码原理与实现</h2><p>在varint编码中，除了最后一个字节外，其余每个字节都会设置一个最高有效位（most significant bit -msb），msb为1表示后面的字节还是属于当前数据的，为0则表示这是该数据的最后一个字节。所以每个字节的低7位为一组存储数字的二进制补码，最低有效组在前面，最高有效组在后面，即是小端存储。</p><p>根据上一段，我们可以算出Varint编码中为什么32位的整型最高需要5个字节来存储。本来每个32位整型需要4个byte来存储，现在改为Varint编码，每个byte只能表示7个bit，那么32个bit就需要<code>32/7=5（向上取整）</code>个byte来存储。</p><p>同理，64位整型使用Varint最多需要10个byte来存储（64/7=10[向上取整]）。</p><p>编码原理如图所示：</p><img src="/2019/10/29/leveldb源码学习4-varint/coding.png"><p>最终十进制123456经过Varint编码后的值变为<code>1100 0000 1100 0100 0000 0111</code>，所以123456占用的三个字节分别是<code>192 196 7</code>，图中一目了然（侵删）。</p><p>LevelDB源码Varint实现：<br><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">char</span>* <span class="title">EncodeVarint32</span><span class="params">(<span class="keyword">char</span>* dst, <span class="keyword">uint32_t</span> v)</span> </span>&#123;</span><br><span class="line">  <span class="comment">// Operate on characters as unsigneds</span></span><br><span class="line">  <span class="comment">// 首先把字符当做无符号来处理，【这么做的原因是为了防止有符号数在进行移位时高位自动补充1从而导致数据错误？？】</span></span><br><span class="line">  <span class="keyword">unsigned</span> <span class="keyword">char</span>* ptr = <span class="keyword">reinterpret_cast</span>&lt;<span class="keyword">unsigned</span> <span class="keyword">char</span>*&gt;(dst);</span><br><span class="line">  <span class="keyword">static</span> <span class="keyword">const</span> <span class="keyword">int</span> B = <span class="number">128</span>;</span><br><span class="line">  <span class="keyword">if</span> (v &lt; (<span class="number">1</span> &lt;&lt; <span class="number">7</span>)) &#123;</span><br><span class="line">    <span class="comment">//v小于128，直接把v赋值给*ptr，因为v的有效位最多7位，</span></span><br><span class="line">    <span class="comment">//v只需要一个byte即可表示，最高有效位是0</span></span><br><span class="line">    *(ptr++) = v;</span><br><span class="line">  &#125; <span class="keyword">else</span> <span class="keyword">if</span> (v &lt; (<span class="number">1</span> &lt;&lt; <span class="number">14</span>)) &#123;</span><br><span class="line">    <span class="comment">//v需要两个byte表示</span></span><br><span class="line">    *(ptr++) = v | B;<span class="comment">//和128进行或运算，使得第一个byte的最高有效位是1</span></span><br><span class="line">    *(ptr++) = v &gt;&gt; <span class="number">7</span>;<span class="comment">//v先右移7位，然后处理第二个byte</span></span><br><span class="line">  &#125; <span class="keyword">else</span> <span class="keyword">if</span> (v &lt; (<span class="number">1</span> &lt;&lt; <span class="number">21</span>)) &#123;</span><br><span class="line">    <span class="comment">//v需要三个byte表示，原理同上</span></span><br><span class="line">    *(ptr++) = v | B;</span><br><span class="line">    *(ptr++) = (v &gt;&gt; <span class="number">7</span>) | B;</span><br><span class="line">    *(ptr++) = v &gt;&gt; <span class="number">14</span>;</span><br><span class="line">  &#125; <span class="keyword">else</span> <span class="keyword">if</span> (v &lt; (<span class="number">1</span> &lt;&lt; <span class="number">28</span>)) &#123;</span><br><span class="line">    <span class="comment">//v需要四个byte表示，原理同上</span></span><br><span class="line">    *(ptr++) = v | B;</span><br><span class="line">    *(ptr++) = (v &gt;&gt; <span class="number">7</span>) | B;</span><br><span class="line">    *(ptr++) = (v &gt;&gt; <span class="number">14</span>) | B;</span><br><span class="line">    *(ptr++) = v &gt;&gt; <span class="number">21</span>;</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    <span class="comment">//v需要五个byte表示，原理同上</span></span><br><span class="line">    *(ptr++) = v | B;</span><br><span class="line">    *(ptr++) = (v &gt;&gt; <span class="number">7</span>) | B;</span><br><span class="line">    *(ptr++) = (v &gt;&gt; <span class="number">14</span>) | B;</span><br><span class="line">    *(ptr++) = (v &gt;&gt; <span class="number">21</span>) | B;</span><br><span class="line">    *(ptr++) = v &gt;&gt; <span class="number">28</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">reinterpret_cast</span>&lt;<span class="keyword">char</span>*&gt;(ptr);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 64位整型Varint编码实现，大体相同，只是这里的实现使用了循环，毕竟10个ifelse会很冗长，而且也没必要</span></span><br><span class="line"><span class="comment">// 要注意的是循环条件，退出循环后还需要处理最后的7位数据</span></span><br><span class="line"><span class="function"><span class="keyword">char</span>* <span class="title">EncodeVarint64</span><span class="params">(<span class="keyword">char</span>* dst, <span class="keyword">uint64_t</span> v)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">static</span> <span class="keyword">const</span> <span class="keyword">int</span> B = <span class="number">128</span>;</span><br><span class="line">  <span class="keyword">unsigned</span> <span class="keyword">char</span>* ptr = <span class="keyword">reinterpret_cast</span>&lt;<span class="keyword">unsigned</span> <span class="keyword">char</span>*&gt;(dst);</span><br><span class="line">  <span class="keyword">while</span> (v &gt;= B) &#123;</span><br><span class="line">    *(ptr++) = v | B;</span><br><span class="line">    v &gt;&gt;= <span class="number">7</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  *(ptr++) = <span class="keyword">static_cast</span>&lt;<span class="keyword">unsigned</span> <span class="keyword">char</span>&gt;(v);</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">reinterpret_cast</span>&lt;<span class="keyword">char</span>*&gt;(ptr);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p><p>除了编码实现之外LevelDB还提供了一个返回编码后占用byte数的方法，即返回整型编码后的长度，同样是使用位运算实现的，代码如下：<br><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">VarintLength</span><span class="params">(<span class="keyword">uint64_t</span> v)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">int</span> len = <span class="number">1</span>;</span><br><span class="line">  <span class="keyword">while</span> (v &gt;= <span class="number">128</span>) &#123;</span><br><span class="line">    v &gt;&gt;= <span class="number">7</span>;</span><br><span class="line">    len++;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> len;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p><h2 id="解码原理与实现"><a href="#解码原理与实现" class="headerlink" title="解码原理与实现"></a>解码原理与实现</h2><p>理解了编码原理，解码其实就是逆操作，可以直接看代码。<br><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></pre></td><td class="code"><pre><span class="line"><span class="comment">//coding.cc</span></span><br><span class="line"><span class="comment">//从Slice获取value的方法，内部调用GetVarint32Ptr</span></span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">GetVarint32</span><span class="params">(Slice* input, <span class="keyword">uint32_t</span>* value)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">const</span> <span class="keyword">char</span>* p = input-&gt;data();</span><br><span class="line">  <span class="keyword">const</span> <span class="keyword">char</span>* limit = p + input-&gt;size();</span><br><span class="line">  <span class="keyword">const</span> <span class="keyword">char</span>* q = GetVarint32Ptr(p, limit, value);</span><br><span class="line">  <span class="keyword">if</span> (q == <span class="literal">nullptr</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    *input = Slice(q, limit - q);</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//coding.h</span></span><br><span class="line"><span class="comment">//该方法处理value&lt;128的情况，直接将result赋值给value，否则调用GetVarint32PtrFallback方法</span></span><br><span class="line"><span class="function"><span class="keyword">inline</span> <span class="keyword">const</span> <span class="keyword">char</span>* <span class="title">GetVarint32Ptr</span><span class="params">(<span class="keyword">const</span> <span class="keyword">char</span>* p, <span class="keyword">const</span> <span class="keyword">char</span>* limit,</span></span></span><br><span class="line"><span class="function"><span class="params">                                  <span class="keyword">uint32_t</span>* value)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (p &lt; limit) &#123;</span><br><span class="line">    <span class="keyword">uint32_t</span> result = *(<span class="keyword">reinterpret_cast</span>&lt;<span class="keyword">const</span> <span class="keyword">unsigned</span> <span class="keyword">char</span>*&gt;(p));</span><br><span class="line">    <span class="keyword">if</span> ((result &amp; <span class="number">128</span>) == <span class="number">0</span>) &#123;</span><br><span class="line">      *value = result;</span><br><span class="line">      <span class="keyword">return</span> p + <span class="number">1</span>;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> GetVarint32PtrFallback(p, limit, value);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//coding.cc</span></span><br><span class="line"><span class="function"><span class="keyword">const</span> <span class="keyword">char</span>* <span class="title">GetVarint32PtrFallback</span><span class="params">(<span class="keyword">const</span> <span class="keyword">char</span>* p, <span class="keyword">const</span> <span class="keyword">char</span>* limit,</span></span></span><br><span class="line"><span class="function"><span class="params">                                   <span class="keyword">uint32_t</span>* value)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">uint32_t</span> result = <span class="number">0</span>;</span><br><span class="line">  <span class="comment">// 每7位循环处理一次</span></span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">uint32_t</span> shift = <span class="number">0</span>; shift &lt;= <span class="number">28</span> &amp;&amp; p &lt; limit; shift += <span class="number">7</span>) &#123;</span><br><span class="line">    <span class="keyword">uint32_t</span> byte = *(<span class="keyword">reinterpret_cast</span>&lt;<span class="keyword">const</span> <span class="keyword">unsigned</span> <span class="keyword">char</span>*&gt;(p));</span><br><span class="line">    p++;</span><br><span class="line">    <span class="keyword">if</span> (byte &amp; <span class="number">128</span>) &#123;</span><br><span class="line">      <span class="comment">// 如果当前byte最高位为1，即说明当前数据后面还有byte</span></span><br><span class="line">      result |= ((byte &amp; <span class="number">127</span>) &lt;&lt; shift);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      <span class="comment">// 当前byte最高位为0，已经到了当前数据的最后一个byte</span></span><br><span class="line">      result |= (byte &lt;&lt; shift);</span><br><span class="line">      *value = result;</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">reinterpret_cast</span>&lt;<span class="keyword">const</span> <span class="keyword">char</span>*&gt;(p);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> <span class="literal">nullptr</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//64位整型处理和32位大同小异，只不过64位没有再分开成两个方法，统一处理了</span></span><br><span class="line"><span class="comment">//从slice解码64位整型数据，内部调用GetVarint64Ptr</span></span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">GetVarint64</span><span class="params">(Slice* input, <span class="keyword">uint64_t</span>* value)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">const</span> <span class="keyword">char</span>* p = input-&gt;data();</span><br><span class="line">  <span class="keyword">const</span> <span class="keyword">char</span>* limit = p + input-&gt;size();</span><br><span class="line">  <span class="keyword">const</span> <span class="keyword">char</span>* q = GetVarint64Ptr(p, limit, value);</span><br><span class="line">  <span class="keyword">if</span> (q == <span class="literal">nullptr</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    *input = Slice(q, limit - q);</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//和32位处理几乎相同，只是循环条件稍微变了下</span></span><br><span class="line"><span class="function"><span class="keyword">const</span> <span class="keyword">char</span>* <span class="title">GetVarint64Ptr</span><span class="params">(<span class="keyword">const</span> <span class="keyword">char</span>* p, <span class="keyword">const</span> <span class="keyword">char</span>* limit, <span class="keyword">uint64_t</span>* value)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">uint64_t</span> result = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">uint32_t</span> shift = <span class="number">0</span>; shift &lt;= <span class="number">63</span> &amp;&amp; p &lt; limit; shift += <span class="number">7</span>) &#123;</span><br><span class="line">    <span class="keyword">uint64_t</span> byte = *(<span class="keyword">reinterpret_cast</span>&lt;<span class="keyword">const</span> <span class="keyword">unsigned</span> <span class="keyword">char</span>*&gt;(p));</span><br><span class="line">    p++;</span><br><span class="line">    <span class="keyword">if</span> (byte &amp; <span class="number">128</span>) &#123;</span><br><span class="line">      <span class="comment">// More bytes are present</span></span><br><span class="line">      result |= ((byte &amp; <span class="number">127</span>) &lt;&lt; shift);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      result |= (byte &lt;&lt; shift);</span><br><span class="line">      *value = result;</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">reinterpret_cast</span>&lt;<span class="keyword">const</span> <span class="keyword">char</span>*&gt;(p);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> <span class="literal">nullptr</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p><h2 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h2><p>另外coding文件中还有几个其他的方法，主要是针对字符串的编解码方法，后续会使用到，这里简单看一下：<br><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></pre></td><td class="code"><pre><span class="line"><span class="comment">//该方法将Slice类的value的长度进行编码当做前缀放在dst中，后面跟value值</span></span><br><span class="line"><span class="comment">//即value编码后后变成这样的格式：[varint编码后的value长度值]+[value本身的data值]</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">PutLengthPrefixedSlice</span><span class="params">(<span class="built_in">std</span>::<span class="built_in">string</span>* dst, <span class="keyword">const</span> Slice&amp; value)</span> </span>&#123;</span><br><span class="line">  PutVarint32(dst, value.size());</span><br><span class="line">  dst-&gt;append(value.data(), value.size());</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//该方法返回去掉长度前缀的整型值，存在result中</span></span><br><span class="line"><span class="function"><span class="keyword">const</span> <span class="keyword">char</span>* <span class="title">GetLengthPrefixedSlice</span><span class="params">(<span class="keyword">const</span> <span class="keyword">char</span>* p, <span class="keyword">const</span> <span class="keyword">char</span>* limit,</span></span></span><br><span class="line"><span class="function"><span class="params">                                   Slice* result)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">uint32_t</span> len;</span><br><span class="line">  p = GetVarint32Ptr(p, limit, &amp;len);<span class="comment">//p指向结果后一位的指针，即p越过了长度前缀</span></span><br><span class="line">  <span class="keyword">if</span> (p == <span class="literal">nullptr</span>) <span class="keyword">return</span> <span class="literal">nullptr</span>;</span><br><span class="line">  <span class="keyword">if</span> (p + len &gt; limit) <span class="keyword">return</span> <span class="literal">nullptr</span>;</span><br><span class="line">  *result = Slice(p, len);<span class="comment">//将p往后的len长度的真正值赋给result</span></span><br><span class="line">  <span class="keyword">return</span> p + len;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//该方法去掉input的前缀，将data和size存到result中，input则变成</span></span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">GetLengthPrefixedSlice</span><span class="params">(Slice* input, Slice* result)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">uint32_t</span> len;</span><br><span class="line">  <span class="keyword">if</span> (GetVarint32(input, &amp;len) &amp;&amp; input-&gt;size() &gt;= len) &#123;</span><br><span class="line">    *result = Slice(input-&gt;data(), len);</span><br><span class="line">    input-&gt;remove_prefix(len);</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p><p>关于字符串的编解码，使用以下代码进行测试：<br><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></pre></td><td class="code"><pre><span class="line"><span class="built_in">std</span>::<span class="built_in">string</span> s;</span><br><span class="line">PutLengthPrefixedSlice(&amp;s, Slice(<span class="string">"alksdjf"</span>));</span><br><span class="line"><span class="built_in">cout</span> &lt;&lt; <span class="string">"s.data = "</span> &lt;&lt; s.data() &lt;&lt; <span class="string">", s.size = "</span> &lt;&lt; s.size() &lt;&lt; <span class="built_in">endl</span>;</span><br><span class="line"><span class="function">Slice <span class="title">input</span><span class="params">(s)</span></span>;</span><br><span class="line">Slice v;</span><br><span class="line">GetLengthPrefixedSlice(&amp;input, &amp;v);</span><br><span class="line"><span class="built_in">cout</span> &lt;&lt; <span class="string">"v.data = "</span> &lt;&lt; v.data() &lt;&lt; <span class="string">", v.size = "</span> &lt;&lt; v.size() &lt;&lt; <span class="built_in">endl</span>;</span><br></pre></td></tr></table></figure></p><p>vs2017运行结果如下：<br><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">s.data = alksdjf, s.size = <span class="number">8</span></span><br><span class="line">v.data = alksdjf, v.size = <span class="number">7</span></span><br></pre></td></tr></table></figure></p><p>要注意的是<code>s</code>中在字符串开头还有一个隐藏字节，保存的是s的真正字符串长度<code>7</code>，只不过ASCII码表里7对应的字符<code>\a</code>无法打印出来的，debug调试是可以看到该值的，如图所示。</p><img src="/2019/10/29/leveldb源码学习4-varint/debug.png"><p>还有一点是测试中<code>input</code>指针的地址在GetLengthPrefixedSlice前后的变化如下<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">调用前：0x00000054296ffbd0</span><br><span class="line">调用后：0x00000054296ffbd8</span><br></pre></td></tr></table></figure></p><p>可以看出来正好向后移动了8位，和s.size相同。即在调用GetLengthPrefixedSlice之后，input会移动到原本数据的下一位，而数据的值会存在result中。</p><p>一通操作，还是很精妙的，建议将该测试代码自行debug一下，品，你细品。</p>]]></content>
    
    <summary type="html">
    
      &lt;h1 id=&quot;简述&quot;&gt;&lt;a href=&quot;#简述&quot; class=&quot;headerlink&quot; title=&quot;简述&quot;&gt;&lt;/a&gt;简述&lt;/h1&gt;&lt;p&gt;这篇文章学习源码中util/coding.h和util/coding.cc文件，这两个文件主要介绍了leveldb中使用的编码方式，包括变长和不变长两种。&lt;/p&gt;
&lt;p&gt;leveldb默认采用小端字节序存储，即低位字节排放在内存的低地址中。&lt;/p&gt;
&lt;p&gt;这篇文章不能简单靠注释了，其中有一些编码算法可以仔细看一下。&lt;/p&gt;
    
    </summary>
    
      <category term="职业学习" scheme="http://yoursite.com/categories/%E8%81%8C%E4%B8%9A%E5%AD%A6%E4%B9%A0/"/>
    
    
      <category term="leveldb" scheme="http://yoursite.com/tags/leveldb/"/>
    
  </entry>
  
  <entry>
    <title>股票训练营笔记</title>
    <link href="http://yoursite.com/2019/10/21/%E8%82%A1%E7%A5%A8%E8%AE%AD%E7%BB%83%E8%90%A5%E7%AC%94%E8%AE%B0/"/>
    <id>http://yoursite.com/2019/10/21/股票训练营笔记/</id>
    <published>2019-10-21T14:46:08.000Z</published>
    <updated>2019-11-12T13:47:58.007Z</updated>
    
    <content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>之前学习基金训练营，现在已经买了一点基金试试，接下来学一些股票的基础知识，本篇笔记就记录关于股票的一些笔记。</p><a id="more"></a><h1 id="2019-10-21"><a href="#2019-10-21" class="headerlink" title="2019/10/21"></a>2019/10/21</h1><p>股票投资的五大流派：</p><ol><li>技术投资派：通过分析股票的价格走势，来预测股票未来的涨跌；</li><li>宏观投资派：这个派别的逻辑是市场经济向好，股市就会向好，研究经济就可以指导股票投资；</li><li>有效市场派：认为市场大部分时候对股票的定价是正确的；</li><li>成长投资派：更关注公司未来是否有足够高的增长；</li><li>价值投资派：看中公司现在是否有足够低的价格，低买高卖就是价值投资的本质，也是最适合普通人的投资方法。</li></ol><h2 id="捡烟蒂投资法"><a href="#捡烟蒂投资法" class="headerlink" title="捡烟蒂投资法"></a>捡烟蒂投资法</h2><p>本杰明·格雷厄姆。</p><p>烟蒂股：毫不起眼、甚至被抛弃的公司。</p><p>捡烟蒂需要的成本远低于他们本身的价值。</p><p>继续下跌的概率小，上涨概率大于下跌概率。</p><h2 id="好公司投资法"><a href="#好公司投资法" class="headerlink" title="好公司投资法"></a>好公司投资法</h2><p>沃伦·巴菲特。</p><p>投资核心：找到好公司，在价格较低的时候买入。</p><p>好公司的价值最终一定会显现在股价上。</p><h2 id="天时地利人和"><a href="#天时地利人和" class="headerlink" title="天时地利人和"></a>天时地利人和</h2><p>天时：看准入场时机。</p><p>地利：合理获取资金，配置自己的投资组合。</p><p>人和：建立过硬的心理素质。</p><h2 id="找准入场时机（天时）"><a href="#找准入场时机（天时）" class="headerlink" title="找准入场时机（天时）"></a>找准入场时机（天时）</h2><p>一家公司的价值 = 现在的价值 + 未来能赚取的价值</p><p>市盈率PE = 市值/净利润，表示多少年能够回本，越小越有投资价值。</p><p>市净率PB = 市值/净资产 = 买下公司需要的钱/属于公司自己的钱，PB越小说明价格越低，越有投资价值。</p><p>如何判断两家公司作为一个整体是否便宜？其实就是把PE和PB的被除数和除数分别加起来再计算。</p><p>放大了说，要算整个A股3000多家公司也是加起来，这时候算出来的PE和PB如果都比较低，就代表整个A股都比较便宜，可以入场。</p><p>当沪深300、中证500中任意一个的PE和PB同时满足：</p><ol><li>PE处于近十年数值的0~50%区间内；</li><li>PB处于近十年数值的0~20%区间内；</li></ol><p>则可以认为对应的指数处于低估状态，可以入场投资，否则不可以。</p><h1 id="2019-10-23"><a href="#2019-10-23" class="headerlink" title="2019/10/23"></a>2019/10/23</h1><p>建立投资组合：合理规避风险（地利）</p><h2 id="风险"><a href="#风险" class="headerlink" title="风险"></a>风险</h2><h3 id="系统性风险"><a href="#系统性风险" class="headerlink" title="系统性风险"></a>系统性风险</h3><ul><li>政策风险：政策改变导致企业生存条件变化</li><li>购买力风险：通货膨胀风险</li><li>利率风险：市场利率会不断波动</li></ul><p>先估值再入市是个有效的规避方法。</p><h3 id="非系统性风险"><a href="#非系统性风险" class="headerlink" title="非系统性风险"></a>非系统性风险</h3><ul><li>经营风险：公司经营的错误决策很可能导致公司业绩大幅下滑。</li><li>信用风险：公司违背信用所产生的风险。</li><li>道德风险：违背道德事件。</li></ul><h2 id="规避非系统性风险"><a href="#规避非系统性风险" class="headerlink" title="规避非系统性风险"></a>规避非系统性风险</h2><p>很难在短期内收到是所有的社会热点和政策变化，打听小道消息更是不靠谱。</p><h3 id="方法1：构建组合投资，把资金分散在多个行业的多只股票上"><a href="#方法1：构建组合投资，把资金分散在多个行业的多只股票上" class="headerlink" title="方法1：构建组合投资，把资金分散在多个行业的多只股票上"></a>方法1：构建组合投资，把资金分散在多个行业的多只股票上</h3><p>鸡蛋不要放在一个篮子里。</p><h4 id="回避风险时，并不是买的股票越多越科学"><a href="#回避风险时，并不是买的股票越多越科学" class="headerlink" title="回避风险时，并不是买的股票越多越科学"></a>回避风险时，并不是买的股票越多越科学</h4><p>经过计算，当股票超过一定数量时，随着股票数量的增加，回避风险的效果只是略微增加。</p><p>一般来说，持有4~8只股票是比较经济、有效的做法。</p><h3 id="方法2：分散行业，同行业的资金占比不要超过30"><a href="#方法2：分散行业，同行业的资金占比不要超过30" class="headerlink" title="方法2：分散行业，同行业的资金占比不要超过30%"></a>方法2：分散行业，同行业的资金占比不要超过30%</h3><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>对于系统性风险：判断入场时机。</p><p>对于非系统性风险：组合投资。</p><h1 id="2019-10-27"><a href="#2019-10-27" class="headerlink" title="2019/10/27"></a>2019/10/27</h1><p>组合投资是贯穿整个资金布局过程中的重要原则。</p><p>这一节就是讲的”人和“。</p><h2 id="资金"><a href="#资金" class="headerlink" title="资金"></a>资金</h2><p>对于刚投资买股票的我们而言，更多的资金是不现实的，也不是最重要的。</p><h2 id="心态"><a href="#心态" class="headerlink" title="心态"></a>心态</h2><p>心态，是优秀投资者必备的素质。</p><p>不可能买了就涨，卖了就跌。</p><p>不应该看到涨就感觉错过一个亿，看到跌又害怕地想卖出。</p><p>不过，在我们连股票都还不会选的现在，心态也不用着急准备。</p><h2 id="选股"><a href="#选股" class="headerlink" title="选股"></a>选股</h2><p>这是刚开始学的时候最重要的事情。</p><p>一个好的股票在上涨的时候有更多的回报，下跌的时候有更大的耐心。</p><p>投资选股是一门技能，需要弄清楚每一步的原理和操作方法，才能在未来独立建立自己的投资组合，实现长期获利。</p><h3 id="头脑清晰，理性看待价格上涨"><a href="#头脑清晰，理性看待价格上涨" class="headerlink" title="头脑清晰，理性看待价格上涨"></a>头脑清晰，理性看待价格上涨</h3><p>价值的上涨可能是跟随价值的上涨而产生的上涨，也有可能只是围绕价值产生的波动。</p><p>所以近期的价格大幅上涨有可能是好的表现，也有可能是被人炒作过热。</p><p>黑马股：本来不被看好，却能出乎意料地在短期大幅上涨。</p><p>不推荐黑马股。</p><h3 id="白马股"><a href="#白马股" class="headerlink" title="白马股"></a>白马股</h3><p>投资回报率高</p><p>长期业绩优秀</p><p>信息相对可靠</p><h3 id="投资回报率"><a href="#投资回报率" class="headerlink" title="投资回报率"></a>投资回报率</h3><p>一只股票的投资回报率 = （卖出价格/买入价格 - 1) * 100%</p><p>年化复合收益率 = [（卖出价格/买入价格）^(1/n) -1 ] * 100%</p><h3 id="如何寻找高投资回报率的股票"><a href="#如何寻找高投资回报率的股票" class="headerlink" title="如何寻找高投资回报率的股票"></a>如何寻找高投资回报率的股票</h3><p>从长期来看，一只股票的回报率与企业发展息息相关。</p><p>ROE（净资产收益率）= 净利润/净资产</p><p>芒格的意思是，如果长期持有一只股票，你的年化复合收益率和企业的ROE就没有任何区别。</p><p>所以想找年化复合收益率高的股票，就要找ROE高的公司。</p><p>白马股要持有七年以上。</p><p>寻马神器——“i问财”. <a href="http://www.iwencai.com/" target="_blank" rel="noopener">http://www.iwencai.com/</a> </p><p>输入搜索关键字，比如：2011年到2018年ROE&gt;=15%，2019年6月30日ROE&gt;=7.5%，上市时间早于2013年6月。</p><p>这就是寻找白马股的第一步。</p><h1 id="2019-10-28"><a href="#2019-10-28" class="headerlink" title="2019/10/28"></a>2019/10/28</h1><p>“好公司”投资法：剔除周期股</p><p>仅仅使用连续7年ROE指标大于等于15%这一个指标，可能会有伪白马股混进来。</p><p>这些容易混进来的，被称为周期股。</p><h2 id="经济周期"><a href="#经济周期" class="headerlink" title="经济周期"></a>经济周期</h2><p>周期性现象具有以下两个属性：</p><ol><li>必然产生，就像地球会一直绕着太阳转</li><li>循环往复</li></ol><p>经济周期就是国民经济呈现扩张与紧缩交替的波动变化。这种变化必然发送、循环往复，因此形成了经济波动。</p><h3 id="行业分类"><a href="#行业分类" class="headerlink" title="行业分类"></a>行业分类</h3><p>公司所处行业不同，受经济周期影响的程度也大相径庭。</p><ul><li>周期性行业，业绩紧跟经济周期起伏，比如汽车行业。</li><li>非周期性行业，受经济周期影响较小，经营业绩更为稳定，比如医药行业、食品行业。</li></ul><p>而有些周期股的周期比较长，但上市时间比较短，这就会对我们产生迷惑。</p><p>行业的周期性决定着公司的周期性。</p><p>要把周期股从白马股中剔除掉。</p><h3 id="如何剔除周期股"><a href="#如何剔除周期股" class="headerlink" title="如何剔除周期股"></a>如何剔除周期股</h3><p>通过判断所处行业是不是周期性行业，就能知道这个股票是不是周期股。</p><p>在证券市场，“行业”有着成熟的分类，可以在同花顺里操作。</p><h3 id="四类要避开的行业"><a href="#四类要避开的行业" class="headerlink" title="四类要避开的行业"></a>四类要避开的行业</h3><ol><li>作为工业基础原材料的大宗商品相关行业，比如：采掘服务、钢铁、化工、化学制品、有色冶炼加工、化工新材料等。</li><li>航运业，比如远洋运输、港口航运、机场航运等。</li><li>非生活必需品行业，以及与之相关的行业，比如国防军工、汽车整车、汽车零部件、建筑材料、房地产。</li><li>非银行的金融行业，比如证券、保险等。</li></ol><h2 id="操作"><a href="#操作" class="headerlink" title="操作"></a>操作</h2><ol><li>上i问财，利用上一节的搜索，搜索内容后面增加“行业”二字，然后搜索。</li><li>点击导数据，去掉不要的列</li><li>打开表格去掉周期性行业</li></ol><h2 id="护城河"><a href="#护城河" class="headerlink" title="护城河"></a>护城河</h2><p>有护城河的公司容易出白马股。</p><p>护城河有四类：</p><ol><li>无形资产护城河：包括公司品牌、专利、政府授权。</li><li>转换成本护城河：比如换手机号的成本太高，你就不会换了</li><li>网络效应护城河：严格说是转换成本的一种，比如微信。</li><li>规模效应护城河。</li></ol><p>晨星公司分析出的五种比较容易出护城河的行业：白酒行业、医药行业、软件行业、媒体行业以及消费行业。</p><h1 id="2019-10-29"><a href="#2019-10-29" class="headerlink" title="2019/10/29"></a>2019/10/29</h1><p>“好公司”投资法：剔除基本面转坏的股票。</p><p>比如诺基亚。</p><p>诺基亚为何会突然败落？</p><p>用历史数据筛选出来的好公司只能确定它曾经有过优异的表现，其次对于新手来说，想要搞懂一家公司的经营状况是很困难的，不深入了解情况，很难搞清楚真实原因。</p><h2 id="如何判断一家公司的业绩是否有下滑迹象？"><a href="#如何判断一家公司的业绩是否有下滑迹象？" class="headerlink" title="如何判断一家公司的业绩是否有下滑迹象？"></a>如何判断一家公司的业绩是否有下滑迹象？</h2><p>想知道生意有没有变好，最直接的方式就是算算今年有没有卖出去更多的货，也就是营业收入有没有增加。</p><p>只要比较公司当前和过去的营业收入以及净利润就行了。</p><p>用两个财务指标来判断公司业绩：</p><ol><li>营业收入增长率，又称作营收增长率【（今年收入-去年收入）/去年收入】</li><li>净利润增长率</li></ol><p>除了年报外，还有季报，可以比较本季度与去年同季度的业绩。</p><p>也就是说，一共四个指标。</p><ol><li>最近的年度营收增长率</li><li>最近的年度净利润增长率</li><li>最近的季度营收增长率</li><li>最近的季度净利润增长率</li></ol><p>如果这四个指标中有一个是负数，就需要剔除（这里是最严格的判断标准，毕竟新手嘛）。</p><h2 id="操作-1"><a href="#操作-1" class="headerlink" title="操作"></a>操作</h2><p>在之前的搜索条件后添加新的搜索条件，比如：</p><p>“2018年3月31日营收增长率，2018年3月31日净利润增长率，2017年营收增长率，2017年净利润增长率”</p><p>剔除其中四个指标有负数的。</p><h1 id="2019-10-30"><a href="#2019-10-30" class="headerlink" title="2019/10/30"></a>2019/10/30</h1><p>财务三表分析</p><p>排除过分美化财报的公司</p><ul><li>收入美化</li><li>资产美化</li></ul><h2 id="如何识别收入美化"><a href="#如何识别收入美化" class="headerlink" title="如何识别收入美化"></a>如何识别收入美化</h2><p>财报是从会计角度记录公司所有经营事务的报表，分为季度报表、半年报表以及年度报表。</p><p>财报有三种表：</p><ol><li>利润表，又称损益表，主要体现公司一段时间内是赚钱还是亏钱</li><li>资产负债表，记录特定的某一天，公司有多少钱、财、物以及欠别人多少钱</li><li>现金流量表，开支流水账，记录公司花出去多少钱，收到多少钱</li></ol><h3 id="利润表"><a href="#利润表" class="headerlink" title="利润表"></a>利润表</h3><p>公司的收入记录记录在利润表，专业名词叫营业收入。</p><p><code>营业收入-营业成本-三费 = 营业利润</code></p><p>三费主要是指管理、销售、财务三种费用。</p><p><code>营业利润-所得税 = 净利润</code></p><p>一般来说，收入的多少直接影响着公司利润的多少。</p><p>预收账款不算收入，货给客户后才转成收入，而赊账是给了货却没有收到钱，依然算收入，应收账款增加、营业收入增加。</p><p>要注意的是：公司只要给了货，无论是否收到钱，都会记入营业收入，其中没有收到钱的部分就不是很靠谱了。</p><p>所以就可以用这部分给了货但是没收到钱的来美化利润表，称为真货假卖。</p><p>找朋友假装买，出了财报再退货。</p><p>这样的话卖货量一直在增加，营业收入一直在增加，业绩很好，但其实账面上的营业收入增加是假的。</p><h3 id="避免真货假卖"><a href="#避免真货假卖" class="headerlink" title="避免真货假卖"></a>避免真货假卖</h3><p>综合看营业收入和应收账款，就能识破真货假卖。</p><p>应收账款：企业卖产品给客户，但还未收的钱，也就是客户签的白条，在资产负债表里。</p><p>营业收入：企业卖产品获得的钱，即使没有收到钱，收到的“白条”也是会算在营业收入里的。</p><p>[定理一：]</p><p><em>连续两年应收账款上升幅度大于营业收入上升幅度，这家公司就需要警惕。</em></p><h2 id="操作-2"><a href="#操作-2" class="headerlink" title="操作"></a>操作</h2><p>理杏仁</p><p>看四年的利润表</p><p>要注意的是，因为银行业务的特殊性，并没有应收账款等科目，银行股不适合定理一。</p><p>银行股就用之前的指标吧~</p><h1 id="2019-11-3"><a href="#2019-11-3" class="headerlink" title="2019/11/3"></a>2019/11/3</h1><h2 id="如何识别资产美化"><a href="#如何识别资产美化" class="headerlink" title="如何识别资产美化"></a>如何识别资产美化</h2><p>资产负债表：</p><p>资产 = 负债 + 所有者权益（又叫净资产）</p><h3 id="资产美化"><a href="#资产美化" class="headerlink" title="资产美化"></a>资产美化</h3><p>问题主要在存货上。</p><p>很明显，好的公司应该以需定产，没有过多的存活，资金才能更好地运用起来。</p><p>存货不仅指生产出的货物，还包括生产用的原材料、生产过程中的半成品。</p><p>存货包含的项目比较多，从财报中只能看到资金总额，这就给了别有用心的公司一个机会。</p><p>【定理二】：</p><p><em>连续两年存货增长大于营业收入的增长，这家公司的存货就可能有问题。</em></p><h3 id="破产风险"><a href="#破产风险" class="headerlink" title="破产风险"></a>破产风险</h3><p>【定理三】：</p><p><em>如果一家公司的流动负债远大于流动资产的话，说明这家公司已经非常接近破产了。</em>如果最近三年有流动比小于1的，就剔除。</p><p>流动资产：一年内可以变现的资产，如货币资金、存货、预付款项。</p><p>流动负债：一年内必须要还的钱，如应付账款、短期借款等。</p><p>流动比率 = 流动资产 / 流动负债</p><p>流动比率&lt; 1， 则说明流动资产小于流动负债，是危险的。</p><h3 id="小技巧"><a href="#小技巧" class="headerlink" title="小技巧"></a>小技巧</h3><ol><li>大品牌更可靠</li><li>不要ST</li><li>曾经出现过违反道德规范、财报作假等重大丑闻的，被证监会立案调查还未有结果的公司不要买。</li></ol><h1 id="2019-11-4"><a href="#2019-11-4" class="headerlink" title="2019/11/4"></a>2019/11/4</h1><p>为什么自由现金流如此重要？？</p><p>现金流量表，记录公司现金的流入和流出情况。也叫作财务状况变动表。</p><p>三表关系紧密。</p><p>现金流量表的资金主要来源：</p><ol><li>利润表中的营业收入会变成现金流量表中经营活动产生的现金流量；</li><li>资产负债表中的投资活动产生的现金流量；</li><li>资产负债表中的筹资活动产生的现金流量。</li></ol><p>经营活动现金流净额 <strong>不等于</strong> 净利润</p><ul><li>收到钱但没有出货：利润表中净利润不会有变化（因为净利润看的是出没出货），但是经营活动现金流净额的增加，这说明这家公司的产品可能需要预定，说明公司对上下游的合作公司有较强的话语权，是一种隐藏的盈利能力；</li><li>卖出货收到钱：净利润和现金流量都会增加</li></ul><p>经营活动产生的现金流净额中，除了净利润，还有其他的现金流入流出。如果这部分的数字足够大，公司赚的现金比净利润还多，这便是公司隐藏的盈利能力。</p><p>【定理四】</p><p>当一家公司的经营活动现金流净额远大于净利润的话，说明这家公司可能有隐藏的盈利能力，有可能是座金矿。</p><p>操作看理杏仁，经营活动现金流净额在现金流量表里可以查到。</p><p>【定理五】</p><p>自由现金流是衡量公司现金流情况的指标，代表着公司真正能自由运用的资金，比净利润更真实，更难作假。</p><p>自由现金流 = 经营活动产生的现金流量净额 - 资金开支</p><p>经营活动现金流净额 = 所有经营活动收到的现金 - 所有经营活动支付的现金</p><p>资本开支就是现金流量表中的“构建固定资产、无形资产和其他长期资产支付的现金”。</p><p>满足定理四和五的个股只是有可能更好，并不一定就是更好的，只是加分项，是个股分析方法之一。</p><h1 id="2019-11-5"><a href="#2019-11-5" class="headerlink" title="2019/11/5"></a>2019/11/5</h1><p>构建白马组合，实操。</p><p>好公司不等于“包赚钱”，好公司也得有个好价钱，我们才能获利。</p><p>股票的贵与便宜是相对公司的价值而言的，而不是只看价格。</p><p>体现价格与价值关系的就是估值，想要避免在价格贵时买入股票，就要用到估值指标——PE和PB，理杏仁网上看50%的分位点。</p><h2 id="筛选之后怎么卖"><a href="#筛选之后怎么卖" class="headerlink" title="筛选之后怎么卖"></a>筛选之后怎么卖</h2><ol><li>股票太多或者钱不够怎么办</li><li>资金应该如何分配：平均分配到每只股票。</li><li>筛不出股票，或者筛出来的股票不足4只，该怎么办？【TODO后续学习】</li></ol><h2 id="卖出的三种情况"><a href="#卖出的三种情况" class="headerlink" title="卖出的三种情况"></a>卖出的三种情况</h2><ol><li>股票的价格高于价值了；</li><li>原来的好公司基本面转坏了；</li><li>发现了更好更便宜的股票。【别人比你好】</li></ol><h2 id="多久能赚钱"><a href="#多久能赚钱" class="headerlink" title="多久能赚钱"></a>多久能赚钱</h2><p>股市变化无常，即使在相对便宜的位置买入白马股，短期内也是有可能下跌的。</p><p>但长期来看股票的价格会向公司的价值靠拢，只要我们买的价格低于公司价值，长期持有就会享受公司发展带来的收益。</p><h1 id="2019-11-6"><a href="#2019-11-6" class="headerlink" title="2019/11/6"></a>2019/11/6</h1><p>捡烟蒂投资法：便宜组合。</p><p>白马股很多人买，价格会变高，贵了就不能再买了。</p><p>所以要寻找别的投资机会，就是便宜组合。</p><p>“价格是杰出投资最主要的因素。优秀投资者的目标不只在于“买好的”，也在于“买得好”。”</p><p>最理想的投资是买便宜的好货！</p><p>价格始终围绕着价值上下波动，但长期看会向价值的均值靠拢，而价值投资者要做的事只有一件，那就是当价格大幅低于价值的时候，买入。——格雷厄姆</p><h2 id="估值指标"><a href="#估值指标" class="headerlink" title="估值指标"></a>估值指标</h2><p>市盈率PE = 公司市值/净利润，越小越好。</p><p>市净率PB = 公司市值/净资产，越小越好。</p><p>坚持走买便宜货不动摇的路线，是能赚到钱的，而且赚的还不少。</p><p>把低市盈率与低市净率结合起来作为筛选标准，只筛选两个指标都很低的几十只股票。</p><p>还有一个估值指标，可以看出公司是不是大方地分钱。</p><p>便宜组合筛选标准：</p><ol><li>0 &lt; PE &lt; 10</li><li>0 &lt; PB &lt; 1.5</li><li>股息率 &gt; 3%</li></ol><p>股息率 = 公司过去一年的累计现金分红 / 公司市值</p><p>A股公司平均的股息率约为3%。</p><p>根据便宜组合能筛选出的股票数量能大致地推断出当前股市的整体热度，数量多，则股市整体估值低。</p><h2 id="实操"><a href="#实操" class="headerlink" title="实操"></a>实操</h2><p>理杏仁</p><h1 id="2019-11-10"><a href="#2019-11-10" class="headerlink" title="2019/11/10"></a>2019/11/10</h1><p>捡烟蒂投资法：便宜组合实操构建</p><h2 id="步骤"><a href="#步骤" class="headerlink" title="步骤"></a>步骤</h2><p>步骤如下：</p><ol><li>打开昨天导出的表格</li><li>给所有股票排序，挑选出最好的：将PE、PB和股息率分别排名，将每只股票3个指标的排名求和，算出所排名</li><li>筛选，选8~10支。筛选小技巧：1行业要分散，同一行业不要超过30%；2用PB分位点进一步挑选低估股票，&lt;20%才要。</li></ol><p>便宜组合大部分都是周期股，但由于我们选的是周期股，当然就得原谅它们这一点。</p><h2 id="资金均分"><a href="#资金均分" class="headerlink" title="资金均分"></a>资金均分</h2><p>确定价格最高的股票买一手的金额，其余股票的金额往这个金额上靠就可以了。</p><p>当某个时刻筛选便宜组合筛选不出来股票时，可以适当放宽筛选条件、寻找别的投资机会以及持币观望，等待入场时机。</p><h2 id="被动投资"><a href="#被动投资" class="headerlink" title="被动投资"></a>被动投资</h2><p>每个半年调仓</p><ol><li>每个半年，重新筛一次便宜组合</li><li>将最新筛出的组合结果和原来的组合结果对照</li><li>新旧组合中重合的股票保留</li><li>卖掉旧组合里有，但新组合里没有的股票</li><li>补入新组合里新的股票</li></ol><p>清楚投资原理、投资方法，了解攀升强度、明白回撤幅度，具备耐心和坚持才配得上优厚回报。</p><h1 id="2019-11-11"><a href="#2019-11-11" class="headerlink" title="2019/11/11"></a>2019/11/11</h1><p>实战：第一次下注买股票：</p><p>交易时间：上午9.30~1.30，下午1:00~3:00，法定休假日除外。</p><p>K线图怎么看？阳线是红，表示涨，阴线是绿，表示跌。</p><p>K线图下面的柱子是成交量，代表的是一段时间内成交的股票数量，主要受供求关系的影响。</p><p>交易单位：股票买卖以“手”为单位，1手=100股，少于100股的1-99股成为零股，交易时，委托买入的最低单位为1手。</p><p>由于分红送股时可能出现零股，因此，卖出委托的时候可以有零股，但是零股必须一次性卖出。</p><p>A股交易费用：印花税、过户费（千分之0.02）和佣金。</p><h2 id="股价报价方式"><a href="#股价报价方式" class="headerlink" title="股价报价方式"></a>股价报价方式</h2><p>限价委托：限价委托就是用户先先定一个买入或者卖出价格。</p><p>好处：价格可控</p><p>坏处：如果股票始终高于限定的价格，那么可能当天无法成交。</p><p>即限价委托价格可控，交易时间不可控。</p><p>市价委托：只指定交易数量，但是不给出具体价格的委托方式。</p><p>好处：同样的报价，市价委托优先于限价委托，因此保证即时成交。</p><p>坏处：成交价格可能会偏贵。</p><p>即市价委托价格不可控，但交易时间可控。</p><h2 id="A股涨跌停板制度"><a href="#A股涨跌停板制度" class="headerlink" title="A股涨跌停板制度"></a>A股涨跌停板制度</h2><p>涨跌幅限制的是股票上涨幅度和下跌幅度只能是上一个交易日收盘价的10%。</p><p>以ST开头的股票，每日的涨跌幅限制只有5%。新股首日伤势，股价涨幅不受10%的限制，但是最高涨幅不得超过发行价的44%。</p><h2 id="交易制度"><a href="#交易制度" class="headerlink" title="交易制度"></a>交易制度</h2><p>A股交易采用T+1交易制度。T表示“trade“。</p><p>T+1交易制度指投资者当天买入的证券不能在当天卖出，需待第二天才能卖。</p><p>当天投资者卖出股票收回的资金只能用来买入新的股票，不能提现，第二天才能提。</p><h1 id="2019-11-12"><a href="#2019-11-12" class="headerlink" title="2019/11/12"></a>2019/11/12</h1><p>股海浮尘，锦囊妙计。</p><p>人和：就是拥有强大的投资者心态，是我们的理性、韧性和耐心。</p><h2 id="三个锦囊"><a href="#三个锦囊" class="headerlink" title="三个锦囊"></a>三个锦囊</h2><ol><li>贪多嚼不烂，股票投资入门简单，精通难，想要获得超额收益，就需要付出超额努力。</li><li>笑看涨跌、波澜不惊，不要每天看盘，一个月一次差不多了。</li><li>保持耐心，长期持有。</li></ol><p>攀升的强度和回撤的幅度就是根据历史数据，是一段时间内最高涨幅和最低跌幅的一个范围。</p>]]></content>
    
    <summary type="html">
    
      &lt;h1 id=&quot;前言&quot;&gt;&lt;a href=&quot;#前言&quot; class=&quot;headerlink&quot; title=&quot;前言&quot;&gt;&lt;/a&gt;前言&lt;/h1&gt;&lt;p&gt;之前学习基金训练营，现在已经买了一点基金试试，接下来学一些股票的基础知识，本篇笔记就记录关于股票的一些笔记。&lt;/p&gt;
    
    </summary>
    
      <category term="大杂烩" scheme="http://yoursite.com/categories/%E5%A4%A7%E6%9D%82%E7%83%A9/"/>
    
    
      <category term="理财投资" scheme="http://yoursite.com/tags/%E7%90%86%E8%B4%A2%E6%8A%95%E8%B5%84/"/>
    
  </entry>
  
  <entry>
    <title>leveldb源码学习3-env</title>
    <link href="http://yoursite.com/2019/10/21/leveldb%E6%BA%90%E7%A0%81%E5%AD%A6%E4%B9%A03-env/"/>
    <id>http://yoursite.com/2019/10/21/leveldb源码学习3-env/</id>
    <published>2019-10-21T14:45:05.000Z</published>
    <updated>2019-10-21T14:45:39.678Z</updated>
    
    <content type="html"><![CDATA[<h1 id="简述"><a href="#简述" class="headerlink" title="简述"></a>简述</h1><p>本系列第三篇文章，分析一下LevelDB中的Env，这个文件主要是为了考虑了移植和灵活性，所以把系统相关的一些处理（文件/进程/时间之类）抽象成Env，用户可以自己实现响应的接口作为options传入。默认使用自带的。</p><p>这么封装的好处是显而易见的：跨平台会更加简单。客户端只需要调用接口抽象出来的一致性方法，不同平台下的代码更加一致，值得借鉴。</p><p>还是选择代码注释的方式（我只是个翻译工。）</p><h1 id="include-leveldb-env-h"><a href="#include-leveldb-env-h" class="headerlink" title="include/leveldb/env.h"></a>include/leveldb/env.h</h1><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><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Env是leveldb中实现用来访问操作系统功能(如文件系统等)的接口</span></span><br><span class="line"><span class="comment">// 调用者可能希望在打开数据库的时候提供一个自定义的Env对象来获得精细增益控制。比如，要限制文件系统操作的速率。</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">ifndef</span> STORAGE_LEVELDB_INCLUDE_ENV_H_</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> STORAGE_LEVELDB_INCLUDE_ENV_H_</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdarg.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdint.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;string&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;vector&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"leveldb/export.h"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"leveldb/status.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> defined(_WIN32)</span></span><br><span class="line"><span class="comment">// Env类提供了一个DeleteFile方法，但同时在windows应用里被广泛应用的&lt;windows.h&gt;里也有一个DeleteFile宏。</span></span><br><span class="line"><span class="comment">// 如果不做任何干预的话，这个不幸的巧合会导致编译器看到的leveldb::Env::DeleteFile方法的名称取决于&lt;windows.h&gt;是否包含在leveldb头文件之前还是之后。</span></span><br><span class="line"><span class="comment">// 为了避免这个问题，在这里undefine DeleteFile方法并且在本文件最后重新定义它，这样可以保证对外的DeleteFile总是leveldb::Env::DeleteFile</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> defined(DeleteFile)</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">undef</span> DeleteFile</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> LEVELDB_DELETEFILE_UNDEFINED</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span>  <span class="comment">// defined(DeleteFile)</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span>  <span class="comment">// defined(_WIN32)</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">namespace</span> leveldb &#123;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">FileLock</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Logger</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">RandomAccessFile</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SequentialFile</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Slice</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">WritableFile</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">LEVELDB_EXPORT</span> <span class="title">Env</span> &#123;</span></span><br><span class="line"> <span class="keyword">public</span>:</span><br><span class="line">  Env() = <span class="keyword">default</span>;</span><br><span class="line"></span><br><span class="line">  Env(<span class="keyword">const</span> Env&amp;) = <span class="keyword">delete</span>;</span><br><span class="line">  Env&amp; <span class="keyword">operator</span>=(<span class="keyword">const</span> Env&amp;) = <span class="keyword">delete</span>;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">virtual</span> ~Env();</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 返回适合当前操作系统的一个默认Env。</span></span><br><span class="line">  <span class="comment">// 返回的结果属于LevelDB并且不能被deleted。</span></span><br><span class="line">  <span class="function"><span class="keyword">static</span> Env* <span class="title">Default</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 创建一个对象，该对象按顺序读取具有指定名称的文件。</span></span><br><span class="line">  <span class="comment">// 成功时，result存储对应指针并返回OK。</span></span><br><span class="line">  <span class="comment">// 失败时，result为空并返回non-OK。</span></span><br><span class="line">  <span class="comment">// 如果文件不存在，返回NotFound。</span></span><br><span class="line">  <span class="comment">// 返回文件在同一时间只能被一个线程获取。</span></span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> Status <span class="title">NewSequentialFile</span><span class="params">(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; fname,</span></span></span><br><span class="line"><span class="function"><span class="params">                                   SequentialFile** result)</span> </span>= <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 创建一个对象，该对象支持随机读取具有指定名称的文件。</span></span><br><span class="line">  <span class="comment">// 其余同上。</span></span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> Status <span class="title">NewRandomAccessFile</span><span class="params">(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; fname,</span></span></span><br><span class="line"><span class="function"><span class="params">                                     RandomAccessFile** result)</span> </span>= <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 创建一个对象，该对象对具有指定名称的文件进行写入。</span></span><br><span class="line">  <span class="comment">// 若文件已存在，则会删除并创建一个新文件。</span></span><br><span class="line">  <span class="comment">// 其余同上。</span></span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> Status <span class="title">NewWritableFile</span><span class="params">(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; fname,</span></span></span><br><span class="line"><span class="function"><span class="params">                                 WritableFile** result)</span> </span>= <span class="number">0</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="comment">// 可能会返回IsNotSupportedError error，这时表示Env不支持对已有文件进行追加。</span></span><br><span class="line">  <span class="comment">// 其余同上</span></span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> Status <span class="title">NewAppendableFile</span><span class="params">(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; fname,</span></span></span><br><span class="line"><span class="function"><span class="params">                                   WritableFile** result)</span></span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 文件存在则返回true</span></span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> <span class="keyword">bool</span> <span class="title">FileExists</span><span class="params">(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; fname)</span> </span>= <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// result会保存指定目录下的所有文件名。result中的本来内容会被覆盖。</span></span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> Status <span class="title">GetChildren</span><span class="params">(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; dir,</span></span></span><br><span class="line"><span class="function"><span class="params">                             <span class="built_in">std</span>::<span class="built_in">vector</span>&lt;<span class="built_in">std</span>::<span class="built_in">string</span>&gt;* result)</span> </span>= <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 删除文件</span></span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> Status <span class="title">DeleteFile</span><span class="params">(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; fname)</span> </span>= <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 创建目录</span></span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> Status <span class="title">CreateDir</span><span class="params">(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; dirname)</span> </span>= <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 删除目录</span></span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> Status <span class="title">DeleteDir</span><span class="params">(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; dirname)</span> </span>= <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 获取文件大小</span></span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> Status <span class="title">GetFileSize</span><span class="params">(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; fname, <span class="keyword">uint64_t</span>* file_size)</span> </span>= <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 重命名文件</span></span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> Status <span class="title">RenameFile</span><span class="params">(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; src,</span></span></span><br><span class="line"><span class="function"><span class="params">                            <span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; target)</span> </span>= <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 锁定指定的文件，在多线程时获取锁。</span></span><br><span class="line">  <span class="comment">// 失败时lock为空。</span></span><br><span class="line">  <span class="comment">// 成功时，保存一个已获得的锁并返回ok。</span></span><br><span class="line">  <span class="comment">// 调用方要使用UnlockFile来解锁。</span></span><br><span class="line">  <span class="comment">// 若其他人已经持有锁，则立刻返回失败，不会等待。</span></span><br><span class="line">  <span class="comment">// 文件不存在时会创建。</span></span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> Status <span class="title">LockFile</span><span class="params">(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; fname, FileLock** lock)</span> </span>= <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 释放锁</span></span><br><span class="line">  <span class="comment">// 锁必须是已经被成功LockFile的，且没有重复unlock。</span></span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> Status <span class="title">UnlockFile</span><span class="params">(FileLock* lock)</span> </span>= <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 在后台线程运行function。</span></span><br><span class="line">  <span class="comment">// 添加到同一个Env中的多个方法会在多个线程中并发跑。</span></span><br><span class="line">  <span class="comment">// 调用方不应认为后台任务是顺序执行的。</span></span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Schedule</span><span class="params">(<span class="keyword">void</span> (*function)(<span class="keyword">void</span>* arg), <span class="keyword">void</span>* arg)</span> </span>= <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 开启一个新线程，调用function。方法return时，线程会被销毁。</span></span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">StartThread</span><span class="params">(<span class="keyword">void</span> (*function)(<span class="keyword">void</span>* arg), <span class="keyword">void</span>* arg)</span> </span>= <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// *path被设值成一个测试用的临时目录。它不一定是刚刚才被创建的。目录在统一线程的多次运行中不一定不同，但后续调用都会返回同一目录。</span></span><br><span class="line">  <span class="comment">// <span class="doctag">TODO:</span>这个方法有些不懂，回头要测一测。</span></span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> Status <span class="title">GetTestDirectory</span><span class="params">(<span class="built_in">std</span>::<span class="built_in">string</span>* path)</span> </span>= <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 创建并返回一个用来存储消息的日志文件。</span></span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> Status <span class="title">NewLogger</span><span class="params">(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; fname, Logger** result)</span> </span>= <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 返回从一个特定时间节点之后到目前为止经过的毫秒数。</span></span><br><span class="line">  <span class="comment">// 只有在计算增量数据时有用。</span></span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> uint64_t <span class="title">NowMicros</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">    </span><br><span class="line">  <span class="comment">// sleep指定的毫秒数。</span></span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">SleepForMicroseconds</span><span class="params">(<span class="keyword">int</span> micros)</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 一种按顺序读取的文件的抽象</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">LEVELDB_EXPORT</span> <span class="title">SequentialFile</span> &#123;</span></span><br><span class="line"> <span class="keyword">public</span>:</span><br><span class="line">  SequentialFile() = <span class="keyword">default</span>;</span><br><span class="line"></span><br><span class="line">  SequentialFile(<span class="keyword">const</span> SequentialFile&amp;) = <span class="keyword">delete</span>;</span><br><span class="line">  SequentialFile&amp; <span class="keyword">operator</span>=(<span class="keyword">const</span> SequentialFile&amp;) = <span class="keyword">delete</span>;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">virtual</span> ~SequentialFile();</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 读取文件中的n个字节。scratch[0..n-1]可能会被写入。</span></span><br><span class="line">  <span class="comment">// *result指向被读取的数据（即使被成功读取的数据字节数小于n）。</span></span><br><span class="line">  <span class="comment">// 可以设置*result指向scratch[0..n-1]中的数据，所以当*result被使用时一定要保证scratch数组可用。</span></span><br><span class="line">  <span class="comment">// 如果出错，则返回非ok。</span></span><br><span class="line">  <span class="comment">// 要求：外部同步</span></span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> Status <span class="title">Read</span><span class="params">(<span class="keyword">size_t</span> n, Slice* result, <span class="keyword">char</span>* scratch)</span> </span>= <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 对文件跳过n个字节。</span></span><br><span class="line">  <span class="comment">// 该方法保证不比读取相同字节数慢，有时会更快。</span></span><br><span class="line">  <span class="comment">// 如果到达文件末尾，skip会停止并返回ok。</span></span><br><span class="line">  <span class="comment">// 要求：外部同步。</span></span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> Status <span class="title">Skip</span><span class="params">(<span class="keyword">uint64_t</span> n)</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 一种随机读取文件的抽象。</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">LEVELDB_EXPORT</span> <span class="title">RandomAccessFile</span> &#123;</span></span><br><span class="line"> <span class="keyword">public</span>:</span><br><span class="line">  RandomAccessFile() = <span class="keyword">default</span>;</span><br><span class="line"></span><br><span class="line">  RandomAccessFile(<span class="keyword">const</span> RandomAccessFile&amp;) = <span class="keyword">delete</span>;</span><br><span class="line">  RandomAccessFile&amp; <span class="keyword">operator</span>=(<span class="keyword">const</span> RandomAccessFile&amp;) = <span class="keyword">delete</span>;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">virtual</span> ~RandomAccessFile();</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 对指定文件从offset偏移处开始读取n个字节。</span></span><br><span class="line">  <span class="comment">// *result和*scratch说明同SequentialFile.read。</span></span><br><span class="line">  <span class="comment">// 对于多线程并发同步是安全的。</span></span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> Status <span class="title">Read</span><span class="params">(<span class="keyword">uint64_t</span> offset, <span class="keyword">size_t</span> n, Slice* result,</span></span></span><br><span class="line"><span class="function"><span class="params">                      <span class="keyword">char</span>* scratch)</span> <span class="keyword">const</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</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="comment">// 实现必须要提供缓存，因为调用者们可能会在同一时间对文件添加多个小段落。</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">LEVELDB_EXPORT</span> <span class="title">WritableFile</span> &#123;</span></span><br><span class="line"> <span class="keyword">public</span>:</span><br><span class="line">  WritableFile() = <span class="keyword">default</span>;</span><br><span class="line"></span><br><span class="line">  WritableFile(<span class="keyword">const</span> WritableFile&amp;) = <span class="keyword">delete</span>;</span><br><span class="line">  WritableFile&amp; <span class="keyword">operator</span>=(<span class="keyword">const</span> WritableFile&amp;) = <span class="keyword">delete</span>;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">virtual</span> ~WritableFile();</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> Status <span class="title">Append</span><span class="params">(<span class="keyword">const</span> Slice&amp; data)</span> </span>= <span class="number">0</span>;</span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> Status <span class="title">Close</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> Status <span class="title">Flush</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> Status <span class="title">Sync</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 写日志消息的接口</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">LEVELDB_EXPORT</span> <span class="title">Logger</span> &#123;</span></span><br><span class="line"> <span class="keyword">public</span>:</span><br><span class="line">  Logger() = <span class="keyword">default</span>;</span><br><span class="line"></span><br><span class="line">  Logger(<span class="keyword">const</span> Logger&amp;) = <span class="keyword">delete</span>;</span><br><span class="line">  Logger&amp; <span class="keyword">operator</span>=(<span class="keyword">const</span> Logger&amp;) = <span class="keyword">delete</span>;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">virtual</span> ~Logger();</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 用指定格式向日志文件写入一个entry</span></span><br><span class="line">  <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">Logv</span><span class="params">(<span class="keyword">const</span> <span class="keyword">char</span>* format, va_list ap)</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 文件锁，标识一个锁定的文件。</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">LEVELDB_EXPORT</span> <span class="title">FileLock</span> &#123;</span></span><br><span class="line"> <span class="keyword">public</span>:</span><br><span class="line">  FileLock() = <span class="keyword">default</span>;</span><br><span class="line"></span><br><span class="line">  FileLock(<span class="keyword">const</span> FileLock&amp;) = <span class="keyword">delete</span>;</span><br><span class="line">  FileLock&amp; <span class="keyword">operator</span>=(<span class="keyword">const</span> FileLock&amp;) = <span class="keyword">delete</span>;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">virtual</span> ~FileLock();</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 如果*info_log不是null，就记录指定的数据。</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Log</span><span class="params">(Logger* info_log, <span class="keyword">const</span> <span class="keyword">char</span>* format, ...)</span></span></span><br><span class="line"><span class="function"><span class="meta">#<span class="meta-keyword">if</span> defined(__GNUC__) || defined(__clang__)</span></span></span><br><span class="line"><span class="function">    __<span class="title">attribute__</span><span class="params">((__format__(__printf__, <span class="number">2</span>, <span class="number">3</span>)))</span></span></span><br><span class="line"><span class="function"><span class="meta">#<span class="meta-keyword">endif</span></span></span></span><br><span class="line"><span class="function">    </span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 一个通用例程：写数据到指定文件。</span></span><br><span class="line"><span class="function">LEVELDB_EXPORT Status <span class="title">WriteStringToFile</span><span class="params">(Env* env, <span class="keyword">const</span> Slice&amp; data,</span></span></span><br><span class="line"><span class="function"><span class="params">                                        <span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; fname)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 一个通用例程：从指定文件中读取数据到*data</span></span><br><span class="line"><span class="function">LEVELDB_EXPORT Status <span class="title">ReadFileToString</span><span class="params">(Env* env, <span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; fname,</span></span></span><br><span class="line"><span class="function"><span class="params">                                       <span class="built_in">std</span>::<span class="built_in">string</span>* data)</span></span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 将所有调用转发给另一个Env的Env实现。对于只想覆盖另一个Env的部分功能的客户端可能很有用。</span></span><br><span class="line"><span class="comment">// TODO 传说中的代理模式？</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">LEVELDB_EXPORT</span> <span class="title">EnvWrapper</span> :</span> <span class="keyword">public</span> Env &#123;</span><br><span class="line"> <span class="keyword">public</span>:</span><br><span class="line">  <span class="comment">// 初始化一个EnvWrapper用来将所有调用委托给*t。</span></span><br><span class="line">  explicit EnvWrapper(Env* t) : target_(t) &#123;&#125;</span><br><span class="line">  <span class="keyword">virtual</span> ~EnvWrapper();</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 返回此Env将所有调用转发给的目标。</span></span><br><span class="line">  <span class="function">Env* <span class="title">target</span><span class="params">()</span> <span class="keyword">const</span> </span>&#123; <span class="keyword">return</span> target_; &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 下面的文本是将所有方法转发到target()的样板文件。</span></span><br><span class="line">  <span class="function">Status <span class="title">NewSequentialFile</span><span class="params">(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; f, SequentialFile** r)</span> override </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> target_-&gt;NewSequentialFile(f, r);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="function">Status <span class="title">NewRandomAccessFile</span><span class="params">(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; f,</span></span></span><br><span class="line"><span class="function"><span class="params">                             RandomAccessFile** r)</span> override </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> target_-&gt;NewRandomAccessFile(f, r);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="function">Status <span class="title">NewWritableFile</span><span class="params">(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; f, WritableFile** r)</span> override </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> target_-&gt;NewWritableFile(f, r);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="function">Status <span class="title">NewAppendableFile</span><span class="params">(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; f, WritableFile** r)</span> override </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> target_-&gt;NewAppendableFile(f, r);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="function"><span class="keyword">bool</span> <span class="title">FileExists</span><span class="params">(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; f)</span> override </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> target_-&gt;FileExists(f);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="function">Status <span class="title">GetChildren</span><span class="params">(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; dir,</span></span></span><br><span class="line"><span class="function"><span class="params">                     <span class="built_in">std</span>::<span class="built_in">vector</span>&lt;<span class="built_in">std</span>::<span class="built_in">string</span>&gt;* r)</span> override </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> target_-&gt;GetChildren(dir, r);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="function">Status <span class="title">DeleteFile</span><span class="params">(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; f)</span> override </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> target_-&gt;DeleteFile(f);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="function">Status <span class="title">CreateDir</span><span class="params">(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; d)</span> override </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> target_-&gt;CreateDir(d);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="function">Status <span class="title">DeleteDir</span><span class="params">(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; d)</span> override </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> target_-&gt;DeleteDir(d);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="function">Status <span class="title">GetFileSize</span><span class="params">(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; f, <span class="keyword">uint64_t</span>* s)</span> override </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> target_-&gt;GetFileSize(f, s);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="function">Status <span class="title">RenameFile</span><span class="params">(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; s, <span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; t)</span> override </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> target_-&gt;RenameFile(s, t);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="function">Status <span class="title">LockFile</span><span class="params">(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; f, FileLock** l)</span> override </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> target_-&gt;LockFile(f, l);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="function">Status <span class="title">UnlockFile</span><span class="params">(FileLock* l)</span> override </span>&#123; <span class="keyword">return</span> target_-&gt;UnlockFile(l); &#125;</span><br><span class="line">  <span class="function"><span class="keyword">void</span> <span class="title">Schedule</span><span class="params">(<span class="keyword">void</span> (*f)(<span class="keyword">void</span>*), <span class="keyword">void</span>* a)</span> override </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> target_-&gt;Schedule(f, a);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="function"><span class="keyword">void</span> <span class="title">StartThread</span><span class="params">(<span class="keyword">void</span> (*f)(<span class="keyword">void</span>*), <span class="keyword">void</span>* a)</span> override </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> target_-&gt;StartThread(f, a);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="function">Status <span class="title">GetTestDirectory</span><span class="params">(<span class="built_in">std</span>::<span class="built_in">string</span>* path)</span> override </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> target_-&gt;GetTestDirectory(path);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="function">Status <span class="title">NewLogger</span><span class="params">(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; fname, Logger** result)</span> override </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> target_-&gt;NewLogger(fname, result);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">uint64_t</span> NowMicros() override &#123; <span class="keyword">return</span> target_-&gt;NowMicros(); &#125;</span><br><span class="line">  <span class="function"><span class="keyword">void</span> <span class="title">SleepForMicroseconds</span><span class="params">(<span class="keyword">int</span> micros)</span> override </span>&#123;</span><br><span class="line">    target_-&gt;SleepForMicroseconds(micros);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span>:</span><br><span class="line">  Env* target_;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">&#125;  <span class="comment">// namespace leveldb</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 重新定义DeleteFile如果有必要的话</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> defined(_WIN32) &amp;&amp; defined(LEVELDB_DELETEFILE_UNDEFINED)</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> defined(UNICODE)</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> DeleteFile DeleteFileW</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">else</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> DeleteFile DeleteFileA</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span>  <span class="comment">// defined(UNICODE)</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span>  <span class="comment">// defined(_WIN32) &amp;&amp; defined(LEVELDB_DELETEFILE_UNDEFINED)</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span>  <span class="comment">// STORAGE_LEVELDB_INCLUDE_ENV_H_</span></span></span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h1 id=&quot;简述&quot;&gt;&lt;a href=&quot;#简述&quot; class=&quot;headerlink&quot; title=&quot;简述&quot;&gt;&lt;/a&gt;简述&lt;/h1&gt;&lt;p&gt;本系列第三篇文章，分析一下LevelDB中的Env，这个文件主要是为了考虑了移植和灵活性，所以把系统相关的一些处理（文件/进程/时间之类）抽
      
    
    </summary>
    
      <category term="职业学习" scheme="http://yoursite.com/categories/%E8%81%8C%E4%B8%9A%E5%AD%A6%E4%B9%A0/"/>
    
    
      <category term="leveldb" scheme="http://yoursite.com/tags/leveldb/"/>
    
  </entry>
  
  <entry>
    <title>leveldb源码学习2-options</title>
    <link href="http://yoursite.com/2019/09/25/leveldb%E6%BA%90%E7%A0%81%E5%AD%A6%E4%B9%A02-options/"/>
    <id>http://yoursite.com/2019/09/25/leveldb源码学习2-options/</id>
    <published>2019-09-25T07:39:26.000Z</published>
    <updated>2019-09-25T07:42:30.083Z</updated>
    
    <content type="html"><![CDATA[<h1 id="简述"><a href="#简述" class="headerlink" title="简述"></a>简述</h1><p>本系列第二篇文章，主要讲述基本概念options类，这是leveldb启动时的一些配置，主要是各个配置字段的含义要了解一下，所以本篇文章就采取源码加注释的方式（其实源码的注释就很完善，我就翻译一下）。</p><a id="more"></a><h1 id="include-leveldb-options-h"><a href="#include-leveldb-options-h" class="headerlink" title="include/leveldb/options.h"></a>include/leveldb/options.h</h1><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="class"><span class="keyword">class</span> <span class="title">Cache</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Comparator</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Env</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">FilterPolicy</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Logger</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Snapshot</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// leveldb中数据库的内容是保存在一系列的blocks中的，每个block包含一系列KV键值对。</span></span><br><span class="line"><span class="comment">// 每个block的数据在保存前可能会被压缩，压缩方法枚举类如下。</span></span><br><span class="line"><span class="keyword">enum</span> CompressionType &#123;</span><br><span class="line">  <span class="comment">// <span class="doctag">NOTE:</span> 不要改变已有的值。</span></span><br><span class="line">  kNoCompression = <span class="number">0x0</span>,</span><br><span class="line">  kSnappyCompression = <span class="number">0x1</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 控制数据库行为的选项 (会被传给DB::Open方法)</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">LEVELDB_EXPORT</span> <span class="title">Options</span> &#123;</span></span><br><span class="line">  <span class="comment">// 默认构造所有字段。</span></span><br><span class="line">  Options();</span><br><span class="line"></span><br><span class="line">  <span class="comment">// -------------------</span></span><br><span class="line">  <span class="comment">// 影响行为的参数。</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">// 表中keys排序所用的比较器。</span></span><br><span class="line">  <span class="comment">// 默认使用字典序。</span></span><br><span class="line">  <span class="comment">//</span></span><br><span class="line">  <span class="comment">// REQUIRES: 客户端必须保证在这里使用的比较器和之前open相同数据库时所使用的的比较器有相同的名字和完全相同的key顺序。</span></span><br><span class="line">  <span class="keyword">const</span> Comparator* comparator;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// open时，db目录不存在的时候是否创建。</span></span><br><span class="line">  <span class="keyword">bool</span> create_if_missing = <span class="literal">false</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// open时，db目录已经存在时是否报错   </span></span><br><span class="line">  <span class="keyword">bool</span> error_if_exists = <span class="literal">false</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 如果true，则实现将会对正在处理的数据进行积极检查，</span></span><br><span class="line">  <span class="comment">// 并在检测到任何错误时提前停止。这可能会导致无法预料的后果。</span></span><br><span class="line">  <span class="keyword">bool</span> paranoid_checks = <span class="literal">false</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 使用特定对象来和环境交互，比如读写文件。</span></span><br><span class="line">  <span class="comment">// 默认: Env::Default()</span></span><br><span class="line">  Env* env;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 打印日志的logger。为空的话就存在同目录下的默认文件中。</span></span><br><span class="line">  Logger* info_log = <span class="literal">nullptr</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// -------------------</span></span><br><span class="line">  <span class="comment">// 影响性能的参数</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">// 在转换为磁盘上排序的文件之前，要在内存中累积的数据量(由磁盘上未排序的日志支持)。</span></span><br><span class="line">  <span class="comment">//</span></span><br><span class="line">  <span class="comment">// memtable的最大值，较大的值能够提升性能，尤其在批量加载时。</span></span><br><span class="line">  <span class="comment">// 同一时刻最多有两个写buffer会存在在内存中，</span></span><br><span class="line">  <span class="comment">// 所以我们可以期待通过调整这个参数来控制内存使用。</span></span><br><span class="line">  <span class="comment">// 当然，更大的写buffer也会造成下次数据库open时更长的恢复时间。</span></span><br><span class="line">  <span class="keyword">size_t</span> write_buffer_size = <span class="number">4</span> * <span class="number">1024</span> * <span class="number">1024</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="comment">// 按照大佬在解析中写的，db中需要打开的文件包括基本的CURRENT/LOG/MANIFEST/LOCK</span></span><br><span class="line">  <span class="comment">// sstable一旦打开，就会将index信息加入TableCache，所以把</span></span><br><span class="line">  <span class="comment">// max_open_files-10 作为tablecache的最大值</span></span><br><span class="line">  <span class="keyword">int</span> max_open_files = <span class="number">1000</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 传入的block数据的cache管理</span></span><br><span class="line">  <span class="comment">// 管理blocks，用户数据被存在一系列blocks中，block也是从磁盘读取数据的单元</span></span><br><span class="line">  <span class="comment">// 如果非空，则使用指定的cache管理blocks</span></span><br><span class="line">  <span class="comment">// 如果为空，就自动创建并使用一个8MB的内部cache</span></span><br><span class="line">  Cache* block_cache = <span class="literal">nullptr</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 每个块的打包用户数据的大概大小。注意这里的block大小是未压缩前的数据。</span></span><br><span class="line">  <span class="comment">// 如果压缩选项被打开的话，从磁盘里读取的数据单元的真实大小可能比该数值小。</span></span><br><span class="line">  <span class="comment">// 这个参数可以动态改变。</span></span><br><span class="line">  <span class="keyword">size_t</span> block_size = <span class="number">4</span> * <span class="number">1024</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// block中对key做前缀压缩的区间长度，这个参数可以动态改变。</span></span><br><span class="line">  <span class="comment">// 大多数客户端都不应该使用这个参数。</span></span><br><span class="line">  <span class="keyword">int</span> block_restart_interval = <span class="number">16</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// Leveldb在切换一个新文件之前，会将以下字节数导入到一个文件中，也就是文件的最大大小。</span></span><br><span class="line">  <span class="comment">// 大多数客户端不需要使用这个参数。但是如果你的文件系统针对大文件效率更高时，可以考虑增大这个值。</span></span><br><span class="line">  <span class="comment">// 这样造成的缺点就是更长的压缩时间以及更长的延迟/响应问题。</span></span><br><span class="line">  <span class="comment">// 还有一个增大该参数的情况是你正在初始填充大型数据库。</span></span><br><span class="line">  <span class="keyword">size_t</span> max_file_size = <span class="number">2</span> * <span class="number">1024</span> * <span class="number">1024</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="comment">// 默认压缩方法：kSnappyCompression，这是一种轻微但快速的压缩方法。</span></span><br><span class="line">  <span class="comment">//</span></span><br><span class="line">  <span class="comment">// Typical speeds of kSnappyCompression on an Intel(R) Core(TM)2 2.4GHz:</span></span><br><span class="line">  <span class="comment">//    ~200-500MB/s compression</span></span><br><span class="line">  <span class="comment">//    ~400-800MB/s decompression</span></span><br><span class="line">  <span class="comment">// 注意该压缩方法的速度快过大多数持久化存储的速度，因此可能并没有理由切换成不压缩。</span></span><br><span class="line">  <span class="comment">// 即使输入数据是不可压缩的，该方法的实现中也会有效识别并切换到不压缩模式。</span></span><br><span class="line">  CompressionType compression = kSnappyCompression;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 实验性的参数，如果为真，当一个数据库被打开时，追加到已存在的MANIFEST和日志文件末尾，这可以提高打开速度。</span></span><br><span class="line">  <span class="comment">// 默认false。</span></span><br><span class="line">  <span class="keyword">bool</span> reuse_logs = <span class="literal">false</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 如果非空，使用该过滤策略减少磁盘读取。</span></span><br><span class="line">  <span class="comment">// 如果在这里传入NewBloomFilterPolicy() ，很多应用都会受益。</span></span><br><span class="line">  <span class="keyword">const</span> FilterPolicy* filter_policy = <span class="literal">nullptr</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 读操作选项设置</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">LEVELDB_EXPORT</span> <span class="title">ReadOptions</span> &#123;</span></span><br><span class="line">  ReadOptions() = <span class="keyword">default</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 如果真，从底层存储读取的所有数据都要根据对应的校验来进行验证。</span></span><br><span class="line">  <span class="keyword">bool</span> verify_checksums = <span class="literal">false</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 读到的block是否加入内存中的block cache？</span></span><br><span class="line">  <span class="comment">// 调用者们可能会喜欢将该字段设置成false来进行批量扫描。</span></span><br><span class="line">  <span class="keyword">bool</span> fill_cache = <span class="literal">true</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 如果非空，读入指定的snapshot(必须属于正在读取且未被released的BD)</span></span><br><span class="line">  <span class="comment">// 若空，使用一个在读取操作开始时状态的隐式快照</span></span><br><span class="line">  <span class="keyword">const</span> Snapshot* snapshot = <span class="literal">nullptr</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 写操作选项设置</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">LEVELDB_EXPORT</span> <span class="title">WriteOptions</span> &#123;</span></span><br><span class="line">  WriteOptions() = <span class="keyword">default</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 若真，则在认为写完成之前将从操作系统缓冲区缓存中清除写入。</span></span><br><span class="line">  <span class="comment">// 若真，写操作会更慢。</span></span><br><span class="line">  <span class="comment">//</span></span><br><span class="line">  <span class="comment">// 若假，当机器crash时，一些最近的写会被丢失。注意如果只是进程崩溃，则不会丢失写。</span></span><br><span class="line">  <span class="comment">//</span></span><br><span class="line">  <span class="comment">// In other words, a DB write with sync==false has similar</span></span><br><span class="line">  <span class="comment">// crash semantics as the "write()" system call.  A DB write</span></span><br><span class="line">  <span class="comment">// with sync==true has similar crash semantics to a "write()"</span></span><br><span class="line">  <span class="comment">// system call followed by "fsync()".</span></span><br><span class="line">  <span class="comment">// </span></span><br><span class="line">  <span class="keyword">bool</span> sync = <span class="literal">false</span>;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      &lt;h1 id=&quot;简述&quot;&gt;&lt;a href=&quot;#简述&quot; class=&quot;headerlink&quot; title=&quot;简述&quot;&gt;&lt;/a&gt;简述&lt;/h1&gt;&lt;p&gt;本系列第二篇文章，主要讲述基本概念options类，这是leveldb启动时的一些配置，主要是各个配置字段的含义要了解一下，所以本篇文章就采取源码加注释的方式（其实源码的注释就很完善，我就翻译一下）。&lt;/p&gt;
    
    </summary>
    
      <category term="职业学习" scheme="http://yoursite.com/categories/%E8%81%8C%E4%B8%9A%E5%AD%A6%E4%B9%A0/"/>
    
    
      <category term="leveldb" scheme="http://yoursite.com/tags/leveldb/"/>
    
  </entry>
  
  <entry>
    <title>基金训练营笔记</title>
    <link href="http://yoursite.com/2019/09/16/%E5%9F%BA%E9%87%91%E8%AE%AD%E7%BB%83%E8%90%A5%E7%AC%94%E8%AE%B0/"/>
    <id>http://yoursite.com/2019/09/16/基金训练营笔记/</id>
    <published>2019-09-16T14:01:29.000Z</published>
    <updated>2019-09-28T06:42:06.203Z</updated>
    
    <content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>本篇笔记记录关于基金的一些学习笔记。</p><a id="more"></a><h1 id="2019-09-16"><a href="#2019-09-16" class="headerlink" title="2019/09/16"></a>2019/09/16</h1><h2 id="什么是基金"><a href="#什么是基金" class="headerlink" title="什么是基金"></a>什么是基金</h2><p>证券市场的基金指的是，由一家基金公司收集很多投资者的钱，汇聚在一起，按照一定规则，进行各种各样投资以获取收益的一种投资品。而通过投资获得的收益或者遭到的风险，则由投资人按投资比例共享或者共担。</p><p>简单概括就是——集合投资、收益共享、风险共担。</p><h2 id="基金优势"><a href="#基金优势" class="headerlink" title="基金优势"></a>基金优势</h2><ol><li>起手金额少；</li><li>有效地分散风险；</li><li>有专业的基金经理帮忙打理。</li></ol><h2 id="基金风险"><a href="#基金风险" class="headerlink" title="基金风险"></a>基金风险</h2><ol><li>不同基金的风险不同，同一只基金的风险，可能比债券高，但是比股票低，最主要的影响因素是基金投资产品的种类，基金投资产品的风险越高，这只基金的风险也就越高。所以基金的风险不能同一而论，只有最适合自己的基金才是好基金。</li><li>基金的资金量大小、基金经理的能力，也会影响基金的风险程度。</li></ol><h1 id="2019-09-17"><a href="#2019-09-17" class="headerlink" title="2019/09/17"></a>2019/09/17</h1><p>是不是闭着眼买基金都能赚？当然不是。</p><h2 id="基金分类"><a href="#基金分类" class="headerlink" title="基金分类"></a>基金分类</h2><p>基金可以按以下四个维度进行分类：</p><ol><li>按投资品种分；</li><li>按交易渠道分；</li><li>按运作方式分；</li><li>按投资方式分。</li></ol><h3 id="按投资品种分"><a href="#按投资品种分" class="headerlink" title="按投资品种分"></a>按投资品种分</h3><ol><li>货币基金</li><li>债券基金</li><li>股票基金</li><li>混合基金。</li></ol><h4 id="货币基金和债券基金"><a href="#货币基金和债券基金" class="headerlink" title="货币基金和债券基金"></a>货币基金和债券基金</h4><p>货币基金和债券基金放的都是国债、政府债、公司债等债券，但是债券基金中债券占比要达到80%以上，且是长期债券，其他比例还可以投股票，而货币基金中投资债券的占比没有要求，除了投资债券（1年以内），它还可以投资银行定期存款等其他收益比较稳定的有价证券。</p><p>货币基金更加安全，收益大概在3%~4%。</p><p>债券基金的收益大概在6%~7%。</p><h4 id="股票基金和混合基金"><a href="#股票基金和混合基金" class="headerlink" title="股票基金和混合基金"></a>股票基金和混合基金</h4><p>股票基金中至少80%是股票，20%是其他。</p><p>混合基金则既有股票又有债券，没有规定的占比。基金经理可以通过调整股票和债券的投资占比，实现收益与风险之间的平衡。</p><p>两种基金的收益大概15%~20%，甚至更高，但风险也比货币基金和债券基金大多了。</p><h3 id="按交易渠道分"><a href="#按交易渠道分" class="headerlink" title="按交易渠道分"></a>按交易渠道分</h3><ol><li>场内基金。</li><li>场外基金。</li></ol><h4 id="场内基金"><a href="#场内基金" class="headerlink" title="场内基金"></a>场内基金</h4><p>有股票账户，在证券交易市场内交易，和你交易的对象是其他的买卖家。</p><p>场内基金的价格是实时变化的。</p><h4 id="场外基金"><a href="#场外基金" class="headerlink" title="场外基金"></a>场外基金</h4><p>是在证券交易场外购买的基金，交易的对象是基金公司。</p><p>场外基金的价格每天以下午三点为分界线。</p><h3 id="按运作方式分"><a href="#按运作方式分" class="headerlink" title="按运作方式分"></a>按运作方式分</h3><ol><li>开放式基金</li><li>封闭式基金</li></ol><h4 id="开放式基金"><a href="#开放式基金" class="headerlink" title="开放式基金"></a>开放式基金</h4><p>开放式基金的资金是不固定的，可以随时买入或者卖出，份额可以增加或减少。</p><h4 id="封闭式基金"><a href="#封闭式基金" class="headerlink" title="封闭式基金"></a>封闭式基金</h4><p>在成立后的一段时间内份额是不变的，投资者只能在场内进行买卖。</p><h3 id="按投资方式分"><a href="#按投资方式分" class="headerlink" title="按投资方式分"></a>按投资方式分</h3><ol><li>主动型基金</li><li>被动型基金</li></ol><h4 id="主动型基金"><a href="#主动型基金" class="headerlink" title="主动型基金"></a>主动型基金</h4><p>基金经理拿了我们的钱来替我们投资，投资哪家的股票、哪家的债券，都由基金经理说了算，主动出击，寻求超越平均水平的超值回报。</p><p>相比较被动型基金来说，主动型基金非常依赖基金经理的能力，基金经理个人能力的好坏直接决定基金业绩，收益可能优于市场平均收益，也有可能低于平均收益。</p><h4 id="被动型基金"><a href="#被动型基金" class="headerlink" title="被动型基金"></a>被动型基金</h4><p>又叫指数基金，是说经理不主动寻求超越时长的表现，一般选取特定的股票作为投资的对象，视图复制整个市场的平均收益率。</p><h3 id="余额宝是什么？"><a href="#余额宝是什么？" class="headerlink" title="余额宝是什么？"></a>余额宝是什么？</h3><p>余额宝是货币基金，也是场外基金，也是开放式基金，并不矛盾，只是分类标准不同。</p><h2 id="基金招募说明书"><a href="#基金招募说明书" class="headerlink" title="基金招募说明书"></a>基金招募说明书</h2><p>是基金发行方提供给投资者关于基金说明的法律文件，很重要。</p><p>但是基金招募书太长了，堪比博士论文，没必要全部看完。</p><p>五分钟看懂基金招募书：</p><h3 id="下载"><a href="#下载" class="headerlink" title="下载"></a>下载</h3><ol><li>巨潮资讯网，在基金公告下的搜索框中输入基金代码或名称，公告类别选择招募设立，很好找。</li><li>基金官网</li><li>上海或者深圳交易所</li></ol><h4 id="我买的是什么"><a href="#我买的是什么" class="headerlink" title="我买的是什么"></a>我买的是什么</h4><p>通过这一问，可以快速判断基金大概的风险程度。</p><p>找到基金募集这一章，可以看到是什么类型的基金。</p><h4 id="我的钱交给谁"><a href="#我的钱交给谁" class="headerlink" title="我的钱交给谁"></a>我的钱交给谁</h4><p>通过这一问，可以放心是否把资金交给他们大理。</p><p>找到基金管理人这一章，查看基金公司和基金经理。找到基金公司，搜索下过去是否有黑历史，无论是何种违规操作，都可以把它拉黑。</p><p>再看下基金经理，主要看他的从业时间，一般来说要3年以上的比较靠谱。至于基金经理的业绩水平后面再看。</p><h4 id="我的钱用在哪"><a href="#我的钱用在哪" class="headerlink" title="我的钱用在哪"></a>我的钱用在哪</h4><p>这一问可以帮助我们进一步指导这只基金的风险程度。</p><p>找到基金投资这一章，来看看消费的投资范围。</p><h1 id="2019-09-18"><a href="#2019-09-18" class="headerlink" title="2019/09/18"></a>2019/09/18</h1><h2 id="货币基金"><a href="#货币基金" class="headerlink" title="货币基金"></a>货币基金</h2><p>货币基金可以和信用卡一起使用来赚点小羊毛。</p><h3 id="如何筛选"><a href="#如何筛选" class="headerlink" title="如何筛选"></a>如何筛选</h3><p>有以下四点指标：</p><h4 id="成立时间"><a href="#成立时间" class="headerlink" title="成立时间"></a>成立时间</h4><p>货币基金的成立时间一般选3~5年以上的比较好，因为太年轻的基金没有历史收益率等数据作为参考，隐藏的风险相比较于老牌货币基金更大。</p><h4 id="基金规模"><a href="#基金规模" class="headerlink" title="基金规模"></a>基金规模</h4><p>货币基金的规模越大，意味着基金中的钱越多，有更充足的资金应对赎回，因为资金问题无法正常运转而被清盘的风险也会比较低。</p><p>一般在20亿~2000亿之间的规模比较好。太大也会降低收益，因为钱多了，但又要控制风险，可选择的投资品就变少了。</p><h4 id="流动性"><a href="#流动性" class="headerlink" title="流动性"></a>流动性</h4><p>流动性是指我们卖出后资金多久能回到我们的账上。</p><p>一般有T+0和T+1两种交割方式。</p><h4 id="收益率"><a href="#收益率" class="headerlink" title="收益率"></a>收益率</h4><p>货币基金的收益情况可以通过“每万份收益”和“7日年化”两个指标判断。</p><p>每万份收益：就是指按上一日或上一个交易日的收益率，一万块能够赚多少钱。</p><p>7日年化则是指，根据过去7天的收益总和，计算出的年化收益率。</p><p>一般来说，货币基金的万份收益在1左右，7日年化在3%左右。</p><p>货币基金主要是为了流动性，收益率都差不多，2%~3%左右，不会有太多区别，不用太在意收益率。</p><h3 id="实操"><a href="#实操" class="headerlink" title="实操"></a>实操</h3><p>上天天基金网。</p><p>货币基金特点：流动性高、风险低、收益稳定。</p><p>主要用来存3~6个月间需要用到的钱。</p><h2 id="债券基金"><a href="#债券基金" class="headerlink" title="债券基金"></a>债券基金</h2><p>独有优势：由专业的基金经理和团队帮你投资，省心又省力；个人投资者资金有限，直接参与债券市场，会受到一些限制；个人投资者很难做到分散投资，降低风险。</p><p>债券基金的收益大概会在5%~6%左右。</p><p>五大指标：成立年限（3年~5年以上）、收益率（选高一些的）、规模（5~100亿）、费率（挑低的）以及基金经理是否频繁更换（最少半年）。</p><p>也是去天天基金网看。</p><p>可以用半年到一年都用不到的钱来买债券基金。</p><h1 id="2019-09-19"><a href="#2019-09-19" class="headerlink" title="2019/09/19"></a>2019/09/19</h1><h2 id="混合基金"><a href="#混合基金" class="headerlink" title="混合基金"></a>混合基金</h2><p>混合基金七大指标：</p><ol><li>基金规模</li><li>成立时间</li><li>收益率</li><li>手续费</li><li>基金公司的盈利能力</li><li>基金经理的更换频率</li><li>基金经理的选股择时能力</li></ol><p>其中五个相同的都和债券基金相似，规模在2亿~100亿之间。</p><p>基金公司的盈利能力：一是看他在同类基金公司中的排名，要选排名靠前的；二是看他的盈利是否跑赢沪深300指数（大致能代表大盘走势），如果能跑赢就好了。</p><p>基金经理的选股择时能力，主要作为排除指标，考察四个指标：从业情况（大于三年）、评分（高于50）、星级（越高越好，三星以下可以排除）和管理的经济收益排名（没有跑赢同类平均水平的也可以排除）。</p><p>去天天基金网熟悉熟悉操作。</p><h2 id="股票基金"><a href="#股票基金" class="headerlink" title="股票基金"></a>股票基金</h2><p>混合型基金可以随时调整股票的投资比例，而股票基金中股票占比必须80%以上。</p><p>七个指标和混合基金相同，筛选步骤也大致相同，多熟悉操作吧。</p><h2 id="注意"><a href="#注意" class="headerlink" title="注意"></a>注意</h2><ol><li>在熊市里表现很烂，但牛市里表现强于大盘的基金要慎重。</li><li>ETF表示交易型开放式指数基金，是开放式基金的一种特殊类型，综合了开放式和封闭式基金的优点。</li></ol><h1 id="2019-09-21"><a href="#2019-09-21" class="headerlink" title="2019/09/21"></a>2019/09/21</h1><p>主动型基金，就是基金经理拿了我们的钱来替我们投资，具体可以看小白营笔记。</p><p>被动型基金，就是经理不主动寻求超越市场的表现，它的风险和收益不依赖基金经理，是由整个市场决定的。</p><p>长期来看，相比较主动型基金，被动型基金的收益更高更稳定。</p><h2 id="指数是什么"><a href="#指数是什么" class="headerlink" title="指数是什么"></a>指数是什么</h2><p>指数其实就是一个选股规则。它按照某个规则挑选出一篮子股票，由专业机构经过复杂的计算，得出一个代表这篮子股票的平均价格，然后用来反映市场上这一类股票的价格水平。</p><p>这个平均价格称为“指数点位”，把放在篮子里的这些股票称为这只指数的成份股。</p><p>指数的成份股是可以变化的，一旦某只股票不能满足原先的规则，就会被替换掉。</p><h2 id="A股是什么"><a href="#A股是什么" class="headerlink" title="A股是什么"></a>A股是什么</h2><p>A股可以简单地理解成中国大陆的股票市场。</p><p>除了A股之外，还有中国香港的港股，除了国内的股票市场外，还有美股，国内大部分公司选择在A股上市，但也有选择去香港或者美国上市的，比如腾讯和阿里。</p><h2 id="A股市场主要指数"><a href="#A股市场主要指数" class="headerlink" title="A股市场主要指数"></a>A股市场主要指数</h2><ol><li>上证50指数，主要是龙头。</li><li>沪深300指数，市值排名前300的上市公司。</li><li>中证500指数，市值排名前800名去掉前300的沪深300后留下的500个，代表中小型上市公司的平均水平。</li><li>创业板指数，100家小型企业，深证开发。</li><li>红利指数，是上证交易所上市的现金股息率高、分红比较稳定、具有一定规模及流动性的50只股票，是上证A股中真正的核心优质资源，上证开发。</li></ol><h2 id="其他市场主要指数"><a href="#其他市场主要指数" class="headerlink" title="其他市场主要指数"></a>其他市场主要指数</h2><p>美股：标普500（相当于沪深300），纳斯达克指数。</p><p>港股：恒生指数（港股上市公司50家，相当于上证50，是港股最重要的指数），H股指数（挑选了香港上市的、规模最大的33家大陆企业）。</p><h2 id="QDII基金"><a href="#QDII基金" class="headerlink" title="QDII基金"></a>QDII基金</h2><p>QDII又称为合格的境内投资者，简单的理解，就是我们可以用人民币投资海外股票市场，可以有效规避人民贬值风险。</p><h2 id="指数基金"><a href="#指数基金" class="headerlink" title="指数基金"></a>指数基金</h2><p>有点：灭绝人性、永垂不朽以及笑到最后。</p><h3 id="灭绝人性"><a href="#灭绝人性" class="headerlink" title="灭绝人性"></a>灭绝人性</h3><p>主动型基金最大的风险之一就是老鼠仓，也叫老鼠吃猫，是指无量的基金经理靠内幕消息帮自己赚钱。</p><p>指数基金是被动型基金，不用管基金经理的决策，可谓灭绝人性。</p><h3 id="永垂不朽"><a href="#永垂不朽" class="headerlink" title="永垂不朽"></a>永垂不朽</h3><p>铁打的指数，流水的公司。</p><p>就算有指数中几家公司倒闭了，也会有新公司补充进来。</p><h3 id="笑到最后"><a href="#笑到最后" class="headerlink" title="笑到最后"></a>笑到最后</h3><p>股市有一个”七亏二平一盈“的魔咒。</p><p>投资指数基金，是通过投资指数成份股，来获得和市场持平的收益。长期看来，只要经济是持续向好的，指数基金就有投资的价值。</p><h2 id="指数基金的风险"><a href="#指数基金的风险" class="headerlink" title="指数基金的风险"></a>指数基金的风险</h2><p>指数基金本质是股票型基金，它依然存在风险。</p><p>虽然指数基金是复制和跟踪指数，来调整篮子里面的股票组合。但是基金经理如果复制得有偏差，或者没有及时跟着指数调整，也会带来收益方面的误差风险。</p><p>指数基金的规模小，或者运作历史不长的话，也会有风险。</p><h2 id="PS"><a href="#PS" class="headerlink" title="PS"></a>PS</h2><p>分级基金是把母基金分成A份额和B份额，进行不同的投资，是比较复杂的基金类型。</p><p>基金在发行前购买是认购，发行后购买是申购。</p><h1 id="2019-09-22"><a href="#2019-09-22" class="headerlink" title="2019/09/22"></a>2019/09/22</h1><h2 id="指数基金分类"><a href="#指数基金分类" class="headerlink" title="指数基金分类"></a>指数基金分类</h2><p>有的指数基金在挑选股票的时候并不限制所在的行业，它覆盖了各方各业，就是属于宽基指数基金，比如沪深300、上证50等。</p><p>有的指数基金在挑选股票的时候，会要求只投资某个行业的股票，这就是行业指数基金，比如上证消费80、中证医疗指数。</p><p>宽基指数基金的最大优势是覆盖的行业更多更广，分配更均匀，所以盈利也就更稳健。</p><p>而行业指数基金就需要考虑整个行业的发展特点，受行业影响大，风险高一些。</p><p>按复制方式分，指数基金可以分为完全复制型指数基金和增强型指数基金。</p><p>完全复制型指数基金指的是完全复制目标指数所包含的所有成份股，追求和指数持平的收益。</p><p>增强型指数基金就是除了复制目标指数外，基金经理还加入自己的一些主管投资，追超超过跟踪指数的收益。</p><p>综上，完全复制型宽基指数基金比较好。</p><h2 id="选基三部曲"><a href="#选基三部曲" class="headerlink" title="选基三部曲"></a>选基三部曲</h2><h3 id="确定想要投资的指数"><a href="#确定想要投资的指数" class="headerlink" title="确定想要投资的指数"></a>确定想要投资的指数</h3><p>选择指数基金的本质就是选择指数。</p><h3 id="竞选靠谱的基金公司"><a href="#竞选靠谱的基金公司" class="headerlink" title="竞选靠谱的基金公司"></a>竞选靠谱的基金公司</h3><p>基金公司的实力，对指数基金的表现有至关重要的作用。</p><p>公司规模是一个重要的衡量标准，目前国内一般资金规模超过1000亿的基金公司实力都不可小觑，低于1000亿的就暂时不要考虑。</p><h3 id="锁定指数基金"><a href="#锁定指数基金" class="headerlink" title="锁定指数基金"></a>锁定指数基金</h3><p>筛选指标有四个：跟踪误差率、基金规模、成立年限、费用成本。</p><h4 id="跟踪误差率"><a href="#跟踪误差率" class="headerlink" title="跟踪误差率"></a>跟踪误差率</h4><p>这个指标要低于同行平均水平，而且越低越好，低表示基金运作水平高。</p><h4 id="基金规模-1"><a href="#基金规模-1" class="headerlink" title="基金规模"></a>基金规模</h4><p>越大越好，规模越大，流动性越强。流动性是指能否顺利地卖出或者买入。不要低于2亿。</p><h4 id="成立年限"><a href="#成立年限" class="headerlink" title="成立年限"></a>成立年限</h4><p>超过三年的。</p><h4 id="费用成本"><a href="#费用成本" class="headerlink" title="费用成本"></a>费用成本</h4><p>越低越好。</p><p>基金的费用包括管理费、托管费、申购费和赎回费。</p><p>大部分在2%~3%，相对来说场内基金的管理费或交易费都远低于场外基金。</p><h2 id="实操-1"><a href="#实操-1" class="headerlink" title="实操"></a>实操</h2><p>天天基金网。这节课主要讲的是怎么买，下节会将如何找到买入的好时机。</p><h2 id="指数基金何时买"><a href="#指数基金何时买" class="headerlink" title="指数基金何时买"></a>指数基金何时买</h2><h3 id="大盘点数"><a href="#大盘点数" class="headerlink" title="大盘点数"></a>大盘点数</h3><p>一般的大盘点数指的是上证综合指数的点数，靠大盘点数决定入场时间是不靠谱的。</p><h3 id="市盈率和市净率"><a href="#市盈率和市净率" class="headerlink" title="市盈率和市净率"></a>市盈率和市净率</h3><p>市盈率（PE）：等于公司市值/净利润，指的是一笔钱投资进一只股票，需要多长时间能够回本。简单理解就是与一只股票的盈利能力相比，目前它的价格是不是够便宜。</p><p>可以通过市盈率初步判断一家公司是贵还是便宜，市盈率越低，公司越便宜，反之同理，但不同作为唯一指标。</p><p>PE作为估值指标，简单粗暴、快速有效是它的一大优点，但也有明显的缺陷。不同的国家地区、不同的指数，估值的波动区间不一样。</p><p>单靠市盈率也是不靠谱的。</p><p>市净率（PB），等于市值/净资产，体现的是公司的净资产是否被低估。市净率高，公司是高估。但紧靠它也不靠谱。</p><h3 id="长投温度"><a href="#长投温度" class="headerlink" title="长投温度"></a>长投温度</h3><p>长投温度经过了市场的验证，是个非常靠谱的估值指标。</p><p>温度越高，说明股市越火爆，风险越大，上涨的空间越小，反之同理。</p><p>0~10度之间：股市萎靡不振，股市韩东，但是是最佳的买入时机。</p><p>10~20度：初春绽放，股市开始回暖，仍是买入的良机。</p><p>20~30：春暖花开，可以继续买。</p><p>30~40：市场气氛热烈，可继续持有，但需提防风险。</p><p>40~50：高温预警，可考虑逐步卖出。</p><p>……</p><p>大于90：人间地狱。</p><p>长投温度=（PE温度+PB温度）/2</p><p>长投温度的高低与价格高低没有必然的联系。</p><p>长投温度的高低反映的是在历史中，低于当前估值出现的概率。</p><h3 id="计算步骤"><a href="#计算步骤" class="headerlink" title="计算步骤"></a>计算步骤</h3><p>理杏仁官网。</p><p>公众号直接看吧。</p><h1 id="2019-9-23"><a href="#2019-9-23" class="headerlink" title="2019/9/23"></a>2019/9/23</h1><h2 id="基金投资方式"><a href="#基金投资方式" class="headerlink" title="基金投资方式"></a>基金投资方式</h2><ol><li>一次性投资，简单省事，无脑操作，缺点也很明显，一次性投完了以后遇到合适的时机就没钱投了，不靠谱。</li><li>不定期投资，择时投资，找到合适时机才下手，缺点是很容易受到主观情绪的极大干扰，理论上拥有不错的选股择时能力时，确实可以自由选择买卖时间，但绝大多数人都做不到。</li><li>定期定额，固定时间投资固定金额，一般人用这种。</li><li>定期不定额，固定时间，金额不固定，根据估值调整金额，这才是最佳方式。</li></ol><h2 id="定投的好处"><a href="#定投的好处" class="headerlink" title="定投的好处"></a>定投的好处</h2><ol><li>强制储蓄、告别月光，也可以给自己实现资金增值。</li><li>避免主观情绪干扰，只要用了有效的定投策略，坚持定投，就能获得合力的投资收益。</li></ol><h2 id="tips"><a href="#tips" class="headerlink" title="tips"></a>tips</h2><ol><li>设置定投日提醒，定期不定额需要手动，所以设个闹钟；</li><li>千万不要在定投过程中加入自己的主观判断；</li><li>投资收益投入再利用。</li></ol><h1 id="2019-9-24"><a href="#2019-9-24" class="headerlink" title="2019/9/24"></a>2019/9/24</h1><p>指数基金怎么买？简投法四步走。</p><h2 id="第一步，确定每个月的投资金额"><a href="#第一步，确定每个月的投资金额" class="headerlink" title="第一步，确定每个月的投资金额"></a>第一步，确定每个月的投资金额</h2><h3 id="有投资目标时，每月投资金额的计算"><a href="#有投资目标时，每月投资金额的计算" class="headerlink" title="有投资目标时，每月投资金额的计算"></a>有投资目标时，每月投资金额的计算</h3><p>公式：<code>PMT(r/12,n*12,,FV,1)</code></p><p>r是预期收益率，n是投资年限，FV=预期收益+本金，算出来的钱是负数，代表支出。</p><h3 id="没有投资目标时，每月投资金额的计算"><a href="#没有投资目标时，每月投资金额的计算" class="headerlink" title="没有投资目标时，每月投资金额的计算"></a>没有投资目标时，每月投资金额的计算</h3><ul><li>首先，确定自己的存量金额</li></ul><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"></span><br><span class="line">存款-应急金（3~6个月基本日常支出，平时放在货币基金）=总存量资金</span><br><span class="line"></span><br><span class="line">总存量资金/20个月 = 每个月的存量资金</span><br></pre></td></tr></table></figure><ul><li>然后，确定每月的增量资金</li></ul><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">工资-日常基本开支-保险/12 = 每月增量资金</span><br></pre></td></tr></table></figure><ul><li>最后，确定自己的风险系数</li></ul><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">100 - 年龄 = 风险系数%</span><br></pre></td></tr></table></figure><p>风险系数也就是高风险资产投资比例。</p><p>如果想对保守，可以把100换成80。</p><ul><li>算每月投资金额</li></ul><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">（每月存量资金+每月增量资金）* 风险系数 = 每月投资金额</span><br></pre></td></tr></table></figure><h2 id="第二步，如何选择指数基金"><a href="#第二步，如何选择指数基金" class="headerlink" title="第二步，如何选择指数基金"></a>第二步，如何选择指数基金</h2><p>长投温度</p><h3 id="第三步，根据长投温度进行定投"><a href="#第三步，根据长投温度进行定投" class="headerlink" title="第三步，根据长投温度进行定投"></a>第三步，根据长投温度进行定投</h3><p>买入时：</p><table><thead><tr><th style="text-align:center">长投温度</th><th style="text-align:center">投资占每月投资金额的比例</th></tr></thead><tbody><tr><td style="text-align:center">[0,10)</td><td style="text-align:center">100%</td></tr><tr><td style="text-align:center">[10,20)</td><td style="text-align:center">80%</td></tr><tr><td style="text-align:center">[20,25)</td><td style="text-align:center">60%</td></tr><tr><td style="text-align:center">[25,30)</td><td style="text-align:center">50%</td></tr><tr><td style="text-align:center">[30,40)</td><td style="text-align:center">停止投资，持有</td></tr></tbody></table><p>卖出时：</p><table><thead><tr><th style="text-align:center">长投温度</th><th style="text-align:center">卖出现有基金份额的比例</th></tr></thead><tbody><tr><td style="text-align:center">[40,50)</td><td style="text-align:center">50%</td></tr><tr><td style="text-align:center">[50,100]</td><td style="text-align:center">全卖了</td></tr></tbody></table><h3 id="第四步，指数切换"><a href="#第四步，指数切换" class="headerlink" title="第四步，指数切换"></a>第四步，指数切换</h3><p>出现另一只指数的长投温度低于当前指数2度以上的时候，我们就要迅速把这只指数对应的基金揽入怀中，重复第三步的买入策略。</p><h3 id="最后"><a href="#最后" class="headerlink" title="最后"></a>最后</h3><p>获利之后可以把钱先存在货币基金里，耐心等待温度降低，再出现投资机会时，再将这些钱当做存量资金，按照四步走重新开始一轮新的投资。</p><h1 id="2019-9-25"><a href="#2019-9-25" class="headerlink" title="2019/9/25"></a>2019/9/25</h1><h2 id="场内和场外的区别"><a href="#场内和场外的区别" class="headerlink" title="场内和场外的区别"></a>场内和场外的区别</h2><p>场内交易需要开户后才能买卖。</p><ol><li>交易渠道不同，场内必须在证券公司的股票交易系统里下单买卖，场外则是通过银行柜台、网银、基金公司网站等进行交易。</li><li>交易费率不同，场内买入或卖出单向交易费率最高不超过0.05%，现在很多券商都能做到万分之三，且没有最低5元的费用限制。而场外的买卖交易申购费一般为0.6%~1.5%，赎回费率一般为0.5%。</li><li>委托方式不同，场内交易的委托方式是“买入卖出”，就是在证券市场上跟想要买卖的人直接交易。而场外的委托方式是“申购赎回”，实际上就是向基金公司申请购买新的基金份额；赎回就是向基金公司申请卖出基金份额。</li><li>到账时间不同，场内交易当天买入后，下一个工作日就可以卖出，卖出当天，钱就会回到自己的证券账户上。场外基金如果是当天下午三点前申购，则会在下一个工作日确认份额，第二个工作日可以赎回，资金则要等到赎回后的2-4个工作日才能到账，然后再体现。如果是下午三点后申购，则所有时间点顺延一天。</li><li>交易价格不同。基金单位净值其实就是一份基金的价值，等于基金当日根据收盘价计算出来的总市值，减去当天的各类成本费用，再除以基金的发型总份额。因为场内交易是跟其他持有者交易，想买的人报价，想卖的人出价，价格一样就成交，所以喧闹的交易市场一直有人报价。但场外申购一天只有一个价格，最后的交易价格以当天收市时的基金单位净值为准。</li><li>分红方式不同。基金分红就是基金公司将基金转到的钱的一部分返还给投资者，主要有现金分红和红利再投资两种。现金分红，就是直接把钱发到账户。红利再投资就是分给你的钱直接继续买这个基金，这样获得的份额是不需要支付申购费用的。一般场内只有现金分红，而场外两种都有。</li><li>自动定投的设定不同。场内无法自动定投，需要自己手动去投，正好符合定期不定额的定投策略，场外可以自动定投。</li></ol><h1 id="2019-9-26"><a href="#2019-9-26" class="headerlink" title="2019/9/26"></a>2019/9/26</h1><p>今天主要是场内场外操作app，没啥好看的。</p><h2 id="场内"><a href="#场内" class="headerlink" title="场内"></a>场内</h2><p>买入：</p><ol><li>开户，找到要买的基金，加自选。如果账户里没钱则需要银证转账进行转款。</li><li>注意下成交量的单位都是手，一手等于100份。买入的当天查不到手续费，第二天才能查询。买入时设定好价格和数量，确认委托。</li><li>最后查看委托有没有成功。</li></ol><p>卖出：</p><ol><li>持仓里找到要买的基金，选择卖出</li><li>填委托价格和数量</li><li>卖出，确认委托。</li></ol><h2 id="场外"><a href="#场外" class="headerlink" title="场外"></a>场外</h2><p>就是支付宝了，就不提了。</p><p>一点就是单位净值等于累计净值时，就代表基金成立以来没有分红过。</p><h1 id="2019-9-27"><a href="#2019-9-27" class="headerlink" title="2019/9/27"></a>2019/9/27</h1><p>心理建设</p><h2 id="投资认知误区："><a href="#投资认知误区：" class="headerlink" title="投资认知误区："></a>投资认知误区：</h2><ol><li>我钱太少，不适合投资。这个误区一是因为鹅小，不自信，二是因为缺乏开源节流和长期规划的投资意识。巴菲特说过：投资是一种放弃今天消费，并试图在未来可消费更多的活动。控制自己不合理的消费是第一步，努力养肥你的鹅才是第二步。</li><li>想把所有的钱全部用来投资，以赚取更多的钱。这是赌博心理，违背了闲钱投资的原则。</li><li>想做短期的波段操作、赚把钱就跑。这是典型的投机心理。这违背了长期投资的原则。<strong>投资基金必须严格遵守的两个原则：闲钱+长期。</strong></li><li>希望股价一直上涨不要跌，喜涨厌跌。而事实上，股市上涨可以让我们眼下赚得更多，但对于定投的我们而言，下跌反而能让我们买的更便宜，拉低持有成本，这样才能在未来赚得更多。</li><li>止盈早了感觉赚少了，很不开心。这主要是不知足心理在作怪，没有很好地进行心理预期管理。钱是赚不完的，但是亏得玩。</li><li>我的基金盈利不如股票，要不也买股票吧。这是盲目从众心理。只要坚持原则，基金平均收益率10%~15%左右是没有问题的。</li></ol><h2 id="最佳投资姿势"><a href="#最佳投资姿势" class="headerlink" title="最佳投资姿势"></a>最佳投资姿势</h2><ol><li>始终坚持“高筑墙（努力寻找低温度指数基金），广积粮（开源节流），缓称王（不急不躁）”方针；</li><li>佛系投资</li></ol><h1 id="2019-9-28"><a href="#2019-9-28" class="headerlink" title="2019/9/28"></a>2019/9/28</h1><p>资产配置。</p><p>把资产按照50-50的比例分配到股权类和债权类资产中，是资产配置最简单易操作的方法。</p><p>债券风险较低，预期年收益6%~7%。</p><p>股票长期来看收益最高，但风险高，不按常理出牌，不能全押。</p><p>两者要同时买，不能时买时不买，也不能只买组合中的部分品种。</p><h2 id="资产配置的特点"><a href="#资产配置的特点" class="headerlink" title="资产配置的特点"></a>资产配置的特点</h2><ol><li>少亏</li><li>少赚</li></ol><h2 id="如何制定和实施资产配置"><a href="#如何制定和实施资产配置" class="headerlink" title="如何制定和实施资产配置"></a>如何制定和实施资产配置</h2><ol><li>根据自己的风险承担能力和偏好确定资产配置的策略和规则。</li><li>每年做一次动态再平衡，根据账户资金的变化，按制定的策略重新调整一次资产比例。</li></ol><h2 id="小技巧"><a href="#小技巧" class="headerlink" title="小技巧"></a>小技巧</h2><ol><li>股票类资产可以再细分成几个不同的指数类型。同时配置大盘股基金和小盘股基金；根据区域经济的不同配置基金，比如同时配置A股和美国或港股的指数基金；还可以看行业指数基金。</li><li>灵活调整股票和债券的配置比例。比如长投温度低的时候就多配指数基金，长投温度高的时候就多配债券。</li></ol><p>【END】</p>]]></content>
    
    <summary type="html">
    
      &lt;h1 id=&quot;前言&quot;&gt;&lt;a href=&quot;#前言&quot; class=&quot;headerlink&quot; title=&quot;前言&quot;&gt;&lt;/a&gt;前言&lt;/h1&gt;&lt;p&gt;本篇笔记记录关于基金的一些学习笔记。&lt;/p&gt;
    
    </summary>
    
      <category term="大杂烩" scheme="http://yoursite.com/categories/%E5%A4%A7%E6%9D%82%E7%83%A9/"/>
    
    
      <category term="理财投资" scheme="http://yoursite.com/tags/%E7%90%86%E8%B4%A2%E6%8A%95%E8%B5%84/"/>
    
  </entry>
  
  <entry>
    <title>五险一金课程</title>
    <link href="http://yoursite.com/2019/09/12/%E4%BA%94%E9%99%A9%E4%B8%80%E9%87%91%E8%AF%BE%E7%A8%8B/"/>
    <id>http://yoursite.com/2019/09/12/五险一金课程/</id>
    <published>2019-09-12T14:08:32.000Z</published>
    <updated>2019-09-12T15:49:59.433Z</updated>
    
    <content type="html"><![CDATA[<h1 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h1><p>小白训练营的课程结束了，但是投资理财的学习之路不能停止，再进一步学习之前，我决定先把每天签到领到的五险一金课程看一遍，本篇文章就是看学习该课程所做的笔记。</p><a id="more"></a><p>最基本的，五险一金指的是养老保险、医疗保险、生育保险、工伤保险、失业保险以及住房公积金。</p><h1 id="养老保险"><a href="#养老保险" class="headerlink" title="养老保险"></a>养老保险</h1><p>养老保险是社保的组成部分之一，顾名思义，养老保险的目标就是为了解决养老问题。</p><p>养老保险钱从哪里来？很简单，由个人和公司共同缴纳。</p><p>按照2019年上海的规定，养老保险个人缴纳工资的8%，公司缴纳工资的16%。</p><p>有些公司为了降低人力成本，会把员工的工资分为基本工资和奖金两部分，这样缴纳养老保险的基数就会变少，公司交的也就少了。</p><p>这些缴纳的钱，个人缴纳的部分会进入个人账户，这个钱就是你的。而公司缴纳的部分会进入统筹账户，这个账户的钱是统筹安排的。按照国家规定，只要缴纳养老保险15年，就可以再退休后领到退休金啦。如果没有缴纳满15年，那就只能领回个人缴纳的部分，也就是三分之一。</p><p>退休后能领到多少养老金呢？</p><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">养老金 = 基础养老金 + 个人账户养老金</span><br><span class="line">基础养老金 = （全省上年度在岗职工月平均工资 + 本人指数化月平均缴费工资）/ 2 * 缴费年限 * 1%</span><br><span class="line">个人账户养老金 = 个人账户储蓄额 / 养老金计发月数</span><br></pre></td></tr></table></figure><p>上面的信息有不知道的可以询问当地社保局。</p><p>换工作不换城市的话养老保险可以转移回老家，但如果换城市的话只有个人账户可以全部转移，单位缴纳的部分不可以转移（这……emmm……）。</p><h1 id="医疗险"><a href="#医疗险" class="headerlink" title="医疗险"></a>医疗险</h1><p>医疗险是为了补偿疾病所带来医疗费用的一种保险。</p><p>同样是公司和个人各交一部分，公司交10%，个人交2%，个人部分全部进入医保卡，单位部分有1%左右进入医保卡，剩下的9%左右进入统筹医疗账户。</p><p>个人账户就是医保卡内的钱，可以用来在定点药店买药，支付门诊费用和住院费用中个人自付的部分；而统筹账户就要由医保中心统一管理了，只有发生符合当地医保报销的费用时才能由统筹账户支付。</p><p>如果得了大病，又能报销多少呢？</p><p>一般来说，平时去医院门诊治疗住院，报销的范畴分为三个部分：起付标准下的自付部分、医疗统筹报销和大病报销。</p><p>简单来说，住院治疗所产生的费用要报销分三种情况：</p><ol><li>医药费没有达到报销的标准，就不能报销了；</li><li>达到了报销标准，按照基本医疗报销标准直接给你报销；</li><li>已经按标准报销了，但是数额特别巨大，报销后还剩一个“大窟窿”，这个时候剩下的大窟窿才能按大病保险报销。</li></ol><h2 id="停缴"><a href="#停缴" class="headerlink" title="停缴"></a>停缴</h2><p>连续两个月没有按时足额缴纳医保，就会被暂停医疗保险待遇，需要及时补足余额及缴纳滞纳金；如果连续三个月及以上没按时足额缴纳医保，虽然账户里的余额不会被清零，但是连续缴纳年限会被清零，补缴之后要重新计算缴纳年限。</p><p>当然如果离职了短期不找新工作，可以把社保缴纳在社保局的个人流动窗口，但这种社保一般只包括养老和医疗两个险种；也可以选择当地的社保代缴公司办理挂靠业务。</p><h2 id="转移"><a href="#转移" class="headerlink" title="转移"></a>转移</h2><p>异地社保转移需要先问清楚社保接受地是否接受，如果可以接受的话，需要在转出地的社保缴纳中心打印自己的社保缴费证明。</p><p>具体手续比养老保险转移简单。</p><h2 id="退休"><a href="#退休" class="headerlink" title="退休"></a>退休</h2><p>职工医保需要缴满一定的年限，才能在退休后享受终身医疗保险待遇。</p><h2 id="异地"><a href="#异地" class="headerlink" title="异地"></a>异地</h2><p>截止到2018年，我国基本实现全国社保一卡通。</p><p>异地就医主要针对4类人群：</p><ol><li>异地安置退休人员；</li><li>异地长期居住人员；</li><li>常驻异地工作人员；</li><li>异地转诊人员。</li></ol><h1 id="生育险"><a href="#生育险" class="headerlink" title="生育险"></a>生育险</h1><p>生育险是和生孩子相关的险种。</p><p>标准定义：生育保险是国家通过立法，在怀孕和分娩的妇女劳动者暂时中断劳动时，由国家和社会提供医疗服务、生育津贴和产假的一种社会保险制度，国家或社会对生育的职工给予必要的经济补偿和医疗保健的社会保险制度。</p><p>生育险主要提供三部分内容：生育津贴、医疗服务和产假。</p><p><code>生育津贴的领取金额 = 企业当月平均缴纳工资金额 / 30 * 产假天数</code></p><p>虽然男性不能直接使用生育险，但如果老婆有工作的话，老公可以享受10日的护理假津贴。如果老婆没有工作没有生育保险，就可以使用老公的生育保险享受生育保险50%的待遇。</p><p>生育险全部由公司缴纳，不需要自己交钱，比例一般在0.5%~1%。</p><h1 id="工伤险"><a href="#工伤险" class="headerlink" title="工伤险"></a>工伤险</h1><p>工伤保险，也称职业伤害保险，是指劳动者在工作中或在规定的特殊情况下，遭受意外伤害或患职业病导致暂时或永久丧失劳动能力以及死亡时，劳动者或其遗属从国家和社会获得物质帮助的一种社会保险制度。</p><p>工伤的界定有严格要求的，具体再看，要记得一点，在非上下班时间上下班途中发生事故，不能算作工伤。</p><p>所以，不要加班！</p><p>工伤保险的钱是由企业或雇主按照国家规定的费率缴纳的，劳动者个人不用缴纳任何费用。</p><h1 id="失业险"><a href="#失业险" class="headerlink" title="失业险"></a>失业险</h1><p>失业保险的作用是那些因失业而暂时中断生活来源的人提供经济帮助、以保障基本生活得以维持。</p><p>失业保险申请条件：</p><ol><li>非本人意愿中断就业；</li><li>按规定缴纳失业保险满1年以上；</li><li>已办理失业登记，并且有求职要求。</li></ol><p>失业保险是由用人单位、个人缴费几国家财政补贴来共同支撑，我们每个月工资会有一部分被强制缴纳失业保险，同时公司也会再缴一部分。</p><p>个人和用人单位各缴0.5%。</p><h1 id="公积金"><a href="#公积金" class="headerlink" title="公积金"></a>公积金</h1><p>定义就不看了，这个还是知道一点的，主要是和房子相关的。</p><p>住房公积金由个人和单位按照同等比例统共缴纳，单位和隔热缴纳的部分全部进入个人账户。</p><p>如果打算全款买房，可以取公积金抵扣房款，不用白不用。</p><p>如果贷款买房，能用公积金贷款就用公积金贷款。</p><p>如果不买房，建造/翻修/大修住房也可以用，租房也可以用，符合低保或特困救助范围的伙伴可以用，治疗家庭成员重大疾病也可以用。</p><p>【END】</p>]]></content>
    
    <summary type="html">
    
      &lt;h1 id=&quot;背景&quot;&gt;&lt;a href=&quot;#背景&quot; class=&quot;headerlink&quot; title=&quot;背景&quot;&gt;&lt;/a&gt;背景&lt;/h1&gt;&lt;p&gt;小白训练营的课程结束了，但是投资理财的学习之路不能停止，再进一步学习之前，我决定先把每天签到领到的五险一金课程看一遍，本篇文章就是看学习该课程所做的笔记。&lt;/p&gt;
    
    </summary>
    
      <category term="大杂烩" scheme="http://yoursite.com/categories/%E5%A4%A7%E6%9D%82%E7%83%A9/"/>
    
    
      <category term="理财投资" scheme="http://yoursite.com/tags/%E7%90%86%E8%B4%A2%E6%8A%95%E8%B5%84/"/>
    
  </entry>
  
  <entry>
    <title>leveldb源码学习1-slice</title>
    <link href="http://yoursite.com/2019/09/03/leveldb%E6%BA%90%E7%A0%81%E5%AD%A6%E4%B9%A01-slice/"/>
    <id>http://yoursite.com/2019/09/03/leveldb源码学习1-slice/</id>
    <published>2019-09-03T15:04:40.000Z</published>
    <updated>2019-09-03T15:06:46.362Z</updated>
    
    <content type="html"><![CDATA[<h1 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h1><p>长那么大还没看过开源项目源码，说出去太菜了，所以一直想找个C++开源项目学习一下。正好前阵子公司项目里用到了RocksDB，了解到它是leveldb的升级版，而且两个开源项目都是C++开发的，于是心动了。</p><p>本来想看RocksDB的，但看了下相比leveldb它升级了很多东西，源码多了很多，编译出来的静态库足有几百兆……所以退缩了，决定先看基础班leveldb，后面有机会再去了解RocksDB。</p><a id="more"></a><p>然而，看了几天leveldb……也好难啊……慢慢啃……</p><p>对于我这个没看过源码不知道阅读源码方法的本菜鸡来说，最好第一个阅读的项目能找到足够的解析文档来帮助学习。谷歌之后从网上找了阿里一位大佬写的《leveldb实现解析》，据说是分析leveldb比较好的文章，于是我也决定借助这篇文档来学习，希望也能学学如何看一个庞大的项目源码。</p><p>这是本次levedb系列学习的第一篇笔记，希望能坚持看完。</p><h1 id="基本概念"><a href="#基本概念" class="headerlink" title="基本概念"></a>基本概念</h1><h2 id="Slice（include-leveldb-slice-h）"><a href="#Slice（include-leveldb-slice-h）" class="headerlink" title="Slice（include/leveldb/slice.h）"></a>Slice（include/leveldb/slice.h）</h2><p>这其实就是leveldb中的string类。</p><p>leveldb没有使用<code>std::string</code>，不记得在哪看过，好像Google内部C++项目里都不使用标准库的string，而都是用slice类来代替，不知道是真是假。</p><p>slice.h其实就是字符串简单的封装，可以直接操控指针避免不必要的数据拷贝。</p><p>Note：感觉面试里让手写一个string类就可以参考这个，不过复制构造函数用的是default，尴尬了。</p><p>整体代码并不长，而且一目了然，陈列如下：<br><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">LEVELDB_EXPORT</span> <span class="title">Slice</span> &#123;</span></span><br><span class="line"> <span class="keyword">public</span>:</span><br><span class="line">  <span class="comment">// Create an empty slice.</span></span><br><span class="line">  Slice() : data_(<span class="string">""</span>), size_(<span class="number">0</span>) &#123;&#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// Create a slice that refers to d[0,n-1].</span></span><br><span class="line">  Slice(<span class="keyword">const</span> <span class="keyword">char</span>* d, <span class="keyword">size_t</span> n) : data_(d), size_(n) &#123;&#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// Create a slice that refers to the contents of "s"</span></span><br><span class="line">  Slice(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>&amp; s) : data_(s.data()), size_(s.size()) &#123;&#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// Create a slice that refers to s[0,strlen(s)-1]</span></span><br><span class="line">  Slice(<span class="keyword">const</span> <span class="keyword">char</span>* s) : data_(s), size_(<span class="built_in">strlen</span>(s)) &#123;&#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// Intentionally copyable.</span></span><br><span class="line">  Slice(<span class="keyword">const</span> Slice&amp;) = <span class="keyword">default</span>;</span><br><span class="line">  Slice&amp; <span class="keyword">operator</span>=(<span class="keyword">const</span> Slice&amp;) = <span class="keyword">default</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// Return a pointer to the beginning of the referenced data</span></span><br><span class="line">  <span class="function"><span class="keyword">const</span> <span class="keyword">char</span>* <span class="title">data</span><span class="params">()</span> <span class="keyword">const</span> </span>&#123; <span class="keyword">return</span> data_; &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// Return the length (in bytes) of the referenced data</span></span><br><span class="line">  <span class="keyword">size_t</span> size() <span class="keyword">const</span> &#123; <span class="keyword">return</span> size_; &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// Return true iff the length of the referenced data is zero</span></span><br><span class="line">  <span class="function"><span class="keyword">bool</span> <span class="title">empty</span><span class="params">()</span> <span class="keyword">const</span> </span>&#123; <span class="keyword">return</span> size_ == <span class="number">0</span>; &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// Return the ith byte in the referenced data.</span></span><br><span class="line">  <span class="comment">// REQUIRES: n &lt; size()</span></span><br><span class="line">  <span class="keyword">char</span> <span class="keyword">operator</span>[](<span class="keyword">size_t</span> n) <span class="keyword">const</span> &#123;</span><br><span class="line">    assert(n &lt; size());</span><br><span class="line">    <span class="keyword">return</span> data_[n];</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// Change this slice to refer to an empty array</span></span><br><span class="line">  <span class="function"><span class="keyword">void</span> <span class="title">clear</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    data_ = <span class="string">""</span>;</span><br><span class="line">    size_ = <span class="number">0</span>;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// Drop the first "n" bytes from this slice.</span></span><br><span class="line">  <span class="function"><span class="keyword">void</span> <span class="title">remove_prefix</span><span class="params">(<span class="keyword">size_t</span> n)</span> </span>&#123;</span><br><span class="line">    assert(n &lt;= size());</span><br><span class="line">    data_ += n;</span><br><span class="line">    size_ -= n;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// Return a string that contains the copy of the referenced data.</span></span><br><span class="line">  <span class="built_in">std</span>::<span class="function"><span class="built_in">string</span> <span class="title">ToString</span><span class="params">()</span> <span class="keyword">const</span> </span>&#123; <span class="keyword">return</span> <span class="built_in">std</span>::<span class="built_in">string</span>(data_, size_); &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// Three-way comparison.  Returns value:</span></span><br><span class="line">  <span class="comment">//   &lt;  0 iff "*this" &lt;  "b",</span></span><br><span class="line">  <span class="comment">//   == 0 iff "*this" == "b",</span></span><br><span class="line">  <span class="comment">//   &gt;  0 iff "*this" &gt;  "b"</span></span><br><span class="line">  <span class="function"><span class="keyword">int</span> <span class="title">compare</span><span class="params">(<span class="keyword">const</span> Slice&amp; b)</span> <span class="keyword">const</span></span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// Return true iff "x" is a prefix of "*this"</span></span><br><span class="line">  <span class="function"><span class="keyword">bool</span> <span class="title">starts_with</span><span class="params">(<span class="keyword">const</span> Slice&amp; x)</span> <span class="keyword">const</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> ((size_ &gt;= x.size_) &amp;&amp; (<span class="built_in">memcmp</span>(data_, x.data_, x.size_) == <span class="number">0</span>));</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span>:</span><br><span class="line">  <span class="keyword">const</span> <span class="keyword">char</span>* data_;</span><br><span class="line">  <span class="keyword">size_t</span> size_;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">inline</span> <span class="keyword">bool</span> <span class="keyword">operator</span>==(<span class="keyword">const</span> Slice&amp; x, <span class="keyword">const</span> Slice&amp; y) &#123;</span><br><span class="line">  <span class="keyword">return</span> ((x.size() == y.size()) &amp;&amp;</span><br><span class="line">          (<span class="built_in">memcmp</span>(x.data(), y.data(), x.size()) == <span class="number">0</span>));</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">inline</span> <span class="keyword">bool</span> <span class="keyword">operator</span>!=(<span class="keyword">const</span> Slice&amp; x, <span class="keyword">const</span> Slice&amp; y) &#123; <span class="keyword">return</span> !(x == y); &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">inline</span> <span class="keyword">int</span> Slice::compare(<span class="keyword">const</span> Slice&amp; b) <span class="keyword">const</span> &#123;</span><br><span class="line">  <span class="keyword">const</span> <span class="keyword">size_t</span> min_len = (size_ &lt; b.size_) ? size_ : b.size_;</span><br><span class="line">  <span class="keyword">int</span> r = <span class="built_in">memcmp</span>(data_, b.data_, min_len);</span><br><span class="line">  <span class="keyword">if</span> (r == <span class="number">0</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (size_ &lt; b.size_)</span><br><span class="line">      r = <span class="number">-1</span>;</span><br><span class="line">    <span class="keyword">else</span> <span class="keyword">if</span> (size_ &gt; b.size_)</span><br><span class="line">      r = +<span class="number">1</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> r;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p><p>该文件本身没有什么值得说道的地方，唯一可以注意一下的是重载运算符<code>!=</code>方法的实现方法是调用重载运算符<code>==</code>，这种实现方式还是很多的，比如后缀<code>++</code>的实现中一般会调用前缀<code>++</code>的函数，然后解引用运算符<code>*</code>和下表运算符<code>[]</code>好像也用了类似的实现方法，不太记得了，可以看下stl实现里面。</p><p>接下来说一下该文件里类声明中包含的<code>LEVELDB_EXPORT</code>，该字段是一个宏，定义不在本文件中，而是在<code>include/leveldb/export.h</code>中，该文件内容如下：<br><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">ifndef</span> STORAGE_LEVELDB_INCLUDE_EXPORT_H_</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> STORAGE_LEVELDB_INCLUDE_EXPORT_H_</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> !defined(LEVELDB_EXPORT)</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> defined(LEVELDB_SHARED_LIBRARY)</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> defined(_WIN32)</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> defined(LEVELDB_COMPILE_LIBRARY)</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> LEVELDB_EXPORT __declspec(dllexport)</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">else</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> LEVELDB_EXPORT __declspec(dllimport)</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span>  <span class="comment">// defined(LEVELDB_COMPILE_LIBRARY)</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">else</span>  <span class="comment">// defined(_WIN32)</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> defined(LEVELDB_COMPILE_LIBRARY)</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> LEVELDB_EXPORT __attribute__((visibility(<span class="meta-string">"default"</span>)))</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">else</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> LEVELDB_EXPORT</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span>  <span class="comment">// defined(_WIN32)</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">else</span>  <span class="comment">// defined(LEVELDB_SHARED_LIBRARY)</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> LEVELDB_EXPORT</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span>  <span class="comment">// !defined(LEVELDB_EXPORT)</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span>  <span class="comment">// STORAGE_LEVELDB_INCLUDE_EXPORT_H_</span></span></span><br></pre></td></tr></table></figure></p><p>说实话看到这玩意我是真的晕了，虽然大致能明白意思，但看的还是很难受，宏定义真的又强大又麻烦。到这里又不得不说谷歌C++规范里提到的在<code>#endif</code>或者右括号<code>}</code>后面跟上对应的注释实在是太必要了，比如上面代码里就在<code>#else</code>和<code>#endif</code>后面添加了必要的注释，提高可读性（同样是不记得在哪里见过，预处理宏定义命令都建议顶格写，可能是因为这个原因所以这里没有缩进）。</p><p>其实还是第一次见到类似<code>#if defined</code>的写法，以前最多见过<code>#ifdef</code>，于是查了下资料，发现其实这两者很相似，唯一区别在于<code>#ifdef</code>是<code>#if defined</code>的缩写形式，前者只能判断单个宏是否定义，而后者可以组成更加复杂的预编译条件。</p><p>比如<code>#if defined(DEBUG) &amp;&amp; VERSION&gt;3</code>，而用<code>#ifdef</code>必须这么写：<br><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">ifdef</span> DEBUG</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> VERSION&gt;3</span></span><br><span class="line">……</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br></pre></td></tr></table></figure></p><p>好了，解决了一些基本问题，可以来看最重要的有关<code>LEVELDB_EXPORT</code>的那几行。</p><p>这里涉及到几个之前没有接触过的函数，包括<code>__declspec(dllexport)</code>、<code>__declspec(dllimport)</code>以及<code>__attribute__((visibility(&quot;default&quot;)))</code>，接下来一一进行简单解释。</p><table><thead><tr><th>函数</th><th>用处</th></tr></thead><tbody><tr><td>__declspec(dllexport)</td><td>将一个函数声明为导出函数，可以省掉在DEF文件中手工定义导出哪些函数。当然如果DLL里都是C++的类的话，就只能导出类。</td></tr><tr><td>__declspec(dllimport)</td><td>相反，就是将一个函数声明为导入函数，是从其他动态库里引入的函数。一般情况下不使用该函数也能正确编译，但使用该函数可以使编译器生成更好的代码。不过当类中有静态变量的时候，必须要引入该函数，否则会报错。</td></tr><tr><td><strong>attribute</strong>((visibility(“default”)))</td><td>控制共享文件导出符号，<code>default</code>表示用它修饰的符号将被导出，动态库中的函数默认是可见的。<code>hidden</code>则意味不可见。其中gcc的visibility是说，如果编译的时候用了这个属性，那么动态库的符号都是hidden的，除非强制声明。</td></tr></tbody></table><p>综上，主要是为了一些导出符号考虑，暂时先了解一下，感觉就是为了让其他模块能够使用slice类吧，深层次的东西咱也不了解，知道就行。</p>]]></content>
    
    <summary type="html">
    
      &lt;h1 id=&quot;背景&quot;&gt;&lt;a href=&quot;#背景&quot; class=&quot;headerlink&quot; title=&quot;背景&quot;&gt;&lt;/a&gt;背景&lt;/h1&gt;&lt;p&gt;长那么大还没看过开源项目源码，说出去太菜了，所以一直想找个C++开源项目学习一下。正好前阵子公司项目里用到了RocksDB，了解到它是leveldb的升级版，而且两个开源项目都是C++开发的，于是心动了。&lt;/p&gt;
&lt;p&gt;本来想看RocksDB的，但看了下相比leveldb它升级了很多东西，源码多了很多，编译出来的静态库足有几百兆……所以退缩了，决定先看基础班leveldb，后面有机会再去了解RocksDB。&lt;/p&gt;
    
    </summary>
    
      <category term="职业学习" scheme="http://yoursite.com/categories/%E8%81%8C%E4%B8%9A%E5%AD%A6%E4%B9%A0/"/>
    
    
      <category term="leveldb" scheme="http://yoursite.com/tags/leveldb/"/>
    
  </entry>
  
  <entry>
    <title>理财小白训练营笔记</title>
    <link href="http://yoursite.com/2019/09/01/%E7%90%86%E8%B4%A2%E5%B0%8F%E7%99%BD%E8%AE%AD%E7%BB%83%E8%90%A5%E7%AC%94%E8%AE%B0/"/>
    <id>http://yoursite.com/2019/09/01/理财小白训练营笔记/</id>
    <published>2019-09-01T08:14:26.000Z</published>
    <updated>2019-09-10T15:19:49.138Z</updated>
    
    <content type="html"><![CDATA[<h1 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h1><p>从去年在网易实习后半段开始我就陆续开始阅读理财投资方面的入门书籍，主要是《穷爸爸富爸爸》、《小狗钱钱》以及《财务自由之路》这三本书，感觉打开了新世界的大门，遂下决心也要抽空培养一下自己的“财商”，希望未来有一天也能实现被动赚钱（说财务自由太夸张了哈哈~但也要有点梦想~）</p><p>转眼毕业上班两个月了，越发觉得要整理下自己的资产，于是最近开始看《财务自由之路》第二遍。</p><a id="more"></a><p>上周正好看到一个9块钱14天的长投小白训练营课程，想着9块钱而已，报一下看看有没有收获，于是便报名参加了课程，每天可以在线上得到一些基础知识的分享，也能解答一些疑惑。目前看来还是有收获的，9块钱感觉很值。</p><p>本着学而不思则罔的原则，便决定用这篇笔记来记录一下这个9块钱课程的一些笔记，这里只记录本人觉得9块钱课程中重要的一些点，三本书里面的观点知识还请有兴趣的小伙伴自行阅读，当然课程和书籍中所谈及的内容是有不少重合的~</p><h1 id="20190827"><a href="#20190827" class="headerlink" title="20190827"></a>20190827</h1><h2 id="时间的金钱价值"><a href="#时间的金钱价值" class="headerlink" title="时间的金钱价值"></a>时间的金钱价值</h2><ul><li>每个人的时间是最宝贵的，你的时间是最有价值的。</li><li>时间大于金钱。尽量花时间去武装大脑，而不是为了节约开支而浪费大把时间。</li><li>理财的第一个思维，重视时间成本。</li></ul><h2 id="金钱的时间价值"><a href="#金钱的时间价值" class="headerlink" title="金钱的时间价值"></a>金钱的时间价值</h2><ul><li>金钱的时间价值，就是指当前所持有的一定数量的货币，比未来同等数量的货币具有更高的购买力，就是通货膨胀。</li><li>对于不同的人而言，金钱的时间价值是不同的，这取决于他们利用这笔钱的预期投资回报率。如果预期投资回报率低于通货膨胀，那肯定花钱啊，不花就亏了，但如果预期投资回报率高于通货膨胀，就可以牺牲即时消费而选择投资。</li><li>通货膨胀是最大的风险。</li></ul><h2 id="学习的时间成本"><a href="#学习的时间成本" class="headerlink" title="学习的时间成本"></a>学习的时间成本</h2><ul><li>人生前期越嫌麻烦，越懒得学，后面就越可能错过好的风景（所以蔡康永那句话还是有道理的）。</li></ul><h1 id="20190828"><a href="#20190828" class="headerlink" title="20190828"></a>20190828</h1><h2 id="两种思维"><a href="#两种思维" class="headerlink" title="两种思维"></a>两种思维</h2><ul><li>不是先有财再去理，而是先理才有财。</li><li>有负债也可以理财，不要妄想等到还清债务再去理，那你将永远还不清。</li><li>负债看消费，盈利靠理财。</li></ul><h2 id="资产与负债"><a href="#资产与负债" class="headerlink" title="资产与负债"></a>资产与负债</h2><ul><li>资产就是能把钱放进你口袋里的东西，它能不断给你带来收入。</li><li>相反，负债就是把钱从你的口袋里取走的东西。</li></ul><h2 id="成为富人的秘密"><a href="#成为富人的秘密" class="headerlink" title="成为富人的秘密"></a>成为富人的秘密</h2><ul><li>富人的第一个秘密是，在一生中不断地买入资产，并且资产品种丰富，给自己带来更多收入，不单一依靠工资。</li><li>富人的第二个秘密是乐意接受新鲜的事物，并在不断增长见识的过程中，提升自己辨别事物的能力，同时结交更多的朋友，扩展自己的全资，进行良性循环。</li><li>如果现在没有这些资产又穷该咋办？1、学会省钱、记账。2、学会花钱，投资自己。</li></ul><h2 id="怎么去致富"><a href="#怎么去致富" class="headerlink" title="怎么去致富"></a>怎么去致富</h2><ul><li>投资自己，提升自己的技能，把自己的单位时间卖的更贵。</li><li>发展副业，爱好也可以带来收入。</li><li>可以将自己的一份时间卖出多次，比如公号文、写书。</li><li>让自己的资产增值，增加被动收入，缓解生活压力。</li><li>节流很重要，但开源更重要。</li><li>培养自己的赚钱能力。</li></ul><h1 id="20190829"><a href="#20190829" class="headerlink" title="20190829"></a>20190829</h1><ul><li>余额宝跑不过通货膨胀，有很大的风险。</li><li>这个世界所谓的规则，都是由头脑好的人制定出来的，他们故意做得让人很难弄明白，这样的话就能从那些不懂得或者懒得思考的人手里多捞好处。</li><li>理财的优势：1、跑赢通货膨胀。2、带来被动收入。3、避免被人挖坑。</li><li>分清“必要”、“需要”和“想要”。“必要”是不花会死的。“需要”是稍微提高质量的，比如买牛奶啥的。”想要“就是欲望。</li></ul><h2 id="通货膨胀"><a href="#通货膨胀" class="headerlink" title="通货膨胀"></a>通货膨胀</h2><ul><li>CPI是居民消费价格指数，定义我也看不懂，反正翻译成人话就是用一些商品价格的变动率来反映整体的物价变化情况，CPI有八大类，其中食品占比最大，34%左右。</li><li>其他通货膨胀的案例和基本解释就不写了，主要就是流通的货币过多，超过经济运行的需求，导致钱不值钱。</li></ul><h2 id="投资陷阱"><a href="#投资陷阱" class="headerlink" title="投资陷阱"></a>投资陷阱</h2><ul><li>不投资等死，乱投资找死。</li><li>沉没成本：已经发生且不可收回的支出。</li><li>防范投资骗局：1、弄清楚每个投资背后的原理，你赚谁的钱？2、要先学习再投资。3、不要相信太高的无风险投资收益率。</li></ul><h1 id="20190830"><a href="#20190830" class="headerlink" title="20190830"></a>20190830</h1><ul><li>人生的财富终值取决于你是否有投资的理念，和你的收入等有一点关系，但关系不大。</li><li>生活变故、中年危机说来就来，我们要在危机之前做好准备。</li><li>决定一个人成功与否的不是学习、不是工作、不是关系，而是思维。</li></ul><h2 id="资产配置"><a href="#资产配置" class="headerlink" title="资产配置"></a>资产配置</h2><ul><li>第一个账户：要花的钱。这是我们的日常开销账户，一般占家庭资产的10%，用来满足我们的短期消费，另外预留3~6个月的生活费作为应急金、梦想相册基金、短期内需要用的钱。这些钱一般放在银行活期存款或者货币基金（余额宝就是其中一种），使用时第一时间就能支取使用。这个账户大家都有，但容易占比过高，后果就是无财可理，月光。</li><li>第二个账户：杠杆账户，用来实现风险的管理和转移，占20%。这个账户是保险，要点是专款专用，这是保命的钱。如果没有这个账户，那我们的资产就随时面临风险。要专款专用，医保的钱就治病，不能用作其他保险。</li><li>第三个账户：投资收益账户，用来追求收益，要点是为家庭创造收益，占30%。这个账户关键在于合理的占比，既要赚的起也要亏得起。细分之下，可以将投资钱一半投资与股票或股票型基金，另一半投资风险较低的固定收益类产品。</li><li>第四个账户：保本升值的钱，也就是长期收益账户，占40%。要点是这个钱用于养老、教育，一定要保证本金不能有损失，并要抵御通货膨胀的侵蚀。重要的有三点：1、不能随意使用。2、每年每月要有固定的钱进入这个账户，积少成多。3、长期来看收益是比较稳定上升的。</li><li>商保的一个原则：双十原则。保费占到收入的10%，保额达到收入的10倍。</li></ul><h1 id="20190831"><a href="#20190831" class="headerlink" title="20190831"></a>20190831</h1><ul><li>在年轻的日子里不对自己的头脑投资，那就是对未来投降。</li><li>每年确立一个以人为师计划，把牛人的优点都长在自己身上。</li><li>一个人的愿望会深刻影响着TA的消费观。</li><li>一切节省，归根到底地都是时间的节省；一切经济，归根到底都是时间经济。——马克思牛逼。</li><li>只说消费升级就能人生升级的都是扯淡，一定要强调两者之间生产升级的重要性。</li></ul><h1 id="20190901"><a href="#20190901" class="headerlink" title="20190901"></a>20190901</h1><ul><li>复利在刚开始的时候效应是很微小的，但它呈指数型增长，等它发展到一定阶段就会产生非常惊人的效果。</li><li>复利的三个因素：本金，收益率和时间。</li><li>本金越少越要注意交易成本。</li><li>复利的方向影响：通货膨胀以及投资成本。这话主要还是为了告诉我们投资要趁早，因为不趁早的话，通货膨胀对你造成的影响就越大，同样趁早投资的话，投资成本就可以小，时间带来的收益却更多。</li><li>阻碍穷人变成富人的很大一部分原因是懒惰。</li></ul><h1 id="20190902"><a href="#20190902" class="headerlink" title="20190902"></a>20190902</h1><ul><li>五险指的是养老保险、医疗保险、工伤保险、生育保险和失业保险。</li><li>社保只是最基本的保障，虽然必不可少，但是作用十分有限。</li><li>商业保险主要包括两大类：人身保险和财产保险。</li><li>人身保险主要分为四大类：意外险、重疾险、医疗险和寿险。意外险：理赔意外伤害而导致的死亡或残疾。重疾险：补偿重大疾病带来的经济损失。医疗险：理赔在医院看病产生的医疗费用。寿险：理赔人的死亡。</li><li>在一个家庭中，首先最应该配置保险的是一个家庭的经济支柱。</li><li>买保险买的是保障，应该关注需求多于产品。保险不能保平安也不能避免风险的发生，但是它能转移风险。</li><li>买保险，财务分析不能少，找专业理财师。</li><li>保险最重要的是保障，不是投资，应该学习其他投资方式。</li><li>目前关于保险的一些错误信息：1、第一个坑：几百种重疾。主要就是重疾险并不是听它覆盖的种类越多越好的，81号文件规定了25种重疾险必须包含的25种重大疾病，其中六种就占了百分之九十左右，所以在没有条件的时候根本不需要追求25种之外的其他重大疾病种类。2、第二个坑：不可抗辩条款。说的就是不要骗保，不要身体不太好的时候才想起来买保险，要提前一些，未雨绸缪吧，保险最大的原则是诚信。</li></ul><h1 id="20190903"><a href="#20190903" class="headerlink" title="20190903"></a>20190903</h1><ul><li>对股票的两种误解：1、认为买股票就是碰运气，盲目进场乱投资。要牢记“不懂的东西不要碰”的原则。2、一想到投资股票有风险，就对股票死心了。在通货膨胀面前，不投资不仅不安全，而且还是最大的不安全因素。</li><li>股票的本质就是公司拿出部分的所有权换取资金，用于后续的经营发展。</li><li>股票赚钱有两种方式：公司分红和低买高卖。</li><li>选择高回报的投资组合，是省心又省力的好方法。</li><li>作为长期品种，股票具有很强的投资价值。</li><li>任何一次投资决策的失误都是由于投资知识的不过关导致的。</li><li>选择高回报的投资组合，是省心又省力的好方法。</li><li>估值，是整个价值投资派的核心。</li><li>不论是做何种投资，都要有自己的独立思考，不能把希望压在别人的身上。选择价值投资，需要有分析市场的能力，也需要精妙的策略，并且有持有的耐心，最终才会收获收益。</li><li>价值投资的另一个好处：通过分析，你对行业能够有更深刻的了解，从而能够找到这个行业的痛点并寻找到风口。</li><li>要给自己设个目标。</li></ul><h1 id="20190904"><a href="#20190904" class="headerlink" title="20190904"></a>20190904</h1><p>投资千变万化，但也逃脱不了五种类型。</p><ul><li>第一类投资品：中间商倒买倒卖。代表有银行信托等。原理：汇集了很多人的钱，然后再把钱借给需要钱的人，以赚取中间差额。注意点：中间人的信用，看他们把钱借给了谁，那些借钱的人能不能还的了欠的钱和利息。</li><li>第二类投资品：无中间商赚差价。代表：债券。原理：把钱借给国家、地方政府或者企业，赚取利息。关注点：借款人的信用资质，看看他们还钱的几率大不大。</li><li>第三类投资品：拥有部分资产。代表：股票。原理：人们用自己的钱买公司的部分资产，与公司共同承担风险，亏盈共享。注意点：你出钱投资的这家公司赚不赚钱。</li><li>第四类投资品：成为资产所有人。代表：黄金、期货、艺术品、房地产等。原理：靠着外部信息，通过预测未来的涨跌赚钱，与自身价值无关。注意点：哪些因素会影响价格，然后综合判断。</li><li>第五类投资品：混合型投资品。代表：银行理财、基金等。原理：它投资的不是单一的东西，里面既有股票也有债券。注意点：高低风险投资品的成分占比。</li></ul><h1 id="20190905"><a href="#20190905" class="headerlink" title="20190905"></a>20190905</h1><ul><li>基金，就是基金公司收集投资者的钱，按照证监会规定的规则，进行各种各样的投资的一种投资品。</li><li>根据投资理念的不同，基金可以分为主动基金和被动型基金。被动型基金又叫指数型基金，指数基金就是基金经理不主动寻求超越市场的表现，复制别人的整个投资，不需要你自己花太多精力来做选择。</li><li>主动型基金的两个缺点是，过于依赖基金经理，交易成本偏高。</li><li>定投就是在固定的日期，投入固定的钱。基金定投的好处是：投资门槛很低；操作非常简单；摊薄投资成本；强制储蓄资金。</li><li>货币基金是专门投资于银行间存款，债券基金是专门投资债券，股票基金就是专门投资股票的基金，通常所说的股票基金就是主动型基金。</li><li>什么是指数？指数就是一个股票的榜单，复杂一点来讲指数就是加权平均值，用来反映市场平均水平。什么是指数基金？以沪深300为例，某基金公司设置某支理财产品，根据沪深300指数按比例买入对应的股票组成基金产品，就是指数基金。巴菲特说过买指数基金就是买国运，只要相信国家经济能继续发展，指数基金就能长期上涨。指数基金的特点为：灭绝人性、长生不老、永远上涨，买指数就是买国运。定投指数基金要选择微笑曲线，从而决定何时入场。</li><li>要学会估值，根据估值来决定是否进场。过去6年时间里指数点位大部分时间都在3000点以下，超过的话大部分就会亏损了。</li></ul><h1 id="2019-09-06"><a href="#2019-09-06" class="headerlink" title="2019/09/06"></a>2019/09/06</h1><ul><li>买基金共有四种渠道：1、证券公司。2、银行。3、基金公司。4、第三方代销平台，如天天基金，蚂蚁。第一种属于场内基金，其余的都是场外基金。</li><li>场内基金的一大好处是便宜。场内基金的交易叫买卖，对手是其他交易者，按照实时价格成交，类似股票交易。场内交易不会影响基金的整体份额。</li><li>场外基金的交易叫做申购赎回，对手是基金公司，按照净值申购赎回。在每天下午3点钱申赎的，按照当天的净值成交，下午3点以后申赎的，按照第二天的净值成交。场外交易会影响基金的整体份额。场外的优势：方便，不用开股票账户，可以自动定投。</li><li>开户中的坑：1、高佣金，开户时候的佣金越便宜，交易成本就越低越划算。股票和基金的佣金不相同，股票证监会规定佣金门槛最低5元，一般不超过万三。基金的手续费相似，万三左右，但华泰证券没有最低5元佣金的限制。2、杂费，主要指经手费和监管费，又被称为规费，有的有诚意的券商会把规费包含在佣金中，有些则不会，需要问清楚。3、叠加套餐，建议不要。</li></ul><h1 id="2019-09-07"><a href="#2019-09-07" class="headerlink" title="2019/09/07"></a>2019/09/07</h1><h2 id="信用卡"><a href="#信用卡" class="headerlink" title="信用卡"></a>信用卡</h2><ul><li>什么是信用卡？信用卡是一种个人、小额、短期、无息、消费贷款工具。</li><li>信用卡首先的特点就是免息期，信用卡持卡人在一个消费周期内使用信用卡消费是免息的。信用卡有两个比较重要的日子，一是账单日，二是还款日。</li><li>信用卡的第二个特点就是高利率，每日万分之五，使用不当就成了高利贷。以下情况信用卡会变成高利贷：1、逾期未还，步步紧会产生逾期费用，而且还会对征信造成污点。2、每月只还最低还款额。这不会影响征信，但会产生大量的高额利息支出。后续想要提额也就很难。3、分期付款。</li><li>信用卡的合理使用：1、合理用好免息期，可以在记账日的后一天买。2、巧用信用额度，多元化刷卡。3、合理利用积分以及各类银行不同的活动。</li><li>信用卡使用tips：1、尽可能利用免息还款期，即采用全额还款模式。2、利用免息还款期高阶玩法，可以办理不同银行的信用卡，并错开它们的账单日。3、将信用卡的免息期和货币基金搭配使用，很多货币基金都提供信用卡还款功能。</li></ul><h2 id="韭菜"><a href="#韭菜" class="headerlink" title="韭菜"></a>韭菜</h2><ul><li>纯韭菜的选股误区：1、以名取股。要知道买股票其实就是买公司。2、投资价格低的股票。我们要看的是市值有没有低于估值，而不是看单股的价格。3、听人推荐选股。跟风是非常危险的。最起码要知道买入卖出的逻辑，知道买点和卖点。4、不清楚股票买卖点。股市是有人买有人卖才能交易，如果你挂出一个价没有人买，也是无法成交的。</li><li>我们是上市公司的消费者，我们的生活和股票是分不开的。</li><li>要扩大格局视野，找到比自己目前高一级的圈子。</li></ul><h1 id="2019-09-08"><a href="#2019-09-08" class="headerlink" title="2019/09/08"></a>2019/09/08</h1><ul><li>如果真正想做一件事，就一定要尽早地融入到行业内部圈子，更加核心或者更加前端，圈外人只有等到变化了才行动，那太慢了。</li><li>道理不是明白了就一定能做到的。投资也不是一蹴而就的。</li><li>注意投入产出比。</li><li>高收益与高风险并存。</li><li>重视风险才能笑到最后。</li></ul><h1 id="2019-09-09"><a href="#2019-09-09" class="headerlink" title="2019/09/09"></a>2019/09/09</h1><ul><li>工资的增长模式是线性的，而互联网商业的增长模式是指数的。</li><li>互联网最大的作用，就是增大了个体的链接力和影响力，和未来不可预测的想象空间。</li><li>雇佣制会退出舞台，合伙制会成为主流。</li><li>虚拟社会大于实体社会；AI人工智能大于应用技能；资本大于劳动力。</li><li>理财第一步：树立正确投资理念。理财第二步：选择正确的方法。</li><li>系统地学习初级知识，然后在这个基础上，选择自己感兴趣的，适合自己的投资方向，构建属于自己的能力圈。</li><li>投资理财的不可能三角：收益性、安全性与流动性三者往往不可兼得，最多只能占两个。</li><li>投资机会不是一直都有的。不要等到错过了才哇哇叫。多学习不同的投资品种。</li><li>破发的两个方面原因：1、发行价的每股收益基数。2、发行市赢率。</li><li>A股是面向国内发行的股票，以人民币作为结算方式。B股则是面向国外发行，主要以美元或者港币作为结算方式。</li></ul><h1 id="2019-09-10"><a href="#2019-09-10" class="headerlink" title="2019/09/10"></a>2019/09/10</h1><h2 id="国债逆回购"><a href="#国债逆回购" class="headerlink" title="国债逆回购"></a>国债逆回购</h2><ul><li>国债逆回购说白了就是借钱给企业，是一种短期贷款。它利率高的时候，就是市场缺钱的时候。</li><li>安全。低风险高收益。操作方便。手续费低。</li><li>适合新手投资初期试水。</li><li>国债逆回购一共有18种，沪深各9种。</li><li>主要买短期的。</li></ul>]]></content>
    
    <summary type="html">
    
      &lt;h1 id=&quot;背景&quot;&gt;&lt;a href=&quot;#背景&quot; class=&quot;headerlink&quot; title=&quot;背景&quot;&gt;&lt;/a&gt;背景&lt;/h1&gt;&lt;p&gt;从去年在网易实习后半段开始我就陆续开始阅读理财投资方面的入门书籍，主要是《穷爸爸富爸爸》、《小狗钱钱》以及《财务自由之路》这三本书，感觉打开了新世界的大门，遂下决心也要抽空培养一下自己的“财商”，希望未来有一天也能实现被动赚钱（说财务自由太夸张了哈哈~但也要有点梦想~）&lt;/p&gt;
&lt;p&gt;转眼毕业上班两个月了，越发觉得要整理下自己的资产，于是最近开始看《财务自由之路》第二遍。&lt;/p&gt;
    
    </summary>
    
      <category term="大杂烩" scheme="http://yoursite.com/categories/%E5%A4%A7%E6%9D%82%E7%83%A9/"/>
    
    
      <category term="理财投资" scheme="http://yoursite.com/tags/%E7%90%86%E8%B4%A2%E6%8A%95%E8%B5%84/"/>
    
  </entry>
  
  <entry>
    <title> 《程序员修炼之道》读书笔记 </title>
    <link href="http://yoursite.com/2019/08/19/%E3%80%8A%E7%A8%8B%E5%BA%8F%E5%91%98%E4%BF%AE%E7%82%BC%E4%B9%8B%E9%81%93%E3%80%8B%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/"/>
    <id>http://yoursite.com/2019/08/19/《程序员修炼之道》读书笔记/</id>
    <published>2019-08-19T14:03:41.000Z</published>
    <updated>2019-08-19T14:05:29.064Z</updated>
    
    <content type="html"><![CDATA[<p>偶然在组里书柜里看到了这本书，听说是新人程序员的圣经，正巧自己最近也在找这种培养思维和习惯的书看，所以就打算趁闲暇看下，希望对自己有所帮助。</p><p>PS：看了几页，很多都是寓意的小故事，没法精确地摘抄某几个句子来表达思想，所以可以的话还是买本书看一看吧。</p><a id="more"></a><h1 id="第一章-注重实效的哲学"><a href="#第一章-注重实效的哲学" class="headerlink" title="第一章 注重实效的哲学"></a>第一章 注重实效的哲学</h1><p>在前言里，书里提到了两个提示，就放在这里记录一下：</p><ul><li>提示1：关心你的技艺。除非你在乎能否漂亮地开发出软件，否则其他事情都是没有意义的。</li><li>提示2：思考！你的工作。在你做某件事情的时候思考你在做什么。</li></ul><h2 id="我的源码让猫给吃了"><a href="#我的源码让猫给吃了" class="headerlink" title="我的源码让猫给吃了"></a>我的源码让猫给吃了</h2><ul><li>提示3：提供各种选择，不要找蹩脚的借口。</li><li>负责，责任是你主动担负的东西。如果你确实同意要为某个结果负责，你就应切实负起责任。</li><li>在你问问题或者说做不到之前，先停下来，在头脑里预演一遍对话，想想其他人可能会说什么，把理由说给猫听，感觉理由是否合理，否则不要麻烦别人。</li></ul><h2 id="软件的熵"><a href="#软件的熵" class="headerlink" title="软件的熵"></a>软件的熵</h2><ul><li>熵是指某个系统中无序的总量。软件中的无序增长时，程序员们称之为“软件腐烂”。</li><li>提示4：不要容忍破窗户。即不要留着低劣的设计、错误决策、糟糕的代码而不去修理。发现一个就修一个。</li><li>置之不理会更快加速腐烂的进程。</li><li>简单来说，就是大家都不会愿意做第一个弄脏东西的人，但如果东西已经有地方脏了，那就无所谓了，所有人都不会再在乎。</li></ul><h2 id="石头汤与煮青蛙"><a href="#石头汤与煮青蛙" class="headerlink" title="石头汤与煮青蛙"></a>石头汤与煮青蛙</h2><ul><li>提示5：做变化的催化剂。在有些情况下，你可能确切地知道要什么，但需要去处理整个事件的时候就会遇到拖延和冷漠，事情会变复杂，每个人都会护卫自己的资源。这时就是你拿出石头的时候，因为人们会觉得参与正在发生的成功更容易，让他们看见未来，你就能让他们狙击在你周围。</li><li>提示6：记住大图景。不要像温水煮青蛙一样，要留心大图景，要持续不断地观察周围发生的事情，而不只是你自己在做的事情。</li></ul><h2 id="足够好的软件"><a href="#足够好的软件" class="headerlink" title="足够好的软件"></a>足够好的软件</h2><ul><li>让你的用户参与权衡。</li><li>提示7：我们所制作的系统的范围和质量应该作为系统需求的一部分规定下来。今天的了不起的软件常常比明天的完美软件更可取。</li><li>不要因为过度修饰和过于求精而毁损完好的程序。</li></ul><h2 id="你的知识资产"><a href="#你的知识资产" class="headerlink" title="你的知识资产"></a>你的知识资产</h2><ul><li>提示8：定期为你的知识资产投资。要点有定期投资、多元化、管理风险、低买高卖以及重新评估和平衡。</li><li>可以设定一些目标，比如一年学一门新语言、一季度看一本技术书……</li><li>提示9：批判地分析你读到的和听到的。要抓住学习机会，要批判地思考。</li></ul><h2 id="交流"><a href="#交流" class="headerlink" title="交流"></a>交流</h2><ul><li>知道你想要说什么，规划想要说的东西。</li><li>了解你的听众。</li><li>选择时机。</li><li>选择风格。</li><li>让文档美观，并在制作过程中让听众参与。</li><li>做倾听者。把会议变成对话。</li><li>回复他人。</li><li>提示10：你说什么和你怎么说同样重要。</li></ul><h1 id="第2章-注重实效的途径"><a href="#第2章-注重实效的途径" class="headerlink" title="第2章 注重实效的途径"></a>第2章 注重实效的途径</h1><h2 id="重复的危害"><a href="#重复的危害" class="headerlink" title="重复的危害"></a>重复的危害</h2><ul><li>提示11：DRY-Don’t Repeat Yourself。系统中的每一项知识都必须具有单一、无歧义、权威的表示。</li><li>无意的重复里提到，即使重复了也要把重复限制在局部，不要暴露给外界。</li><li>提示12：让复用变得容易。</li></ul><h2 id="正交性"><a href="#正交性" class="headerlink" title="正交性"></a>正交性</h2><ul><li>在计算机技术里，正交是指某种不依赖性或解耦性，如果两个或更多事物中的一个发生变化，不会影响其他事物，这些事物就是正交的。比如在设计良好的系统中，数据库代码和用户界面就是正交的。</li><li>提示13：消除无关事物之间的影响。</li><li>编写正交的系统，可以提高生产率并降低风险。</li><li>团队划分方面的一点建议就是将基础设施与应用分离，每个主要的基础设施组件（比如数据库、通信接口、中间件等）有自己的子团队。</li></ul><h2 id="可撤销性"><a href="#可撤销性" class="headerlink" title="可撤销性"></a>可撤销性</h2><ul><li>提示14：不存在最终决策。要考虑到决策的可撤销性。</li></ul><h2 id="曳光弹"><a href="#曳光弹" class="headerlink" title="曳光弹"></a>曳光弹</h2><ul><li>提示15：用曳光弹找到目标。</li><li>总有改动需要完成，总有功能需要增加。</li><li>曳光代码有很多优点：用户能够及早看到能工作的东西；开发者构建了一个他们能在其中工作的结构；你有了一个集成平台；你有了可用于演示的东西；你将更能够感觉到工作进展。</li><li>感觉就是先搭个架子，再步步逼近。</li><li>曳光和原型编程还有区别，原型编程是生成用过就扔的代码，而曳光代码虽然简约，却是完整的（当然我并没有理解……）。可以把原型制作视为在第一发曳光弹发射之前进行的侦查和情报搜集工作。</li></ul><h2 id="原型与便笺"><a href="#原型与便笺" class="headerlink" title="原型与便笺"></a>原型与便笺</h2><ul><li>建立原型的原因是为了分析和揭示风险，并以大大降低的带来来为修正提供机会，就像是汽车制造商造的某种模型，概念图，只是为了展示某一个方面，但却不是真正能用的（这么一想感觉原型和曳光弹确实有区别好像……）。</li><li>提示16： 为了学习而制作原型。原型的设计目的地是会大一些问题，可以忽略不重要的细节，比如制作GUI原型的时候就不要在意取到的数据正确与否。原型的价值不在于所产生的代码，而在于学习的经验教训。</li><li>构建原型时，可以忽略以下细节：正确性、完整性、健壮性、风格。</li></ul><h2 id="领域语言"><a href="#领域语言" class="headerlink" title="领域语言"></a>领域语言</h2><ul><li>提示17：靠近问题领域编程。</li><li>可以通过两种不同的方式使用你实现的语言：数据语言和命令语言。</li><li>没看太明白，感觉好像说的是写一串公用的话，然后利用这段话解析成所需代码。</li></ul><h2 id="估算"><a href="#估算" class="headerlink" title="估算"></a>估算</h2><ul><li>提示18：估算，以避免发生意外。</li><li>建议这样估算时间，十五天内用天，八周内用周，30周内用月，超出30周的时候请努力思考一下再估算。要选择能反映你想要传达的精度的单位。</li><li>理解提问内容，建立系统的模型，把模型分解成组件，给每个参数指定值，计算答案，追踪你的估算能力</li><li>提示19：通过代码对进度表进行迭代。</li></ul><h1 id="第3章-基本工具"><a href="#第3章-基本工具" class="headerlink" title="第3章 基本工具"></a>第3章 基本工具</h1><h2 id="纯文本的威力"><a href="#纯文本的威力" class="headerlink" title="纯文本的威力"></a>纯文本的威力</h2><ul><li>提示20：用纯文本保存知识。</li><li>纯文本有两个主要缺点：1、与压缩的二进制格式相比，存储纯文本所需空间更多；2、要解释及处理纯文本文件，计算上的代价可能更昂贵。</li><li>好处：保证不过时，杠杆作用，更易于测试。</li></ul><h2 id="shell游戏"><a href="#shell游戏" class="headerlink" title="shell游戏"></a>shell游戏</h2><ul><li>提示21：利用命令shell的力量。</li></ul><h2 id="强力编辑"><a href="#强力编辑" class="headerlink" title="强力编辑"></a>强力编辑</h2><ul><li>提示22：用好一种编辑器。</li><li>编辑器特性：可配置、可扩展、可编程</li><li>用好一款编辑器可以提高生产率。</li></ul><h2 id="源码控制"><a href="#源码控制" class="headerlink" title="源码控制"></a>源码控制</h2><ul><li>提示23：总是使用源码控制。</li></ul><h2 id="调试"><a href="#调试" class="headerlink" title="调试"></a>调试</h2><ul><li>要接受事实：调试就是解决问题，要据此发起进攻。</li><li>提示24：要修正问题，而不是发出指责。</li><li>提示25：不要恐慌。这是调试的第一准则。</li><li>如果你目睹bug或见到bug报告时的第一反应是“那不可能”，那你就错了，不要把脑细胞浪费在以“那不可能”起头的思路上，因为已经发生了。</li><li>要总是设法找出问题的根源，而不只是问题的特定表现。</li><li>从何处开始，在解决问题时，可能需要搜集所有的相关数据，比如可能需要观察报告bug用户的操作，以获取足够程度的细节。</li><li>测试策略，一旦你认为你知道了在发生什么，就到了找出程序认为在发生什么的时候了。</li><li>开始修正bug的最佳途径是让其可再现。使数据可视化。</li><li>调试器通常会聚焦于程序现在的状态，但有时需要更多的东西——可能需要观察程序或数据结构随时间变化的状态。</li><li>橡皮鸭</li><li>bug有可能存在于第三方库——但不应该是你的第一想法。提示26：”select”没有问题。</li><li>提示27：不要假定，要证明。</li><li>当遇到令人吃惊的bug时，除了只是修正它之外，还需要确定先前为什么没有找出这个故障。考虑是否需要改进单元测试。</li><li>如果bug是一些坏数据的结果，那是否能进行更好的参数检查来隔离它们。</li><li>考虑造成这个bug的条件是否存在于系统中的其他地方。</li></ul><h2 id="文本操纵"><a href="#文本操纵" class="headerlink" title="文本操纵"></a>文本操纵</h2><ul><li>提示28：学习一种文本操纵语言，比如Perl（这两天迁移代码的时候刚遇到过）。</li></ul><h2 id="代码生成器"><a href="#代码生成器" class="headerlink" title="代码生成器"></a>代码生成器</h2><ul><li>提示29：编写能编写代码的代码。</li><li>分为被动代码生成器以及主动代码生成器。</li><li>被动代码生成器减少敲键次数，本质上是参数化模板，结果一旦生成，就变成项目中充分的源文件。</li><li>通过主动代码生成器，可以取某项知识的一种表现形式，将其转化为你的应用需要的所有形式。</li></ul><h1 id="第4章-注重实效的偏执"><a href="#第4章-注重实效的偏执" class="headerlink" title="第4章 注重实效的偏执"></a>第4章 注重实效的偏执</h1><ul><li>提示30：你不可能写出完美的软件。</li></ul><h2 id="按合约设计"><a href="#按合约设计" class="headerlink" title="按合约设计"></a>按合约设计</h2><ul><li>什么是正确的程序？不多不少，做它声明要做的事情的程序。用文档记载这样的声明，并进行校验，是按合约设计（DBC）的核心。</li><li>提示31：通过合约进行设计。</li><li>在设计时简单地列举输入域的范围是什么、边界条件是什么、例程允诺交付什么——或者更重要的，它不允诺交付什么——是向着编写更好的软件的一次飞跃。</li><li>如果要对参数进行任何显式的检查，就必须由调用者来完成。</li></ul><h2 id="死程序不说谎"><a href="#死程序不说谎" class="headerlink" title="死程序不说谎"></a>死程序不说谎</h2><ul><li>防卫性编程。</li><li>提示32：早崩溃。要崩溃，不要破坏。有很多时候，让你的程序崩溃是你的最佳选择。</li><li>基本的原则：但给你的代码发现，某件被认为是不可能的事情已经发生时，你的程序就不再有存活能力。</li></ul><h2 id="断言式编程"><a href="#断言式编程" class="headerlink" title="断言式编程"></a>断言式编程</h2><ul><li>提示33：如果它不可能发生，用断言确保它不会发生。不过绝不要把必须执行的代码放在assert中。不要用断言代替真正的错误处理，断言检查的是绝不应该发生的事情。</li><li>海森堡虫子：调试改变了被调试系统的行为。</li></ul><h2 id="何时使用异常"><a href="#何时使用异常" class="headerlink" title="何时使用异常"></a>何时使用异常</h2><ul><li>异常很少应该作为程序的正常流程的一部分使用，异常应该保留给意外事件。</li><li>提示34：将异常用于异常的问题。</li></ul><h2 id="怎样配平资源"><a href="#怎样配平资源" class="headerlink" title="怎样配平资源"></a>怎样配平资源</h2><ul><li>提示35：要有始有终。分配资源、使用它，然后解除分配。分配资源的例程也应该负责释放它。</li><li>在嵌套的分配情况下：有两点建议，一是以与资源分配的次序相反的次序解除资源的分配。二是在代码的不同地方分配同一组资源时，总是以相同的顺序分配它们。这会降低死锁的可能性。</li></ul><h1 id="第5章-弯曲，或折断"><a href="#第5章-弯曲，或折断" class="headerlink" title="第5章 弯曲，或折断"></a>第5章 弯曲，或折断</h1><h2 id="解耦与德墨忒尔法则"><a href="#解耦与德墨忒尔法则" class="headerlink" title="解耦与德墨忒尔法则"></a>解耦与德墨忒尔法则</h2><ul><li>提示36：使模块之间的耦合减至最少。</li><li>响应集的定义：类的各个方法直接调用的函数的数目。</li><li>得墨忒尔法则：某个对象的任何方法都应该只调用属于以下情形的方法：它自身、传入该方法的任何参数、该方法内new创建的任何对象以及任何直接持有的组件对象。</li><li>事实上，如果对得墨忒尔法则进行反转，使模块紧密耦合，有时就可以获得重大的性能改进。这就需要看情况来权衡。 </li></ul><h2 id="元程序设计"><a href="#元程序设计" class="headerlink" title="元程序设计"></a>元程序设计</h2><ul><li>动态配置，提示37：要配置，不要集成。</li><li>为一般情况编写程序，把具体情况放在别处——在编译的代码库之外。提示38：把抽象放进代码，细节放进元数据。</li><li>没有元数据，你的代码就不可能获得它应有的适应性与灵活性。</li></ul><h2 id="时间耦合"><a href="#时间耦合" class="headerlink" title="时间耦合"></a>时间耦合</h2><ul><li>在设计时间要素时，有两个方面对我们很重要：并发和次序。</li><li>我们需要容许并发，并考虑解除任何时间或次序上的依赖。</li><li>提示39：分析工作流，以改善并发性。</li><li>提示40：用服务进行设计。</li><li>提示41：总是为并发进行设计。</li></ul><h2 id="它只是视图"><a href="#它只是视图" class="headerlink" title="它只是视图"></a>它只是视图</h2><ul><li>模块或类的一个好定义就是，它具有单一的、定义良好的责任。</li><li>发布/订阅模式，Model-View-Controller模式：既让模型与表示模型的GUI分离，也让模型与管理视图的控件分离。提示42：使视图与模型分离。</li><li>模型：表示目标对象的抽象数据模型。模型对任何视图或控制器都没有直接的了解</li><li>视图：解释模型的方式，它订阅模型中的变化和来自控制器的逻辑事件。</li><li>控制器：控制视图、并向模型提供新数据的途径，它既向模型、也向视图发布时间。</li></ul><h2 id="黑板"><a href="#黑板" class="headerlink" title="黑板"></a>黑板</h2><ul><li>黑板系统让我们能够完全解除对象之间的耦合，并提供一个论坛，知识消费者和生产者可以在那里匿名、异步地交换数据。</li><li>提示43：用黑板协调工作流。</li></ul><h1 id="第6章：当你编码时"><a href="#第6章：当你编码时" class="headerlink" title="第6章：当你编码时"></a>第6章：当你编码时</h1><h2 id="靠巧合编程"><a href="#靠巧合编程" class="headerlink" title="靠巧合编程"></a>靠巧合编程</h2><ul><li>避免靠巧合编程——依靠运气和偶然的成功——而要深思熟虑地编程。</li><li>对于你的例程的调用，要只依靠记入了文档的行为。如果处于任何原因你无法做到这一点，那就充分地把你的各种假定记入文档。</li><li>提示44：不要靠巧合编程。并非以明确的事实为基础的假定是所有项目的祸害。</li><li>怎样深思熟虑地编程：1、总是意识到你在做什么。2、不要盲目地编程。3、按照计划行事。4、依靠可靠的事物。5、为你的假定建立文档。6、不要只是测试你的代码，还要测试你的假定。7、为你的工作划分优先级。8、不要做历史的奴隶，不要让已有的代码支配将来的代码。</li></ul><h2 id="算法速率"><a href="#算法速率" class="headerlink" title="算法速率"></a>算法速率</h2><ul><li>提示45：估算你的算法的阶。</li><li>不确定代码运行时间的时候可以试着运行它，并记录不同的输入和运行时间，把结果绘制成图标。</li><li>提示46：测试你的估算。</li></ul><h2 id="重构"><a href="#重构" class="headerlink" title="重构"></a>重构</h2><ul><li>代码需要演化：它不是静态的事物。</li><li>无论代码具有下面的哪些特征，都应该考虑重构代码：重复、非正交的设计、过时的知识、性能。</li><li>提示47：早重构，常重构。</li><li>怎样进行利大于弊的重构：1、不要在重构的同时增加功能；2、在开始重构之前，确保拥有良好的测试，并尽可能经常地运行它们。3、采取短小、深思熟虑的步骤。</li></ul><h2 id="易于测试的代码"><a href="#易于测试的代码" class="headerlink" title="易于测试的代码"></a>易于测试的代码</h2><ul><li>我们需要从一开始就把可测试性构建进软件中，并且在把各个部分连接在一起之前对每个部分进行彻底的测试。</li><li>提示48：为测试而设计。</li><li>提示49：测试你的软件，否则你的用户就得测试。</li></ul><h2 id="邪恶的向导"><a href="#邪恶的向导" class="headerlink" title="邪恶的向导"></a>邪恶的向导</h2><ul><li>提示50：不要使用你不理解的向导代码。</li><li>感觉说的就是不要使用你不理解的自动生成的代码。</li></ul><h1 id="第7章：在项目开始之前"><a href="#第7章：在项目开始之前" class="headerlink" title="第7章：在项目开始之前"></a>第7章：在项目开始之前</h1><h2 id="需求之坑"><a href="#需求之坑" class="headerlink" title="需求之坑"></a>需求之坑</h2><ul><li>提示51：不要搜集需求——挖掘它们。</li><li>找出用户为何要做特定事情的原因、而不只是他们目前做这件事情的方式。</li><li>提示52：与用户一同工作，以像用户一样思考。</li><li>需求不是架构，不是设计，不是用户界面，而是需要。</li><li>提示53：抽象比细节活得更长久。</li><li>管理需求增长的关键是向项目出资人指出每项新特性对项目进度的影响。</li><li>要创建并维护项目词汇表。提示54：使用项目词汇表。</li></ul><h2 id="解开不可能解开的谜题"><a href="#解开不可能解开的谜题" class="headerlink" title="解开不可能解开的谜题"></a>解开不可能解开的谜题</h2><ul><li>提示55：不要在盒子外面思考——要找到盒子。在面对棘手的问题的时候，列出所有在你面前的可能途径。不要排除任何东西，不管它听起来有多无用或愚蠢。</li><li>所需要的只是真正的约束、令人误解的约束、还有区分它们的智慧。</li></ul><h2 id="等你准备好"><a href="#等你准备好" class="headerlink" title="等你准备好"></a>等你准备好</h2><ul><li>提示56：倾听反复出现的疑虑——等你准备好再开始。</li></ul><h2 id="规范陷阱"><a href="#规范陷阱" class="headerlink" title="规范陷阱"></a>规范陷阱</h2><ul><li>编写规范是一项重要职责。</li><li>提示57：对有些事情“做”胜于“描述”。</li><li>没有给编码者留下任何解释余地的设计剥夺了他们发挥技巧和艺术才能的权利。</li><li>越是把规范当做安乐毯，进入编码截断就会越困难。</li></ul><h2 id="圆圈与箭头"><a href="#圆圈与箭头" class="headerlink" title="圆圈与箭头"></a>圆圈与箭头</h2><ul><li>提示58：不要做形式方法的努力。</li><li>应该使用形式方法，但要记住它只是工具箱里的又一种工具。</li><li>提示59：昂贵的工具不一定能制作出更好的设计。</li></ul><h1 id="第8章：注重实效的项目"><a href="#第8章：注重实效的项目" class="headerlink" title="第8章：注重实效的项目"></a>第8章：注重实效的项目</h1><h2 id="注重实效的团队"><a href="#注重实效的团队" class="headerlink" title="注重实效的团队"></a>注重实效的团队</h2><ul><li>认为项目的各种活动——分析、设计、编码——会孤立地发生，这是一个错误。它们不会孤立发生。它们是看待同一问题的不同方式，人为地分隔它们会带来许多麻烦。</li><li>提示60：围绕功能、而不是工作职务进行组织。</li></ul><h2 id="无处不在的自动化"><a href="#无处不在的自动化" class="headerlink" title="无处不在的自动化"></a>无处不在的自动化</h2><ul><li>提示61：不要使用手工流程。</li></ul><h2 id="无情的测试"><a href="#无情的测试" class="headerlink" title="无情的测试"></a>无情的测试</h2><ul><li>提示62：早测试，常测试，自动测试。</li><li>提示63：要到通过全部测试，编码才算完成。</li><li>我们需要查看项目范围测试的三个主要方面：测试什么、怎样测试以及何时测试。</li><li>单元测试是对某个模块进行演练的代码。是所有其他形式的测试的基础。</li><li>集成测试说明组成项目的主要子系统能工作，并且能很好地协同。</li><li>验证和校验。</li><li>资源耗尽、错误及恢复。</li><li>性能测试，压力测试。</li><li>可用性测试。</li><li>怎样测试包括：回归测试、测试数据、演练GUI系统、对测试进行测试、彻底测试。</li><li>回归测试把当前测试的输出与先前值进行对比。 </li><li>提示64：通过“蓄意破坏”测试你的测试。</li><li>提示65：测试状态覆盖，而不是代码覆盖。</li><li>提示66：一个bug只抓一次。一旦测试人员找到了某个bug，就应该是最后一次发现这个bug。增加新的测试，从此每次都检查这个特定的bug。</li></ul><h2 id="全都是写"><a href="#全都是写" class="headerlink" title="全都是写"></a>全都是写</h2><ul><li>注重实效的程序员会把文档当做整个开发过程的完整组成部分加以接受。</li><li>提示67：把英语当做又一种编程语言。</li><li>提示68：把文档建在里面，不要拴在外面。</li><li>一般而言，注释应该讨论为何要做模式、它的目的和目标。</li><li>不应该出现在注释中的一些内容：文件中的代码导出的函数的列表、修行历史、该文件使用的其他文件的列表、文件名。</li><li>在源文件里应该出现的最重要的信息之一是作者的姓名。</li><li>文档和代码是同一底层模型的不同视图，但视图是唯一应该不同的东西。</li></ul><h2 id="极大的期望"><a href="#极大的期望" class="headerlink" title="极大的期望"></a>极大的期望</h2><ul><li>在现实中，项目的成功是由它在多大程度上满足了用户的期望来衡量的。</li><li>提示69：温和地超出用户的期望。</li></ul><h2 id="傲慢与偏见"><a href="#傲慢与偏见" class="headerlink" title="傲慢与偏见"></a>傲慢与偏见</h2><ul><li>提示70：在你的作品上签名。</li></ul>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;偶然在组里书柜里看到了这本书，听说是新人程序员的圣经，正巧自己最近也在找这种培养思维和习惯的书看，所以就打算趁闲暇看下，希望对自己有所帮助。&lt;/p&gt;
&lt;p&gt;PS：看了几页，很多都是寓意的小故事，没法精确地摘抄某几个句子来表达思想，所以可以的话还是买本书看一看吧。&lt;/p&gt;
    
    </summary>
    
      <category term="职业学习" scheme="http://yoursite.com/categories/%E8%81%8C%E4%B8%9A%E5%AD%A6%E4%B9%A0/"/>
    
    
      <category term="职业素养" scheme="http://yoursite.com/tags/%E8%81%8C%E4%B8%9A%E7%B4%A0%E5%85%BB/"/>
    
  </entry>
  
  <entry>
    <title>Vim配置</title>
    <link href="http://yoursite.com/2019/08/04/Vim%E9%85%8D%E7%BD%AE/"/>
    <id>http://yoursite.com/2019/08/04/Vim配置/</id>
    <published>2019-08-04T12:33:07.000Z</published>
    <updated>2019-08-04T12:42:33.559Z</updated>
    
    <content type="html"><![CDATA[<p>上周装了Ubuntu16.04，接下来打算在上面学习点C++开发，所以得先配个环境，打算配置一下Vim以及装一些插件，接下来就搞一下。</p><a id="more"></a><h1 id="Vim升级"><a href="#Vim升级" class="headerlink" title="Vim升级"></a>Vim升级</h1><p>用的时候发现ubuntu默认的Vim、g++和gcc版本都偏低了，先更新一下，把Vim升级到8以上，g++更新升级到4.8.5以上以支持c++11。</p><figure class="highlight shell"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span> 安装依赖</span><br><span class="line">sudo apt-get install libncurses5-dev</span><br><span class="line">sudo apt-get install build-essential cmake</span><br><span class="line">sudo apt-get install python-dev python3-dev</span><br><span class="line">sudo apt-get install libgmp-dev libmpfr-dev libmpc-dev libisl-dev libcloog-isl-dev zlib1g-dev</span><br><span class="line">sudo apt-get install autogen</span><br><span class="line">sudo apt-get install libclang-dev</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span> 升级GCC</span><br><span class="line">wget ftp://ftp.gnu.org/gnu/gcc/gcc-4.9.2/gcc-4.9.2.tar.gz</span><br><span class="line">cd gcc-4.9.2</span><br><span class="line">./configure --prefix=/opt/gcc-4.9.2 --enable-languages=c,c++ --disable-multilib --disable-bootstrap --with-system-zlib</span><br><span class="line">make &amp;&amp; make check</span><br><span class="line">sudo make install</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span> 配置好，如果之前有这两个链接文件的话就删掉重新链接就行了</span><br><span class="line">sudo ln -s /opt/gcc-4.9.2/bin/gcc /usr/bin/gcc</span><br><span class="line">sudo ln -s /opt/gcc-4.9.2/bin/g++ /usr/bin/g++</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span> 升级Vim</span><br><span class="line">sudo add-apt-repository ppa:jonathonf/vim</span><br><span class="line">sudo apt-get update</span><br><span class="line">sudo apt-get install vim-nox-py2</span><br><span class="line">sudo mv /usr/local/bin/vim /usr/local/bin/vim.old</span><br><span class="line">sudo ln -s /usr/bin/vim.nox-py2 /usr/local/bin/vim</span><br><span class="line"><span class="meta">#</span> 参考 https://blog.csdn.net/yanjiee/article/details/76066936</span><br></pre></td></tr></table></figure><h1 id="Vim-Plug基本使用"><a href="#Vim-Plug基本使用" class="headerlink" title="Vim-Plug基本使用"></a>Vim-Plug基本使用</h1><p>Vim-plug 是一个自由、开源、速度非常快的、极简的 vim 插件管理器。</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></pre></td><td class="code"><pre><span class="line">curl -fLo ~/.vim/autoload/plug.vim --create-dirs \</span><br><span class="line">    https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim</span><br></pre></td></tr></table></figure><h2 id="插件安装"><a href="#插件安装" class="headerlink" title="插件安装"></a>插件安装</h2><p>安装插件也很方便，主要有以下几步：</p><ul><li>在<code>~/.vimrc</code>中声明需要安装的插件，这里以<code>ligntline.vim</code>插件为例，如下图所示</li></ul><img src="/2019/08/04/Vim配置/addSetting.png"><p>配置如下：</p><figure class="highlight shell"><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></pre></td><td class="code"><pre><span class="line">let g:lightline = &#123;</span><br><span class="line">       \ 'colorscheme': 'wombat',</span><br><span class="line">       \ 'active': &#123;</span><br><span class="line">       \   'left': [ [ 'mode', 'paste' ],</span><br><span class="line">       \             [ 'readonly', 'filename', 'modified', 'helloworld' ] ]</span><br><span class="line">       \ &#125;,</span><br><span class="line">       \ 'component': &#123;</span><br><span class="line">       \   'helloworld': 'I am writing shit...'</span><br><span class="line">       \ &#125;,</span><br><span class="line">       \ &#125;</span><br><span class="line"> </span><br><span class="line">set laststatus=2</span><br></pre></td></tr></table></figure><ul><li>重新打开vim，使用<code>:PlugStatus</code>命令查看插件状态，如图：</li></ul><img src="/2019/08/04/Vim配置/notInstall.png"><ul><li>接着输入<code>:PlugInstall</code>完成插件安装</li></ul><img src="/2019/08/04/Vim配置/installDone.png"><h2 id="更新插件"><a href="#更新插件" class="headerlink" title="更新插件"></a>更新插件</h2><p>更新插件就运行<code>:PlugUpdate</code>即可，更新插件后，可以按<code>d</code>查看更改，或者也可以之后输入<code>:PlugDiff</code></p><h2 id="审查插件"><a href="#审查插件" class="headerlink" title="审查插件"></a>审查插件</h2><p>有时候更新的插件会有问题或不能正常工作，要解决这个问题就可以回滚，输入<code>:PlugDiff</code>的命令按回车键查看上次的更改，然后在每个段落上按<code>X</code>将每个插件回滚到前一个状态。</p><h2 id="删除插件"><a href="#删除插件" class="headerlink" title="删除插件"></a>删除插件</h2><ul><li>首先将<code>~/.vimrc</code>文件中对应的插件配置plug命令删除或者注释，然后重启Vim编辑器，如图：</li></ul><img src="/2019/08/04/Vim配置/delete.png"><ul><li>然后在Vim里输入<code>:PlugClean</code>命令，接着按<code>y</code>，就可以删除已经不存在配置文件中的插件了。</li></ul><img src="/2019/08/04/Vim配置/deletey.png"><h2 id="升级Vim-Plug本身"><a href="#升级Vim-Plug本身" class="headerlink" title="升级Vim-Plug本身"></a>升级Vim-Plug本身</h2><p>输入<code>:PlugUpgrade</code>就可以升级Vim-Plug本身了。</p><h1 id="安装ctags"><a href="#安装ctags" class="headerlink" title="安装ctags"></a>安装ctags</h1><p>需要重新安装ctags，使用Universal CTags，默认的Exuberant CTags太旧了。</p><figure class="highlight shell"><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">sudo apt install autoconf</span><br><span class="line">cd /tmp</span><br><span class="line">git clone https://github.com/universal-ctags/ctags</span><br><span class="line">cd ctags</span><br><span class="line">./autogen.sh</span><br><span class="line">./configure --prefix=PATH  # 安装路径,自己的情况调整。</span><br><span class="line">make</span><br><span class="line">sudo make install</span><br></pre></td></tr></table></figure><p>在<code>.vimrc</code>里添加<code>set tags=./tags;,tags</code></p><p>然后再用<code>sudo apt install global</code>安装gtags，这时已经可以通过在项目根目录运行<code>ctags -R *</code>来生成tags文件，就可以用了。</p><h2 id="自动生成tags"><a href="#自动生成tags" class="headerlink" title="自动生成tags"></a>自动生成tags</h2><p>使用vim-gutentags插件。</p><p><code>.vimrc</code>里加入<code>Plug &#39;ludovicchabant/vim-gutentags&#39;</code></p><p>然后加入以下配置：</p><figure class="highlight shell"><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></pre></td><td class="code"><pre><span class="line">" gutentags 搜索工程目录的标志，碰到这些文件/目录名就停止向上一级目录递归</span><br><span class="line">let g:gutentags_project_root = ['.root', '.svn', '.git', '.hg', '.project']</span><br><span class="line"></span><br><span class="line">" 所生成的数据文件的名称</span><br><span class="line">let g:gutentags_ctags_tagfile = '.tags'</span><br><span class="line"></span><br><span class="line">" 将自动生成的 tags 文件全部放入 ~/.cache/tags 目录中，避免污染工程目录</span><br><span class="line">let s:vim_tags = expand('~/.cache/tags')</span><br><span class="line">let g:gutentags_cache_dir = s:vim_tags</span><br><span class="line"></span><br><span class="line">" 配置 ctags 的参数</span><br><span class="line">let g:gutentags_ctags_extra_args = ['--fields=+niazS', '--extra=+q']</span><br><span class="line">let g:gutentags_ctags_extra_args += ['--c++-kinds=+px']</span><br><span class="line">let g:gutentags_ctags_extra_args += ['--c-kinds=+px']</span><br><span class="line"></span><br><span class="line">" 检测 ~/.cache/tags 不存在就新建</span><br><span class="line">if !isdirectory(s:vim_tags)</span><br><span class="line">   silent! call mkdir(s:vim_tags, 'p')</span><br><span class="line">endif</span><br></pre></td></tr></table></figure><p>现在只要项目根目录里有<code>&#39;.root&#39;, &#39;.svn&#39;, &#39;.git&#39;, &#39;.hg&#39;, &#39;.project&#39;</code>这些文件，当使用vim编辑文件的时候就会自动生成.tag文件了，该文件可以在<code>~/.cache/tags</code>里看到。</p><p>现在就可以使用<code>ctrl+]</code>进行跳转了，但是建议使用<code>ctrl+w+]</code>用新窗口打开或者<code>ctrl+w+}</code>使用预览窗口，<code>:pclose</code>关闭预览窗口。</p><h1 id="安装AsyncRun"><a href="#安装AsyncRun" class="headerlink" title="安装AsyncRun"></a>安装AsyncRun</h1><p>Vim8以后，利用异步模式，可以让编译更方便，用AsyncRun插件，配置如下：</p><figure class="highlight shell"><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></pre></td><td class="code"><pre><span class="line">Plug 'skywind3000/asyncrun.vim'</span><br><span class="line">let g:asyncrun_rootmarks = ['.svn', '.git', '.root', '_darcs', 'build.xml']</span><br><span class="line">" 自动打开 quickfix window ，高度为 6</span><br><span class="line">let g:asyncrun_open = 6</span><br><span class="line"></span><br><span class="line">" 任务结束时候响铃提醒</span><br><span class="line">let g:asyncrun_bell = 1</span><br><span class="line"></span><br><span class="line">" 设置 F10 打开/关闭 Quickfix 窗口</span><br><span class="line">nnoremap &lt;F10&gt; :call asyncrun#quickfix_toggle(6)&lt;cr&gt;</span><br><span class="line"></span><br><span class="line">" 设置F7编译整个项目，注意makefile的目录，可以自行修改</span><br><span class="line">nnoremap &lt;silent&gt; &lt;F7&gt; :AsyncRun -cwd=&lt;root&gt;/src make &lt;cr&gt;</span><br></pre></td></tr></table></figure><h1 id="安装代码检查ALE"><a href="#安装代码检查ALE" class="headerlink" title="安装代码检查ALE"></a>安装代码检查ALE</h1><p>配置：</p><figure class="highlight shell"><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">Plug 'dense-analysis/ale'</span><br><span class="line">let g:ale_linters_explicit = 1</span><br><span class="line">let g:ale_linters = &#123;</span><br><span class="line">  \   'csh': ['shell'],</span><br><span class="line">  \   'zsh': ['shell'],</span><br><span class="line">  \   'go': ['gofmt', 'golint'],</span><br><span class="line">  \   'python': ['flake8', 'mypy', 'pylint'],</span><br><span class="line">  \   'c': ['gcc', 'cppcheck'],</span><br><span class="line">  \   'cpp': ['gcc', 'cppcheck'],</span><br><span class="line">  \   'text': [],</span><br><span class="line">  \&#125;</span><br><span class="line">let g:ale_completion_delay = 500</span><br><span class="line">let g:ale_echo_delay = 20</span><br><span class="line">let g:ale_lint_delay = 500</span><br><span class="line">let g:ale_echo_msg_format = '[%linter%] %code: %%s'</span><br><span class="line">let g:ale_lint_on_text_changed = 'normal'</span><br><span class="line">let g:ale_lint_on_insert_leave = 1</span><br><span class="line">let g:airline#extensions#ale#enabled = 1</span><br><span class="line"></span><br><span class="line">let g:ale_c_gcc_options = '-Wall -O2 -std=c99'</span><br><span class="line">let g:ale_cpp_gcc_options = '-Wall -O2 -std=c++14'</span><br><span class="line">let g:ale_c_cppcheck_options = ''</span><br><span class="line">let g:ale_cpp_cppcheck_options = ''</span><br></pre></td></tr></table></figure><p>这个插件比较大，装的比较久，成功后如图：</p><img src="/2019/08/04/Vim配置/aleExample.png"><h1 id="安装YouCompleteMe"><a href="#安装YouCompleteMe" class="headerlink" title="安装YouCompleteMe"></a>安装YouCompleteMe</h1><p>这个也有点麻烦，走了不少坑，首先要对git做下设置，否则git clone的时候会不能获取到一些国外的repo，原因嘛……</p><figure class="highlight shell"><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">git config --global http.proxy 'socks5://127.0.0.1:1080'</span><br><span class="line"></span><br><span class="line">git config --global https.proxy 'socks5://127.0.0.1:1080'</span><br></pre></td></tr></table></figure><p>运行上述两条命令，结合之前已经搞好的科学上网，就可以正常clone啦，而且速度好快哦～</p><p>配置如下：</p><figure class="highlight shell"><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">let g:ycm_global_ycm_extra_conf='~/.vim/plugged/YouCompleteMe/third_party/ycmd/.ycm_extra_conf.py'</span><br><span class="line">let g:ycm_add_preview_to_completeopt = 0</span><br><span class="line">let g:ycm_show_diagnostics_ui = 0</span><br><span class="line">let g:ycm_server_log_level = 'info'</span><br><span class="line">let g:ycm_min_num_identifier_candidate_chars = 2</span><br><span class="line">let g:ycm_collect_identifiers_from_comments_and_strings = 1</span><br><span class="line">let g:ycm_complete_in_strings=1</span><br><span class="line">let g:ycm_key_invoke_completion = '&lt;c-z&gt;'                    " 使用 Ctrl+Z 主动触发语义补全</span><br><span class="line">noremap &lt;c-z&gt; &lt;NOP&gt;</span><br><span class="line">set completeopt=menu,menuone</span><br></pre></td></tr></table></figure><p>应该没问题了，但如果出现<code>YouCompleteMe unavailable no module named builtins</code>错误，则cd到YouCompleteMe目录下运行<code>git submodule update --init --recursive</code>，这个问题应该是因为网速问题没下完整。</p><p>如果出现<code>The ycmd server SHUT DOWN (restart with &#39;:YcmRestartServer&#39;). Unexpected exit code 1.</code>类似问题，则cd到YouCompleteMe目录下运行<code>/usr/bin/python install.py</code>。</p><h1 id="NerdTree"><a href="#NerdTree" class="headerlink" title="NerdTree"></a>NerdTree</h1><p>目录树，配置如下，按F3就可以打开目录树：</p><figure class="highlight shell"><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">Plug 'scrooloose/nerdtree'</span><br><span class="line"></span><br><span class="line">noremap &lt;F3&gt; :NERDTreeToggle&lt;cr&gt;</span><br></pre></td></tr></table></figure><h1 id="vim-cpp-enhanced-highlight"><a href="#vim-cpp-enhanced-highlight" class="headerlink" title="vim-cpp-enhanced-highlight"></a>vim-cpp-enhanced-highlight</h1><p>C++语法高亮插件，直接加入即可，不需多余配置。</p><p><code>Plug &#39;octol/vim-cpp-enhanced-highlight&#39;</code></p><h1 id="nerdcommerter"><a href="#nerdcommerter" class="headerlink" title="nerdcommerter"></a>nerdcommerter</h1><p>注释的插件，快捷键<code>&lt;leader&gt;cc</code>和<code>&lt;leader&gt;c&lt;space&gt;</code>。</p><h1 id="LeaderF"><a href="#LeaderF" class="headerlink" title="LeaderF"></a>LeaderF</h1><p>函数列表插件，配置如下：</p><figure class="highlight shell"><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">Plug 'Yggdroot/LeaderF', &#123; 'do': './install.sh' &#125;</span><br><span class="line">let g:Lf_ShortcutF = '&lt;c-p&gt;'</span><br><span class="line">let g:Lf_ShortcutB = '&lt;m-n&gt;'</span><br><span class="line">noremap &lt;c-n&gt; :LeaderfMru&lt;cr&gt;</span><br><span class="line">" 设置F2显示本文件的函数列表，这里Vim映射Alt键不成功，所以自己改成F2</span><br><span class="line">noremap &lt;F2&gt; :LeaderfFunction!&lt;cr&gt;</span><br><span class="line">noremap &lt;m-n&gt; :LeaderfBuffer&lt;cr&gt;</span><br><span class="line">noremap &lt;m-m&gt; :LeaderfTag&lt;cr&gt;</span><br><span class="line">let g:Lf_StlSeparator = &#123; 'left': '', 'right': '', 'font': '' &#125;</span><br><span class="line"></span><br><span class="line">let g:Lf_RootMarkers = ['.project', '.root', '.svn', '.git']</span><br><span class="line">let g:Lf_WorkingDirectoryMode = 'Ac'</span><br><span class="line">let g:Lf_WindowHeight = 0.30</span><br><span class="line">let g:Lf_CacheDirectory = expand('~/.vim/cache')</span><br><span class="line">let g:Lf_ShowRelativePath = 0</span><br><span class="line">let g:Lf_HideHelp = 1</span><br><span class="line">let g:Lf_StlColorscheme = 'powerline'</span><br><span class="line">let g:Lf_PreviewResult = &#123;'Function':0, 'BufTag':0&#125;</span><br></pre></td></tr></table></figure><h1 id="echodoc-vim"><a href="#echodoc-vim" class="headerlink" title="echodoc.vim"></a>echodoc.vim</h1><p>显示参数列表，配置：</p><figure class="highlight shell"><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">Plug 'Shougo/echodoc.vim'</span><br><span class="line"></span><br><span class="line">set noshowmode</span><br></pre></td></tr></table></figure><p>当用YCM的tab补全函数名后，输入左括号即可显示参数信息，和YCM配合结果如图：</p><img src="/2019/08/04/Vim配置/ycm.png"><h1 id="Vim所有配置"><a href="#Vim所有配置" class="headerlink" title="Vim所有配置"></a>Vim所有配置</h1><figure class="highlight shell"><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><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br></pre></td><td class="code"><pre><span class="line">set number</span><br><span class="line">set hlsearch</span><br><span class="line">set incsearch</span><br><span class="line">set softtabstop =4         " Tab key indents by 4 spaces.</span><br><span class="line">set hidden                 " Switch between buffers without having to save first.</span><br><span class="line">set noshowmode</span><br><span class="line">" set cmdheight =2</span><br><span class="line">" 插件列表</span><br><span class="line"></span><br><span class="line">call plug#begin('~/.vim/plugged')</span><br><span class="line">Plug 'itchyny/lightline.vim'</span><br><span class="line">" Plug 'tenfyzhong/CompleteParameter.vim'</span><br><span class="line">Plug 'ludovicchabant/vim-gutentags'</span><br><span class="line">Plug 'skywind3000/asyncrun.vim'</span><br><span class="line">Plug 'octol/vim-cpp-enhanced-highlight'</span><br><span class="line">Plug 'dense-analysis/ale'</span><br><span class="line">Plug 'scrooloose/nerdtree'</span><br><span class="line">Plug 'scrooloose/nerdcommenter'     " 注释的插件 &lt;leader&gt;cc和&lt;leader&gt;c&lt;space&gt;</span><br><span class="line">Plug 'Yggdroot/LeaderF', &#123; 'do': './install.sh' &#125;</span><br><span class="line">Plug 'Valloric/YouCompleteMe', &#123; 'do': './install.py --clang-completer --go-completer' &#125;</span><br><span class="line">Plug 'Shougo/echodoc.vim'</span><br><span class="line">call plug#end()</span><br><span class="line"></span><br><span class="line">" ###################################################################</span><br><span class="line">" lightline</span><br><span class="line"></span><br><span class="line">let g:lightline = &#123;</span><br><span class="line">      \ 'colorscheme': 'wombat',</span><br><span class="line">      \ 'active': &#123;</span><br><span class="line">      \   'left': [ [ 'mode', 'paste' ],</span><br><span class="line">      \             [ 'readonly', 'filename', 'modified', 'helloworld' ] ]</span><br><span class="line">      \ &#125;,</span><br><span class="line">      \ 'component': &#123;</span><br><span class="line">      \   'helloworld': 'I am writing shit...'</span><br><span class="line">      \ &#125;,</span><br><span class="line">      \ &#125;</span><br><span class="line"></span><br><span class="line">set laststatus=2</span><br><span class="line">" ###################################################################</span><br><span class="line">" ctags</span><br><span class="line">set tags=./.tags;,.tags</span><br><span class="line">" gutentags 搜索工程目录的标志，碰到这些文件/目录名就停止向上一级目录递归</span><br><span class="line">let g:gutentags_project_root = ['.root', '.svn', '.git', '.hg', '.project']</span><br><span class="line"></span><br><span class="line">" 所生成的数据文件的名称</span><br><span class="line">let g:gutentags_ctags_tagfile = '.tags'</span><br><span class="line"></span><br><span class="line">" 将自动生成的 tags 文件全部放入 ~/.cache/tags 目录中，避免污染工程目录</span><br><span class="line">let s:vim_tags = expand('~/.cache/tags')</span><br><span class="line">let g:gutentags_cache_dir = s:vim_tags</span><br><span class="line"></span><br><span class="line">" 配置 ctags 的参数</span><br><span class="line">let g:gutentags_ctags_extra_args = ['--fields=+niazS', '--extra=+q']</span><br><span class="line">let g:gutentags_ctags_extra_args += ['--c++-kinds=+px']</span><br><span class="line">let g:gutentags_ctags_extra_args += ['--c-kinds=+px']</span><br><span class="line"></span><br><span class="line">" 检测 ~/.cache/tags 不存在就新建</span><br><span class="line">if !isdirectory(s:vim_tags)</span><br><span class="line">   silent! call mkdir(s:vim_tags, 'p')</span><br><span class="line">   endif</span><br><span class="line">" ###########################################################</span><br><span class="line"></span><br><span class="line">" asyncrun</span><br><span class="line"></span><br><span class="line">let g:asyncrun_rootmarks = ['.svn', '.git', '.root', '_darcs', 'build.xml']</span><br><span class="line">" 自动打开 quickfix window ，高度为 6</span><br><span class="line">let g:asyncrun_open = 6</span><br><span class="line"></span><br><span class="line">" 任务结束时候响铃提醒</span><br><span class="line">let g:asyncrun_bell = 1</span><br><span class="line"></span><br><span class="line">" 设置 F10 打开/关闭 Quickfix 窗口</span><br><span class="line">nnoremap &lt;F10&gt; :call asyncrun#quickfix_toggle(6)&lt;cr&gt;</span><br><span class="line"></span><br><span class="line">" 设置F7编译整个项目，注意makefile的目录，可以自行修改</span><br><span class="line">nnoremap &lt;silent&gt; &lt;F7&gt; :AsyncRun -cwd=&lt;root&gt;/src make &lt;cr&gt;</span><br><span class="line">" ###########################################################</span><br><span class="line"></span><br><span class="line">" ALE</span><br><span class="line">let g:ale_linters_explicit = 1</span><br><span class="line">let g:ale_linters = &#123;</span><br><span class="line">  \   'csh': ['shell'],</span><br><span class="line">  \   'zsh': ['shell'],</span><br><span class="line">  \   'go': ['gofmt', 'golint'],</span><br><span class="line">  \   'python': ['flake8', 'mypy', 'pylint'],</span><br><span class="line">  \   'c': ['gcc', 'cppcheck'],</span><br><span class="line">  \   'cpp': ['gcc', 'cppcheck'],</span><br><span class="line">  \   'text': [],</span><br><span class="line">  \&#125;</span><br><span class="line">let g:ale_completion_delay = 500</span><br><span class="line">let g:ale_echo_delay = 20</span><br><span class="line">let g:ale_lint_delay = 500</span><br><span class="line">let g:ale_echo_msg_format = '[%linter%] %code: %%s'</span><br><span class="line">let g:ale_lint_on_text_changed = 'normal'</span><br><span class="line">let g:ale_lint_on_insert_leave = 1</span><br><span class="line">let g:airline#extensions#ale#enabled = 1</span><br><span class="line"></span><br><span class="line">let g:ale_c_gcc_options = '-Wall -O2 -std=c99'</span><br><span class="line">let g:ale_cpp_gcc_options = '-Wall -O2 -std=c++14'</span><br><span class="line">let g:ale_c_cppcheck_options = ''</span><br><span class="line">let g:ale_cpp_cppcheck_options = ''</span><br><span class="line"></span><br><span class="line">" ###########################################################</span><br><span class="line">" YouCompleteMe</span><br><span class="line">let g:ycm_global_ycm_extra_conf='~/.vim/plugged/YouCompleteMe/third_party/ycmd/.ycm_extra_conf.py'</span><br><span class="line">let g:ycm_add_preview_to_completeopt = 0</span><br><span class="line">let g:ycm_show_diagnostics_ui = 0</span><br><span class="line">let g:ycm_server_log_level = 'info'</span><br><span class="line">let g:ycm_min_num_identifier_candidate_chars = 2</span><br><span class="line">let g:ycm_collect_identifiers_from_comments_and_strings = 1</span><br><span class="line">let g:ycm_complete_in_strings=1</span><br><span class="line">let g:ycm_key_invoke_completion = '&lt;c-z&gt;'                    " 使用 Ctrl+Z 主动触发语义补全</span><br><span class="line">noremap &lt;c-z&gt; &lt;NOP&gt;</span><br><span class="line">set completeopt=menu,menuone</span><br><span class="line"></span><br><span class="line">" 修改补全列表配色</span><br><span class="line">highlight PMenu ctermfg=0 ctermbg=242 guifg=black guibg=darkgrey</span><br><span class="line">highlight PMenuSel ctermfg=242 ctermbg=8 guifg=darkgrey guibg=black</span><br><span class="line"></span><br><span class="line">" 对指定源文件，输入两个字母后即触发语义补全</span><br><span class="line">let g:ycm_semantic_triggers =  &#123;</span><br><span class="line">           \ 'c,cpp,python,java,go,erlang,perl': ['re!\w&#123;2&#125;'],</span><br><span class="line">           \ 'cs,lua,javascript': ['re!\w&#123;2&#125;'],</span><br><span class="line">           \ &#125;</span><br><span class="line"></span><br><span class="line">let g:ycm_filetype_whitelist = &#123; </span><br><span class="line">            \ "c":1,</span><br><span class="line">            \ "cpp":1, </span><br><span class="line">            \ "go":1,</span><br><span class="line">            \ "python":1,</span><br><span class="line">            \ "sh":1,</span><br><span class="line">            \ "zsh":1,</span><br><span class="line">            \ &#125;</span><br><span class="line"></span><br><span class="line">let g:ycm_filetype_blacklist = &#123;</span><br><span class="line">        \ 'markdown' : 1,</span><br><span class="line">        \ 'text' : 1,</span><br><span class="line">        \ 'pandoc' : 1,</span><br><span class="line">        \ 'infolog' : 1,</span><br><span class="line">        \&#125;</span><br><span class="line">" ###########################################################</span><br><span class="line"></span><br><span class="line">" LeaderF</span><br><span class="line">let g:Lf_ShortcutF = '&lt;c-p&gt;'</span><br><span class="line">let g:Lf_ShortcutB = '&lt;m-n&gt;'</span><br><span class="line">noremap &lt;c-n&gt; :LeaderfMru&lt;cr&gt;</span><br><span class="line">" 设置F2显示本文件的函数列表，这里Vim映射Alt键不成功，所以自己改成F2</span><br><span class="line">noremap &lt;F2&gt; :LeaderfFunction!&lt;cr&gt;</span><br><span class="line">noremap &lt;m-n&gt; :LeaderfBuffer&lt;cr&gt;</span><br><span class="line">noremap &lt;m-m&gt; :LeaderfTag&lt;cr&gt;</span><br><span class="line">let g:Lf_StlSeparator = &#123; 'left': '', 'right': '', 'font': '' &#125;</span><br><span class="line"></span><br><span class="line">let g:Lf_RootMarkers = ['.project', '.root', '.svn', '.git']</span><br><span class="line">let g:Lf_WorkingDirectoryMode = 'Ac'</span><br><span class="line">let g:Lf_WindowHeight = 0.30</span><br><span class="line">let g:Lf_CacheDirectory = expand('~/.vim/cache')</span><br><span class="line">let g:Lf_ShowRelativePath = 0</span><br><span class="line">let g:Lf_HideHelp = 1</span><br><span class="line">let g:Lf_StlColorscheme = 'powerline'</span><br><span class="line">let g:Lf_PreviewResult = &#123;'Function':0, 'BufTag':0&#125;</span><br><span class="line"></span><br><span class="line">" ###########################################################</span><br><span class="line">" nerdtree</span><br><span class="line"></span><br><span class="line">noremap &lt;F3&gt; :NERDTreeToggle&lt;cr&gt;</span><br><span class="line">" ###########################################################</span><br><span class="line">" echodoc</span><br><span class="line">let g:echodoc_enable_at_startup = 1</span><br><span class="line"></span><br><span class="line">" ###########################################################</span><br><span class="line">" CompleteParameter</span><br><span class="line">" inoremap &lt;silent&gt;&lt;expr&gt; ( complete_parameter#pre_complete("()")</span><br><span class="line">" smap &lt;c-j&gt; &lt;Plug&gt;(complete_parameter#goto_next_parameter)</span><br><span class="line">" imap &lt;c-j&gt; &lt;Plug&gt;(complete_parameter#goto_next_parameter)</span><br><span class="line">" smap &lt;c-k&gt; &lt;Plug&gt;(complete_parameter#goto_previous_parameter)</span><br><span class="line">" imap &lt;c-k&gt; &lt;Plug&gt;(complete_parameter#goto_previous_parameter)</span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;上周装了Ubuntu16.04，接下来打算在上面学习点C++开发，所以得先配个环境，打算配置一下Vim以及装一些插件，接下来就搞一下。&lt;/p&gt;
    
    </summary>
    
      <category term="职业学习" scheme="http://yoursite.com/categories/%E8%81%8C%E4%B8%9A%E5%AD%A6%E4%B9%A0/"/>
    
    
      <category term="Linux" scheme="http://yoursite.com/tags/Linux/"/>
    
      <category term="Vim" scheme="http://yoursite.com/tags/Vim/"/>
    
  </entry>
  
  <entry>
    <title>win10安装Ubuntu16.04双系统记录</title>
    <link href="http://yoursite.com/2019/07/28/win10%E5%AE%89%E8%A3%85Ubuntu16-04%E5%8F%8C%E7%B3%BB%E7%BB%9F%E8%AE%B0%E5%BD%95/"/>
    <id>http://yoursite.com/2019/07/28/win10安装Ubuntu16-04双系统记录/</id>
    <published>2019-07-28T13:07:41.000Z</published>
    <updated>2019-07-28T15:03:36.111Z</updated>
    
    <content type="html"><![CDATA[<p>本文包括以下内容：</p><ul><li>双系统安装</li><li>Ubuntu访问Google</li><li>Ubuntu下Tim和微信的安装使用</li><li>双系统互相访问文件</li><li>Ubuntu搜狗输入法安装</li></ul><a id="more"></a><p>由于目前工作主要用的语言是C++，且是在Linux上开发，所以便想在自己电脑上也搞个Linux系统用来平时学习，之前装过虚拟机也试过Win10下的Ubuntu子系统，但嫌弃虚拟机用起来太麻烦而且有时候会有点卡顿，子系统看网上又说IO性能不行，我又有点挑刺的毛病，所以便想要不要干脆整个双系统算了，但是我现在用的是128G的MagicBook，要整个双系统硬盘大小又有点尴尬。</p><p>其实……我想的最好的办法是买台Mac，但是……穷的一笔，而且这个问题还没法解决，真是太悲伤了，于是这个想法作罢。</p><p>最后在三个选择里纠结了一下，选择匀出20G装个Ubuntu双系统吧，版本16.04，自己还能学学装系统，万一以后要靠这个谋生呢……不过修电脑装系统也不是装Linux啊……awsl……</p><p>网上教程很多，我这里更多的是记录，如果有些细节没有的话可以看我贴出来的链接，那里面图多，但是看图更简单，所以可以第一遍看图操作，第二遍看我的文字操作再次加深记忆，然后我觉得就差不多记住了。</p><p>下面进入正题。</p><h1 id="安装Ubuntu双系统"><a href="#安装Ubuntu双系统" class="headerlink" title="安装Ubuntu双系统"></a>安装Ubuntu双系统</h1><ul><li>首先下载系统镜像文件，就是iso后缀文件，从<a href="https://ubuntu.com/download" target="_blank" rel="noopener">https://ubuntu.com/download</a>下载就行，我下的是桌面版，现在已经更新到19.04了，不过我很早以前就下过Ubuntu镜像，所以就用的以前的版本，即16.04,没有的话就可以下载新的，也可以找老版本下载，不过我一般下载东西的时候都不会下载最新版，我会下载次新或者第三新或者用的比较多的版本，因为最新版本必然网上资料不够多，遇到一些奇奇怪怪的问题不好解决（主要是我太菜）。下载好之后大概是这样：</li></ul><img src="/2019/07/28/win10安装Ubuntu16-04双系统记录/iso.jpg"><ul><li>下载好镜像文件后便制作U盘启动盘，下载Ultraiso软碟通软件，试用就行，无需付费，下载地址<a href="https://cn.ultraiso.net/" target="_blank" rel="noopener">https://cn.ultraiso.net/</a>。下载好插入U盘，打开软件，选择文件打开，选中iso镜像，然后点击菜单里的启动，写入硬盘映像，接着在弹出的窗口中硬盘驱动器一栏里选择U盘，注意这里不要选错了，一定要选U盘呀，要是不知道U盘的名字就看大小，一般U盘大小总不会比你的硬盘还大吧……选好之后写入方式选择<code>USB-HDD+</code>，然后写入。这种写入操作都会清空U盘的，所以你要是选错了，清空硬盘的话……那就有意思了。最后等待写入完成。</li><li>然后需要关闭Win10的快速启动（FastBoot）和安全启动（SecureBoot），快速启动可以按以下操作进行：<code>Win+x</code>，选择电源选项，出现下图。</li></ul><img src="/2019/07/28/win10安装Ubuntu16-04双系统记录/dianyuan1.jpg"><ul><li>选择<code>其他电源设置</code>，然后点击左侧<code>选择电源按钮的功能</code>，记着点击<code>更改当前不可用的设置</code>，最后把下面<code>启用快速启动</code>的勾给去掉，最后保存修改。</li><li>然后就需要在硬盘上分一部分空间留给后面要装的Ubuntu了，我的硬盘容量不多了，所以只分了20G，多的话随便你们分多少，不过我觉得不要低于20G比较好，因为我装完之后空间还剩7个多G的样子，我目前个人学习是够了，你们可以参考一下，建议有条件的情况下大一些，谁知道你会在Linux里装多少东西呢。</li><li><code>Win+x</code>，选择磁盘管理，在弹出的窗口里可以看到目前的磁盘分布情况，然后选择一个可用空间满足你要求的磁盘，右击，压缩卷，输入压缩空间量，这个压缩空间量其实就是你要留给Ubuntu的空间，看你自己情况而定，我记得我当时写的21000吧，然后点压缩，就会看到一个黑色的空闲未分配的磁盘块了，OK。</li><li>接下来要进入BIOS，我的MagicBook是按<code>F2</code>，另外说一句<code>F12</code>是进入Boot，一会儿也要用到，如果你的电脑型号和我不一样就得自己上网去查下这两个按键，不过大体就那几个键。</li><li>重启，在屏幕出现电脑商标的时候按<code>F2</code>进入BIOS，调整SecureBoot为Disable，然后保存并退出。</li><li>插入U盘，再次重启，这次在屏幕出现电脑商标的时候按<code>F12</code>进入Boot，选择USB启动，就可以进入Ubuntu安装步骤。当然，如果在上一步的时候就已经插了U盘，那就可以再保存完BIOS设置后出现商标时直接按<code>F12</code>进入Boot，省掉一次重启。</li><li>进入Ubuntu安装步骤之后正常来说就点下一步就行了，包括一些简单设置，什么要不要连网啊，时区选择啊，用户密码啊，语言选择啊，建议这里语言选英文吧，因为我一开始选的中文，但是到了命令行里发现要cd到中文目录的时候好麻烦啊，还是改回了英文。当然也可以像我一样先选中文后面再改回英文，因为在安装过程中看中文还是要舒服一点。</li><li>这里有几点要说明的，会出现一个选择安装方式的界面，第一个好像是什么多个系统共存，最后一个是其他选项，建议选择其他选项，这个其他选项就是要自己去分区（这才是Linux的精髓啊，可是这次弄得很简单），点击继续。</li><li>接下来的窗口里就会看到硬盘分布，你可以找到之前你预留出来的空闲区，可以根据大小来判断。选中空闲区，然后点击左下角的<code>+</code>号，对空闲区进行分配。这里简单起见，只分两个区：交换区和根目录<code>/</code>，交换区一般要比你电脑的内存大一些，比如8G内存就分8G到10G，我的电脑就是8G内存，但是因为硬盘不够，所以我这交换区分的并不多，你们自己看就行。</li><li>点击<code>+</code>号之后，勾选<code>逻辑分区</code>，<code>空间起始位置</code>，用于<code>交换空间</code>，确定。然后如法炮制，将剩下的空间都分配给<code>/</code>。</li><li>分好后，记得看下挂载点<code>/</code>在哪个设备上，显示应该是/dev/sdaX，然后在下面的<code>安装启动引导器的设备</code>中选择对应的sdaX，这表示会把启动引导器装在<code>/</code>里。</li><li>最后点击安装，确定，等待安装完毕。</li><li>完毕后重启，会进入grub2的选择界面，会让你选择是进入Windows还是Ubuntu，自行选择即可。</li><li>参考教程<a href="https://blog.csdn.net/jiajinrang93/article/details/63892208" target="_blank" rel="noopener">https://blog.csdn.net/jiajinrang93/article/details/63892208</a>，图比较多，第一遍可以照着来。</li></ul><h1 id="Ubuntu科学上网"><a href="#Ubuntu科学上网" class="headerlink" title="Ubuntu科学上网"></a>Ubuntu科学上网</h1><p>这块搞了我好长时间，昨天搞到三点也没好，明明都是按照别人的教程来的啊，为什么别人翻得我翻不得？</p><p>顺便吐槽百度，不能Google的情况下，Bing好用。</p><p>怀着深深怨念入睡，今天起床准备再战三百回合，结果就好了……好了……了……</p><p>你对得起我的黑眼圈吗！</p><p>不过能Google就行……咱大度，不计较。</p><p>当然，我是用的ShadowSocks，能翻墙的前提是你有对应的账号。</p><p>开始。</p><ul><li>首先下载ShadowSocks客户端，这有两种方法，一个是下载命令行客户端，另一个是下载图形化客户端，这里都简单介绍一下。</li><li>命令行客户端下载使用以下命令：</li></ul><figure class="highlight shell"><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">sudo apt-get install software-properties-common -y</span><br><span class="line">sudo add-apt-repository ppa:max-c-lv/shadowsocks-libev -y</span><br><span class="line">sudo apt-get update</span><br><span class="line">sudo apt install shadowsocks-libev</span><br></pre></td></tr></table></figure><ul><li>图形化客户端ss-qt5下载方式如下：</li></ul><figure class="highlight shell"><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">sudo add-apt-repository ppa:hzwhuang/ss-qt5</span><br><span class="line">sudo apt-get update</span><br><span class="line">sudo apt-get install shadowsocks-qt5</span><br></pre></td></tr></table></figure><ul><li>两者安装一个就好了，不过我因为被坑了，鼓捣的过程里把两个都装了。</li><li>接下来就是编写json配置文件，就是把你的账号服务器填一下，格式如下：</li></ul><figure class="highlight json"><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">&#123;</span><br><span class="line"><span class="attr">"server"</span>:<span class="string">"服务器 IP 或是域名"</span>,</span><br><span class="line"><span class="attr">"server_port"</span>:端口号,</span><br><span class="line"><span class="attr">"local_address"</span>: <span class="string">"127.0.0.1"</span>,</span><br><span class="line"><span class="attr">"local_port"</span>:<span class="number">1080</span>,</span><br><span class="line"><span class="attr">"password"</span>:<span class="string">"密码"</span>,</span><br><span class="line"><span class="attr">"timeout"</span>:<span class="number">300</span>,</span><br><span class="line"><span class="attr">"method"</span>:<span class="string">"加密方式 (chacha20-ietf-poly1305 / aes-256-cfb)"</span>,</span><br><span class="line"><span class="attr">"fast_open"</span>: <span class="literal">false</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li>一般就去你买的服务商那里复制粘贴json格式保存文件就行了。</li><li>接下来启动客户端，命令行使用以下命令<code>ss-local -c ssconfig.json</code>，后面的<code>ssconfig.json</code>要填你自己编写的配置文件和路径。</li><li>如果是qt5客户端，就在命令行里输入<code>ss-qt5</code>启动客户端，然后为了下次启动方便可以直接把图标固定在开始栏，下次就可以直接单击启动了，接着按照图形化界面添加配置就行了，添加好后点击<code>connect</code>按钮进行连接，连接好后可以按<code>test latency</code>按钮测测延迟，如果不是error就说明连上了。</li><li>至此，shadowsocks都配好了，但Linux下比较麻烦的是还需要配置浏览器，我这用的是Chrome，也推荐用Chrome。</li><li>当然，不能访问谷歌的时候好像也下不了Chrome，这个自行解决吧，我是回到我的windows里下好Linux版本的Chrome再回到Ubuntu里安装的，安装好之后命令行输入<code>google-chrome</code>便可以启动浏览器。</li><li>然后安装<code>SwitchOmega</code>插件，当然，也没法从Chrome商店里安装，所以只能手动安装，去<a href="https://github.com/FelisCatus/SwitchyOmega/releases" target="_blank" rel="noopener">https://github.com/FelisCatus/SwitchyOmega/releases</a>下载.crx文件，接着将后缀crx改为zip，解压。然后打开Chrome浏览器，地址栏输入<code>chrome://extensions/</code>，打开右上角的开发者模式，接着点左上角的<code>加载已解压的扩展程序</code>，选择解压的文件夹，就OK了，虽然插件好像会有Error，但不影响。</li><li>最后就是配置SwitchOmega了，还有点麻烦，可以看<a href="https://www.qcgzxw.cn/2988.html#toc-2" target="_blank" rel="noopener">https://www.qcgzxw.cn/2988.html#toc-2</a>，这是我找了好久才找到的没有被屏蔽的配置教程，希望你们看的时候也没被屏蔽。如果屏蔽了……就看下我现在写的简单过程吧，先启动插件，右键选择options进入配置，左侧选择proxy，右侧选择协议SOCKS5，代理服务器填127.0.0.1，端口1080（这和你的json里一致），然后点左侧应用选项保存配置。接着还没好，选择auto switch继续配置自动切换规则，规则列表格式选择AutoProxy，规则列表网址填<code>https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt</code>，然后点击下方的<code>立即更新情景模式</code>按钮，接着规则列表设置上面的部分，勾选<code>勾选列表规则</code>，上面的几条配置可以删了，只要在规则列表规则后面选择<code>proxy</code>就好了，简单说意思就是在规则列表里的网址就使用proxy，否则就直连，最后备别忘了保存。</li><li>最后在浏览器里右上角的插件里设置成<code>auto switch</code>就行了。</li><li>ok，正常可以访问Google了，但是我昨天搞到凌晨三点也不行，今天一觉起来就行了，很莫名其妙。最后可以看下这个连接<a href="https://zhuanlan.zhihu.com/p/47706985" target="_blank" rel="noopener">https://zhuanlan.zhihu.com/p/47706985</a>，是使用命令行客户端的一个教程，比较清晰。</li></ul><h1 id="Ubuntu下Tim和微信的安装使用"><a href="#Ubuntu下Tim和微信的安装使用" class="headerlink" title="Ubuntu下Tim和微信的安装使用"></a>Ubuntu下Tim和微信的安装使用</h1><p>主要参考<a href="https://www.lulinux.com/archives/1319" target="_blank" rel="noopener">https://www.lulinux.com/archives/1319</a>。</p><p>主要步骤：</p><ol><li>安装deepin-wine环境，上<a href="https://github.com/wszqkzqk/deepin-wine-ubuntu" target="_blank" rel="noopener">https://github.com/wszqkzqk/deepin-wine-ubuntu</a>，我是按照本地安装来安装的，正常装完即可。</li><li>安装容器，即QQ、Tim或者微信。</li></ol><ul><li>Tim：<a href="http://mirrors.aliyun.com/deepin/pool/non-free/d/deepin.com.qq.office/" target="_blank" rel="noopener">http://mirrors.aliyun.com/deepin/pool/non-free/d/deepin.com.qq.office/</a></li><li>QQ：<a href="http://mirrors.aliyun.com/deepin/pool/non-free/d/deepin.com.qq.im/" target="_blank" rel="noopener">http://mirrors.aliyun.com/deepin/pool/non-free/d/deepin.com.qq.im/</a></li><li>微信：<a href="http://mirrors.aliyun.com/deepin/pool/non-free/d/deepin.com.wechat/" target="_blank" rel="noopener">http://mirrors.aliyun.com/deepin/pool/non-free/d/deepin.com.wechat/</a></li></ul><h1 id="双系统互相访问文件"><a href="#双系统互相访问文件" class="headerlink" title="双系统互相访问文件"></a>双系统互相访问文件</h1><p>Linux可以直接访问Windows，不需要做任何操作，厉害呀。</p><p>Windows想要访问Liunx，下载一个叫做LinuxReader的软件即可，网上也有说别的软件的，但我下了不行，所以就用这个了。</p><p>下载链接<a href="https://www.diskinternals.com/linux-reader/" target="_blank" rel="noopener">https://www.diskinternals.com/linux-reader/</a>，try it free即可。</p><h1 id="Ubuntu搜狗输入法安装"><a href="#Ubuntu搜狗输入法安装" class="headerlink" title="Ubuntu搜狗输入法安装"></a>Ubuntu搜狗输入法安装</h1><p>参考<a href="https://jingyan.baidu.com/article/642c9d341b3ccb644a46f7ac.html" target="_blank" rel="noopener">https://jingyan.baidu.com/article/642c9d341b3ccb644a46f7ac.html</a>。</p><ul><li>下载搜狗输入法For Linux，一个.deb文件，用<code>dpkg -i file</code>来安装，但好像不需要这个命令了，可以直接看下一步（不过我没试过直接用下一步，毕竟我是装了之后不能用才去找教程的嘛）。</li><li>但现在还不能用，继续操作，输入<code>sudo apt-get install gdebi</code>安装Gdebi，然后cd到.deb文件目录，执行<code>sudo gdebi sogoupinyin.deb</code>，等待安装好。</li><li>重启电脑，就行了。</li></ul><p>最后可以愉快地用Ubuntu啦，当然还有听歌软件啊啥的没研究，回头再说，毕竟Vim还没配好。</p><p>慢慢来。</p><p>【END】</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;本文包括以下内容：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;双系统安装&lt;/li&gt;
&lt;li&gt;Ubuntu访问Google&lt;/li&gt;
&lt;li&gt;Ubuntu下Tim和微信的安装使用&lt;/li&gt;
&lt;li&gt;双系统互相访问文件&lt;/li&gt;
&lt;li&gt;Ubuntu搜狗输入法安装&lt;/li&gt;
&lt;/ul&gt;
    
    </summary>
    
      <category term="职业学习" scheme="http://yoursite.com/categories/%E8%81%8C%E4%B8%9A%E5%AD%A6%E4%B9%A0/"/>
    
    
      <category term="Linux" scheme="http://yoursite.com/tags/Linux/"/>
    
  </entry>
  
  <entry>
    <title>Vim学习记录</title>
    <link href="http://yoursite.com/2019/06/29/Vim%E5%AD%A6%E4%B9%A0%E8%AE%B0%E5%BD%95/"/>
    <id>http://yoursite.com/2019/06/29/Vim学习记录/</id>
    <published>2019-06-29T08:20:07.000Z</published>
    <updated>2019-07-28T15:13:56.365Z</updated>
    
    <content type="html"><![CDATA[<p>因为工作中需要用到Vim，所以本文简单记录下学习Vim编辑器的一些笔记和技巧。</p><h1 id="Vimtutor"><a href="#Vimtutor" class="headerlink" title="Vimtutor"></a>Vimtutor</h1><p>Vimtutor是Vim的一个简易教程，前前后后做了两遍，记录一下一些实用的快捷键吧。</p><a id="more"></a><table><thead><tr><th style="text-align:center">快捷键</th><th style="text-align:center">功能</th></tr></thead><tbody><tr><td style="text-align:center">h/j/k/l</td><td style="text-align:center">左下上右</td></tr><tr><td style="text-align:center">x</td><td style="text-align:center">删除光标处的字母</td></tr><tr><td style="text-align:center">i</td><td style="text-align:center">切换至输入模式，在光标前输入</td></tr><tr><td style="text-align:center">A</td><td style="text-align:center">切换至输入模式，在行尾输入</td></tr><tr><td style="text-align:center">dw</td><td style="text-align:center">从光标处删除字符直到下个字开始</td></tr><tr><td style="text-align:center">de</td><td style="text-align:center">从光标处删除字符直到该字尾</td></tr><tr><td style="text-align:center">u</td><td style="text-align:center">撤销</td></tr><tr><td style="text-align:center">U</td><td style="text-align:center">撤销一整行的操作，使该行恢复到最初</td></tr><tr><td style="text-align:center">d&amp;</td><td style="text-align:center">从光标处删除字符直到行尾</td></tr><tr><td style="text-align:center">dd</td><td style="text-align:center">删除该行，其实也可以理解成剪切一行</td></tr><tr><td style="text-align:center">y</td><td style="text-align:center">个人感觉类似复制</td></tr><tr><td style="text-align:center">p</td><td style="text-align:center">个人感觉类似于粘贴</td></tr><tr><td style="text-align:center">r+字符</td><td style="text-align:center">用新的字符替换光标所在位置的字符</td></tr><tr><td style="text-align:center">R</td><td style="text-align:center">替换多个字符</td></tr><tr><td style="text-align:center">ce</td><td style="text-align:center">将一个字从光标处开始直到字尾的字符进行替换</td></tr><tr><td style="text-align:center">ctrl+g</td><td style="text-align:center">显示当前位置在整个文档的位置占比</td></tr><tr><td style="text-align:center">gg</td><td style="text-align:center">跳转到文档开头</td></tr><tr><td style="text-align:center">G</td><td style="text-align:center">跳转到文档结尾，number+G就跳转到第number行</td></tr><tr><td style="text-align:center">/+字符串</td><td style="text-align:center">往下搜索某字符串，搜到后n是下一个，N是上一个，Ctrl+o回到原处</td></tr><tr><td style="text-align:center">?+字符串</td><td style="text-align:center">往上搜索某字符串，搜到后n是下一个，N是上一个，Ctrl+o回到原处</td></tr><tr><td style="text-align:center">%</td><td style="text-align:center">寻找匹配的括号</td></tr><tr><td style="text-align:center">%s/old/new/g</td><td style="text-align:center">全文替换，用new替换old</td></tr><tr><td style="text-align:center">!+外部命令</td><td style="text-align:center">!后可以输入外部shell命令，如ls</td></tr><tr><td style="text-align:center">o</td><td style="text-align:center">在光标下方新增一行并进入插入模式，如果是大写的O则是在光标上方新增一行</td></tr><tr><td style="text-align:center">help+command</td><td style="text-align:center">打开help文档查看command命令的说明</td></tr></tbody></table><p>很多命令的格式都是<code>operation [number] motion</code>，比如<code>d2w</code>就是删除两个字。</p><p>在Vim里使用了<code>:</code>后，可以按<code>ctrl+d</code>来查看可以使用的命令。</p><h1 id="《Vim实用技巧》"><a href="#《Vim实用技巧》" class="headerlink" title="《Vim实用技巧》"></a>《Vim实用技巧》</h1><h1 id="一-Vim解决问题的方式"><a href="#一-Vim解决问题的方式" class="headerlink" title="一.Vim解决问题的方式"></a>一.Vim解决问题的方式</h1><h2 id="技巧1-结识-命令"><a href="#技巧1-结识-命令" class="headerlink" title="技巧1 结识.命令"></a>技巧1 结识<code>.</code>命令</h2><ul><li>首先要明确什么是修改，一次修改的单位可以是字符、整行，甚至是整个文件。当进入插入模式的那一刻起，直到返回普通模式为止，Vim会记录每一个操作，这些所有的操作在返回普通模式后被统称为一次修改，按<code>.</code>键即可重新执行一次所有操作。</li></ul><h2 id="技巧2-不要自我重复"><a href="#技巧2-不要自我重复" class="headerlink" title="技巧2 不要自我重复"></a>技巧2 不要自我重复</h2><ul><li>用<code>A</code>代替<code>$a</code></li><li>有一些复合命令可以代替等效的长命令（这里还是得多用多记吧，不过这些命令的共同处是都会把普通模式切换到插入模式，本来以为这会让多次连续使用<code>.</code>命令出现问题，但试验之后好像没有？比如按下<code>ko</code>会进入插入模式，但返回普通模式后按<code>.</code>，虽然也换行了但是并没有进入插入模式。）</li></ul><h2 id="技巧3-以退为进"><a href="#技巧3-以退为进" class="headerlink" title="技巧3 以退为进"></a>技巧3 以退为进</h2><ul><li><code>s</code>命令包含两个动作：删除光标处的字符，进入插入模式。</li><li><code>f{char}</code>命令查找该行下一处指定字符出现的位置，如果找到就直接把光标移到该处。而<code>;</code>命令可以重复上次的<code>f{char}</code>命令。</li></ul><h2 id="技巧4-执行、重复、回退"><a href="#技巧4-执行、重复、回退" class="headerlink" title="技巧4 执行、重复、回退"></a>技巧4 执行、重复、回退</h2><ul><li>类似于<code>u</code>可以回退<code>.</code>的修改，<code>,</code>也可以用来回退<code>;</code></li></ul><h2 id="技巧5-查找并手动替换"><a href="#技巧5-查找并手动替换" class="headerlink" title="技巧5 查找并手动替换"></a>技巧5 查找并手动替换</h2><ul><li><code>*</code>命令可以查找当前光标所在单词</li></ul><h2 id="技巧6-结识-范式"><a href="#技巧6-结识-范式" class="headerlink" title="技巧6 结识.范式"></a>技巧6 结识<code>.</code>范式</h2><ul><li>理想模式：一键移动，一键执行。（谨记！）</li></ul><h1 id="二、普通模式"><a href="#二、普通模式" class="headerlink" title="二、普通模式"></a>二、普通模式</h1><h2 id="技巧7-停顿时请移开画笔"><a href="#技巧7-停顿时请移开画笔" class="headerlink" title="技巧7 停顿时请移开画笔"></a>技巧7 停顿时请移开画笔</h2><ul><li>就像画家只花一小部分时间真正画画一样，程序员也只花一小部分时间编写代码，绝大多数时间用来思考，这个时候就是普通模式。（其实用作家码字来比喻可能我更喜欢~）</li></ul><h2 id="技巧8-把撤销单元切成块"><a href="#技巧8-把撤销单元切成块" class="headerlink" title="技巧8 把撤销单元切成块"></a>技巧8 把撤销单元切成块</h2><ul><li>在插入模式中移动光标会重置修改状态，即相当于切回普通模式使用了<code>hjkl</code>，只是看起来没退出插入模式罢了。</li></ul><h2 id="技巧9-构造可重复的修改"><a href="#技巧9-构造可重复的修改" class="headerlink" title="技巧9 构造可重复的修改"></a>技巧9 构造可重复的修改</h2><ul><li>当完成一个修改有多种方法的时候，可以考量不同方法的VimGolf，小者获胜，当VimGolf相同时则可以思考在不同的方法下，继续按<code>.</code>会各自有什么效果，选其中最有价值的那个，即将修改构造成了可重复性的修改。（真是太秀了，忍不住666）</li></ul><h2 id="技巧10-用次数做简单的算数运算"><a href="#技巧10-用次数做简单的算数运算" class="headerlink" title="技巧10 用次数做简单的算数运算"></a>技巧10 用次数做简单的算数运算</h2><ul><li><code>ctrl+a</code>表示+1，<code>ctrl+x</code>表示-1</li></ul><h2 id="技巧11-能够重复，就别用次数"><a href="#技巧11-能够重复，就别用次数" class="headerlink" title="技巧11 能够重复，就别用次数"></a>技巧11 能够重复，就别用次数</h2><ul><li>次数和<code>.</code>命令要斟酌着选择使用</li></ul><h2 id="技巧12-双剑合璧，天下无敌"><a href="#技巧12-双剑合璧，天下无敌" class="headerlink" title="技巧12 双剑合璧，天下无敌"></a>技巧12 双剑合璧，天下无敌</h2><ul><li>操作符 + 动作命令 = 操作</li><li>Vim语法只有一条额外规则，即当一个操作符命令被连续调用两次时，它会作用于当前行。</li></ul><h1 id="三、插入模式"><a href="#三、插入模式" class="headerlink" title="三、插入模式"></a>三、插入模式</h1><h2 id="技巧13-在插入模式下可即时更正错误"><a href="#技巧13-在插入模式下可即时更正错误" class="headerlink" title="技巧13 在插入模式下可即时更正错误"></a>技巧13 在插入模式下可即时更正错误</h2><ul><li><code>ctrl+h</code>删除前一个字符</li><li><code>ctrl+w</code>删除前一个单词</li><li><code>ctrl+u</code>删除至行首</li></ul><h2 id="技巧14-返回普通模式"><a href="#技巧14-返回普通模式" class="headerlink" title="技巧14 返回普通模式"></a>技巧14 返回普通模式</h2><p>可以使用<code>Esc</code>或<code>ctrl+[</code>来返回普通模式，还可以使用<code>ctrl+o</code>切换到插入-普通模式。在插入-普通模式中，可以执行一次普通模式下的命令然后自动变回插入模式。</p><h2 id="技巧15-不离开插入模式，粘贴寄存器中的文本"><a href="#技巧15-不离开插入模式，粘贴寄存器中的文本" class="headerlink" title="技巧15 不离开插入模式，粘贴寄存器中的文本"></a>技巧15 不离开插入模式，粘贴寄存器中的文本</h2><ul><li>看书上的描述，是可以把文本复制到寄存器中，然后再在指定位置把寄存器的文本粘贴出来。具体命令回头再看吧，也记不住。</li></ul><h2 id="技巧16-随时随地做运算"><a href="#技巧16-随时随地做运算" class="headerlink" title="技巧16 随时随地做运算"></a>技巧16 随时随地做运算</h2><ul><li>利用表达式寄存器我们可以做一些运算并把结果直接插入到文本中。输入<code>&lt;ctrl+r&gt;=</code>就可以访问该寄存器，然后输入表达式（如1+1）按回车就可以在光标处插入对应结果了（如2）。</li></ul><h2 id="技巧17-用字符编码插入非常用字符"><a href="#技巧17-用字符编码插入非常用字符" class="headerlink" title="技巧17 用字符编码插入非常用字符"></a>技巧17 用字符编码插入非常用字符</h2><ul><li>Vim可以用字符编码来插入任意字符，使用此功能可以很方便地输入键盘上找不到的符号，只要输入<code>&lt;ctrl+v&gt;{code}</code>即可。</li><li>另外如果想要知道光标处的字符的编码，按<code>ga</code>即可。</li></ul><h2 id="技巧18-用二合字母插入非常用字符"><a href="#技巧18-用二合字母插入非常用字符" class="headerlink" title="技巧18 用二合字母插入非常用字符"></a>技巧18 用二合字母插入非常用字符</h2><ul><li>感觉和技巧17类似，只不过技巧17需要用编码不方便记忆，使用二合字母似乎好记忆一些（它这么说的，我也不敢说啥），命令<code>&lt;ctrl+k&gt;{char1}{char2}</code>。比如<code>&lt;ctrl+k&gt;12</code>就可以输出分数1/2.  </li></ul><h2 id="技巧19-用替换模式替换已有文本"><a href="#技巧19-用替换模式替换已有文本" class="headerlink" title="技巧19 用替换模式替换已有文本"></a>技巧19 用替换模式替换已有文本</h2><ul><li><code>R</code>命令进入替换模式，<code>r</code>替换一个字符并返回普通模式。</li><li>当有制表符的时候用<code>R</code>进入替换模式替换时，会用一个字符替换掉整个制表符所占长度的字符，从而缩减行的长度，这可能不是我们所希望的，这时候可以使用<code>gR</code>命令进入虚拟替换模式来替换，就不会有这样的问题。</li></ul><h1 id="四、可视模式"><a href="#四、可视模式" class="headerlink" title="四、可视模式"></a>四、可视模式</h1><p>Vim具有三种不同的可视模式，分别用于操作字符文本、行文本或块文本。</p><h2 id="技巧20-深入理解可视模式"><a href="#技巧20-深入理解可视模式" class="headerlink" title="技巧20 深入理解可视模式"></a>技巧20 深入理解可视模式</h2><ul><li>在普通模式中，先触发修改命令再选中作用范围，但是在可视模式中是先选中选区，然后再触发命令。注意次序是颠倒的。</li></ul><h2 id="技巧21-选择高亮选区"><a href="#技巧21-选择高亮选区" class="headerlink" title="技巧21 选择高亮选区"></a>技巧21 选择高亮选区</h2><ul><li><code>v</code>切换到面向字符的可视模式，<code>V</code>切换到面向行的可视模式，而<code>&lt;ctrl+v&gt;</code>切换到面向列块的可视模式。<code>gv</code>命令可以重新选择上次可视模式选择的区域。</li><li>可视模式之间的切换也就是按对应的键就行了。</li><li>可视模式选择中可以利用<code>o</code>来切换选区的活动端。</li></ul><h2 id="技巧22-重复执行面向行的可视命令"><a href="#技巧22-重复执行面向行的可视命令" class="headerlink" title="技巧22 重复执行面向行的可视命令"></a>技巧22 重复执行面向行的可视命令</h2><ul><li>合适的场景下可以使用<code>.</code>命令来重复之前面向行的可视命令。</li></ul><h2 id="技巧23-只要可能，最好用操作符命令而不是可视命令"><a href="#技巧23-只要可能，最好用操作符命令而不是可视命令" class="headerlink" title="技巧23 只要可能，最好用操作符命令而不是可视命令"></a>技巧23 只要可能，最好用操作符命令而不是可视命令</h2><ul><li>如果想让<code>.</code>命令能够重复某些有用的工作的话，那么最好不要用可视模式，首选操作符命令。</li></ul><h2 id="技巧24-用面向列块的可视模式编辑表格数据"><a href="#技巧24-用面向列块的可视模式编辑表格数据" class="headerlink" title="技巧24 用面向列块的可视模式编辑表格数据"></a>技巧24 用面向列块的可视模式编辑表格数据</h2><ul><li>这个就是要多练了，熟悉命令就行。</li></ul><h2 id="技巧25-修改列文本"><a href="#技巧25-修改列文本" class="headerlink" title="技巧25 修改列文本"></a>技巧25 修改列文本</h2><h2 id="技巧26-在长短不一的高亮块后添加文本"><a href="#技巧26-在长短不一的高亮块后添加文本" class="headerlink" title="技巧26 在长短不一的高亮块后添加文本"></a>技巧26 在长短不一的高亮块后添加文本</h2><ul><li>从普通模式切换到插入模式时<code>i</code>和<code>a</code>分别表示把光标置于当前字符之前或之后，但是在可视模式或操作符待决模式中，这两个命令被当做一个文本对象的组成部分，想要进入插入模式需要按<code>I</code>或<code>A</code>。</li></ul><h1 id="五、命令行模式"><a href="#五、命令行模式" class="headerlink" title="五、命令行模式"></a>五、命令行模式</h1><p>初时，先有ed，ed为ex之父，ex为vi之父，vi为vim之父。</p><h2 id="技巧27-结识Vim的命令行模式"><a href="#技巧27-结识Vim的命令行模式" class="headerlink" title="技巧27 结识Vim的命令行模式"></a>技巧27 结识Vim的命令行模式</h2><ul><li>命令行模式会提示我们输入一条Ex命令、一个查找模式或一个表达式。</li><li>Ex命令影响相比普通模式下的命令范围更广而且距离更远。</li></ul><h2 id="技巧28-在一行或多个连续行上执行命令"><a href="#技巧28-在一行或多个连续行上执行命令" class="headerlink" title="技巧28 在一行或多个连续行上执行命令"></a>技巧28 在一行或多个连续行上执行命令</h2><ul><li>很多Ex命令可以用[rang]指定要操作的范围，可以用行号、位置标记或是查找模式来指定范围的开始位置及结束位置。</li><li>在Ex命令里，<code>.</code>代表当前行的地址，<code>%</code>代表当前文件的所有行。<code>&#39;&lt;</code>表示选区首行，<code>&#39;&gt;</code>表示选区末行。</li><li>可以用模式指定范围，也可以用偏移（如+1、-1）对地址进行修正。</li><li>总而言之，定义范围的语法很灵活。</li></ul><h2 id="技巧29-使用-t和-m命令复制和移动行"><a href="#技巧29-使用-t和-m命令复制和移动行" class="headerlink" title="技巧29 使用:t和:m命令复制和移动行"></a>技巧29 使用<code>:t</code>和<code>:m</code>命令复制和移动行</h2><ul><li>重复上次的Ex命令非常简单，只需使用<code>@:</code>命令即可。</li></ul><h2 id="技巧30-在指定范围上执行普通模式命令"><a href="#技巧30-在指定范围上执行普通模式命令" class="headerlink" title="技巧30 在指定范围上执行普通模式命令"></a>技巧30 在指定范围上执行普通模式命令</h2><ul><li>如果想在一系列连续行上执行一条普通模式命令，则可以使用<code>:normal</code>。</li><li>在执行普通模式命令之前，Vim会把光标移到行首，因此在执行命令时不需要担心光标的位置。</li></ul><h2 id="技巧31-重复上次的Ex命令"><a href="#技巧31-重复上次的Ex命令" class="headerlink" title="技巧31 重复上次的Ex命令"></a>技巧31 重复上次的Ex命令</h2><ul><li>重复上次的Ex命令非常简单，只需使用<code>@:</code>命令即可。</li><li><code>bnext</code>可以在缓冲区列表项中正向移动，而<code>bprevious</code>则是反向移动。</li></ul><h2 id="技巧32-自动补全Ex命令"><a href="#技巧32-自动补全Ex命令" class="headerlink" title="技巧32 自动补全Ex命令"></a>技巧32 自动补全Ex命令</h2><ul><li>如同在shell中一样，在命令行上也可以用<tab>键自动补全命令。</tab></li><li><code>&lt;ctrl+d&gt;</code>可以显示Vim可用的命令补全列表。</li></ul><h2 id="技巧33-把当前单词插入到命令行"><a href="#技巧33-把当前单词插入到命令行" class="headerlink" title="技巧33 把当前单词插入到命令行"></a>技巧33 把当前单词插入到命令行</h2><ul><li>在Vim的命令行下，<code>&lt;ctrl+r&gt;&lt;ctrl+w&gt;</code>会复制光标下的单词并把它插入到命令行中。</li></ul><h2 id="技巧34-回溯历史命令"><a href="#技巧34-回溯历史命令" class="headerlink" title="技巧34 回溯历史命令"></a>技巧34 回溯历史命令</h2><ul><li>历史命令不仅仅是为当前编辑会话记录的，这些记录即使在退出Vim再重启之后仍然存在。</li><li>输入<code>q:</code>可以打开命令行窗口。在命令行窗口里可以用任何习以为常的动作命令进行移动，也可以在高亮选区上操作，或是切换到插入模式中。可以按<code>:q</code>或者回车来关闭命令行窗口。具体要多练。</li><li>当我们在命令行窗口按回车时，该命令在活动窗口的上下文中执行。所谓活动窗口，指的是打开命令行窗口之前处于活动的那个窗口，要注意。</li></ul><h2 id="技巧35-运行Shell命令"><a href="#技巧35-运行Shell命令" class="headerlink" title="技巧35 运行Shell命令"></a>技巧35 运行Shell命令</h2><ul><li>不用离开Vim就可以方便地调用外部程序，还可以把缓冲区的内容当做标准输入发送给一个外部命令，或是把外部命令的标准输出导入到缓冲区中。</li><li>给命令加一个前缀<code>!</code>号就可以调用外部命令一次。</li><li>如果想要执行多次外部命令，则可以用<code>:shell</code>命令打开一个交互的shell，用<code>exit</code>退出。</li><li>当然也可以用<code>&lt;ctrl+z&gt;</code>把Vim进程挂起，运行完shell命令之后再用<code>jobs</code>和<code>fg</code>命令切换回来。</li><li>可以用<code>:read !{cmd}</code>把外部命令的输出读入到当前缓冲区中。而<code>:write !{cmd}</code>做相反的事，把缓冲区的内容作为外部命令的输入。但要注意的是在write中感叹号位置不同表示的含义有所不同，<code>:write! sh</code>会把缓冲区内容写入到一个名为sh的文件中，叹号表示无论如何都覆盖。</li><li><code>:[range]!{filter}</code>可以实现某个范围内的过滤，意思是把该范围内的内容作为标准输入，处理之后再把结果输出到该范围之内。</li></ul><h1 id="六、管理多个文件"><a href="#六、管理多个文件" class="headerlink" title="六、管理多个文件"></a>六、管理多个文件</h1><h2 id="技巧36-用缓冲区列表管理打开的文件"><a href="#技巧36-用缓冲区列表管理打开的文件" class="headerlink" title="技巧36 用缓冲区列表管理打开的文件"></a>技巧36 用缓冲区列表管理打开的文件</h2><ul><li>在一次的编辑会话中，可以打开多个文件，用Vim的缓冲区列表可以对这些文件进行管理。</li><li>Vim允许同时在多个缓冲区上工作，打开多个文件后可以用<code>:ls</code>命令查看所有被载入到内存中的缓冲区的列表，然后用<code>:bnext</code>命令切换到列表中的下一个缓冲区，<code>:bprev</code>切换到前一个，此外还有<code>:bfirst</code>和<code>:blast</code>两个命令也可以切换。</li><li>使用<code>:ls</code>命令时，#符号表示轮换文件，可以用<code>&lt;ctrl+^&gt;</code>来切换到#所指文件。</li></ul><h2 id="技巧37-用参数列表将缓冲区分组"><a href="#技巧37-用参数列表将缓冲区分组" class="headerlink" title="技巧37 用参数列表将缓冲区分组"></a>技巧37 用参数列表将缓冲区分组</h2><ul><li>参数列表易于管理，适用于对一批文件进行分组，使其更容易访问。用<code>:argdo</code>命令可以在参数列表中的每个文件上执行一条Ex命令。</li><li>可以用<code>:args {argList}</code>来填充参数列表，argList也可以使用模式来指定，还可以使用反引号。比如args  `cat .chapters` 就会先在shell中执行<code>cat .chapters</code>命令，然后将该命令的输出作为args的参数。</li></ul><h2 id="技巧38-管理隐藏缓冲区"><a href="#技巧38-管理隐藏缓冲区" class="headerlink" title="技巧38 管理隐藏缓冲区"></a>技巧38 管理隐藏缓冲区</h2><ul><li>打开多个缓冲区后，如果修改了某个缓冲区，再使用<code>:bnext</code>时会提醒当前缓冲区中有未保存的改动，可以加上<code>!</code>来强制切换，也可以保存后再切换。如果选择了强制切换，那么在退出时需要再次处理每个缓冲区，可以用<code>qa!</code>摒弃所有改动，也可以用<code>:wa!</code>把所有改动写入磁盘。</li><li>大多数情况下Vim提醒缓冲区改动未保存是一个好事，但是当涉及到<code>:argdo</code>或者<code>:bufdo</code>等命令时则很不方便，所以在使用这些命令前可以启动<code>hidden</code>选项，最后退出时再处理。</li></ul><h2 id="技巧39-将工作区切分成窗口"><a href="#技巧39-将工作区切分成窗口" class="headerlink" title="技巧39 将工作区切分成窗口"></a>技巧39 将工作区切分成窗口</h2><ul><li>Vim允许我们将工作区切分成多个若干窗口，在窗口里并排显示多个缓冲区。</li><li><code>&lt;ctrl+w&gt;s</code>水平切割窗口，<code>&lt;ctrl+w&gt;v</code>垂直切割窗口。</li><li><code>close</code>命令可以关闭活动窗口，<code>only</code>命令可以只保留活动窗口而关闭其他窗口。</li></ul><h2 id="技巧40-用标签页将窗口分组"><a href="#技巧40-用标签页将窗口分组" class="headerlink" title="技巧40 用标签页将窗口分组"></a>技巧40 用标签页将窗口分组</h2><ul><li>标签页的这部分看的不是特别明白，书中也没有给出好的例子。以后再说吧。</li></ul><h1 id="七、打开及保存文件"><a href="#七、打开及保存文件" class="headerlink" title="七、打开及保存文件"></a>七、打开及保存文件</h1><h2 id="技巧41-用-edit命令打开文件"><a href="#技巧41-用-edit命令打开文件" class="headerlink" title="技巧41 用:edit命令打开文件"></a>技巧41 用<code>:edit</code>命令打开文件</h2><ul><li>在Vim中，可以用<code>:edit</code>命令通过文件的绝对或相对路径来打开文件。</li><li><code>%</code>符号代表活动缓冲区的完整文件路径，按<code>Tab</code>键可以将其展开。<code>%:h</code>则可以显示去掉文件名的活动缓冲区完整文件路径。</li></ul><h2 id="技巧42-使用-find打开文件"><a href="#技巧42-使用-find打开文件" class="headerlink" title="技巧42 使用:find打开文件"></a>技巧42 使用<code>:find</code>打开文件</h2><ul><li>这个技巧里讲的主要是配置path，然后就可以用<code>find</code>命令来打开文件了。</li></ul><h2 id="技巧43-使用netrw管理文件系统"><a href="#技巧43-使用netrw管理文件系统" class="headerlink" title="技巧43 使用netrw管理文件系统"></a>技巧43 使用netrw管理文件系统</h2><ul><li>Vim还可以查看目录，netrw就是它自带的文件管理器插件。</li><li>可以用<code>:edit {path}</code>打开文件管理器窗口。此外，<code>:Explore</code>命令也可以打开文件管理器窗口，并显示活动缓冲区所在的目录。</li><li>可以与分割窗口协同工作</li></ul><h2 id="技巧44-把文件保存到不存在的目录中"><a href="#技巧44-把文件保存到不存在的目录中" class="headerlink" title="技巧44 把文件保存到不存在的目录中"></a>技巧44 把文件保存到不存在的目录中</h2><ul><li>当用<code>:edit {file}</code>命令打开未存在的目录中的未存在文件时，不能直接保存，需要先创建该目录，可以用<code>:!mkdir %:h</code>命令。</li></ul><h2 id="技巧45-以超级用户权限保存文件"><a href="#技巧45-以超级用户权限保存文件" class="headerlink" title="技巧45 以超级用户权限保存文件"></a>技巧45 以超级用户权限保存文件</h2><ul><li>这个就不管了，感觉不太会用到，记一下书中用到的命令好了<code>:w !sudo tee % &gt; /dev/null</code>。</li></ul><h1 id="八、用动作命令在文档中移动"><a href="#八、用动作命令在文档中移动" class="headerlink" title="八、用动作命令在文档中移动"></a>八、用动作命令在文档中移动</h1><ul><li>可以通过<code>:h motion.txt</code>获得完整的动作命令列表</li></ul><h2 id="技巧46-让手指保持在本位行上"><a href="#技巧46-让手指保持在本位行上" class="headerlink" title="技巧46 让手指保持在本位行上"></a>技巧46 让手指保持在本位行上</h2><ul><li>用<code>hjkl</code>移动，戒掉使用光标键的习惯，可以在vimrc里添加对应的辅助设置，p102</li></ul><h2 id="技巧47-区分实际行与屏幕行"><a href="#技巧47-区分实际行与屏幕行" class="headerlink" title="技巧47 区分实际行与屏幕行"></a>技巧47 区分实际行与屏幕行</h2><ul><li>所谓实际行说的是真正的行，屏幕行则是因为屏幕宽度限制而出现的行</li><li><code>hjkl0$</code>命令都是针对实际行的，前缀加<code>g</code>就能对应命令改为针对屏幕行的。</li></ul><h2 id="技巧48-基于单词移动"><a href="#技巧48-基于单词移动" class="headerlink" title="技巧48 基于单词移动"></a>技巧48 基于单词移动</h2><ul><li><code>wbe</code>是基于单词的移动动作，对应的<code>WBE</code>则是针对子串的移动动作。</li></ul><h2 id="技巧49-对字符进行查找"><a href="#技巧49-对字符进行查找" class="headerlink" title="技巧49 对字符进行查找"></a>技巧49 对字符进行查找</h2><ul><li><code>f{char}</code>是在Vim里移动最快的方式之一，它会在光标与行尾之间搜寻指定的字符，找到了就移过去。</li><li><code>;</code>可以重复上一次的<code>f{char}</code>命令，<code>,</code>可以反向跳。</li><li><code>t{char}</code>正向移动到下一个{char}所在之处的前一个字符上，<code>T{char</code>反向移动到char的后一个字符上。</li><li>使用这些命令的时候，要学会找到频率少的单词，这样才能提高移动效率。</li></ul><h2 id="技巧50-通过查找进行移动"><a href="#技巧50-通过查找进行移动" class="headerlink" title="技巧50 通过查找进行移动"></a>技巧50 通过查找进行移动</h2><ul><li>用<code>/</code>来进行查找并移动光标</li><li>还可以将操作文本的动作和查找结合在一起。</li></ul><h2 id="技巧51-用精确的文本对象选择选区"><a href="#技巧51-用精确的文本对象选择选区" class="headerlink" title="技巧51 用精确的文本对象选择选区"></a>技巧51 用精确的文本对象选择选区</h2><ul><li>文本对象允许操作括号、被引用的文本、XML标签以及其他文本中的常见结构。</li><li>Vim的文本对象由两个字符组成，第一个字符永远是<code>i</code>或者<code>a</code>。以<code>i</code>开头的文本对象会选择分隔符内部的文本，而以<code>a</code>开头的文本对象则会选择包括分隔符在内的整个文本。具体可以用到的时候再说吧。</li></ul><h2 id="技巧52-删除周边，修改内部"><a href="#技巧52-删除周边，修改内部" class="headerlink" title="技巧52 删除周边，修改内部"></a>技巧52 删除周边，修改内部</h2><ul><li>除了被括号或引号括起来的分隔符文本对象，还有另外一种范围文本对象，可以操作一个单词、一个子串、一个句子、一个段落。具体命令可以看书p117</li></ul><h2 id="技巧53-设置位置标记，以便快速跳回"><a href="#技巧53-设置位置标记，以便快速跳回" class="headerlink" title="技巧53 设置位置标记，以便快速跳回"></a>技巧53 设置位置标记，以便快速跳回</h2><ul><li>可以用<code>m{a-zA-Z}</code>标记当前光标所在位置，然后用`{a-zA-Z}命令跳回来。</li></ul><h2 id="技巧54-在匹配括号间跳转"><a href="#技巧54-在匹配括号间跳转" class="headerlink" title="技巧54 在匹配括号间跳转"></a>技巧54 在匹配括号间跳转</h2><ul><li><code>%</code>命令可以在成对的括号间跳转</li><li>Vim在发布时携带一个名为matchit的插件，可以用来在配对的关键字之间跳转，还有个Surround.vim的插件，可以很容易地给选中的文本加分隔符。</li></ul><h1 id="九-在文件间跳转"><a href="#九-在文件间跳转" class="headerlink" title="九 在文件间跳转"></a>九 在文件间跳转</h1><h2 id="技巧55-遍历跳转列表"><a href="#技巧55-遍历跳转列表" class="headerlink" title="技巧55 遍历跳转列表"></a>技巧55 遍历跳转列表</h2><ul><li>可以用<code>jumps</code>查看跳转列表的内容</li><li>大于等于句子级别的动作命令会被当做跳转，小范围的动作命令则只是移动。</li></ul><h2 id="技巧56-遍历改变列表"><a href="#技巧56-遍历改变列表" class="headerlink" title="技巧56 遍历改变列表"></a>技巧56 遍历改变列表</h2><ul><li>每当对文档做出修改后，Vim都会记录当时光标所在的位置。</li><li><code>changes</code>命令可以查看改变列表的内容。可以用<code>g;</code>和<code>g,</code>命令来反向或正向遍历改变列表。</li><li>`.总会跳到指向上次修改的地方。</li><li>`^标记指向上次插入的地方。</li></ul><h2 id="技巧57-跳转到光标下的文件"><a href="#技巧57-跳转到光标下的文件" class="headerlink" title="技巧57 跳转到光标下的文件"></a>技巧57 跳转到光标下的文件</h2><ul><li>Vim会把文档中的文件名当成一个超链接，在进行了正确的配置之后，就可以用<code>gf</code>命令跳转到光标下的文件了。</li><li>跳转列表和改变列表允许我们原路返回，而<code>gf</code>和<code>&lt;ctrl+]&gt;</code>则像虫洞，可以把我们从代码的一个地方传送到另一个文件地方。</li></ul><h2 id="技巧58-用全局位置标记在文件间快速跳转"><a href="#技巧58-用全局位置标记在文件间快速跳转" class="headerlink" title="技巧58 用全局位置标记在文件间快速跳转"></a>技巧58 用全局位置标记在文件间快速跳转</h2><ul><li><code>m{A-Z}</code>可以设置一个全局标签，这对使用vimgrep等命令跳转到其他地方后想要再跳回来很有帮助，要养成在跳转前考虑是否需要全局标签的习惯。</li></ul><h1 id="十、复制与粘贴"><a href="#十、复制与粘贴" class="headerlink" title="十、复制与粘贴"></a>十、复制与粘贴</h1><ul><li>Vim的寄存器是一组用于保存文本的简单容器。它们既可以像剪贴板那样，剪切、复制和粘贴文本；也可以记录一系列按键操作，把它们录制成宏。</li></ul><h2 id="技巧59-用无名寄存器实现删除、复制与粘贴操作"><a href="#技巧59-用无名寄存器实现删除、复制与粘贴操作" class="headerlink" title="技巧59 用无名寄存器实现删除、复制与粘贴操作"></a>技巧59 用无名寄存器实现删除、复制与粘贴操作</h2><ul><li>在Vim的术语里，当提到剪切、复制与粘贴时，指的不是剪贴板而是寄存器。比如<code>xp</code>命令，先删除光标下的字符，然后粘贴到下一个字符之后，连起来的作用就是将光标下的字符和下一个字符交换位置。同理，<code>ddp</code>命令可以用来交换两行的顺序。</li></ul><h2 id="技巧60-深入理解Vim寄存器"><a href="#技巧60-深入理解Vim寄存器" class="headerlink" title="技巧60 深入理解Vim寄存器"></a>技巧60 深入理解Vim寄存器</h2><ul><li>Vim不使用单一的剪贴板进行剪切、复制和粘贴，而是为这些操作提供了多组寄存器。</li><li>Vim的删除、复制和粘贴命令都会用到众多寄存器中的一个，可以通过给命令加<code>&quot;{register}</code>前缀的方式指定要用的寄存器，若不指定则默认使用无名寄存器。</li><li>显式调用无名寄存器时要用<code>&quot;&quot;</code></li><li>复制专用寄存器<code>&quot;0</code>，要复制的文本不仅会被拷贝到无名寄存器中，而且也会被拷贝到复制专用寄存器中，仅当使用<code>y{motion}</code>命令时才会被赋值。使用<code>:reg &quot;0</code>则可以查看该寄存器的内容。</li><li>有名寄存器(“a-“z)。用小写字母引用有名寄存器，会覆盖该寄存器的原有内容，而换用大写字母时，则会将新内容append到原内容后面。</li><li>黑洞寄存器(_ )可以真正删除文本，命令如<code>&quot;_dd</code>可以删除整行而不复制到寄存器里去。黑洞寄存器是个有去无回的地方。</li><li>系统剪贴板<code>&quot;+</code>，如果要从Vim复制文本到外部程序（反之亦然），则需要使用系统剪贴板。还有一个<code>&quot;*</code>表示X11主剪贴板，用鼠标中键操作（Win和MacOS没有）。</li><li>表达式寄存器<code>&quot;=</code>，其他寄存器通常被认为是保存一段文本的容器，然后通过表达式寄存器是个例外。从表达式寄存器获取内容时，Vim将跳转到命令行模式，并显示提示符<code>=</code>，这时可以输入一段Vim脚本表达式执行，将会返回结果。</li><li>还有几组可被隐式赋值的寄存器，只读。当前文件名<code>&quot;%</code>。轮换文件名<code>&quot;#</code>。上次插入的文本<code>&quot;.</code>。上次执行的Ex命令<code>&quot;:</code>。上次查找的模式<code>&quot;/</code>。技术上讲/寄存器并非只读，可以用<code>:let</code>命令赋值，但为方便仍归于此类。</li></ul><h2 id="技巧61-用寄存器的内容替换高亮选区的文本"><a href="#技巧61-用寄存器的内容替换高亮选区的文本" class="headerlink" title="技巧61 用寄存器的内容替换高亮选区的文本"></a>技巧61 用寄存器的内容替换高亮选区的文本</h2><ul><li>Vim的粘贴命令在可视模式下使用时，会体现出一些不同寻常的特性。在可视模式下使用p，将用我们指定的寄存器来替换高亮选区的文本。</li><li>使用p命令的时候，会先从寄存器里取出内容，然后把高亮选区的内容存入无名寄存器。</li></ul><h2 id="技巧62-把寄存器的内容粘贴出来"><a href="#技巧62-把寄存器的内容粘贴出来" class="headerlink" title="技巧62 把寄存器的内容粘贴出来"></a>技巧62 把寄存器的内容粘贴出来</h2><ul><li>面向行的复制或删除操作将创建面向行的寄存器，而面向字符的复制或者删除操作则会创建面向字符的寄存器。</li></ul><h2 id="技巧63-与系统剪贴板进行交互"><a href="#技巧63-与系统剪贴板进行交互" class="headerlink" title="技巧63 与系统剪贴板进行交互"></a>技巧63 与系统剪贴板进行交互</h2><ul><li>在Vim里使用系统粘贴版粘贴的时候往往缩进会出问题，为了解决这个问题，可以使用<code>:set paste</code>命令，然后切换到插入模式下进行粘贴，粘贴完再用<code>:set paste!</code>切换回来。</li><li>可以用<code>:set pastetoggle=&lt;F5&gt;</code>来做个映射，以后按F5就可以切换paste。</li></ul><h1 id="十一、宏"><a href="#十一、宏" class="headerlink" title="十一、宏"></a>十一、宏</h1><ul><li>可以用宏来把任意数目的按键操作录制到寄存器，用于之后的回放。<h2 id="技巧64-宏的读取与执行"><a href="#技巧64-宏的读取与执行" class="headerlink" title="技巧64 宏的读取与执行"></a>技巧64 宏的读取与执行</h2></li><li><code>q</code>是录制宏的开始与结束。比如<code>qa</code>会把接下来的一组命令保存在有名寄存器a里面。</li><li>可以使用<code>reg a</code>来查看寄存器a的内容。</li><li>可以使用<code>@{register}</code>来调用对应寄存器里保存的宏，用<code>@@</code>来重复上次调用过的宏命令。</li><li>在多次执行某个宏的时候有串行和并行两种方式，串行是一次一次执行，报错则停止，并行并不是真正的并行，只是说有一次执行出错的时候不会影响其他的宏。</li></ul><h2 id="技巧65-规范光标位置、直达目标以及中止宏"><a href="#技巧65-规范光标位置、直达目标以及中止宏" class="headerlink" title="技巧65 规范光标位置、直达目标以及中止宏"></a>技巧65 规范光标位置、直达目标以及中止宏</h2><ul><li>黄金法则：在录制一个宏时，要确保每条命令都可被重复执行。</li><li>一旦开始录制宏，就要问自己几个问题：我在哪？我从哪里来？我要去哪里？</li><li>规范光标的位置</li><li>用可重复的动作命令直达目标</li><li>当动作命令失败时，宏将中止。这种实现的好处在于在执行宏时，可以不顾忌执行的次数。</li></ul><h2 id="技巧66-加次数回放宏"><a href="#技巧66-加次数回放宏" class="headerlink" title="技巧66 加次数回放宏"></a>技巧66 加次数回放宏</h2><ul><li>对于次数不多的工作，可以用点范式，但它不能指定执行的次数。为了克服该限制，我们可以录制一个廉价的一次性的宏，然后再加次数进行回放。</li><li>不是每个宏都能用估算次数的方法调用。</li></ul><h2 id="技巧67-在连续的文本上重复修改"><a href="#技巧67-在连续的文本上重复修改" class="headerlink" title="技巧67 在连续的文本上重复修改"></a>技巧67 在连续的文本上重复修改</h2><ul><li>将下一个单词的首字母变为大写：<code>w~</code></li><li>以串行方式执行宏，类似于数字方法：<code>3@a</code></li><li>以并行方式执行宏，利用高亮选区，然后调用宏，在每一行上进行宏操作，这样就是并行方式，在书中的例子里，会比串行方式少一个j操作。p157</li></ul><h2 id="技巧68-给宏追加命令"><a href="#技巧68-给宏追加命令" class="headerlink" title="技巧68  给宏追加命令"></a>技巧68  给宏追加命令</h2><ul><li><code>q</code>后面跟大写字母，Vim会把后续的的按键操作附加到对应小写寄存器的内容后面。可以用这种方式来修正录制的宏的错误（但一般只能弥补结尾漏命令的情况）。</li></ul><h2 id="技巧69-在一组文件中执行宏"><a href="#技巧69-在一组文件中执行宏" class="headerlink" title="技巧69 在一组文件中执行宏"></a>技巧69 在一组文件中执行宏</h2><ul><li>利用<code>argdo</code>一系列命令，串行就是在宏里面录制一个next命令，使命令得以串行执行下去，而并行就是对选择的所有文件执行同一个命令，就是这个意思吧……具体命令还是以后再说吧。</li></ul><h2 id="技巧70-用迭代求值的方式给列表编号"><a href="#技巧70-用迭代求值的方式给列表编号" class="headerlink" title="技巧70 用迭代求值的方式给列表编号"></a>技巧70 用迭代求值的方式给列表编号</h2><ul><li>技巧10里提到过<code>&lt;ctrl+a&gt;</code>和<code>&lt;ctrl+x&gt;</code>两个简单计算方式</li><li>通过使用<code>:let i=0</code>命令，可以创建一个名为i的变量，并给其赋值0。</li></ul><h2 id="技巧71-编辑宏的内容"><a href="#技巧71-编辑宏的内容" class="headerlink" title="技巧71 编辑宏的内容"></a>技巧71 编辑宏的内容</h2><ul><li>为了修改宏的内容，可以先跳到文档最后，使用类似<code>:put a</code>的命令把某个寄存器中的值复制到文本里，然后对该文本进行就该，最后再把文本考回寄存器中，使用<code>0</code>和<code>&quot;ay$</code>命令将该行命令整个重新复制到寄存器a中，之所以不用<code>&quot;add</code>是因为这会把该行最后的回车符也拷贝进寄存器，而这有时候会产生问题。</li></ul><h1 id="十一、按模式匹配及按原义匹配"><a href="#十一、按模式匹配及按原义匹配" class="headerlink" title="十一、按模式匹配及按原义匹配"></a>十一、按模式匹配及按原义匹配</h1><h2 id="技巧72-调整查找模式的大小写敏感性"><a href="#技巧72-调整查找模式的大小写敏感性" class="headerlink" title="技巧72 调整查找模式的大小写敏感性"></a>技巧72 调整查找模式的大小写敏感性</h2><ul><li>既可以全局性地调整Vim查找功能的大小写敏感性，也可以在每次查找时进行局部调整。</li><li>如果启用<code>ignorecase</code>，Vim将不会区分大小写。</li><li>通过使用元字符\c或者\C则可以在本次查找中覆盖Vim的全局设置，\c忽略大小写，\C强制大小写。</li><li>Vim还有一个更智能的大小写敏感性设置，就是<code>smartcase</code>，当该选项被启用时，只要在查找模式中输入了大写字母，<code>ignorecase</code>设置就不再生效。换句话说，如果查找模式全是小写的，则忽略大小写，但只要有一个大写字母，就会区分大小写。</li></ul><h2 id="技巧73-按正则表达式查找时，使用-v模式开关"><a href="#技巧73-按正则表达式查找时，使用-v模式开关" class="headerlink" title="技巧73 按正则表达式查找时，使用\v模式开关"></a>技巧73 按正则表达式查找时，使用\v模式开关</h2><ul><li>正则表达式学得不咋地，以后再看。</li></ul><h2 id="技巧74-按照原义查找文本时，使用-V原义开关"><a href="#技巧74-按照原义查找文本时，使用-V原义开关" class="headerlink" title="技巧74 按照原义查找文本时，使用\V原义开关"></a>技巧74 按照原义查找文本时，使用\V原义开关</h2><ul><li>比如<code>/ \Va.k.a.</code>查找命令只会匹配a.k.a，不会再利用.的特殊含义去匹配类似backward的词。</li></ul><h2 id="技巧75-使用圆括号捕获子匹配"><a href="#技巧75-使用圆括号捕获子匹配" class="headerlink" title="技巧75 使用圆括号捕获子匹配"></a>技巧75 使用圆括号捕获子匹配</h2><ul><li><code>\_s</code>会匹配空白字符</li></ul><h2 id="技巧76-界定单词的边界"><a href="#技巧76-界定单词的边界" class="headerlink" title="技巧76 界定单词的边界"></a>技巧76 界定单词的边界</h2><ul><li>在very magic搜索模式下，用&lt;和&gt;符号表示单词定界符。</li><li>可以在圆括号前面加上%来匹配却不将其内容捕获保存给寄存器。</li></ul><h2 id="技巧77-界定匹配的边界"><a href="#技巧77-界定匹配的边界" class="headerlink" title="技巧77 界定匹配的边界"></a>技巧77 界定匹配的边界</h2><ul><li>有时候我们想指定一个范围较广的模式，但只对匹配结果的一部分感兴趣。Vim中的元字符\zs和\ze可以帮助我们处理这种情况。</li><li>比如查找模式为：<code>/Practical \zsVim\ze</code>，则只有跟在Practical后面的Vim会被高亮查到。</li></ul><h2 id="技巧78-转义问题字符"><a href="#技巧78-转义问题字符" class="headerlink" title="技巧78 转义问题字符"></a>技巧78 转义问题字符</h2><ul><li>‘\?/‘等字符需要手动转义，也可以使用vim自带的函数escape和getcmdtype，并借助表达式寄存器来解决，知道就行了。</li><li>在VIM脚本中，<code>.</code>操作符用来连接字符串。</li></ul><h1 id="十三、查找"><a href="#十三、查找" class="headerlink" title="十三、查找"></a>十三、查找</h1><h2 id="技巧79-结识查找命令"><a href="#技巧79-结识查找命令" class="headerlink" title="技巧79 结识查找命令"></a>技巧79 结识查找命令</h2><ul><li>如果只想在当前光标位置至文档结尾的范围内查找，而不想循环绕回去的话，可以关闭<code>wrapscan</code>选项。</li><li>如果不提供模式而直接查找，Vim将重用上一次查找的模式。</li></ul><h2 id="技巧80-高亮查找匹配"><a href="#技巧80-高亮查找匹配" class="headerlink" title="技巧80 高亮查找匹配"></a>技巧80 高亮查找匹配</h2><ul><li>启用<code>hlsearch</code>选项可以高亮</li></ul><h2 id="技巧81-在执行查找前预览第一处匹配"><a href="#技巧81-在执行查找前预览第一处匹配" class="headerlink" title="技巧81 在执行查找前预览第一处匹配"></a>技巧81 在执行查找前预览第一处匹配</h2><ul><li><code>incsearch</code>选项可以让Vim在真正执行查找命令前预览第一处匹配。</li><li>该技巧也可以用来检查是否存在一处匹配。</li><li>快捷键<code>&lt;ctrl+r&gt;&lt;ctrl+w&gt;</code>会根据当前预览的匹配结果对查找域进行自动补全。不过如果使用了元字符\v则该快捷键会有些瑕疵。</li></ul><h2 id="技巧82-统计当前模式的匹配个数"><a href="#技巧82-统计当前模式的匹配个数" class="headerlink" title="技巧82 统计当前模式的匹配个数"></a>技巧82 统计当前模式的匹配个数</h2><ul><li><code>:%s///gn</code>可以统计次数，查找域用的是上次的查找模式，n会抑制正常的替换作用，改为简单的技术，所以替换域留空即可。</li></ul><h2 id="技巧83-将光标偏移到查找匹配的结尾"><a href="#技巧83-将光标偏移到查找匹配的结尾" class="headerlink" title="技巧83 将光标偏移到查找匹配的结尾"></a>技巧83 将光标偏移到查找匹配的结尾</h2><ul><li>查找模式后面跟/e可以将光标偏移到匹配的结尾处。</li></ul><h2 id="技巧84-对完整的查找匹配进行操作"><a href="#技巧84-对完整的查找匹配进行操作" class="headerlink" title="技巧84 对完整的查找匹配进行操作"></a>技巧84 对完整的查找匹配进行操作</h2><ul><li>感觉就是在查找模式中利用\e、f{char}之类的标志位或命令选中完整的匹配。</li></ul><h2 id="技巧85-利用查找历史，迭代完成复杂的模式"><a href="#技巧85-利用查找历史，迭代完成复杂的模式" class="headerlink" title="技巧85 利用查找历史，迭代完成复杂的模式"></a>技巧85 利用查找历史，迭代完成复杂的模式</h2><ul><li><code>q/</code>可以唤出命令历史。</li><li>需要捕获引号括起来的内容的时候就记得可以用\1这种寄存器。</li></ul><h2 id="技巧86-查找当前高亮选区中的文本"><a href="#技巧86-查找当前高亮选区中的文本" class="headerlink" title="技巧86 查找当前高亮选区中的文本"></a>技巧86 查找当前高亮选区中的文本</h2><ul><li>这个目前可以忽略吧。</li></ul><h1 id="十四、替换"><a href="#十四、替换" class="headerlink" title="十四、替换"></a>十四、替换</h1><h2 id="技巧87-结识substitute命令"><a href="#技巧87-结识substitute命令" class="headerlink" title="技巧87 结识substitute命令"></a>技巧87 结识substitute命令</h2><ul><li>基本的替换语法如下：<code>:[range]s[ubstitute]/{pattern}/{string}/[flags]</code></li></ul><h2 id="技巧88-在文件范围内查找并替换每一处匹配"><a href="#技巧88-在文件范围内查找并替换每一处匹配" class="headerlink" title="技巧88 在文件范围内查找并替换每一处匹配"></a>技巧88 在文件范围内查找并替换每一处匹配</h2><ul><li>缺省情况下，substitute命令只会作用于当前行且只修改第一处匹配。</li><li>/g标志位可以使替换命令修改一整行的所有匹配，range域填%即可使其作用于所有每一行，两者结合就是全局替换。</li></ul><h2 id="技巧89-手动控制每一次替换操作"><a href="#技巧89-手动控制每一次替换操作" class="headerlink" title="技巧89 手动控制每一次替换操作"></a>技巧89 手动控制每一次替换操作</h2><ul><li>/c标志位让我们可以控制每一次匹配的地方是否需要进行替换。</li></ul><h2 id="技巧90-重用上次的查找模式"><a href="#技巧90-重用上次的查找模式" class="headerlink" title="技巧90 重用上次的查找模式"></a>技巧90 重用上次的查找模式</h2><ul><li>将查找域留空，可以使Vim重用上次的查找模式。</li><li>需要注意，把查找域留空，会在命令历史中留下一项不完整的记录。这在有些时候会带来不便，因为查找模式的命令和替换操作的命令所保存的地方不一样。</li></ul><h2 id="技巧91-用寄存器的内容替换"><a href="#技巧91-用寄存器的内容替换" class="headerlink" title="技巧91 用寄存器的内容替换"></a>技巧91 用寄存器的内容替换</h2><ul><li>如果某段文本已经在当前文档中出现过，我们可以先把它复制到寄存器，再通过传值或引用的方式将寄存器的内容应用到替换域。</li><li>假设我们已经复制了多行文本到寄存器0中，现在需要在替换域中使用这份内容，则可以使用<code>:%s//\=@0/g</code>。<code>\=</code>表示Vim将执行一段表达式脚本。</li></ul><h2 id="技巧92-重复上一次的substitute命令"><a href="#技巧92-重复上一次的substitute命令" class="headerlink" title="技巧92 重复上一次的substitute命令"></a>技巧92 重复上一次的substitute命令</h2><ul><li>假如我们刚刚执行完一条替换命令，突然意识到了失误，应该加上%才对，这时可以使用<code>g&amp;</code>，这条命令等价于<code>:%s//~/&amp;</code>，即可在整个文件的范围内重复该条命令。</li><li>总是可以指定一个新的范围，并使用<code>:&amp;&amp;</code>命令重新执行替换操作。</li><li>&amp;命令是:s命令的同义词，用于重复上一次的替换操作。但遗憾的是，不论上次使用的是什么标志位，&amp;命令都将忽略他们。所以我们会用:&amp;&amp;，后一个&amp;命令会保留标志位。</li></ul><h2 id="技巧93-使用子匹配重排CSV文件的字段"><a href="#技巧93-使用子匹配重排CSV文件的字段" class="headerlink" title="技巧93 使用子匹配重排CSV文件的字段"></a>技巧93 使用子匹配重排CSV文件的字段</h2><ul><li>可以在查找模式中利用()捕获子匹配，并在替换域中引用它们。</li></ul><h2 id="技巧94-在替换过程中执行算术运算"><a href="#技巧94-在替换过程中执行算术运算" class="headerlink" title="技巧94 在替换过程中执行算术运算"></a>技巧94 在替换过程中执行算术运算</h2><ul><li>替换域中的内容不一定非得是简单的字符串，我们可以执行一段Vim脚本表达式，然后用其结果充当字符串使用。</li><li>一般是先用正则表达式匹配我们要替换的区域，然后使用表达式寄存器，调用函数submatch(0)进行操作。</li></ul><h2 id="技巧95-交换两个或更多的单词"><a href="#技巧95-交换两个或更多的单词" class="headerlink" title="技巧95 交换两个或更多的单词"></a>技巧95 交换两个或更多的单词</h2><ul><li>越来越复杂了，有点搞不定了。选择，替换。</li></ul><h2 id="技巧96-在多个文件中执行查找与替换"><a href="#技巧96-在多个文件中执行查找与替换" class="headerlink" title="技巧96 在多个文件中执行查找与替换"></a>技巧96 在多个文件中执行查找与替换</h2><ul><li>Vim没有直接提供这样的功能，只能通过一些简单命令的组合，间接来实现这种功能。</li><li>有一种方法可以用<code>:argdo</code>命令，先打开所有文件，然后用该命令去替换。</li><li>但这会打开很多多余文件，还有一种方法，可以先选择匹配查找模式的文件，然后再在这些文件上执行命令。涉及到什么quickfix列表、copen命令，暂时不用管吧。</li></ul><h1 id="十五、global命令"><a href="#十五、global命令" class="headerlink" title="十五、global命令"></a>十五、global命令</h1><h2 id="技巧97-结识global命令"><a href="#技巧97-结识global命令" class="headerlink" title="技巧97 结识global命令"></a>技巧97 结识global命令</h2><ul><li><code>:global</code>命令结合了Ex命令和Vim的模式匹配两种功能，允许我们在某个指定模式的所有匹配行上执行Ex命令，语法如下<code>:[range] global[!] /{pattern}/ [cmd]</code></li><li>缺省情况下，global命令的作用范围是整个文件。</li><li>global!或者vglobal命令表示反转，会在没有匹配到模式的行上执行cmd命令。</li></ul><h2 id="技巧98-删除所有包含模式的文本行"><a href="#技巧98-删除所有包含模式的文本行" class="headerlink" title="技巧98 删除所有包含模式的文本行"></a>技巧98 删除所有包含模式的文本行</h2><ul><li>将<code>:global</code>和<code>:delete</code>命令一起组合使用，可快速剪裁文本。</li><li>用<code>:g/re/d</code>可以删除匹配的所有行，相反<code>:v/re/d</code>可以删除不匹配的所有行。</li><li>其实grep命令即是<code>:g/re/p</code>，这样就能记住了。</li></ul><h2 id="技巧99-将TODO项收集至寄存器"><a href="#技巧99-将TODO项收集至寄存器" class="headerlink" title="技巧99 将TODO项收集至寄存器"></a>技巧99 将TODO项收集至寄存器</h2><ul><li>和上条相似，将<code>:global</code>和<code>:yank</code>一起组合使用，就可以把匹配项文本行收集到某个寄存器中。</li><li><code>:t</code>命令见技巧29，主要是把一些内容显示到文本结尾，不想影响寄存器内容的时候可以用。</li></ul><h2 id="技巧100-将CSS文件中所有规则的属性按照字母排序"><a href="#技巧100-将CSS文件中所有规则的属性按照字母排序" class="headerlink" title="技巧100 将CSS文件中所有规则的属性按照字母排序"></a>技巧100 将CSS文件中所有规则的属性按照字母排序</h2><ul><li><code>:global</code>的广义模式<code>:g/{start}/ .,{finish} [cmd]</code>，可以理解成从start开始，到finish结束的所有行进行指定的cmd操作。<code>.</code>在这里表示当前行。</li></ul><h1 id="十六、通过ctags建立索引，并引用其浏览源代码"><a href="#十六、通过ctags建立索引，并引用其浏览源代码" class="headerlink" title="十六、通过ctags建立索引，并引用其浏览源代码"></a>十六、通过ctags建立索引，并引用其浏览源代码</h1><h2 id="技巧101-结识ctags"><a href="#技巧101-结识ctags" class="headerlink" title="技巧101 结识ctags"></a>技巧101 结识ctags</h2><ul><li>例如在Ubuntu上，可以通过<code>sudo apt-get install exuberant-ctags</code>的方式安装该程序</li><li>标签文件的前几行由元数据组成，而后每一行文本均有关键字、文件名以及关键字在源代码中的位置这3项内容构成。关键字会按照字母顺序排列。</li><li>用模式定位关键字，而不是用行号。</li><li>用元数据标记关键字</li></ul><h2 id="技巧102-配置Vim使用ctags"><a href="#技巧102-配置Vim使用ctags" class="headerlink" title="技巧102 配置Vim使用ctags"></a>技巧102 配置Vim使用ctags</h2><ul><li><code>:set tags?</code>可以查看ctags缺省配置</li><li>通过<code>:!ctags -R</code>可以在Vim中直接调用生成tags文件。</li><li>还可以使用映射项以及<code>:autocmd BufWritePost * call system(&quot;ctags -R&quot;)</code>命令实现在每次保存文件时自动调用ctags。</li><li>还有一种策略可以实现在每次提交代码改动时自动更新代码库的索引，详见p239。</li></ul><h2 id="技巧103-使用Vim的标签跳转命令，浏览关键字的定义"><a href="#技巧103-使用Vim的标签跳转命令，浏览关键字的定义" class="headerlink" title="技巧103 使用Vim的标签跳转命令，浏览关键字的定义"></a>技巧103 使用Vim的标签跳转命令，浏览关键字的定义</h2><ul><li><code>&lt;ctrl+]&gt;</code>可以跳转到关键字的定义处。此时<code>&lt;ctrl+t&gt;</code>会充当后退到原处的功能。</li><li><code>g&lt;ctrl+]&gt;</code>可以在有多次匹配定义的时候让我们自行挑选需要跳转的地方。</li><li>其实不必非得将光标移到关键字上才能进行标签跳转，也可以用Ex命令达到同样的目的，例如<code>:tag {keyward}</code>与<code>:tjump {keyward}</code>分别等同于上述两个命令。</li></ul><h1 id="十七、编译代码，并通过Quickfix列表浏览错误信息"><a href="#十七、编译代码，并通过Quickfix列表浏览错误信息" class="headerlink" title="十七、编译代码，并通过Quickfix列表浏览错误信息"></a>十七、编译代码，并通过Quickfix列表浏览错误信息</h1><h2 id="技巧104-不用离开Vim也能编译代码"><a href="#技巧104-不用离开Vim也能编译代码" class="headerlink" title="技巧104 不用离开Vim也能编译代码"></a>技巧104 不用离开Vim也能编译代码</h2><ul><li>在Vim中可以直接使用<code>:make</code>编译代码，不止会显示make命令的结果以外，还会解析每一行内容，对于每一条错误信息都会在quickfix列表中为其创建一项纪录，运行后会跳转到quickfix列表的第一项纪录。</li><li>如果不想跳转到第一项纪录，可以<code>:make!</code>。</li></ul><h2 id="技巧105-浏览Quickfix列表"><a href="#技巧105-浏览Quickfix列表" class="headerlink" title="技巧105 浏览Quickfix列表"></a>技巧105 浏览Quickfix列表</h2><ul><li>quickfix列表会保存一组针对单个或多个文件内容的位置信息，这些信息来自于<code>:make</code>、<code>:grep</code>以及<code>:vimgrep</code>。</li><li>对于每一条用于填充quickfix列表的命令，前面加个l都能操作对应的位置列表。位置列表可以理解成每个缓冲区的局部变量，而quickfix列表是全局变量。</li><li><code>:cnext</code>和<code>:cprevios</code>两个命令用来操作最基本的quickfix列表前后移动。<code>:copen</code>可以打开包含quickfix列表内容的窗口。</li></ul><h2 id="技巧106-回溯以前的Quickfix列表"><a href="#技巧106-回溯以前的Quickfix列表" class="headerlink" title="技巧106 回溯以前的Quickfix列表"></a>技巧106 回溯以前的Quickfix列表</h2><ul><li>更新quickfix列表时，Vim并不会覆盖之前的内容，而是将使用过的quickfix列表结果保存起来，方便回溯。</li><li><code>:colder</code>命令可以回溯quickfix列表之前的某个版本（Vim保存最近10个）。为了从旧的回到新一版的，则可以运行<code>:cnewer</code>。</li></ul><h2 id="技巧107-定制外部编译器"><a href="#技巧107-定制外部编译器" class="headerlink" title="技巧107 定制外部编译器"></a>技巧107 定制外部编译器</h2><ul><li>Vim的<code>:make</code>不仅限于调用外部的make程序，也可以调用任何安装在你机器上的编译器。</li><li>这节主要写了个例子，讲述如何在vim里配置别的编译器，没有细看</li><li>在Vim的术语中，编译器是指任何可以针对文档进行处理，并生成错误警告的外部程序。而<code>:make</code>命令指负责调用外部编译器，并对其输出进行解析，以此构建一个可供浏览的quickfix列表。</li><li><code>vim -u NONE -N file</code></li></ul><h1 id="十八-通过grep、vimgrep以及其他工具对整个工程进行查找"><a href="#十八-通过grep、vimgrep以及其他工具对整个工程进行查找" class="headerlink" title="十八 通过grep、vimgrep以及其他工具对整个工程进行查找"></a>十八 通过grep、vimgrep以及其他工具对整个工程进行查找</h1><h2 id="技巧108-不必离开Vim也能调用grep"><a href="#技巧108-不必离开Vim也能调用grep" class="headerlink" title="技巧108 不必离开Vim也能调用grep"></a>技巧108 不必离开Vim也能调用grep</h2><ul><li>-n选项会在grep的结果中加入行号信息</li><li>Vim中外部grep命令进行了封装，可以直接调用。Vim会解析grep的输出并根据输出创建一个quickfix列表，然后我们可以通过quickfix列表进行跳转，内部的grep命令会自动封装-n选项。如果要忽略大小写，需要手动加-i选项。</li></ul><h2 id="技巧109-定制grep"><a href="#技巧109-定制grep" class="headerlink" title="技巧109 定制grep"></a>技巧109 定制grep</h2><ul><li>Vim中的grep命令是外部grep程序的包装器，通过配置<code>grepprg</code>和<code>grepformat</code>两个选项来对Vim查找的行为进行定制。</li><li>主要可以安装一个ack命令来用，暂时没有细看。</li></ul><h2 id="技巧110-使用Vim内部的grep"><a href="#技巧110-使用Vim内部的grep" class="headerlink" title="技巧110 使用Vim内部的grep"></a>技巧110 使用Vim内部的grep</h2><ul><li><code>:vimgrep</code>命令允许我们使用Vim自带的正则表达式引擎，实现跨文件的查找功能。此命令可以缩写成<code>:vim</code>。格式如<code>:vim[grep][!] /{pattern}/[g][j] {file} ...</code></li><li>通配符<code>*</code>会匹配某个目录下的任意文件，而通配符<code>**</code>会匹配指定目录以及所有子目录文件。<code>##</code>会被扩展成参数列表中的所有文件。</li><li>如果模式域为空，则会匹配所有行。</li><li>如果想使用最近一次的查找模式，必须通过<code>&lt;ctrl+r&gt;/</code>将其直接粘贴到查找域才行。</li></ul><h1 id="十九-自动补全"><a href="#十九-自动补全" class="headerlink" title="十九 自动补全"></a>十九 自动补全</h1><h2 id="技巧111-结识Vim的关键字自动补全"><a href="#技巧111-结识Vim的关键字自动补全" class="headerlink" title="技巧111 结识Vim的关键字自动补全"></a>技巧111 结识Vim的关键字自动补全</h2><ul><li>Vim的自动补全功能可以在插入模式下被触发。</li><li>通过<code>&lt;ctrl+p&gt;</code>和<code>&lt;ctrl+n&gt;</code>可以实现普通关键字自动补全，可以在插入模式下触发Vim的自动补全，还可以利用他们在补全列表里正向或反向寻找。</li><li>除了最常用的<code>&lt;ctrl+p&gt;&lt;ctrl+n&gt;</code>两个命令外还有一些其他的补全命令，见表19-1，p263。</li></ul><h2 id="技巧112-与自动补全的弹出式菜单进行交互"><a href="#技巧112-与自动补全的弹出式菜单进行交互" class="headerlink" title="技巧112 与自动补全的弹出式菜单进行交互"></a>技巧112 与自动补全的弹出式菜单进行交互</h2><ul><li>有几个重要的快捷键记忆一下。<code>&lt;ctrl+y&gt;</code>确认使用当前选中的匹配行，<code>&lt;ctrl+e&gt;</code>还原最早输入的文本，即退出自动补全。<code>&lt;ctrl+h&gt;</code>从当前匹配项中删除一个字符，<code>&lt;ctrl+l&gt;</code>从当前匹配项中增加一个字符。</li><li>建议浏览补全列表的时候不要用上下键，因为还需要按回车才能选中，而且手指得从本位行上移开。</li><li>连续输入<code>&lt;ctrl+p&gt;&lt;strl+n&gt;</code>可以实现实时过滤补全列表，很好用。</li></ul><h2 id="技巧113-掌握关键字的来龙去脉"><a href="#技巧113-掌握关键字的来龙去脉" class="headerlink" title="技巧113 掌握关键字的来龙去脉"></a>技巧113 掌握关键字的来龙去脉</h2><ul><li>普通关键字自动补全会把来自多个来源的内容编入其补全列表，我们可以对生成补全列表项的来源加以限定。</li><li><code>:!ls</code>可以用来查看缓冲区列表。</li><li><code>&lt;ctrl+x&gt;&lt;ctrl+i&gt;</code>可以补全一些来自其他代码里的单词，就像include的一样。还有比如<code>&lt;ctrl+x&gt;&lt;ctrl+]&gt;</code>可以补全ctags生成的文件里的单词。总的来说，普通关键字补全是最全的，但如果嫌多想要特定来源的补全的话，就用<code>&lt;ctrl+x&gt;</code>加特定的快捷键来实现，见表19-1。</li></ul><h2 id="技巧114-使用字典中的单词进行自动补全"><a href="#技巧114-使用字典中的单词进行自动补全" class="headerlink" title="技巧114 使用字典中的单词进行自动补全"></a>技巧114 使用字典中的单词进行自动补全</h2><ul><li><code>&lt;ctrl+x&gt;&lt;ctrl+k&gt;</code>可以实现自动补全某个字典单词功能。为了激活该功能，我们需要为Vim提供一份合适的单词列表，最简单的办法就是运行<code>:set spell</code>激活Vim的拼写检查功能。</li></ul><h2 id="技巧115-自动补全整行文本"><a href="#技巧115-自动补全整行文本" class="headerlink" title="技巧115 自动补全整行文本"></a>技巧115 自动补全整行文本</h2><ul><li><code>&lt;ctrl+x&gt;&lt;ctrl+l&gt;</code>面向行自动补全。</li></ul><h2 id="技巧116-自动补全文件名"><a href="#技巧116-自动补全文件名" class="headerlink" title="技巧116 自动补全文件名"></a>技巧116 自动补全文件名</h2><ul><li><code>&lt;ctrl+x&gt;&lt;ctrl+f&gt;</code>可以自动补全文件名。</li><li>Vim的文件名自动补全功能只能相对于工作目录的路径进行扩展，而不是相对于当前编辑文件的路径。</li><li><code>:cd -</code>可以在Vim中切换到之前的工作目录。</li></ul><h2 id="技巧117-根据上下文自动补全"><a href="#技巧117-根据上下文自动补全" class="headerlink" title="技巧117 根据上下文自动补全"></a>技巧117 根据上下文自动补全</h2><ul><li><code>&lt;ctrl+x&gt;&lt;ctrl+o&gt;</code>实现该功能，全能补全。</li><li><p>实际上，该功能由专用的文件类型插件实现，需要下载以下配置行：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">set nocompatible</span><br><span class="line">filetype plugin on</span><br></pre></td></tr></table></figure></li><li><p>此外还需要安装一个为所用语言实现了全能补全功能的插件。</p></li></ul><h1 id="二十-利用Vim的拼写检查器，查找并更正拼写错误"><a href="#二十-利用Vim的拼写检查器，查找并更正拼写错误" class="headerlink" title="二十 利用Vim的拼写检查器，查找并更正拼写错误"></a>二十 利用Vim的拼写检查器，查找并更正拼写错误</h1><h2 id="技巧118-对你的工作进行拼写检查"><a href="#技巧118-对你的工作进行拼写检查" class="headerlink" title="技巧118 对你的工作进行拼写检查"></a>技巧118 对你的工作进行拼写检查</h2><ul><li>使用<code>:set spell</code>可以对所有未在拼写文件中出现过的单词进行高亮标记。</li><li>可以使用<code>[s</code>和<code>]s</code>命令在拼写错误的单词间进行跳转。当光标位于某个拼错的单词上时，可以使用<code>z=</code>命令来获取Vim提供的更正建议列表。</li></ul><h2 id="技巧119-使用其他拼写字典"><a href="#技巧119-使用其他拼写字典" class="headerlink" title="技巧119 使用其他拼写字典"></a>技巧119 使用其他拼写字典</h2><ul><li>修改配置<code>spelllang</code>选项可以更改缺省的拼写字典，要注意的是这不是全局性的，永远只在本地缓冲区生效。这意味着可以在编辑两个或多个文档时采用不同的拼写字典。</li><li>可以使用spellfile.vim的插件安装其他所需的语言拼写字典，为了激活这个功能，需要在vimrc中添加两行，具体看p276吧。</li></ul><h2 id="技巧120-将单词添加到拼写文件中"><a href="#技巧120-将单词添加到拼写文件中" class="headerlink" title="技巧120 将单词添加到拼写文件中"></a>技巧120 将单词添加到拼写文件中</h2><ul><li>我们可以自定义拼写文件里的词。</li><li><code>zg</code>命令可以把光标下的单词添加到拼写文件中，<code>zw</code>则是相反功能，将单词从拼写文件中删除，<code>zug</code>则是撤销光标所在单词执行过的<code>zg</code>或者<code>zw</code>。</li></ul><h2 id="技巧121-在插入模式下更正拼写错误"><a href="#技巧121-在插入模式下更正拼写错误" class="headerlink" title="技巧121 在插入模式下更正拼写错误"></a>技巧121 在插入模式下更正拼写错误</h2><ul><li>插入模式下使用<code>&lt;ctrl+x&gt;s</code>或者<code>&lt;ctrl+x&gt;&lt;ctrl+s&gt;</code>可以使用拼写自动补全功能。其中<code>&lt;ctrl+x&gt;s</code>会有点特殊，它会使Vim从光标所在位置开始方向扫描，直到发现一处拼写错误为止，然后再根据更正建议创建单词列表并显示在弹出菜单里，适合写完一行修正这一行的所有错误时使用。</li></ul><h1 id="最后"><a href="#最后" class="headerlink" title="最后"></a>最后</h1><ul><li>动态改变Vim的设置项：以<code>ignorecase</code>为例，其可被缩写成<code>ic</code>。</li></ul><table><thead><tr><th>命令</th><th>效果</th></tr></thead><tbody><tr><td>:set ignorecase</td><td>开启ignorecase</td></tr><tr><td>:set noignorecase</td><td>关闭ignorecase</td></tr><tr><td>:set ignorecase!</td><td>反转</td></tr><tr><td>:set ignorecase?</td><td>获取当前设置的状态</td></tr><tr><td>:set ignorecase&amp;</td><td>恢复默认状态</td></tr></tbody></table><ul><li>在Vim里内使用<code>:edit $MYVIMRC</code>可以打开vimrc。</li><li>可以为特定类型的文件应用个性化设置。</li></ul><p>【END】</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;因为工作中需要用到Vim，所以本文简单记录下学习Vim编辑器的一些笔记和技巧。&lt;/p&gt;
&lt;h1 id=&quot;Vimtutor&quot;&gt;&lt;a href=&quot;#Vimtutor&quot; class=&quot;headerlink&quot; title=&quot;Vimtutor&quot;&gt;&lt;/a&gt;Vimtutor&lt;/h1&gt;&lt;p&gt;Vimtutor是Vim的一个简易教程，前前后后做了两遍，记录一下一些实用的快捷键吧。&lt;/p&gt;
    
    </summary>
    
      <category term="职业学习" scheme="http://yoursite.com/categories/%E8%81%8C%E4%B8%9A%E5%AD%A6%E4%B9%A0/"/>
    
    
      <category term="Linux" scheme="http://yoursite.com/tags/Linux/"/>
    
      <category term="Vim" scheme="http://yoursite.com/tags/Vim/"/>
    
  </entry>
  
  <entry>
    <title>LeetCode刷题记录</title>
    <link href="http://yoursite.com/2019/04/16/LeetCode%E5%88%B7%E9%A2%98%E8%AE%B0%E5%BD%95/"/>
    <id>http://yoursite.com/2019/04/16/LeetCode刷题记录/</id>
    <published>2019-04-16T06:32:34.000Z</published>
    <updated>2019-07-28T15:13:08.628Z</updated>
    
    <content type="html"><![CDATA[<p>想养成刷题的习惯，之前刷过一点，但校招之后就断了，现在想捡起来，定个小目标，从头开始刷题吧，看能坚持多久。</p><h1 id="1-Two-Sum"><a href="#1-Two-Sum" class="headerlink" title="1. Two Sum"></a>1. Two Sum</h1><p>2019/4/16，易。</p><p>这题以前做过，记得第一次做的时候应该是用的最蠢的两重遍历方法相加求解，毫无疑问超时了，隐约记得可以使用查找<code>目标值-某个值</code>是否存在该vector中来反向求解，简单写了一下，通过了。其实是一个反向思维的题，正面求解超时，则反向来求。仍然属于蛮力法的范畴，n<sup>2</sup>时间复杂度，1空间复杂度，LeetCode平台耗时136ms。</p><p>尝试降低时间复杂度，想到以空间换时间，在查找<code>目标值-某个值</code>的时候，上述蛮力法使用<code>std::find</code>方法，说白了也是一层遍历，这层遍历目的是为了查找差值是否存在于vector中并返回下标，自然可以想到用哈希表来代替这一层遍历。当然，事先需要遍历一次原数组构建哈希表。如此时间复杂度n，空间复杂度n。</p><a id="more"></a><p>最终代码如下，本版本耗时仅16ms。</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt; twoSum(<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&amp; nums, <span class="keyword">int</span> target) &#123;</span><br><span class="line">        <span class="built_in">std</span>::<span class="built_in">unordered_map</span>&lt;<span class="keyword">int</span>, <span class="keyword">int</span>&gt; <span class="built_in">map</span>;<span class="comment">//哈希表</span></span><br><span class="line">        <span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt; res;</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>;i&lt;nums.size();i++)&#123;</span><br><span class="line">            <span class="built_in">map</span>[nums[i]]=i;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">auto</span> it=nums.begin();it!=nums.end();it++)&#123;</span><br><span class="line">            <span class="keyword">auto</span> com=<span class="built_in">map</span>.find(target-*it);</span><br><span class="line">            <span class="keyword">if</span>(com!=<span class="built_in">map</span>.end()&amp;&amp;com-&gt;second!=it-nums.begin())&#123;</span><br><span class="line">                res.push_back(it-nums.begin());</span><br><span class="line">                res.push_back(com-&gt;second);</span><br><span class="line">                <span class="keyword">return</span> res;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h1 id="2-Add-Two-Numbers（again）"><a href="#2-Add-Two-Numbers（again）" class="headerlink" title="2. Add Two Numbers（again）"></a>2. Add Two Numbers（again）</h1><p>2019/4/19，中。</p><p>平心而论是个比较简单的链表题了，但是太久不做题竟然觉得很难理清楚，这也说明了常做题保持手感很重要。</p><p>本题也没啥特别的方法，注意循环进位即可，另外链表的题往往一开始会定义两个变量，一个用于最后返回，一个用来遍历处理。</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function">ListNode* <span class="title">addTwoNumbers</span><span class="params">(ListNode* l1, ListNode* l2)</span> </span>&#123;</span><br><span class="line">        ListNode* res=<span class="keyword">new</span> ListNode(<span class="number">-1</span>);</span><br><span class="line">        ListNode* p=res;</span><br><span class="line">        <span class="keyword">int</span> carry=<span class="number">0</span>;<span class="comment">//进位</span></span><br><span class="line">        <span class="keyword">while</span>(l1||l2)&#123;</span><br><span class="line">            <span class="keyword">int</span> sum = (l1?l1-&gt;val:<span class="number">0</span>) + (l2?l2-&gt;val:<span class="number">0</span>) + carry;</span><br><span class="line">            carry=sum/<span class="number">10</span>; </span><br><span class="line">            p-&gt;next = <span class="keyword">new</span> ListNode(sum%<span class="number">10</span>);</span><br><span class="line">            p=p-&gt;next;</span><br><span class="line">            <span class="keyword">if</span>(l1)</span><br><span class="line">            &#123;</span><br><span class="line">                l1=l1-&gt;next;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span>(l2)</span><br><span class="line">            &#123;</span><br><span class="line">                l2=l2-&gt;next;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span>(carry==<span class="number">1</span>)</span><br><span class="line">            p-&gt;next = <span class="keyword">new</span> ListNode(carry);</span><br><span class="line">        <span class="keyword">return</span> res-&gt;next;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h1 id="3-Longest-Substring-Without-Repeating-Characters（again）"><a href="#3-Longest-Substring-Without-Repeating-Characters（again）" class="headerlink" title="3. Longest Substring Without Repeating Characters（again）"></a>3. Longest Substring Without Repeating Characters（again）</h1><p>2019/4/21，中。</p><p>一道经典dp题，准备找工作的时候刷过，以为很简单，但写的时候却发现细节又已经遗忘了，虽然最后还是一遍过了，但还是感慨得要经常刷题保持手感啊，忘性太大了。</p><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">lengthOfLongestSubstring</span><span class="params">(<span class="built_in">string</span> s)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(s.size()&lt;=<span class="number">0</span>)</span><br><span class="line">            <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">        <span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt; dp(s.size(),<span class="number">0</span>);</span><br><span class="line">        dp[<span class="number">0</span>]=<span class="number">1</span>;</span><br><span class="line">        <span class="built_in">map</span>&lt;<span class="keyword">char</span>,<span class="keyword">int</span>&gt; m;</span><br><span class="line">        m[s[<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&lt;s.size();i++)&#123;</span><br><span class="line">            <span class="keyword">auto</span> it=m.find(s[i]);</span><br><span class="line">            <span class="keyword">if</span>(it==m.end())&#123;</span><br><span class="line">                dp[i]=dp[i<span class="number">-1</span>]+<span class="number">1</span>;</span><br><span class="line">            &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">                <span class="keyword">if</span>(i-it-&gt;second&gt;dp[i<span class="number">-1</span>])&#123;</span><br><span class="line">                    dp[i]=dp[i<span class="number">-1</span>]+<span class="number">1</span>;</span><br><span class="line">                &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">                    dp[i]=i-m[s[i]];</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            m[s[i]]=i;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">int</span> max=dp[<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&lt;dp.size();i++)&#123;</span><br><span class="line">            <span class="keyword">if</span>(dp[i]&gt;max)</span><br><span class="line">                max=dp[i];</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> max;       </span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><h1 id="4-Median-of-Two-Sorted-Arrays（again）"><a href="#4-Median-of-Two-Sorted-Arrays（again）" class="headerlink" title="4.Median of Two Sorted Arrays（again）"></a>4.Median of Two Sorted Arrays（again）</h1><p>2019/4/22，难。</p><p>想法一开始就很明确，将两个有序数组Merge成一个新的有序数组就是了，然后直接返回中间值即可。后来稍微改进了下代码，因为Merge其实只需要Merge到中间数即可，后面的数并不需要处理了，所以去除了冗余排序，感觉时间复杂度是n+m，空间复杂度也是n+m。</p><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">double</span> <span class="title">findMedianSortedArrays</span><span class="params">(<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&amp; nums1, <span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&amp; nums2)</span> </span>&#123;</span><br><span class="line">        <span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt; res;</span><br><span class="line">        <span class="keyword">int</span> i=<span class="number">0</span>,j=<span class="number">0</span>;</span><br><span class="line">        <span class="keyword">int</span> length1=nums1.size(),length2=nums2.size();</span><br><span class="line">        <span class="keyword">int</span> sumLen=length1+length2;</span><br><span class="line">        <span class="keyword">int</span> midIndex=(length1+length2)/<span class="number">2</span>;</span><br><span class="line">        <span class="keyword">while</span>(res.size()&lt;midIndex+<span class="number">1</span>)&#123;</span><br><span class="line">            <span class="keyword">if</span> (j == length2 || (i &lt; nums1.size() &amp;&amp; nums1[i] &lt; nums2[j])) &#123;</span><br><span class="line">    res.push_back(nums1[i]);</span><br><span class="line">    i++;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span> <span class="keyword">if</span> (i == length1 || (j&lt;nums2.size() &amp;&amp; nums1[i] &gt;= nums2[j])) &#123;</span><br><span class="line">    res.push_back(nums2[j]);</span><br><span class="line">    j++;</span><br><span class="line">    &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span>(sumLen%<span class="number">2</span>==<span class="number">1</span>)&#123;</span><br><span class="line">            <span class="keyword">return</span> res.back();</span><br><span class="line">        &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">            <span class="keyword">double</span> r=(res[res.size()<span class="number">-1</span>]+res[res.size()<span class="number">-2</span>])/<span class="number">2.0</span>;</span><br><span class="line">            <span class="keyword">return</span> r;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><p>但后来发现题目要求的时间复杂度是log(n+m)，才感觉到为什么这道题目难度级别是hard，不过我习惯从这个要求的时间复杂度就得到该题应该要使用二分查找或者是二分查找的变形，看了网上的解答，应该是查找第K小数字的变体，最后代码如下：</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">double</span> <span class="title">findMedianSortedArrays</span><span class="params">(<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&amp; nums1, <span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&amp; nums2)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">int</span> length1=nums1.size(),length2=nums2.size();</span><br><span class="line">        <span class="keyword">int</span> sumLen=length1+length2;</span><br><span class="line">        <span class="keyword">if</span>(sumLen%<span class="number">2</span>==<span class="number">1</span>)&#123;</span><br><span class="line">            <span class="keyword">return</span> FindKth(nums1,length1,nums2,length2,sumLen/<span class="number">2</span>+<span class="number">1</span>);</span><br><span class="line">        &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">            <span class="keyword">return</span> (FindKth(nums1,length1,nums2,length2,sumLen/<span class="number">2</span>)+</span><br><span class="line">                    FindKth(nums1,length1,nums2,length2,sumLen/<span class="number">2</span>+<span class="number">1</span>))/<span class="number">2.0</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="function"><span class="keyword">double</span> <span class="title">FindKth</span><span class="params">(<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&amp; nums1,<span class="keyword">int</span> length1,<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&amp; nums2,<span class="keyword">int</span> length2,<span class="keyword">int</span> k)</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(length1&gt;length2)</span><br><span class="line">            <span class="keyword">return</span> FindKth(nums2,length2,nums1,length1,k);</span><br><span class="line">        <span class="keyword">if</span>(length1==<span class="number">0</span>)</span><br><span class="line">            <span class="keyword">return</span> nums2[k<span class="number">-1</span>];</span><br><span class="line">        <span class="keyword">if</span>(k==<span class="number">1</span>)</span><br><span class="line">            <span class="keyword">return</span> min(nums1[<span class="number">0</span>],nums2[<span class="number">0</span>]);</span><br><span class="line">        <span class="keyword">int</span> pa=min(k/<span class="number">2</span>,length1),pb=k-pa;</span><br><span class="line">        <span class="keyword">if</span>(nums1[pa<span class="number">-1</span>]&lt;nums2[pb<span class="number">-1</span>])&#123;</span><br><span class="line">            <span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt; tmp(nums1.begin()+pa,nums1.end());</span><br><span class="line">            <span class="keyword">return</span> FindKth(tmp,length1-pa,nums2,length2,k-pa);</span><br><span class="line">        &#125;<span class="keyword">else</span> <span class="keyword">if</span>(nums1[pa<span class="number">-1</span>]&gt;nums2[pb<span class="number">-1</span>])&#123;</span><br><span class="line">            <span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt; tmp(nums2.begin()+pb,nums2.end());</span><br><span class="line">            <span class="keyword">return</span> FindKth(nums1,length1,tmp,length2-pb,k-pb);</span><br><span class="line">        &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">            <span class="keyword">return</span> nums1[pa<span class="number">-1</span>];</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>参考<a href="https://blog.csdn.net/lis_12/article/details/53128594" target="_blank" rel="noopener">https://blog.csdn.net/lis_12/article/details/53128594</a></p><h1 id="5-Longest-Palindromic-Substring（again）"><a href="#5-Longest-Palindromic-Substring（again）" class="headerlink" title="5.Longest Palindromic Substring（again）"></a>5.Longest Palindromic Substring（again）</h1><p>2019/4/23，中。</p><p>求最长回文子串，看到题目之后我感觉这是一道dp题，但是太菜了，还是写不出来，查了解析后代码如下：</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="built_in">string</span> <span class="title">longestPalindrome</span><span class="params">(<span class="built_in">string</span> s)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(s.size()&lt;=<span class="number">0</span>)</span><br><span class="line">            <span class="keyword">return</span> <span class="string">""</span>;</span><br><span class="line">        <span class="built_in">vector</span>&lt;<span class="built_in">vector</span>&lt;<span class="keyword">bool</span>&gt;&gt; dp(s.size(),<span class="built_in">vector</span>&lt;<span class="keyword">bool</span>&gt;(s.size(),<span class="literal">true</span>));</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">int</span> max=<span class="number">1</span>;</span><br><span class="line">        <span class="keyword">int</span> start=<span class="number">0</span>;</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">2</span>;i&lt;=s.size();i++)&#123;<span class="comment">//i表示子串长度</span></span><br><span class="line">            <span class="keyword">for</span>(<span class="keyword">int</span> leftIdx=<span class="number">0</span>;leftIdx&lt;=s.size()-i;leftIdx++)&#123;<span class="comment">//j表示子串起始坐标</span></span><br><span class="line">                <span class="keyword">int</span> rightIdx=leftIdx+i<span class="number">-1</span>;</span><br><span class="line">                <span class="keyword">if</span>(s[leftIdx]==s[rightIdx]&amp;&amp;dp[leftIdx+<span class="number">1</span>][rightIdx<span class="number">-1</span>])&#123;</span><br><span class="line">                    dp[leftIdx][rightIdx]=<span class="literal">true</span>;</span><br><span class="line">                    max=i;</span><br><span class="line">                    start=leftIdx;</span><br><span class="line">                &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">                    dp[leftIdx][rightIdx]=<span class="literal">false</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> s.substr(start,max);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>时间复杂度n<sup>2</sup>，空间复杂度n<sup>2</sup>。</p><p>利用中心扩展法可以将空间复杂度降低到1。</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="built_in">string</span> <span class="title">longestPalindrome</span><span class="params">(<span class="built_in">string</span> s)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(s.size()&lt;=<span class="number">1</span>)</span><br><span class="line">            <span class="keyword">return</span> s;</span><br><span class="line">        <span class="keyword">int</span> start=<span class="number">0</span>,end=<span class="number">0</span>;</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>;i&lt;s.size();i++)&#123;</span><br><span class="line">            <span class="keyword">int</span> len1=expandAroundCenter(s,i,i);<span class="comment">//奇数</span></span><br><span class="line">            <span class="keyword">int</span> len2=expandAroundCenter(s,i,i+<span class="number">1</span>);<span class="comment">//偶数</span></span><br><span class="line">            <span class="keyword">int</span> len=max(len1,len2);</span><br><span class="line">            <span class="keyword">if</span>(len&gt;end-start)&#123;</span><br><span class="line">                start=i-(len<span class="number">-1</span>)/<span class="number">2</span>;</span><br><span class="line">                end=i+len/<span class="number">2</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> s.substr(start,end-start+<span class="number">1</span>);</span><br><span class="line">    &#125;</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">expandAroundCenter</span><span class="params">(<span class="built_in">string</span>&amp; s,<span class="keyword">int</span> left,<span class="keyword">int</span> right)</span></span>&#123;</span><br><span class="line">        <span class="keyword">int</span> len = s.size();</span><br><span class="line">    <span class="keyword">while</span> (left&gt;=<span class="number">0</span> &amp;&amp; right&lt;len &amp;&amp; s[left] == s[right]) </span><br><span class="line">    &#123;</span><br><span class="line">    left--;</span><br><span class="line">    right++;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> right-left<span class="number">-1</span>;<span class="comment">//返回长度</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>最后还有一种Manacher方法，能将时间复杂度降到n，同时空间复杂度也是n，没看得太明白，以后再说。<a href="http://www.cnblogs.com/bitzhuwei/p/Longest-Palindromic-Substring-Part-II.html" target="_blank" rel="noopener">http://www.cnblogs.com/bitzhuwei/p/Longest-Palindromic-Substring-Part-II.html</a></p><h1 id="6-ZigZag-Conversion"><a href="#6-ZigZag-Conversion" class="headerlink" title="6.ZigZag Conversion"></a>6.ZigZag Conversion</h1><p>2019/4/24，中。</p><p>之字形排列字符串然后按行打印。</p><p>刚看到时候第一种办法就是自己定义一个二维数组排一下然后按行输出得了，蛮力法，代码如下：</p><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="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="comment">//蛮力法</span></span><br><span class="line">    <span class="function"><span class="built_in">string</span> <span class="title">convert</span><span class="params">(<span class="built_in">string</span> s, <span class="keyword">int</span> numRows)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(numRows==<span class="number">1</span>)</span><br><span class="line">            <span class="keyword">return</span> s;</span><br><span class="line">        <span class="comment">//构建一个二维字符数组存数组</span></span><br><span class="line">        <span class="built_in">vector</span>&lt;<span class="built_in">vector</span>&lt;<span class="built_in">string</span>&gt;&gt; <span class="built_in">array</span>(numRows,<span class="built_in">vector</span>&lt;<span class="built_in">string</span>&gt;(s.size()/<span class="number">2</span>+<span class="number">1</span>,<span class="string">"null"</span>));</span><br><span class="line">        <span class="keyword">int</span> i=<span class="number">0</span>,j=<span class="number">0</span>;</span><br><span class="line">        <span class="keyword">bool</span> direction=<span class="literal">true</span>;<span class="comment">//记录方向，ture表示向下，false向上</span></span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> idx=<span class="number">0</span>;idx&lt;s.size();idx++)&#123;</span><br><span class="line">            <span class="built_in">array</span>[i][j]=s[idx];</span><br><span class="line">            <span class="keyword">if</span>(direction)&#123;</span><br><span class="line">                i++;</span><br><span class="line">                <span class="keyword">if</span>(i==numRows)&#123;</span><br><span class="line">                    j++;</span><br><span class="line">                    i=i<span class="number">-2</span>;</span><br><span class="line">                    direction=<span class="literal">false</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">                i--;</span><br><span class="line">                j++;</span><br><span class="line">                <span class="keyword">if</span>(i==<span class="number">-1</span>)&#123;</span><br><span class="line">                    i=i+<span class="number">2</span>;</span><br><span class="line">                    j--;</span><br><span class="line">                    direction=<span class="literal">true</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="built_in">string</span> res;</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> p=<span class="number">0</span>;p&lt;numRows;p++)&#123;</span><br><span class="line">            <span class="keyword">for</span>(<span class="keyword">int</span> q=<span class="number">0</span>;q&lt;s.size()/<span class="number">2</span>+<span class="number">1</span>;q++)&#123;</span><br><span class="line">                <span class="keyword">if</span>(<span class="built_in">array</span>[p][q]!=<span class="string">"null"</span>)&#123;</span><br><span class="line">                   res+=<span class="built_in">array</span>[p][q]; </span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> res;       </span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>提交后虽然通过了，但花费时间560ms，空间占有400MB，感觉效率太低了，于是尝试另一种方法。</p><p>另一种方法也很好想到，既然是按某种规律排列并输出，那自然把规律找出来就好了，多在草稿纸上排了几个用例后发现每一行的间隔都是有规律的，主要规律是2*numRows-2，代码如下：</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="comment">//找规律直接输出</span></span><br><span class="line">    <span class="function"><span class="built_in">string</span> <span class="title">convert</span><span class="params">(<span class="built_in">string</span> s, <span class="keyword">int</span> numRows)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(numRows==<span class="number">1</span>)</span><br><span class="line">            <span class="keyword">return</span> s;</span><br><span class="line">        <span class="keyword">int</span> maxInterval=<span class="number">2</span>*numRows<span class="number">-2</span>;<span class="comment">//最大间隔</span></span><br><span class="line">        <span class="built_in">string</span> res=<span class="string">""</span>;</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>;i&lt;numRows;i++)&#123;</span><br><span class="line">            <span class="keyword">int</span> startIdx=i;</span><br><span class="line">            <span class="keyword">int</span> interval=maxInterval<span class="number">-2</span>*i;</span><br><span class="line">            <span class="keyword">if</span>(i==numRows<span class="number">-1</span>)</span><br><span class="line">                interval=maxInterval;</span><br><span class="line">            <span class="keyword">while</span>(startIdx&lt;s.size())&#123;</span><br><span class="line">                res+=s[startIdx];</span><br><span class="line">                startIdx+=interval;</span><br><span class="line">                interval=(maxInterval-interval!=<span class="number">0</span>)?maxInterval-interval:interval;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>提交后时间降到16ms，空间占有降低到10MB，效率提升还是很明显的。</p><p>这道题算是这几天做的比较顺利的题了，阿弥陀佛。</p><h1 id="7-Reverse-Integer"><a href="#7-Reverse-Integer" class="headerlink" title="7.Reverse Integer"></a>7.Reverse Integer</h1><p>2019/4/25，易。</p><p>反转一个整数，本来以为挺简单的，但是却没有注意大数越界，又琢磨了一会儿，要注意大数问题啊。</p><p>两种差不多的代码如下：</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">reverse</span><span class="params">(<span class="keyword">int</span> x)</span> </span>&#123;</span><br><span class="line">        <span class="comment">//注意要转换类型，否则大数会出错</span></span><br><span class="line">    <span class="keyword">long</span> <span class="keyword">long</span> <span class="keyword">int</span> absX = <span class="built_in">abs</span>((<span class="keyword">long</span> <span class="keyword">long</span> <span class="keyword">int</span>)x);</span><br><span class="line">    <span class="built_in">string</span> tmp = to_string(absX);</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; tmp.size() / <span class="number">2</span>; i++) &#123;</span><br><span class="line">    <span class="keyword">char</span> a = tmp[i];</span><br><span class="line">    tmp[i] = tmp[tmp.size() - <span class="number">1</span> - i];</span><br><span class="line">    tmp[tmp.size() - <span class="number">1</span> - i] = a;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">long</span> <span class="keyword">long</span> <span class="keyword">int</span> res = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; tmp.size(); i++) &#123;</span><br><span class="line">    res = res * <span class="number">10</span> + (tmp[i]-<span class="string">'0'</span>);</span><br><span class="line">            <span class="keyword">if</span>(res&gt;INT_MAX)<span class="comment">//注意要比较是否越界，因为这里已经是绝对值了，所以只需和INT_MAX比较</span></span><br><span class="line">                <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> (x &lt; <span class="number">0</span>) ? (<span class="number">-1</span> * res) : res;</span><br><span class="line">&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//查了下其他人的方法，可以有第二种写法，更为简单，如下：</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">reverse</span><span class="params">(<span class="keyword">int</span> x)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">long</span> <span class="keyword">long</span> <span class="keyword">int</span> res=<span class="number">0</span>;</span><br><span class="line">        <span class="keyword">while</span>(x!=<span class="number">0</span>)&#123;</span><br><span class="line">            res=res*<span class="number">10</span>+x%<span class="number">10</span>;</span><br><span class="line">            x=x/<span class="number">10</span>;</span><br><span class="line">            <span class="keyword">if</span>(res&gt; INT_MAX)</span><br><span class="line">                <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">            <span class="keyword">if</span>(res&lt;INT_MIN)</span><br><span class="line">                <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>两种代码耗时都是4ms，空间占有也差不多，整体效率相仿。</p><h1 id="8-String-to-Integer-atoi"><a href="#8-String-to-Integer-atoi" class="headerlink" title="8. String to Integer (atoi)"></a>8. String to Integer (atoi)</h1><p>2019/4/26，中。</p><p>字符串转整数，需要注意大数问题、正负号、空格，题目里已经写得很清楚了，代码如下：</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">myAtoi</span><span class="params">(<span class="built_in">string</span> str)</span> </span>&#123;</span><br><span class="line">       <span class="comment">//去除前面的空格</span></span><br><span class="line">    str.erase(<span class="number">0</span>, str.find_first_not_of(<span class="string">" "</span>));</span><br><span class="line">    <span class="comment">//处理返回0的情况</span></span><br><span class="line">    <span class="keyword">if</span> (str == <span class="string">""</span>)</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">if</span> (!<span class="built_in">isdigit</span>(str[<span class="number">0</span>]) &amp;&amp; str[<span class="number">0</span>] != <span class="string">'-'</span>&amp;&amp;str[<span class="number">0</span>] != <span class="string">'+'</span>)</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">if</span> (str[<span class="number">0</span>] == <span class="string">'-'</span> || str[<span class="number">0</span>] == <span class="string">'+'</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (str.size() &lt;= <span class="number">1</span> || !<span class="built_in">isdigit</span>(str[<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">    &#125;</span><br><span class="line">    <span class="comment">//非0</span></span><br><span class="line">    <span class="keyword">bool</span> positive = str[<span class="number">0</span>] == <span class="string">'-'</span> ? <span class="literal">false</span> : <span class="literal">true</span>;</span><br><span class="line">    <span class="keyword">if</span> (str[<span class="number">0</span>] == <span class="string">'-'</span> || str[<span class="number">0</span>] == <span class="string">'+'</span>)</span><br><span class="line">    str = str.substr(<span class="number">1</span>);</span><br><span class="line">    <span class="keyword">long</span> <span class="keyword">long</span> <span class="keyword">int</span> res = <span class="number">0</span>;</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> (i&lt;str.size() &amp;&amp; <span class="built_in">isdigit</span>(str[i])) &#123;</span><br><span class="line">    <span class="keyword">if</span> (positive)</span><br><span class="line">    res = res * <span class="number">10</span> + (str[i] - <span class="string">'0'</span>);</span><br><span class="line">    <span class="keyword">else</span> </span><br><span class="line">    res = res * <span class="number">10</span> - (str[i] - <span class="string">'0'</span>);</span><br><span class="line">    <span class="keyword">if</span> (res &gt; INT_MAX)</span><br><span class="line">    <span class="keyword">return</span> INT_MAX;</span><br><span class="line">    <span class="keyword">if</span> (res &lt; INT_MIN)</span><br><span class="line">    <span class="keyword">return</span> INT_MIN;</span><br><span class="line">    i++;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>看了下其他提交，方法都大同小异，只不过大佬们写的C++代码要简洁一些，不像我写的那么臃肿，大佬们的代码就是在原字符串的基础上往后遍历处理，而我的代码里还用erase/substr方法把原字符串改来改去，导致时间上慢了几ms，慢慢练吧~</p><h1 id="9-Palindrome-Number"><a href="#9-Palindrome-Number" class="headerlink" title="9.Palindrome Number"></a>9.Palindrome Number</h1><p>2019/4/27，易。</p><p>判断一个整数是否是回文数，最简单的方法就是转化成字符然后前后循环判断，代码如下：</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">bool</span> <span class="title">isPalindrome</span><span class="params">(<span class="keyword">int</span> x)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(x&lt;<span class="number">0</span>)</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">        <span class="built_in">string</span> str=to_string(x);</span><br><span class="line">        <span class="keyword">if</span>(str.size()==<span class="number">1</span>)</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>;i&lt;str.size()/<span class="number">2</span>;i++)&#123;</span><br><span class="line">            <span class="keyword">if</span>(str[i]!=str[str.size()<span class="number">-1</span>-i])</span><br><span class="line">                <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>运行时间32ms，内存8.4MB。</p><p>后来看到题目里的扩展，如何不转换成string进行判断？</p><p>想到回文数字其实就是前后读相同，那么将该数字对半分后应该能分成两个相同数字，比如1221，就分成12和12（后一个12从右往左读），而131就可以同样分成13和13（3用两次），根据这种想法写出以下代码：</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">bool</span> <span class="title">isPalindrome</span><span class="params">(<span class="keyword">int</span> x)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(x&lt;<span class="number">0</span>)</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">        <span class="comment">//1、算出整数位数</span></span><br><span class="line">        <span class="keyword">int</span> len=<span class="number">0</span>;</span><br><span class="line">        <span class="keyword">int</span> t=x;</span><br><span class="line">        <span class="keyword">while</span>(t!=<span class="number">0</span>)&#123;</span><br><span class="line">            len++;</span><br><span class="line">            t/=<span class="number">10</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//2、拆分数字</span></span><br><span class="line">        t=x;</span><br><span class="line">        <span class="keyword">int</span> tmp=<span class="number">0</span>;</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>(i&lt;len/<span class="number">2</span>)&#123;</span><br><span class="line">            tmp=tmp*<span class="number">10</span>+t%<span class="number">10</span>;</span><br><span class="line">            t/=<span class="number">10</span>;</span><br><span class="line">            i++;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//3、注意如果是奇数位数的整数，还需要将中间数重复利用一次</span></span><br><span class="line">        <span class="keyword">if</span>(len%<span class="number">2</span>==<span class="number">1</span>)&#123;</span><br><span class="line">            tmp=tmp*<span class="number">10</span>+t%<span class="number">10</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span>(tmp==t)</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>同样是32ms，内存8.2MB。</p><p>后来看了下大佬们的提交，大致思路和上述第二种方法相似，但大佬的代码更加精炼，把我代码中很多直白的部分都进一步浓缩了，如下：</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">bool</span> <span class="title">isPalindrome</span><span class="params">(<span class="keyword">int</span> x)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(x&lt;<span class="number">0</span>|| (x!=<span class="number">0</span> &amp;&amp;x%<span class="number">10</span>==<span class="number">0</span>)) <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">        <span class="keyword">int</span> sum=<span class="number">0</span>;</span><br><span class="line">        <span class="comment">//这里精炼后不需要再计算整数位数，直接用x&gt;sum来循环</span></span><br><span class="line">        <span class="keyword">while</span>(x&gt;sum)</span><br><span class="line">        &#123;</span><br><span class="line">            sum = sum*<span class="number">10</span>+x%<span class="number">10</span>;</span><br><span class="line">            x = x/<span class="number">10</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> (x==sum)||(x==sum/<span class="number">10</span>);<span class="comment">//位数是偶数，则x==sum；位数是奇数，则x==sum/10，不需</span></span><br><span class="line">            <span class="comment">//要像我代码中奇数位数的整数多进行一次处理，实在高呀~</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h1 id="10-Regular-Expression-Matching（again"><a href="#10-Regular-Expression-Matching（again" class="headerlink" title="10.Regular Expression Matching（again)"></a>10.Regular Expression Matching（again)</h1><p>2019/4/29，难。</p><p>一开始以为这道题和《剑指offer》上的某道题一样，遂用那道题的解法来进行求解，后发现有点问题，经过修补后写下如下代码：</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">bool</span> <span class="title">isMatch</span><span class="params">(<span class="built_in">string</span> s, <span class="built_in">string</span> p)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(s!=<span class="string">""</span>&amp;&amp;p==<span class="string">""</span>)</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">        <span class="comment">//先进行一下简单的检查，这部分代码就是修补，很丑</span></span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>;i&lt;p.size();i++)&#123;</span><br><span class="line">            <span class="keyword">if</span>(p[i]!=<span class="string">'.'</span>&amp;&amp;p[i]!=<span class="string">'*'</span>)&#123;</span><br><span class="line">                <span class="keyword">if</span>(s.find(p[i])==<span class="built_in">string</span>::npos)&#123;</span><br><span class="line">                    <span class="keyword">if</span>(i==p.size()<span class="number">-1</span>)</span><br><span class="line">                        <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">                    <span class="keyword">else</span>&#123;</span><br><span class="line">                        <span class="keyword">if</span>(p[i+<span class="number">1</span>]!=<span class="string">'*'</span>)</span><br><span class="line">                            <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> matchCore(s,p);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="function"><span class="keyword">bool</span> <span class="title">matchCore</span><span class="params">(<span class="built_in">string</span> s,<span class="built_in">string</span> p)</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(s==<span class="string">""</span>&amp;&amp;p==<span class="string">""</span>)</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">        <span class="keyword">if</span>(s!=<span class="string">""</span>&amp;&amp;p==<span class="string">""</span>)</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">if</span>(p[<span class="number">1</span>]==<span class="string">'*'</span>)&#123;</span><br><span class="line">            <span class="keyword">if</span>(s[<span class="number">0</span>]==p[<span class="number">0</span>]||(p[<span class="number">0</span>]==<span class="string">'.'</span>&amp;&amp;s!=<span class="string">""</span>))&#123;</span><br><span class="line">                <span class="keyword">return</span> matchCore(s.substr(<span class="number">1</span>),p)<span class="comment">//*表示多个</span></span><br><span class="line">                    ||matchCore(s.substr(<span class="number">1</span>),p.substr(<span class="number">2</span>))<span class="comment">//*表示1个</span></span><br><span class="line">                    ||matchCore(s,p.substr(<span class="number">2</span>));<span class="comment">//*表示0个</span></span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">else</span>&#123;<span class="comment">//不等，则*只能表示0个还有机会</span></span><br><span class="line">                <span class="keyword">return</span> matchCore(s,p.substr(<span class="number">2</span>));</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span>&#123;</span><br><span class="line">            <span class="keyword">if</span>(s[<span class="number">0</span>]==p[<span class="number">0</span>]||(p[<span class="number">0</span>]==<span class="string">'.'</span>&amp;&amp;s!=<span class="string">""</span>))&#123;</span><br><span class="line">                <span class="keyword">return</span> matchCore(s.substr(<span class="number">1</span>),p.substr(<span class="number">1</span>));</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>最终通过了，但是代码很丑，效率很低，整体用了五百多毫秒，内存占用17.5MB左右，效率太差了。</p><p>然后发现可以用DP来求解，研究后代码如下：</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">bool</span> <span class="title">isMatch</span><span class="params">(<span class="built_in">string</span> s, <span class="built_in">string</span> p)</span> </span>&#123;</span><br><span class="line">        <span class="comment">//代码中因为定义dp数组的时候默认值就是false，所以代码中对数组元素赋值false的语句都可删除，</span></span><br><span class="line">        <span class="comment">//但这里仍然写出来，是为了便于理解。</span></span><br><span class="line">        <span class="comment">//1、定义dp数组</span></span><br><span class="line">        <span class="built_in">vector</span>&lt;<span class="built_in">vector</span>&lt;<span class="keyword">bool</span>&gt;&gt; dp(s.size()+<span class="number">1</span>,<span class="built_in">vector</span>&lt;<span class="keyword">bool</span>&gt;(p.size()+<span class="number">1</span>,<span class="literal">false</span>));</span><br><span class="line">        <span class="comment">//2、赋值初始状态</span></span><br><span class="line">        dp[<span class="number">0</span>][<span class="number">0</span>]=<span class="literal">true</span>;</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>;i&lt;=s.size();i++)<span class="comment">//空模式不会匹配非空字符串</span></span><br><span class="line">            dp[i][<span class="number">0</span>]=<span class="literal">false</span>;</span><br><span class="line">        <span class="comment">//非空模式想要匹配空字符串，最后一个字符必须是*</span></span><br><span class="line">        dp[<span class="number">0</span>][<span class="number">1</span>]=<span class="literal">false</span>;</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">2</span>;i&lt;=p.size();i++)&#123;</span><br><span class="line">            <span class="keyword">if</span>(p[i<span class="number">-1</span>]==<span class="string">'*'</span>&amp;&amp;dp[<span class="number">0</span>][i<span class="number">-2</span>])</span><br><span class="line">                dp[<span class="number">0</span>][i]=<span class="literal">true</span>;</span><br><span class="line">            <span class="keyword">else</span></span><br><span class="line">                dp[<span class="number">0</span>][i]=<span class="literal">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//3、计算</span></span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>;i&lt;=s.size();i++)&#123;</span><br><span class="line">            <span class="keyword">for</span>(<span class="keyword">int</span> j=<span class="number">1</span>;j&lt;=p.size();j++)&#123;</span><br><span class="line">                <span class="keyword">if</span>(s[i<span class="number">-1</span>]==p[j<span class="number">-1</span>])</span><br><span class="line">                    dp[i][j]=dp[i<span class="number">-1</span>][j<span class="number">-1</span>];</span><br><span class="line">                <span class="keyword">else</span> <span class="keyword">if</span>(p[j<span class="number">-1</span>]==<span class="string">'.'</span>)</span><br><span class="line">                    dp[i][j]=dp[i<span class="number">-1</span>][j<span class="number">-1</span>];</span><br><span class="line">                <span class="keyword">else</span> <span class="keyword">if</span>(p[j<span class="number">-1</span>]==<span class="string">'*'</span>)&#123;</span><br><span class="line">                    <span class="keyword">if</span>(j&gt;=<span class="number">2</span>)&#123;</span><br><span class="line">                        <span class="keyword">if</span>(s[i<span class="number">-1</span>]!=p[j<span class="number">-2</span>]&amp;&amp;p[j<span class="number">-2</span>]!=<span class="string">'.'</span>)<span class="comment">//不匹配，*只能表示0次</span></span><br><span class="line">                            dp[i][j]=dp[i][j<span class="number">-2</span>];</span><br><span class="line">                        <span class="keyword">else</span><span class="comment">//匹配，*表示0/1/多次</span></span><br><span class="line">                            dp[i][j]=dp[i][j<span class="number">-2</span>]||dp[i<span class="number">-1</span>][j]||dp[i<span class="number">-1</span>][j<span class="number">-2</span>];</span><br><span class="line">                    &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">                        dp[i][j]=<span class="literal">false</span>;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;<span class="keyword">else</span></span><br><span class="line">                    dp[i][j]=<span class="literal">false</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> dp[s.size()][p.size()];</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>利用DP解法耗时降到8ms，内存占用降低到9.1MB，主要思路参考<a href="https://zhuanlan.zhihu.com/p/40294596" target="_blank" rel="noopener">https://zhuanlan.zhihu.com/p/40294596</a>，但个人认为该链接里dp最后一种情况推导公式有误，应该是我代码中写的<code>dp[i][j]=dp[i][j-2]||dp[i-1][j]||dp[i-1][j-2]</code>，且该链接给出的最后代码感觉有点问题，应该不能直接用，只是个伪代码吧，不过主要思路是阐述得很清楚了。</p><h1 id="11-Container-With-Most-Water"><a href="#11-Container-With-Most-Water" class="headerlink" title="11. Container With Most Water"></a>11. Container With Most Water</h1><p>2019/4/30，中。</p><p>一开始看到这道题的时候想的是用最直接的暴力法——挨个遍历，但是可以预料到耗时肯定会超出限制，所以想着改进该方法。想到在暴力遍历中其实有很多种情况是重复的，所以想到用DP数组先存前一种情况的值，再根据已知情况的值来进行当前情况的求解，能够省去一重循环，遂写出下列代码：</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">maxArea</span><span class="params">(<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&amp; height)</span> </span>&#123;</span><br><span class="line">        <span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt; dp(height.size(),<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&lt;height.size();i++)&#123;</span><br><span class="line">            <span class="keyword">int</span> max=dp[i<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&lt;i;j++)&#123;</span><br><span class="line">                <span class="keyword">int</span> volume=(i-j)*min(height[i],height[j]);</span><br><span class="line">                <span class="keyword">if</span>(volume&gt;max)</span><br><span class="line">                    max=volume;</span><br><span class="line">            &#125;</span><br><span class="line">            dp[i]=max;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> dp[height.size()<span class="number">-1</span>];</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>提交，通过测试，但效率极低，耗时1300ms左右，占用内存10MB左右，仍需改进，该方法的时间复杂度是n<sup>2</sup>，所以考虑是否有时间复杂度为n的方法，看到一年前做这道题时用的是前后双指针法，代码如下：</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">maxArea</span><span class="params">(<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&amp; height)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(height.size()&lt;<span class="number">2</span>)</span><br><span class="line">            <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">int</span> i=<span class="number">0</span>,j=height.size()<span class="number">-1</span>;</span><br><span class="line">        <span class="keyword">int</span> maxSize=<span class="number">0</span>;</span><br><span class="line">        <span class="keyword">while</span>(i&lt;j)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">int</span> currentSize=(j-i)*min(height[i],height[j]);</span><br><span class="line">            <span class="keyword">if</span>(currentSize&gt;maxSize)</span><br><span class="line">                maxSize=currentSize;</span><br><span class="line">            height[i]&lt;height[j]?(++i):(--j);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> maxSize;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>耗时20ms，效率提升明显，主要重点在<code>height[i]&lt;height[j]?(++i):(--j)</code>，即每次收缩的时候都收缩边界较小的那一侧，因为这样就可以省去很多冗余情况的判断。</p><h1 id="12-Integer-to-Roman"><a href="#12-Integer-to-Roman" class="headerlink" title="12. Integer to Roman"></a>12. Integer to Roman</h1><p>2019/5/2，中。</p><p>整数转换成罗马数字，整数范围1~3999。</p><p>按部就班就行，首先写出的代码如下：</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="built_in">string</span> <span class="title">intToRoman</span><span class="params">(<span class="keyword">int</span> num)</span> </span>&#123;</span><br><span class="line">        <span class="built_in">map</span>&lt;<span class="keyword">int</span>,<span class="built_in">string</span>&gt; intToString=&#123;</span><br><span class="line">            &#123;<span class="number">1</span>,<span class="string">"I"</span>&#125;,</span><br><span class="line">            &#123;<span class="number">5</span>,<span class="string">"V"</span>&#125;,</span><br><span class="line">            &#123;<span class="number">10</span>,<span class="string">"X"</span>&#125;,</span><br><span class="line">            &#123;<span class="number">50</span>,<span class="string">"L"</span>&#125;,</span><br><span class="line">            &#123;<span class="number">100</span>,<span class="string">"C"</span>&#125;,</span><br><span class="line">            &#123;<span class="number">500</span>,<span class="string">"D"</span>&#125;,</span><br><span class="line">            &#123;<span class="number">1000</span>,<span class="string">"M"</span>&#125;</span><br><span class="line">        &#125;;</span><br><span class="line">        <span class="built_in">string</span> res=<span class="string">""</span>;</span><br><span class="line">        <span class="keyword">int</span> tmp=num;</span><br><span class="line">        <span class="keyword">int</span> p=<span class="number">1</span>;<span class="comment">//表示数位</span></span><br><span class="line">        <span class="keyword">for</span>(;tmp!=<span class="number">0</span>;tmp/=<span class="number">10</span>)&#123;</span><br><span class="line">            <span class="keyword">int</span> digit=tmp%<span class="number">10</span>;</span><br><span class="line">            <span class="keyword">if</span>(digit&gt;=<span class="number">1</span>&amp;&amp;digit&lt;=<span class="number">3</span>)&#123;</span><br><span class="line">                <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>;i&lt;digit;i++)&#123;</span><br><span class="line">                    res=intToString[p]+res;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;<span class="keyword">else</span> <span class="keyword">if</span>(digit==<span class="number">4</span>)&#123;</span><br><span class="line">                res=intToString[p]+intToString[<span class="number">5</span>*p]+res;</span><br><span class="line">            &#125;<span class="keyword">else</span> <span class="keyword">if</span>(digit&gt;=<span class="number">5</span>&amp;&amp;digit&lt;=<span class="number">8</span>)&#123;</span><br><span class="line">                <span class="built_in">string</span> s=intToString[p*<span class="number">5</span>];</span><br><span class="line">                <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>;i&lt;digit<span class="number">-5</span>;i++)</span><br><span class="line">                    s=s+intToString[p];</span><br><span class="line">                res=s+res;</span><br><span class="line">            &#125;<span class="keyword">else</span> <span class="keyword">if</span>(digit==<span class="number">9</span>)&#123;</span><br><span class="line">                res=intToString[p]+intToString[<span class="number">10</span>*p]+res;</span><br><span class="line">            &#125;</span><br><span class="line">            p=p*<span class="number">10</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> res;       </span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>耗时24ms，空间占用12.2MB。</p><p>提交后看了下其他人的代码，基本上思想没什么变化，只不过初始化的时候如果初始化的更具体一点，转换耗时就会更快，代码如下：</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="built_in">string</span> <span class="title">intToRoman</span><span class="params">(<span class="keyword">int</span> num)</span> </span>&#123;</span><br><span class="line">    <span class="built_in">string</span> table[<span class="number">4</span>][<span class="number">10</span>] = &#123;&#123;<span class="string">""</span>, <span class="string">"I"</span>, <span class="string">"II"</span>, <span class="string">"III"</span>, <span class="string">"IV"</span>, <span class="string">"V"</span>, <span class="string">"VI"</span>, <span class="string">"VII"</span>, <span class="string">"VIII"</span>, <span class="string">"IX"</span>&#125;,</span><br><span class="line">                           &#123;<span class="string">""</span>, <span class="string">"X"</span>, <span class="string">"XX"</span>, <span class="string">"XXX"</span>, <span class="string">"XL"</span>, <span class="string">"L"</span>, <span class="string">"LX"</span>, <span class="string">"LXX"</span>, <span class="string">"LXXX"</span>, <span class="string">"XC"</span>&#125;,</span><br><span class="line">                           &#123;<span class="string">""</span>, <span class="string">"C"</span>, <span class="string">"CC"</span>, <span class="string">"CCC"</span>, <span class="string">"CD"</span>, <span class="string">"D"</span>, <span class="string">"DC"</span>, <span class="string">"DCC"</span>, <span class="string">"DCCC"</span>, <span class="string">"CM"</span>&#125;,</span><br><span class="line">                           &#123;<span class="string">""</span>, <span class="string">"M"</span>, <span class="string">"MM"</span>, <span class="string">"MMM"</span>&#125;</span><br><span class="line">                          &#125;;</span><br><span class="line">    <span class="built_in">string</span> result;</span><br><span class="line">    <span class="keyword">int</span> count = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">while</span>(num &gt; <span class="number">0</span>)&#123;</span><br><span class="line">        <span class="keyword">int</span> temp = num % <span class="number">10</span>;</span><br><span class="line">        result = table[count][temp] + result;</span><br><span class="line">        num /= <span class="number">10</span>;</span><br><span class="line">        count++;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>耗时16ms，占用空间8.4MB。</p><h1 id="13-Roman-to-Integer"><a href="#13-Roman-to-Integer" class="headerlink" title="13. Roman to Integer"></a>13. Roman to Integer</h1><p>2019/5/3，易。</p><p>罗马数字转整数，很笨的办法就行，<code>if</code>语句看起来有点乱，但能通过，耗时16ms，8.3MB内存，可以转成<code>switch</code>语句，我这就没有转了。</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">romanToInt</span><span class="params">(<span class="built_in">string</span> s)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">int</span> res=<span class="number">0</span>;</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>;i&lt;s.size();i++)&#123;</span><br><span class="line">            <span class="keyword">if</span>(s[i]==<span class="string">'I'</span>)&#123;</span><br><span class="line">                <span class="keyword">if</span>(i&lt;s.size()<span class="number">-1</span>)&#123;</span><br><span class="line">                    <span class="keyword">if</span>(s[i+<span class="number">1</span>]==<span class="string">'V'</span>)&#123;</span><br><span class="line">                        res+=<span class="number">4</span>;</span><br><span class="line">                        i++;</span><br><span class="line">                    &#125;<span class="keyword">else</span> <span class="keyword">if</span>(s[i+<span class="number">1</span>]==<span class="string">'X'</span>)&#123;</span><br><span class="line">                        res+=<span class="number">9</span>;</span><br><span class="line">                        i++;</span><br><span class="line">                    &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">                        res+=<span class="number">1</span>;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">else</span>&#123;</span><br><span class="line">                    res+=<span class="number">1</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;<span class="keyword">else</span> <span class="keyword">if</span>(s[i]==<span class="string">'V'</span>)&#123;</span><br><span class="line">                res+=<span class="number">5</span>;</span><br><span class="line">            &#125;<span class="keyword">else</span> <span class="keyword">if</span>(s[i]==<span class="string">'X'</span>)&#123;</span><br><span class="line">               <span class="keyword">if</span>(i&lt;s.size()<span class="number">-1</span>)&#123;</span><br><span class="line">                    <span class="keyword">if</span>(s[i+<span class="number">1</span>]==<span class="string">'L'</span>)&#123;</span><br><span class="line">                        res+=<span class="number">40</span>;</span><br><span class="line">                        i++;</span><br><span class="line">                    &#125;<span class="keyword">else</span> <span class="keyword">if</span>(s[i+<span class="number">1</span>]==<span class="string">'C'</span>)&#123;</span><br><span class="line">                        res+=<span class="number">90</span>;</span><br><span class="line">                        i++;</span><br><span class="line">                    &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">                        res+=<span class="number">10</span>;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">else</span>&#123;</span><br><span class="line">                    res+=<span class="number">10</span>;</span><br><span class="line">                &#125; </span><br><span class="line">            &#125;<span class="keyword">else</span> <span class="keyword">if</span>(s[i]==<span class="string">'L'</span>)&#123;</span><br><span class="line">                res+=<span class="number">50</span>;</span><br><span class="line">            &#125;<span class="keyword">else</span> <span class="keyword">if</span>(s[i]==<span class="string">'C'</span>)&#123;</span><br><span class="line">                <span class="keyword">if</span>(i&lt;s.size()<span class="number">-1</span>)&#123;</span><br><span class="line">                    <span class="keyword">if</span>(s[i+<span class="number">1</span>]==<span class="string">'D'</span>)&#123;</span><br><span class="line">                        res+=<span class="number">400</span>;</span><br><span class="line">                        i++;</span><br><span class="line">                    &#125;<span class="keyword">else</span> <span class="keyword">if</span>(s[i+<span class="number">1</span>]==<span class="string">'M'</span>)&#123;</span><br><span class="line">                        res+=<span class="number">900</span>;</span><br><span class="line">                        i++;</span><br><span class="line">                    &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">                        res+=<span class="number">100</span>;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">else</span>&#123;</span><br><span class="line">                    res+=<span class="number">100</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;<span class="keyword">else</span> <span class="keyword">if</span>(s[i]==<span class="string">'D'</span>)&#123;</span><br><span class="line">                res+=<span class="number">500</span>;</span><br><span class="line">            &#125;<span class="keyword">else</span> <span class="keyword">if</span>(s[i]==<span class="string">'M'</span>)&#123;</span><br><span class="line">                res+=<span class="number">1000</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h1 id="14-Longest-Common-Prefix"><a href="#14-Longest-Common-Prefix" class="headerlink" title="14. Longest Common Prefix"></a>14. Longest Common Prefix</h1><p>2019/5/5，易。</p><p>求一组字符串的最长公共前缀，直接暴力解就行了，代码如下：</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="built_in">string</span> <span class="title">longestCommonPrefix</span><span class="params">(<span class="built_in">vector</span>&lt;<span class="built_in">string</span>&gt;&amp; strs)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(strs.empty())</span><br><span class="line">            <span class="keyword">return</span> <span class="string">""</span>;</span><br><span class="line">        </span><br><span class="line">        <span class="built_in">string</span> pre=strs[<span class="number">0</span>];<span class="comment">//最长公共前缀最长不会超过第一个元素的长度，所以先把前缀设为第一个元素</span></span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>;i&lt;strs.size();i++)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">for</span>(<span class="keyword">int</span> j=<span class="number">0</span>;j&lt;pre.size();j++)</span><br><span class="line">            &#123;</span><br><span class="line">                <span class="keyword">if</span>(pre[j]!=strs[i][j])<span class="comment">//一旦有字符不等，表示最长前缀结束了</span></span><br><span class="line">                &#123;</span><br><span class="line">                    pre=pre.substr(<span class="number">0</span>,j);</span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span>(pre==<span class="string">""</span>)</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> pre;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h1 id="15-3Sum（again）"><a href="#15-3Sum（again）" class="headerlink" title="15. 3Sum（again）"></a>15. 3Sum（again）</h1><p>2019/5/8，中。</p><p>求数组中三个数和为0的子集。</p><p>一开始自己用的回溯法，虽然结果能对，但是超时了，代码还是暂时列在这里，这代码里去掉了一些无用的迭代，然而还是没啥用，还是超时。</p><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></pre></td><td class="code"><pre><span class="line"><span class="comment">//超时</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">vector</span>&lt;<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&gt; threeSum(<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&amp; nums) &#123;</span><br><span class="line">        sort(nums.begin(),nums.end());</span><br><span class="line">        <span class="built_in">vector</span>&lt;<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&gt; res;</span><br><span class="line">        <span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt; p;</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>;i&lt;nums.size();i++)&#123;</span><br><span class="line">            <span class="keyword">if</span>(i&gt;<span class="number">0</span>&amp;&amp;nums[i]==nums[i<span class="number">-1</span>])</span><br><span class="line">                <span class="keyword">continue</span>;</span><br><span class="line">            p.push_back(nums[i]);</span><br><span class="line">            backTracking(nums,i,p,res);</span><br><span class="line">            p.pop_back();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//vector&lt;vector&lt;int&gt;&gt; resVec(res.size());</span></span><br><span class="line">        <span class="comment">//std::copy(res.begin(), res.end(), resVec.begin());</span></span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">backTracking</span><span class="params">(<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&amp; nums,<span class="keyword">int</span> i,<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&amp; p,<span class="built_in">vector</span>&lt;<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&gt;&amp; res)</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(p.size()==<span class="number">3</span>)&#123;</span><br><span class="line">            <span class="keyword">if</span>(p[<span class="number">0</span>]+p[<span class="number">1</span>]+p[<span class="number">2</span>]==<span class="number">0</span>)&#123;</span><br><span class="line">               <span class="comment">// vector&lt;int&gt; tmp = p;//不能直接对p排序，会导致p发生变化，后续回溯出错</span></span><br><span class="line"><span class="comment">//sort(tmp.begin(), tmp.end());</span></span><br><span class="line">res.push_back(p);</span><br><span class="line">                <span class="keyword">return</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> j=i+<span class="number">1</span>;j&lt;nums.size();j++)&#123;</span><br><span class="line">            <span class="keyword">if</span>(j&gt;i+<span class="number">1</span>&amp;&amp;nums[j]==nums[j<span class="number">-1</span>])</span><br><span class="line">                <span class="keyword">continue</span>;</span><br><span class="line">            p.push_back(nums[j]);</span><br><span class="line">            backTracking(nums,j,p,res);</span><br><span class="line">            p.pop_back();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>后面看了其他提交者的代码，采用的是先排序再利用前后指针的方法：</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">vector</span>&lt;<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&gt; threeSum(<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&amp; nums) &#123;</span><br><span class="line">        sort(nums.begin(), nums.end());</span><br><span class="line">        <span class="built_in">vector</span>&lt;<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&gt; res;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">unsigned</span> <span class="keyword">int</span> i=<span class="number">0</span>; i&lt;nums.size(); i++) &#123;</span><br><span class="line">            <span class="keyword">if</span> ((i&gt;<span class="number">0</span>) &amp;&amp; (nums[i]==nums[i<span class="number">-1</span>]))<span class="comment">//防止重复</span></span><br><span class="line">                <span class="keyword">continue</span>;</span><br><span class="line">            <span class="keyword">int</span> l = i+<span class="number">1</span>, r = nums.size()<span class="number">-1</span>;</span><br><span class="line">            <span class="keyword">while</span> (l&lt;r) &#123;</span><br><span class="line">                <span class="keyword">int</span> s = nums[i]+nums[l]+nums[r];</span><br><span class="line">                <span class="keyword">if</span> (s&gt;<span class="number">0</span>) r--;</span><br><span class="line">                <span class="keyword">else</span> <span class="keyword">if</span> (s&lt;<span class="number">0</span>) l++;</span><br><span class="line">                <span class="keyword">else</span> &#123;</span><br><span class="line">                    res.push_back(<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt; &#123;nums[i], nums[l], nums[r]&#125;);</span><br><span class="line">                    <span class="comment">//剔除重复</span></span><br><span class="line">                    <span class="keyword">while</span> (l&lt;r&amp;&amp;nums[l]==nums[l+<span class="number">1</span>]) l++;</span><br><span class="line">                    <span class="keyword">while</span> (l&lt;r&amp;&amp;nums[r]==nums[r<span class="number">-1</span>]) r--;</span><br><span class="line">                    l++; r--;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h1 id="16-3Sum-Closest"><a href="#16-3Sum-Closest" class="headerlink" title="16.3Sum Closest"></a>16.3Sum Closest</h1><p>2019/5/9，中。</p><p>和15很类似，这题求的是和给定值target最近的三个数的和，方法类似，也是用两个指针从前后向中间逼近，代码如下：</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">threeSumClosest</span><span class="params">(<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&amp; nums, <span class="keyword">int</span> target)</span> </span>&#123;</span><br><span class="line">        sort(nums.begin(), nums.end());</span><br><span class="line">        <span class="keyword">int</span> min_bias = INT8_MAX;</span><br><span class="line">        <span class="keyword">int</span> res = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; nums.size(); i++) &#123;</span><br><span class="line">            <span class="keyword">int</span> l = i + <span class="number">1</span>;</span><br><span class="line">            <span class="keyword">int</span> r = (<span class="keyword">int</span>)nums.size() - <span class="number">1</span>;</span><br><span class="line">            <span class="keyword">while</span> (l &lt; r) &#123;</span><br><span class="line">                <span class="keyword">int</span> s = nums[i] + nums[l] + nums[r];</span><br><span class="line">                <span class="keyword">if</span> (s == target)</span><br><span class="line">                    <span class="keyword">return</span> s;</span><br><span class="line">                <span class="keyword">int</span> tmp=<span class="built_in">abs</span>(s-target);</span><br><span class="line">                <span class="keyword">if</span>(tmp&lt;min_bias)&#123;</span><br><span class="line">                    min_bias=tmp;</span><br><span class="line">                    res=s;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">if</span>(s&gt;target)</span><br><span class="line">                    r--;</span><br><span class="line">                <span class="keyword">else</span></span><br><span class="line">                    l++;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h1 id="17-Letter-Combinations-of-a-Phone-Number"><a href="#17-Letter-Combinations-of-a-Phone-Number" class="headerlink" title="17. Letter Combinations of a Phone Number"></a>17. Letter Combinations of a Phone Number</h1><p>2019/5/10，中。</p><p>一道简单的回溯题，没有啥特别的地方，代码如下：</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">vector</span>&lt;<span class="built_in">string</span>&gt; letterCombinations(<span class="built_in">string</span> digits) &#123;</span><br><span class="line">        <span class="built_in">vector</span>&lt;<span class="built_in">string</span>&gt; res;</span><br><span class="line">        <span class="keyword">if</span>(digits==<span class="string">""</span>)</span><br><span class="line">            <span class="keyword">return</span> res;</span><br><span class="line">        <span class="built_in">vector</span>&lt;<span class="built_in">vector</span>&lt;<span class="built_in">string</span>&gt;&gt; chas=&#123;&#123;<span class="string">"a"</span>,<span class="string">"b"</span>,<span class="string">"c"</span>&#125;,&#123;<span class="string">"d"</span>,<span class="string">"e"</span>,<span class="string">"f"</span>&#125;,&#123;<span class="string">"g"</span>,<span class="string">"h"</span>,<span class="string">"i"</span>&#125;,</span><br><span class="line">                                    &#123;<span class="string">"j"</span>,<span class="string">"k"</span>,<span class="string">"l"</span>&#125;,&#123;<span class="string">"m"</span>,<span class="string">"n"</span>,<span class="string">"o"</span>&#125;,&#123;<span class="string">"p"</span>,<span class="string">"q"</span>,<span class="string">"r"</span>,<span class="string">"s"</span>&#125;,</span><br><span class="line">                                    &#123;<span class="string">"t"</span>,<span class="string">"u"</span>,<span class="string">"v"</span>&#125;,&#123;<span class="string">"w"</span>,<span class="string">"x"</span>,<span class="string">"y"</span>,<span class="string">"z"</span>&#125;&#125;;</span><br><span class="line">        <span class="built_in">string</span> tmp=<span class="string">""</span>;</span><br><span class="line">        backTracking(digits,chas,res,tmp);</span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">backTracking</span><span class="params">(<span class="built_in">string</span>&amp; digits,<span class="keyword">const</span> <span class="built_in">vector</span>&lt;<span class="built_in">vector</span>&lt;<span class="built_in">string</span>&gt;&gt;&amp; chas,<span class="built_in">vector</span>&lt;<span class="built_in">string</span>&gt;&amp; res,<span class="built_in">string</span>&amp; tmp)</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(tmp.size()==digits.size())&#123;</span><br><span class="line">            res.push_back(tmp);</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</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&lt;chas[digits[tmp.size()]-<span class="string">'0'</span><span class="number">-2</span>].size();i++)&#123;</span><br><span class="line">            tmp+=chas[digits[tmp.size()]-<span class="string">'0'</span><span class="number">-2</span>][i];</span><br><span class="line">            backTracking(digits,chas,res,tmp);</span><br><span class="line">            tmp=tmp.substr(<span class="number">0</span>,tmp.size()<span class="number">-1</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h1 id="18-4Sum"><a href="#18-4Sum" class="headerlink" title="18. 4Sum"></a>18. 4Sum</h1><p>2019/5/11，中。</p><p>和前面的2Sum以及3Sum是一个系列的，使用和3Sum一样的思想即可，AC，耗时8ms左右。</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">vector</span>&lt;<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&gt; fourSum(<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&amp; nums, <span class="keyword">int</span> target) &#123;</span><br><span class="line">        <span class="built_in">vector</span>&lt;<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&gt; res;</span><br><span class="line">        <span class="keyword">if</span>(nums.size() &lt; <span class="number">4</span>) </span><br><span class="line">            <span class="keyword">return</span> res;</span><br><span class="line">        sort(nums.begin(),nums.end());</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>;i&lt;nums.size();i++)&#123;</span><br><span class="line">            <span class="keyword">if</span>(i&gt;<span class="number">0</span>&amp;&amp;nums[i]==nums[i<span class="number">-1</span>])</span><br><span class="line">                <span class="keyword">continue</span>;</span><br><span class="line">            <span class="comment">//以下两个判断可以剔除很多无效循环，没有这两个判断的话也能AC，但是耗时会在40ms左右</span></span><br><span class="line">            <span class="keyword">if</span>(i+<span class="number">3</span>&lt;nums.size()&amp;&amp;nums[i] + nums[i+<span class="number">1</span>] + nums[i+<span class="number">2</span>] + nums[i+<span class="number">3</span>] &gt; target) </span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">if</span>(nums[i] + nums[nums.size()<span class="number">-1</span>] + nums[nums.size()<span class="number">-2</span>] + nums[nums.size()<span class="number">-3</span>] &lt; target) </span><br><span class="line">                <span class="keyword">continue</span>;</span><br><span class="line">            <span class="keyword">for</span>(<span class="keyword">int</span> j=i+<span class="number">1</span>;j&lt;nums.size();j++)&#123;</span><br><span class="line">                <span class="keyword">if</span>(j&gt;i+<span class="number">1</span>&amp;&amp;nums[j]==nums[j<span class="number">-1</span>])</span><br><span class="line">                    <span class="keyword">continue</span>;</span><br><span class="line">                <span class="keyword">int</span> l=j+<span class="number">1</span>,r=nums.size()<span class="number">-1</span>;</span><br><span class="line">                <span class="keyword">while</span>(l&lt;r)&#123;</span><br><span class="line">                    <span class="keyword">int</span> sum=nums[i]+nums[j]+nums[l]+nums[r];</span><br><span class="line">                    <span class="keyword">if</span>(sum==target)&#123;</span><br><span class="line">                        res.push_back(<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&#123;nums[i],nums[j],nums[l],nums[r]&#125;);</span><br><span class="line">                        <span class="keyword">while</span>(l&lt;r&amp;&amp;nums[l+<span class="number">1</span>]==nums[l])</span><br><span class="line">                            l++;</span><br><span class="line">                        <span class="keyword">while</span>(l&lt;r&amp;&amp;nums[r<span class="number">-1</span>]==nums[r])</span><br><span class="line">                            r--;</span><br><span class="line">                        l++;r--;</span><br><span class="line">                    &#125;<span class="keyword">else</span> <span class="keyword">if</span>(sum&gt;target)</span><br><span class="line">                        r--;</span><br><span class="line">                    <span class="keyword">else</span> </span><br><span class="line">                        l++;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h1 id="19-Remove-Nth-Node-From-End-of-List"><a href="#19-Remove-Nth-Node-From-End-of-List" class="headerlink" title="19. Remove Nth Node From End of List"></a>19. Remove Nth Node From End of List</h1><p>2019/5/12，中。</p><p>移除链表中倒数第N个元素，做过，代码如下：</p><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></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Definition for singly-linked list.</span></span><br><span class="line"><span class="comment"> * struct ListNode &#123;</span></span><br><span class="line"><span class="comment"> *     int val;</span></span><br><span class="line"><span class="comment"> *     ListNode *next;</span></span><br><span class="line"><span class="comment"> *     ListNode(int x) : val(x), next(NULL) &#123;&#125;</span></span><br><span class="line"><span class="comment"> * &#125;;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function">ListNode* <span class="title">removeNthFromEnd</span><span class="params">(ListNode* head, <span class="keyword">int</span> n)</span> </span>&#123;</span><br><span class="line">        <span class="comment">//只有一个节点并且要删除这个节点</span></span><br><span class="line">        <span class="keyword">if</span>(head-&gt;next==<span class="literal">NULL</span>&amp;&amp;n==<span class="number">1</span>)</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line">        ListNode* pre=head;</span><br><span class="line">        ListNode* cur=head;</span><br><span class="line">        <span class="keyword">while</span>(n--)&#123;</span><br><span class="line">            pre=pre-&gt;next;</span><br><span class="line">            <span class="keyword">if</span>(!pre&amp;&amp;n!=<span class="number">0</span>)</span><br><span class="line">                <span class="keyword">return</span> head;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">while</span>(pre)&#123;</span><br><span class="line">            pre=pre-&gt;next;</span><br><span class="line">            cur=cur-&gt;next;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//删除的是第一个节点</span></span><br><span class="line">        <span class="keyword">if</span>(cur==head)&#123;</span><br><span class="line">            <span class="keyword">return</span> head-&gt;next;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//要删除的不是最后一个节点</span></span><br><span class="line">        <span class="keyword">if</span>(cur-&gt;next)&#123;</span><br><span class="line">            cur-&gt;val=cur-&gt;next-&gt;val;</span><br><span class="line">            cur-&gt;next=cur-&gt;next-&gt;next;</span><br><span class="line">        &#125;<span class="keyword">else</span>&#123;<span class="comment">//删除最后一个节点</span></span><br><span class="line">            pre=head;</span><br><span class="line">            <span class="keyword">while</span>(pre-&gt;next!=cur)</span><br><span class="line">                pre=pre-&gt;next;</span><br><span class="line">            pre-&gt;next=<span class="literal">NULL</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> head;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h1 id="20-Valid-Parentheses"><a href="#20-Valid-Parentheses" class="headerlink" title="20. Valid Parentheses"></a>20. Valid Parentheses</h1><p>2019/5/13，易。</p><p>判断括号是否有效，用一个栈即可，没什么难度，自己是用ifelse写的，另外找了一个看起来清爽一些但意思一样的代码放在这里：</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">bool</span> <span class="title">isValid</span><span class="params">(<span class="built_in">string</span> s)</span> </span>&#123;</span><br><span class="line">        <span class="built_in">stack</span>&lt;<span class="keyword">char</span>&gt; paren;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">char</span>&amp; c : s) &#123;</span><br><span class="line">            <span class="keyword">switch</span> (c) &#123;</span><br><span class="line">                <span class="keyword">case</span> <span class="string">'('</span>: </span><br><span class="line">                <span class="keyword">case</span> <span class="string">'&#123;'</span>: </span><br><span class="line">                <span class="keyword">case</span> <span class="string">'['</span>: paren.push(c); <span class="keyword">break</span>;</span><br><span class="line">                <span class="keyword">case</span> <span class="string">')'</span>: <span class="keyword">if</span> (paren.empty() || paren.top()!=<span class="string">'('</span>) <span class="keyword">return</span> <span class="literal">false</span>; <span class="keyword">else</span> paren.pop(); <span class="keyword">break</span>;</span><br><span class="line">                <span class="keyword">case</span> <span class="string">'&#125;'</span>: <span class="keyword">if</span> (paren.empty() || paren.top()!=<span class="string">'&#123;'</span>) <span class="keyword">return</span> <span class="literal">false</span>; <span class="keyword">else</span> paren.pop(); <span class="keyword">break</span>;</span><br><span class="line">                <span class="keyword">case</span> <span class="string">']'</span>: <span class="keyword">if</span> (paren.empty() || paren.top()!=<span class="string">'['</span>) <span class="keyword">return</span> <span class="literal">false</span>; <span class="keyword">else</span> paren.pop(); <span class="keyword">break</span>;</span><br><span class="line">                <span class="keyword">default</span>: ; <span class="comment">// pass</span></span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> paren.empty() ;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h1 id="21-Merge-Two-Sorted-Lists"><a href="#21-Merge-Two-Sorted-Lists" class="headerlink" title="21. Merge Two Sorted Lists"></a>21. Merge Two Sorted Lists</h1><p>2019/5/15，易。</p><p>合并两个有序数组，简单题，最常用的方法就是循环依次比较，这里就不放这种方法的代码了，放一个递归的代码，《剑指offer》里也是这种递归代码。</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function">ListNode* <span class="title">mergeTwoLists</span><span class="params">(ListNode* l1, ListNode* l2)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(!l1&amp;&amp;!l2)</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line">        <span class="keyword">if</span>(!l1)</span><br><span class="line">            <span class="keyword">return</span> l2;</span><br><span class="line">        <span class="keyword">if</span>(!l2)</span><br><span class="line">            <span class="keyword">return</span> l1;</span><br><span class="line">        </span><br><span class="line">        ListNode* node=<span class="literal">NULL</span>;</span><br><span class="line">        <span class="keyword">if</span>(l1-&gt;val&lt;l2-&gt;val)</span><br><span class="line">        &#123;</span><br><span class="line">            node=l1;</span><br><span class="line">            node-&gt;next=mergeTwoLists(l1-&gt;next,l2);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span></span><br><span class="line">        &#123;</span><br><span class="line">            node=l2;</span><br><span class="line">            node-&gt;next=mergeTwoLists(l1,l2-&gt;next);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> node;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h1 id="22-Generate-Parentheses（again）"><a href="#22-Generate-Parentheses（again）" class="headerlink" title="22. Generate Parentheses（again）"></a>22. Generate Parentheses（again）</h1><p>2019/5/16，中。</p><p>生成括号，用递归解法。</p><p>总结出来三点，就是选择、限制、结束条件是这种递归和回溯的主要部分，本题代码如下：</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">vector</span>&lt;<span class="built_in">string</span>&gt; generateParenthesis(<span class="keyword">int</span> n) &#123;</span><br><span class="line">        <span class="built_in">vector</span>&lt;<span class="built_in">string</span>&gt; res;</span><br><span class="line">        recursion(res,<span class="string">""</span>,n,<span class="number">0</span>);</span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">recursion</span><span class="params">(<span class="built_in">vector</span>&lt;<span class="built_in">string</span>&gt;&amp; res,<span class="built_in">string</span> s,<span class="keyword">int</span> left,<span class="keyword">int</span> right)</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(left==<span class="number">0</span>&amp;&amp;right==<span class="number">0</span>)&#123;</span><br><span class="line">            res.push_back(s);</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span>(left&gt;<span class="number">0</span>)</span><br><span class="line">            recursion(res,s+<span class="string">"("</span>,left<span class="number">-1</span>,right+<span class="number">1</span>);</span><br><span class="line">        <span class="keyword">if</span>(right&gt;<span class="number">0</span>)</span><br><span class="line">            recursion(res,s+<span class="string">")"</span>,left,right<span class="number">-1</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h1 id="23-Merge-k-Sorted-Lists"><a href="#23-Merge-k-Sorted-Lists" class="headerlink" title="23. Merge k Sorted Lists"></a>23. Merge k Sorted Lists</h1><p>2019/5/17，难。</p><p>第21题的升级版，最容易想到的方法就是循环调用第21题的代码，代码如下：</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function">ListNode* <span class="title">mergeKLists</span><span class="params">(<span class="built_in">vector</span>&lt;ListNode*&gt;&amp; lists)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(lists.size()==<span class="number">0</span>)</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line">        ListNode* res;</span><br><span class="line">        res=lists[<span class="number">0</span>];</span><br><span class="line">        <span class="comment">//循环调用21题的方法</span></span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>;i&lt;lists.size();i++)&#123;</span><br><span class="line">            res=mergeTwoLists(res,lists[i]);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="function">ListNode* <span class="title">mergeTwoLists</span><span class="params">(ListNode*&amp; l1, ListNode* l2)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(!l1&amp;&amp;!l2)</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line">        <span class="keyword">if</span>(!l1)</span><br><span class="line">            <span class="keyword">return</span> l2;</span><br><span class="line">        <span class="keyword">if</span>(!l2)</span><br><span class="line">            <span class="keyword">return</span> l1;</span><br><span class="line">        ListNode* tmp;</span><br><span class="line">        <span class="keyword">if</span>(l1-&gt;val&lt;l2-&gt;val)&#123;</span><br><span class="line">            tmp=l1;</span><br><span class="line">            tmp-&gt;next=mergeTwoLists(l1-&gt;next,l2);</span><br><span class="line">        &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">            tmp=l2;</span><br><span class="line">            tmp-&gt;next=mergeTwoLists(l1,l2-&gt;next);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> tmp;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>最后提交发现该方法可以AC，但耗时240ms，占内存11MB左右，效率不是特别好。</p><p>为提高效率，采用分治法的思想，两两合并再合并，代码如下：</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function">ListNode* <span class="title">mergeKLists</span><span class="params">(<span class="built_in">vector</span>&lt;ListNode*&gt;&amp; lists)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(lists.size()==<span class="number">0</span>)</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line">        ListNode* res;</span><br><span class="line">        <span class="keyword">int</span> n=lists.size();</span><br><span class="line">        <span class="keyword">while</span>(n&gt;<span class="number">1</span>)&#123;</span><br><span class="line">            <span class="keyword">int</span> k=(n+<span class="number">1</span>)/<span class="number">2</span>;</span><br><span class="line">            <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>;i&lt;n/<span class="number">2</span>;i++)</span><br><span class="line">                lists[i]=mergeTwoLists(lists[i],lists[i+k]);</span><br><span class="line">            n=k;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> lists[<span class="number">0</span>];</span><br><span class="line">    &#125;</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="function">ListNode* <span class="title">mergeTwoLists</span><span class="params">(ListNode*&amp; l1, ListNode* l2)</span> </span>&#123;</span><br><span class="line">        <span class="comment">//...此函数相同</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>该方法耗时24ms，效率提升很多。</p><h1 id="24-Swap-Nodes-in-Pairs"><a href="#24-Swap-Nodes-in-Pairs" class="headerlink" title="24. Swap Nodes in Pairs"></a>24. Swap Nodes in Pairs</h1><p>2019/5/21，中。</p><p>链表题，主要就是搞清楚指针的变换和空指针的情况，循环遍历下去即可，代码如下：</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function">ListNode* <span class="title">swapPairs</span><span class="params">(ListNode* head)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(!head)</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line">        <span class="keyword">if</span>(!head-&gt;next)</span><br><span class="line">            <span class="keyword">return</span> head;</span><br><span class="line">        ListNode* cur=head,*next=head-&gt;next;</span><br><span class="line">        ListNode* newHead=next;<span class="comment">//记录新的头结点</span></span><br><span class="line">        ListNode* pre=<span class="literal">NULL</span>;</span><br><span class="line">        <span class="keyword">while</span>(next)&#123;</span><br><span class="line">            <span class="keyword">if</span>(pre==<span class="literal">NULL</span>)</span><br><span class="line">                pre=cur;</span><br><span class="line">            <span class="keyword">else</span></span><br><span class="line">                pre-&gt;next=next;</span><br><span class="line">            cur-&gt;next=next-&gt;next;</span><br><span class="line">            next-&gt;next=cur;</span><br><span class="line">            </span><br><span class="line">            pre=cur;</span><br><span class="line">            cur=cur-&gt;next;</span><br><span class="line">            <span class="keyword">if</span>(cur)</span><br><span class="line">                next=cur-&gt;next;</span><br><span class="line">            <span class="keyword">else</span></span><br><span class="line">                next=<span class="literal">NULL</span>;</span><br><span class="line">            </span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> newHead;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h1 id="25-Reverse-Nodes-in-k-Group"><a href="#25-Reverse-Nodes-in-k-Group" class="headerlink" title="25. Reverse Nodes in k-Group"></a>25. Reverse Nodes in k-Group</h1><p>2019/5/26，难。</p><p>最近等毕业论文审核通知，心烦意乱，没有什么心情，所以做题耽搁了些。</p><p>这是题24的升级版，题24是两两反转，而本题是按数字k来反转，变成了更一般的情况，我的想法是按段分割整个链表，对每一段链表分别进行反转，注意好节点指针，还是比较容易漏的，测试了好久，代码如下：</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function">ListNode* <span class="title">reverseKGroup</span><span class="params">(ListNode* head, <span class="keyword">int</span> k)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(!head)</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line">        <span class="comment">//1 计算链表长度</span></span><br><span class="line">        <span class="keyword">int</span> len=<span class="number">0</span>;</span><br><span class="line">        ListNode* cur=head;</span><br><span class="line">        ListNode* res=<span class="literal">NULL</span>;<span class="comment">//记录最后返回的头结点</span></span><br><span class="line">        <span class="keyword">while</span>(cur)&#123;</span><br><span class="line">            len++;</span><br><span class="line">            cur=cur-&gt;next;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span>(k&gt;len||k==<span class="number">1</span>)</span><br><span class="line">            <span class="keyword">return</span> head;</span><br><span class="line">        <span class="keyword">int</span> i=len/k;<span class="comment">//2 计算反转链表的循环次数</span></span><br><span class="line">        cur=head;</span><br><span class="line">        <span class="keyword">bool</span> first=<span class="literal">true</span>;<span class="comment">//记录是否是第一次，用来保存调整后的头结点</span></span><br><span class="line">        ListNode* last=<span class="literal">NULL</span>;<span class="comment">//记录上一次调整的最后一个节点</span></span><br><span class="line">        <span class="keyword">while</span>(i--)&#123;</span><br><span class="line">            <span class="keyword">int</span> n=k;</span><br><span class="line">            ListNode* tail=cur;</span><br><span class="line">            <span class="comment">//得到本次需要调整的最后一个节点</span></span><br><span class="line">            <span class="keyword">while</span>(n&gt;<span class="number">1</span>)&#123;</span><br><span class="line">                tail=tail-&gt;next;</span><br><span class="line">                n--;</span><br><span class="line">            &#125;</span><br><span class="line">            ListNode* tmp=tail-&gt;next,*tmp1=cur;<span class="comment">//tmp记录下一次调整的头结点，tmp1记录本次调整的头结点，也就是本次调整完的最后一个节点</span></span><br><span class="line">            <span class="keyword">if</span>(first)<span class="comment">//如果是第一次调整则记录最终头结点</span></span><br><span class="line">            &#123;</span><br><span class="line">                res=reverseList(last,cur,tail,k);</span><br><span class="line">                first=<span class="literal">false</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">else</span></span><br><span class="line">                reverseList(last,cur,tail,k);</span><br><span class="line">            last=tmp1;</span><br><span class="line">            cur=tmp;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="comment">//反转部分链表</span></span><br><span class="line">    <span class="function">ListNode* <span class="title">reverseList</span><span class="params">(ListNode*&amp; last,ListNode*&amp; head,ListNode*&amp; tail,<span class="keyword">int</span> k)</span></span>&#123;</span><br><span class="line">        ListNode* pre=tail-&gt;next;</span><br><span class="line">        ListNode* next=<span class="literal">NULL</span>;</span><br><span class="line">        <span class="keyword">while</span>(k--)&#123;</span><br><span class="line">            next=head-&gt;next;</span><br><span class="line">            head-&gt;next=pre;</span><br><span class="line">            pre=head;</span><br><span class="line">            head=next;</span><br><span class="line">            <span class="keyword">if</span>(k==<span class="number">1</span>&amp;&amp;last)</span><br><span class="line">            &#123;</span><br><span class="line">                last-&gt;next=head;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> pre;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>最后耗时20ms，内存9.7MB左右。</p><h1 id="26-Remove-Duplicates-from-Sorted-Array"><a href="#26-Remove-Duplicates-from-Sorted-Array" class="headerlink" title="26. Remove Duplicates from Sorted Array"></a>26. Remove Duplicates from Sorted Array</h1><p>2019/5/27，易。</p><p>去除排序数组中的重复数组。</p><p>本题本来以为是需要将重复数字删掉，但题目的意思其实是只需要让单独的数字出现在前面，超出单独数字长度后的数字可以不用删除，因为不用删除所有可以省很多时间，代码如下：</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">removeDuplicates</span><span class="params">(<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&amp; nums)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(nums.empty())</span><br><span class="line">            <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">int</span> index=<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&lt;nums.size();i++)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">if</span>(nums[i]!=nums[index])</span><br><span class="line">            &#123;</span><br><span class="line">                index++;</span><br><span class="line">                nums[index]=nums[i];</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> index+<span class="number">1</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>不过一开始我以为是需要删除元素，所以用了迭代器来删除数组元素，最后也可以跑通，只是耗时会比较多，代码如下：</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">removeDuplicates</span><span class="params">(<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&amp; nums)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(nums.empty())</span><br><span class="line">            <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">        <span class="comment">//检查的过程中删除元素，改变了原数组的长度，耗时较长</span></span><br><span class="line">        <span class="keyword">int</span> cur=nums[<span class="number">0</span>];</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">auto</span> it=nums.begin()+<span class="number">1</span>;it!=nums.end();)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">if</span>(*it==cur)</span><br><span class="line">            &#123;</span><br><span class="line">                it=nums.erase(it);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">else</span></span><br><span class="line">            &#123;</span><br><span class="line">                cur=*it;</span><br><span class="line">                it++;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> nums.size();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h1 id="27-Remove-Element"><a href="#27-Remove-Element" class="headerlink" title="27. Remove Element"></a>27. Remove Element</h1><p>2019/5/31，易。</p><p>删除数组中指定元素，很简单的一道题，可以用vector的erase方法来删除，但联想到上一题，觉得题目要求应该只需要将非指定值的元素放在数组前面部分即可，所以最后写出的代码也没删除，只是替换了一下。</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">removeElement</span><span class="params">(<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&amp; nums, <span class="keyword">int</span> val)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(nums.size()==<span class="number">0</span>)</span><br><span class="line">            <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">int</span> end=nums.size()<span class="number">-1</span>;</span><br><span class="line">        <span class="keyword">while</span>(end&gt;=<span class="number">0</span>&amp;&amp;nums[end]==val)</span><br><span class="line">            end--;</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>;i&lt;end;i++)&#123;</span><br><span class="line">            <span class="keyword">if</span>(nums[i]==val)</span><br><span class="line">            &#123;</span><br><span class="line">                <span class="keyword">int</span> tmp=nums[i];</span><br><span class="line">                nums[i]=nums[end];</span><br><span class="line">                nums[end]=tmp;</span><br><span class="line">                <span class="keyword">while</span>(end&gt;=<span class="number">0</span>&amp;&amp;nums[end]==val)</span><br><span class="line">                    end--;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> end+<span class="number">1</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>正常AC了，后来看别人的提交，其实连替换都不用，若有指定数字直接覆盖就行了，不过大同小异，不去深究。</p><h1 id="28-Implement-strStr"><a href="#28-Implement-strStr" class="headerlink" title="28. Implement strStr()"></a>28. Implement strStr()</h1><p>2019/6/1，易。</p><p>判断是否是子串，由于这道题难度是简单，所以用最简单的遍历查找即可，至于KMP算法可以参见另一篇文章《剑指Offer+常用手写算法(C++)》。</p><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></pre></td><td class="code"><pre><span class="line"><span class="comment">//最简单的遍历比较法</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">strStr</span><span class="params">(<span class="built_in">string</span> haystack, <span class="built_in">string</span> needle)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">int</span> m=haystack.size(),n=needle.size();</span><br><span class="line">        <span class="keyword">if</span>(!n)</span><br><span class="line">            <span class="keyword">return</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">0</span>;i&lt;m-n+<span class="number">1</span>;i++)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">int</span> j=<span class="number">0</span>;</span><br><span class="line">            <span class="keyword">for</span>(;j&lt;n;j++)</span><br><span class="line">            &#123;</span><br><span class="line">                <span class="keyword">if</span>(haystack[i+j]!=needle[j])</span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span>(j==n)</span><br><span class="line">                <span class="keyword">return</span> i;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h1 id="29-Divide-Two-Integers-again"><a href="#29-Divide-Two-Integers-again" class="headerlink" title="29. Divide Two Integers(again)"></a>29. Divide Two Integers(again)</h1><p>2019/6/3，中。</p><p>不用乘法、除法以及模运算完成两个整数的除法，主要想法是使用移位运算，每次双倍，再做操作和累加，代码如下：</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">divide</span><span class="params">(<span class="keyword">int</span> dividend, <span class="keyword">int</span> divisor)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(divisor==<span class="number">0</span>||(dividend == INT_MIN &amp;&amp; divisor == <span class="number">-1</span>))</span><br><span class="line">            <span class="keyword">return</span> INT_MAX;</span><br><span class="line">        <span class="keyword">if</span>(divisor==<span class="number">1</span>)</span><br><span class="line">            <span class="keyword">return</span> dividend;</span><br><span class="line">        <span class="keyword">int</span> sign = ((dividend &lt; <span class="number">0</span>) ^ (divisor &lt; <span class="number">0</span>)) ? <span class="number">-1</span> : <span class="number">1</span> ;</span><br><span class="line">        <span class="keyword">long</span> <span class="keyword">long</span> dvd = <span class="built_in">labs</span>(dividend);</span><br><span class="line">        <span class="keyword">long</span> <span class="keyword">long</span> dvs = <span class="built_in">labs</span>(divisor);</span><br><span class="line">        <span class="keyword">int</span> res = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">while</span>(dvd &gt;= dvs)&#123;</span><br><span class="line">            <span class="keyword">long</span> <span class="keyword">long</span> tmp = dvs , m = <span class="number">1</span>;</span><br><span class="line">            <span class="keyword">while</span> (dvd &gt;= (tmp &lt;&lt; <span class="number">1</span>)) &#123;</span><br><span class="line">                tmp &lt;&lt;= <span class="number">1</span>;</span><br><span class="line">                m &lt;&lt;= <span class="number">1</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            dvd -= tmp;</span><br><span class="line">            res += m;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> sign==<span class="number">1</span> ? res : -res;</span><br><span class="line">        </span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h1 id="30-Substring-with-Concatenation-of-All-Words（again）"><a href="#30-Substring-with-Concatenation-of-All-Words（again）" class="headerlink" title="30. Substring with Concatenation of All Words（again）"></a>30. Substring with Concatenation of All Words（again）</h1><p>2019/6/5，难。</p><p>有点难度的一道题，不过基本方法很好想，就依次遍历n*len的子串，针对每个子串进行验证是否成立，代码如下：</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt; findSubstring(<span class="built_in">string</span> s, <span class="built_in">vector</span>&lt;<span class="built_in">string</span>&gt;&amp; words) &#123;</span><br><span class="line">        <span class="comment">//主要步骤，先找出所有n*len长度的子串，再一一验证</span></span><br><span class="line">        <span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt; res;</span><br><span class="line">        <span class="keyword">if</span>(s==<span class="string">""</span>||words.size()==<span class="number">0</span>)</span><br><span class="line">            <span class="keyword">return</span> res;</span><br><span class="line">        <span class="keyword">int</span> len=<span class="number">0</span>;</span><br><span class="line">        <span class="keyword">if</span>(words.size()&gt;<span class="number">0</span>)</span><br><span class="line">            len=words[<span class="number">0</span>].size();</span><br><span class="line">        <span class="keyword">int</span> lenOfSubstr=len*words.size();</span><br><span class="line">        <span class="keyword">if</span>(s.size()&lt;lenOfSubstr)</span><br><span class="line">            <span class="keyword">return</span> res;</span><br><span class="line">        <span class="built_in">unordered_map</span>&lt;<span class="built_in">string</span>, <span class="keyword">int</span>&gt; wordCnt;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">auto</span> &amp;word : words) </span><br><span class="line">            ++wordCnt[word];</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>;i&lt;=s.size()-lenOfSubstr;i++)&#123;</span><br><span class="line">            <span class="built_in">unordered_map</span>&lt;<span class="built_in">string</span>, <span class="keyword">int</span>&gt; strCnt;</span><br><span class="line">            <span class="keyword">int</span> j = <span class="number">0</span>; </span><br><span class="line">            <span class="keyword">for</span> (j = <span class="number">0</span>; j &lt; words.size(); ++j) &#123;</span><br><span class="line">                <span class="built_in">string</span> t = s.substr(i + j * len, len);</span><br><span class="line">                <span class="keyword">if</span> (!wordCnt.count(t)) <span class="keyword">break</span>;</span><br><span class="line">                ++strCnt[t];</span><br><span class="line">                <span class="keyword">if</span> (strCnt[t] &gt; wordCnt[t]) <span class="keyword">break</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (j == words.size()) </span><br><span class="line">                res.push_back(i);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>能够通过，只是效率比较低，看网上还有一种利用滑动窗口的方法，能够提高效率，可以百度看看。</p><h1 id="31-Next-Permutation"><a href="#31-Next-Permutation" class="headerlink" title="31. Next Permutation"></a>31. Next Permutation</h1><p>2019/6/10，中。</p><p>求字符数组按照字典序的下一个排列。</p><p>研究了几个排列后发现了一些规律，写出如下代码：</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">nextPermutation</span><span class="params">(<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&amp; nums)</span> </span>&#123;</span><br><span class="line">        <span class="comment">//尝试思路：从右往左找第一个逆序对（idx1,idx2），交换位置，对idx1后面的数字重新排序，若没有逆序对则说明是最后一个排列，返回第一个排序即可</span></span><br><span class="line">        <span class="keyword">if</span>(nums.size()&lt;=<span class="number">1</span>)</span><br><span class="line">            <span class="keyword">return</span> ;</span><br><span class="line">        <span class="comment">//1 从右往左找第一个逆序对</span></span><br><span class="line">        <span class="keyword">int</span> idx1=<span class="number">-1</span>,idx2=<span class="number">-1</span>;</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i=nums.size()<span class="number">-1</span>;i&gt;=<span class="number">1</span>;i--)&#123;</span><br><span class="line">            <span class="keyword">if</span>(nums[i]&gt;nums[i<span class="number">-1</span>])</span><br><span class="line">            &#123;</span><br><span class="line">                idx1=i<span class="number">-1</span>;</span><br><span class="line">                idx2=i;</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//2 往右寻找比该数大的最小值</span></span><br><span class="line">        <span class="keyword">if</span>(idx1!=<span class="number">-1</span>)&#123;</span><br><span class="line">            <span class="keyword">for</span>(<span class="keyword">int</span> j=idx1+<span class="number">1</span>;j&lt;nums.size();j++)&#123;</span><br><span class="line">                <span class="keyword">if</span>(nums[j]&gt;nums[idx1]&amp;&amp;nums[j]&lt;nums[idx2])</span><br><span class="line">                    idx2=j;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//3 交换排序或者直接排序</span></span><br><span class="line">        <span class="keyword">if</span>(idx1!=<span class="number">-1</span>)&#123;</span><br><span class="line">            <span class="keyword">int</span> tmp=nums[idx1];</span><br><span class="line">            nums[idx1]=nums[idx2];</span><br><span class="line">            nums[idx2]=tmp;</span><br><span class="line">            sort(nums.begin()+idx1+<span class="number">1</span>,nums.end());</span><br><span class="line">        &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">            sort(nums.begin(),nums.end());</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>提交通过了。</p><p>当然，C++本身还有一个<code>next_permutation</code>函数，直接用的话本题也能通过：</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">nextPermutation</span><span class="params">(<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&amp; nums)</span> </span>&#123;</span><br><span class="line">        next_permutation( nums.begin(), nums.end() ); </span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h1 id="32-Longest-Valid-Parentheses（again）"><a href="#32-Longest-Valid-Parentheses（again）" class="headerlink" title="32. Longest Valid Parentheses（again）"></a>32. Longest Valid Parentheses（again）</h1><p>2019/6/13，难。</p><p>求最长有效括号子串，一开始就想到应该用动态规划或者栈的方法来做，但自己编程水平还是太菜，写了半天没写出来，看了网上的解答后觉得自己很蠢，虽然难度是难，但本题其实感觉并不难，给出代码吧，头疼。</p><p>不过这题有个技巧，栈的话会先在栈里放一个-1，动态规划的话则会在原字符串前加一个<code>)</code>，都是为了使处理更加方便，可能这就是自己没想到的地方吧，值得重视。</p><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></pre></td><td class="code"><pre><span class="line"><span class="comment">//栈</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">longestValidParentheses</span><span class="params">(<span class="built_in">string</span> s)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(s.length() == <span class="number">0</span>)</span><br><span class="line">            <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">int</span> res = <span class="number">0</span>;</span><br><span class="line">        <span class="built_in">stack</span>&lt;<span class="keyword">int</span>&gt; st;</span><br><span class="line">        st.push(<span class="number">-1</span>);</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>; i&lt;s.length(); ++i)&#123;</span><br><span class="line">            <span class="keyword">if</span>(s[i] == <span class="string">'('</span>)&#123;</span><br><span class="line">                st.push(i);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">else</span>&#123;</span><br><span class="line">                st.pop();</span><br><span class="line">                <span class="keyword">if</span>(!st.empty())&#123;</span><br><span class="line">                    res = max(res, i-st.top());</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">else</span>&#123;</span><br><span class="line">                    st.push(i);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="comment">//dp</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">longestValidParentheses</span><span class="params">(<span class="built_in">string</span> s)</span> </span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">int</span> result=<span class="number">0</span>;</span><br><span class="line">        s=<span class="string">')'</span>+s;</span><br><span class="line">        <span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt; dp(s.length(),<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&lt;s.length();i++)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">if</span>(s[i]==<span class="string">')'</span>)</span><br><span class="line">            &#123;</span><br><span class="line">                <span class="keyword">if</span>(s[i<span class="number">-1</span>-dp[i<span class="number">-1</span>]]==<span class="string">'('</span>) dp[i]=dp[i<span class="number">-1</span>]+<span class="number">2</span>;<span class="comment">//累加本次的长度</span></span><br><span class="line">                dp[i]+=dp[i-dp[i]];<span class="comment">//和前面已经计算过的长度再做一次累加得到最后的数字</span></span><br><span class="line">            &#125;</span><br><span class="line">            result=max(result,dp[i]);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> result;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h1 id="33-Search-in-Rotated-Sorted-Array-again"><a href="#33-Search-in-Rotated-Sorted-Array-again" class="headerlink" title="33. Search in Rotated Sorted Array(again)"></a>33. Search in Rotated Sorted Array(again)</h1><p>2019/6/21，中。</p><p>这两天奔波找房子参加毕业典礼啥的就没刷题，这道题之前做过类似的，主要使用二分法，并且在排除的过程中注意根据有序的部分数组来进行判断，以便决定去除左右哪一部分无效数据。</p><p>代码如下：</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">search</span><span class="params">(<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&amp; nums, <span class="keyword">int</span> target)</span> </span>&#123;</span><br><span class="line">        <span class="comment">//使用二分法</span></span><br><span class="line">        <span class="keyword">if</span>(nums.empty())</span><br><span class="line">            <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">int</span> left=<span class="number">0</span>;</span><br><span class="line">        <span class="keyword">int</span> right=nums.size()<span class="number">-1</span>;</span><br><span class="line">        <span class="keyword">int</span> mid=<span class="number">0</span>;</span><br><span class="line">        <span class="keyword">while</span>(left&lt;=right)</span><br><span class="line">        &#123;</span><br><span class="line">            mid=left+((right-left)&gt;&gt;<span class="number">1</span>);</span><br><span class="line">            <span class="keyword">if</span>(nums[mid]==target)</span><br><span class="line">                <span class="keyword">return</span> mid;</span><br><span class="line">            </span><br><span class="line">            <span class="keyword">if</span>(nums[left]&lt;=nums[mid])</span><br><span class="line">            &#123;</span><br><span class="line">                <span class="keyword">if</span>(target&gt;=nums[left]&amp;&amp;target&lt;nums[mid])</span><br><span class="line">                    right=mid<span class="number">-1</span>;</span><br><span class="line">                <span class="keyword">else</span></span><br><span class="line">                    left=mid+<span class="number">1</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">else</span></span><br><span class="line">            &#123;</span><br><span class="line">                <span class="keyword">if</span>(target&gt;nums[mid]&amp;&amp;target&lt;=nums[right])</span><br><span class="line">                    left=mid+<span class="number">1</span>;</span><br><span class="line">                <span class="keyword">else</span></span><br><span class="line">                    right=mid<span class="number">-1</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h1 id="34-Find-First-and-Last-Position-of-Element-in-Sorted-Array"><a href="#34-Find-First-and-Last-Position-of-Element-in-Sorted-Array" class="headerlink" title="34. Find First and Last Position of Element in Sorted Array"></a>34. Find First and Last Position of Element in Sorted Array</h1><p>2019/6/26，中。</p><p>《剑指Offer》上有类似的题，又复习了一遍，提交的时候发现之前在LeetCode上做过这道题，用的是比较笨的办法，但在LeetCode上的执行效率却比递归方法高，有点意思，给出下面两种代码，核心思想仍然是二分。</p><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></pre></td><td class="code"><pre><span class="line"><span class="comment">//普通方法</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt; searchRange(<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&amp; nums, <span class="keyword">int</span> target) &#123;</span><br><span class="line">        <span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt; res=&#123;<span class="number">-1</span>,<span class="number">-1</span>&#125;;</span><br><span class="line">        <span class="keyword">if</span>(nums.empty())</span><br><span class="line">            <span class="keyword">return</span> res;</span><br><span class="line">        <span class="keyword">int</span> left=<span class="number">0</span>;</span><br><span class="line">        <span class="keyword">int</span> right=nums.size()<span class="number">-1</span>;</span><br><span class="line">        <span class="keyword">int</span> mid=<span class="number">0</span>;</span><br><span class="line">        <span class="keyword">while</span>(left&lt;=right)</span><br><span class="line">        &#123;</span><br><span class="line">            mid=left+((right-left)&gt;&gt;<span class="number">1</span>);</span><br><span class="line">            <span class="keyword">if</span>(nums[mid]&lt;target)</span><br><span class="line">                left=mid+<span class="number">1</span>;</span><br><span class="line">            <span class="keyword">else</span> <span class="keyword">if</span>(nums[mid]&gt;target)</span><br><span class="line">                right=mid<span class="number">-1</span>;</span><br><span class="line">            <span class="keyword">else</span></span><br><span class="line">            &#123;</span><br><span class="line">                <span class="keyword">int</span> i=mid,j=mid;</span><br><span class="line">                <span class="keyword">while</span>(i&gt;=<span class="number">0</span>&amp;&amp;nums[i]==target)</span><br><span class="line">                    i--;</span><br><span class="line">                <span class="keyword">while</span>(j&lt;nums.size()&amp;&amp;nums[j]==target)</span><br><span class="line">                    j++;</span><br><span class="line">                res[<span class="number">0</span>]=i+<span class="number">1</span>;</span><br><span class="line">                res[<span class="number">1</span>]=j<span class="number">-1</span>;</span><br><span class="line">                <span class="keyword">return</span> res;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="comment">//递归方法</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt; searchRange(<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&amp; nums, <span class="keyword">int</span> target) &#123;</span><br><span class="line">        <span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt; res(<span class="number">2</span>,<span class="number">-1</span>);</span><br><span class="line">        <span class="keyword">if</span>(nums.size()&lt;=<span class="number">0</span>)</span><br><span class="line">            <span class="keyword">return</span> res;</span><br><span class="line">        <span class="comment">//利用递归</span></span><br><span class="line">        res[<span class="number">0</span>]=getFirst(nums,<span class="number">0</span>,nums.size()<span class="number">-1</span>,target);</span><br><span class="line">        res[<span class="number">1</span>]=getLast(nums,<span class="number">0</span>,nums.size()<span class="number">-1</span>,target);</span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">getFirst</span><span class="params">(<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&amp; nums, <span class="keyword">int</span> left, <span class="keyword">int</span> right,<span class="keyword">int</span> target)</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(left&gt;right)</span><br><span class="line">            <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">        <span class="keyword">int</span> mid=left+((right-left)&gt;&gt;<span class="number">1</span>);</span><br><span class="line">        <span class="keyword">if</span>(nums[mid]==target)&#123;</span><br><span class="line">            <span class="keyword">if</span>(mid==<span class="number">0</span>||(mid&gt;<span class="number">0</span>&amp;&amp;nums[mid<span class="number">-1</span>]!=target))</span><br><span class="line">                <span class="keyword">return</span> mid;</span><br><span class="line">            <span class="keyword">else</span></span><br><span class="line">                right=mid<span class="number">-1</span>;</span><br><span class="line">        &#125;<span class="keyword">else</span> <span class="keyword">if</span>(nums[mid]&lt;target)</span><br><span class="line">            left=mid+<span class="number">1</span>;</span><br><span class="line">        <span class="keyword">else</span></span><br><span class="line">            right=mid<span class="number">-1</span>;</span><br><span class="line">        <span class="keyword">return</span> getFirst(nums,left,right,target);</span><br><span class="line">        </span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">getLast</span><span class="params">(<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&amp; nums, <span class="keyword">int</span> left, <span class="keyword">int</span> right,<span class="keyword">int</span> target)</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(left&gt;right)</span><br><span class="line">            <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">        <span class="keyword">int</span> mid=left+((right-left)&gt;&gt;<span class="number">1</span>);</span><br><span class="line">        <span class="keyword">if</span>(nums[mid]==target)&#123;</span><br><span class="line">            <span class="keyword">if</span>((mid&lt;nums.size()<span class="number">-1</span>&amp;&amp;nums[mid+<span class="number">1</span>]!=target)||mid==nums.size()<span class="number">-1</span>)</span><br><span class="line">                <span class="keyword">return</span> mid;</span><br><span class="line">            <span class="keyword">else</span></span><br><span class="line">                left=mid+<span class="number">1</span>;</span><br><span class="line">        &#125;<span class="keyword">else</span> <span class="keyword">if</span>(nums[mid]&lt;target)</span><br><span class="line">            left=mid+<span class="number">1</span>;</span><br><span class="line">        <span class="keyword">else</span></span><br><span class="line">            right=mid<span class="number">-1</span>;</span><br><span class="line">        <span class="keyword">return</span> getLast(nums,left,right,target);        </span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h1 id="35-Search-Insert-Position"><a href="#35-Search-Insert-Position" class="headerlink" title="35. Search Insert Position"></a>35. Search Insert Position</h1><p>2019/7/6，易。</p><p>本题相对简单，写的时候也一次通过了，代码如下：</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">searchInsert</span><span class="params">(<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&amp; nums, <span class="keyword">int</span> target)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(nums.size() &lt;= <span class="number">0</span>)&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">int</span> left = <span class="number">0</span>, right = nums.size()<span class="number">-1</span>;</span><br><span class="line">        <span class="keyword">int</span> res = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">while</span>(left&lt;=right)&#123;</span><br><span class="line">            <span class="keyword">int</span> mid = left + ((right - left) &gt;&gt; <span class="number">1</span>);</span><br><span class="line">            <span class="keyword">if</span>(nums[mid] == target)</span><br><span class="line">                <span class="keyword">return</span> mid;</span><br><span class="line">            <span class="comment">//不等</span></span><br><span class="line">            <span class="keyword">if</span>(mid == <span class="number">0</span> &amp;&amp; nums[mid] &gt; target)</span><br><span class="line">                <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">            <span class="keyword">if</span>(mid == nums.size()<span class="number">-1</span> &amp;&amp; nums[mid] &lt; target)</span><br><span class="line">                <span class="keyword">return</span> nums.size();</span><br><span class="line">            <span class="keyword">if</span>(nums[mid] &gt; target &amp;&amp; nums[mid<span class="number">-1</span>] &lt; target)</span><br><span class="line">                <span class="keyword">return</span> mid;</span><br><span class="line">            <span class="keyword">if</span>(nums[mid] &lt; target &amp;&amp; nums[mid+<span class="number">1</span>] &gt; target)</span><br><span class="line">                <span class="keyword">return</span> mid+<span class="number">1</span>;</span><br><span class="line">            </span><br><span class="line">            <span class="keyword">if</span>(nums[mid] &lt; target)</span><br><span class="line">                left = mid + <span class="number">1</span>;</span><br><span class="line">            <span class="keyword">if</span>(nums[mid] &gt; target)</span><br><span class="line">                right = mid - <span class="number">1</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>但是后来看别人提交的代码的时候发现自己又把问题复杂化了，根本就不是二分查找的变种，而是最基本的二分法！要说变化也就是最后返回的值变成了left！还是对问题的理解程度太弱了，所谓寻找插入的下标，说白了原来就是返回left就行了，试验几次就会看出这个规律了，代码如下：</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">searchInsert</span><span class="params">(<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&amp; nums, <span class="keyword">int</span> target)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">int</span> l = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">int</span> r = nums.size()<span class="number">-1</span>;</span><br><span class="line">        <span class="keyword">while</span> (l &lt;= r) &#123;</span><br><span class="line">            <span class="keyword">int</span> middle = (l + r) / <span class="number">2</span>;</span><br><span class="line">            <span class="keyword">if</span> (nums[middle] &gt; target) r = middle - <span class="number">1</span>;</span><br><span class="line">            <span class="keyword">else</span> <span class="keyword">if</span> (nums[middle] &lt; target) l = middle + <span class="number">1</span>;</span><br><span class="line">            <span class="keyword">else</span> <span class="keyword">return</span> middle;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> l;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h1 id="36-Valid-Sudoku"><a href="#36-Valid-Sudoku" class="headerlink" title="36. Valid Sudoku"></a>36. Valid Sudoku</h1><p>2019/7/7，中。</p><p>这道题我还记得之前第一次做的时候以为要把整个数独都填完呢，后来发现自己还是把问题复杂化了（似乎我的思维有这个毛病，得改），本题的意思其实只是判断input里每一行每一列每个九宫格有没有重复数字而已，并不用填充整个数独。</p><p>所以最简单的办法就是遍历判断好了，代码如下：</p><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">bool</span> <span class="title">isValidSudoku</span><span class="params">(<span class="built_in">vector</span>&lt;<span class="built_in">vector</span>&lt;<span class="keyword">char</span>&gt;&gt;&amp; board)</span> </span>&#123;</span><br><span class="line">        <span class="comment">//即检查每一行每一列每一个九宫格内是否有重复数字</span></span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">9</span>; i ++)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="built_in">unordered_map</span>&lt;<span class="keyword">char</span>, <span class="keyword">bool</span>&gt; m1;   <span class="comment">//负责检查行</span></span><br><span class="line">            <span class="built_in">unordered_map</span>&lt;<span class="keyword">char</span>, <span class="keyword">bool</span>&gt; m2;   <span class="comment">//负责检查列</span></span><br><span class="line">            <span class="built_in">unordered_map</span>&lt;<span class="keyword">char</span>, <span class="keyword">bool</span>&gt; m3;   <span class="comment">//负责检查九宫格</span></span><br><span class="line">            <span class="keyword">for</span>(<span class="keyword">int</span> j = <span class="number">0</span>; j &lt; <span class="number">9</span>; j ++)</span><br><span class="line">            &#123;</span><br><span class="line">                <span class="comment">//分别检查第i行，第i列，第i个九宫格中的九个数，j表示第j个数</span></span><br><span class="line">                </span><br><span class="line">                <span class="comment">//每一行的坐标，不需要转换</span></span><br><span class="line">                <span class="keyword">if</span>(board[i][j] != <span class="string">'.'</span>)</span><br><span class="line">                &#123;</span><br><span class="line">                    <span class="keyword">if</span>(m1[board[i][j]] == <span class="literal">true</span>)</span><br><span class="line">                        <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">                    m1[board[i][j]] = <span class="literal">true</span>;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="comment">//每一列的坐标，横纵坐标互换即可</span></span><br><span class="line">                <span class="keyword">if</span>(board[j][i] != <span class="string">'.'</span>)</span><br><span class="line">                &#123;</span><br><span class="line">                    <span class="keyword">if</span>(m2[board[j][i]] == <span class="literal">true</span>)</span><br><span class="line">                        <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">                    m2[board[j][i]] = <span class="literal">true</span>;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="comment">//九宫格内坐标转换</span></span><br><span class="line">                <span class="keyword">if</span>(board[i/<span class="number">3</span>*<span class="number">3</span>+j/<span class="number">3</span>][i%<span class="number">3</span>*<span class="number">3</span>+j%<span class="number">3</span>] != <span class="string">'.'</span>)</span><br><span class="line">                &#123;</span><br><span class="line">                    <span class="keyword">if</span>(m3[board[i/<span class="number">3</span>*<span class="number">3</span>+j/<span class="number">3</span>][i%<span class="number">3</span>*<span class="number">3</span>+j%<span class="number">3</span>]] == <span class="literal">true</span>)</span><br><span class="line">                        <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">                    m3[board[i/<span class="number">3</span>*<span class="number">3</span>+j/<span class="number">3</span>][i%<span class="number">3</span>*<span class="number">3</span>+j%<span class="number">3</span>]] = <span class="literal">true</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>查看别人的代码后发现有很精简的代码，但逻辑内核不变，这里也就不贴了。</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;想养成刷题的习惯，之前刷过一点，但校招之后就断了，现在想捡起来，定个小目标，从头开始刷题吧，看能坚持多久。&lt;/p&gt;
&lt;h1 id=&quot;1-Two-Sum&quot;&gt;&lt;a href=&quot;#1-Two-Sum&quot; class=&quot;headerlink&quot; title=&quot;1. Two Sum&quot;&gt;&lt;/a&gt;1. Two Sum&lt;/h1&gt;&lt;p&gt;2019/4/16，易。&lt;/p&gt;
&lt;p&gt;这题以前做过，记得第一次做的时候应该是用的最蠢的两重遍历方法相加求解，毫无疑问超时了，隐约记得可以使用查找&lt;code&gt;目标值-某个值&lt;/code&gt;是否存在该vector中来反向求解，简单写了一下，通过了。其实是一个反向思维的题，正面求解超时，则反向来求。仍然属于蛮力法的范畴，n&lt;sup&gt;2&lt;/sup&gt;时间复杂度，1空间复杂度，LeetCode平台耗时136ms。&lt;/p&gt;
&lt;p&gt;尝试降低时间复杂度，想到以空间换时间，在查找&lt;code&gt;目标值-某个值&lt;/code&gt;的时候，上述蛮力法使用&lt;code&gt;std::find&lt;/code&gt;方法，说白了也是一层遍历，这层遍历目的是为了查找差值是否存在于vector中并返回下标，自然可以想到用哈希表来代替这一层遍历。当然，事先需要遍历一次原数组构建哈希表。如此时间复杂度n，空间复杂度n。&lt;/p&gt;
    
    </summary>
    
      <category term="职业学习" scheme="http://yoursite.com/categories/%E8%81%8C%E4%B8%9A%E5%AD%A6%E4%B9%A0/"/>
    
    
      <category term="C++" scheme="http://yoursite.com/tags/C/"/>
    
      <category term="刷题" scheme="http://yoursite.com/tags/%E5%88%B7%E9%A2%98/"/>
    
  </entry>
  
</feed>
