<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>xbsNotes</title>
  
  
  <link href="/atom.xml" rel="self"/>
  
  <link href="https://chrisxb1996.github.io/"/>
  <updated>2020-07-17T10:42:19.178Z</updated>
  <id>https://chrisxb1996.github.io/</id>
  
  <author>
    <name>xNotes</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>剑指offer-困难篇</title>
    <link href="https://chrisxb1996.github.io/2020/07/16/%E5%89%91%E6%8C%87offer/%E5%89%91%E6%8C%87offer-%E5%9B%B0%E9%9A%BE%E7%AF%87/"/>
    <id>https://chrisxb1996.github.io/2020/07/16/%E5%89%91%E6%8C%87offer/%E5%89%91%E6%8C%87offer-%E5%9B%B0%E9%9A%BE%E7%AF%87/</id>
    <published>2020-07-16T11:59:35.000Z</published>
    <updated>2020-07-17T10:42:19.178Z</updated>
    
    <content type="html"><![CDATA[<h4 id="对称的二叉树"><a href="#对称的二叉树" class="headerlink" title="对称的二叉树"></a>对称的二叉树</h4><p><strong>题目描述：</strong>叉树同此二叉树的镜像是同样的，定义其为对称的。</p><p><u>思路</u>：递归，编写方法，判断以两根节点的二叉树是否对称<a id="more"></a></p><figure class="highlight java"><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"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Solution</span> </span>&#123;</span><br><span class="line">  <span class="function"><span class="keyword">boolean</span> <span class="title">isSymmetrical</span><span class="params">(TreeNode pRoot)</span></span>&#123;</span><br><span class="line">    <span class="keyword">if</span>(pRoot == <span class="keyword">null</span>) <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    <span class="keyword">return</span> isSymmetrical(pRoot.left, pRoot.right);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">boolean</span> <span class="title">isSymmetrical</span><span class="params">(TreeNode node1, TreeNode node2)</span></span>&#123;</span><br><span class="line">    <span class="keyword">if</span>(node1 == <span class="keyword">null</span> &amp;&amp; node2 == <span class="keyword">null</span>) <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    <span class="keyword">if</span>(node1 == <span class="keyword">null</span> || node2 == <span class="keyword">null</span>) <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">    <span class="keyword">if</span>(node1.val != node2.val) <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">    <span class="keyword">return</span> isSymmetrical(node1.left, node2.right) &amp;&amp; isSymmetrical(node1.right, node2.left);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="数组中的逆序对"><a href="#数组中的逆序对" class="headerlink" title="数组中的逆序对"></a>数组中的逆序对</h4><p><strong>题目描述：</strong>在数组中的两个数字，如果前面一个数字大于后面的数字，则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007</p><p><u>思路</u>：</p><ol><li>穷举：超时；</li><li></li></ol><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">InversePairs</span><span class="params">(<span class="keyword">int</span> [] array)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">int</span> count = <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; array.length;i++)&#123;</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">if</span>(array[j] &gt; array[i])&#123;</span><br><span class="line">        count++;</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> count%<span class="number">1000000007</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight java"><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"></span><br><span class="line"></span><br></pre></td></tr></table></figure><br><br><h4 id="从上往下打印二叉树"><a href="#从上往下打印二叉树" class="headerlink" title="从上往下打印二叉树"></a>从上往下打印二叉树</h4><p><strong>题目描述：</strong>从上往下打印出二叉树的每个节点，同层节点从左至右打印。 </p><p><u>思路</u>：二叉树层次遍历，利用队列</p><figure class="highlight java"><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="function"><span class="keyword">public</span> ArrayList&lt;Integer&gt; <span class="title">PrintFromTopToBottom</span><span class="params">(TreeNode root)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">if</span>(root == <span class="keyword">null</span>) <span class="keyword">return</span> <span class="keyword">new</span> ArrayList&lt;Integer&gt;();</span><br><span class="line">  ArrayList&lt;Integer&gt; res = <span class="keyword">new</span> ArrayList&lt;Integer&gt;();</span><br><span class="line">  Queue&lt;TreeNode&gt; queue = <span class="keyword">new</span> LinkedList&lt;&gt;();</span><br><span class="line">  </span><br><span class="line">  queue.add(root);</span><br><span class="line">  <span class="keyword">while</span>(!queue.isEmpty())&#123;</span><br><span class="line">    <span class="keyword">int</span> n = queue.size();</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">      TreeNode node = queue.poll();</span><br><span class="line">      res.add(node.val);</span><br><span class="line">      <span class="keyword">if</span>(node.left != <span class="keyword">null</span>) queue.add(node.left);</span><br><span class="line">      <span class="keyword">if</span>(node.right != <span class="keyword">null</span>) queue.add(node.right);</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></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      &lt;h4 id=&quot;对称的二叉树&quot;&gt;&lt;a href=&quot;#对称的二叉树&quot; class=&quot;headerlink&quot; title=&quot;对称的二叉树&quot;&gt;&lt;/a&gt;对称的二叉树&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;题目描述：&lt;/strong&gt;叉树同此二叉树的镜像是同样的，定义其为对称的。&lt;/p&gt;
&lt;p&gt;&lt;u&gt;思路&lt;/u&gt;：递归，编写方法，判断以两根节点的二叉树是否对称&lt;/p&gt;
    
    </summary>
    
    
      <category term="剑指offer" scheme="https://chrisxb1996.github.io/categories/%E5%89%91%E6%8C%87offer/"/>
    
      <category term="数据结构和算法" scheme="https://chrisxb1996.github.io/categories/%E5%89%91%E6%8C%87offer/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/"/>
    
    
      <category term="数据结构和算法" scheme="https://chrisxb1996.github.io/tags/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/"/>
    
      <category term="剑指offer" scheme="https://chrisxb1996.github.io/tags/%E5%89%91%E6%8C%87offer/"/>
    
  </entry>
  
  <entry>
    <title>mysql数据库</title>
    <link href="https://chrisxb1996.github.io/2020/06/26/mysql%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
    <id>https://chrisxb1996.github.io/2020/06/26/mysql%E6%95%B0%E6%8D%AE%E5%BA%93/</id>
    <published>2020-06-26T03:43:06.000Z</published>
    <updated>2020-06-28T09:15:02.446Z</updated>
    
    <content type="html"><![CDATA[<h3 id="登录和退出MySQL服务器"><a href="#登录和退出MySQL服务器" class="headerlink" title="登录和退出MySQL服务器"></a>登录和退出MySQL服务器</h3><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">mysql -uroot -p12345612;</span><br><span class="line">#退出</span><br><span class="line">exit;</span><br></pre></td></tr></table></figure><br><p><br><a id="more"></a></p><h3 id="增删改查基本语法"><a href="#增删改查基本语法" class="headerlink" title="增删改查基本语法"></a>增删改查基本语法</h3><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></pre></td><td class="code"><pre><span class="line">-- 显示所有数据库</span><br><span class="line">show databases;</span><br><span class="line"></span><br><span class="line">-- 创建数据库</span><br><span class="line">CREATE DATABASE test;</span><br><span class="line"></span><br><span class="line">-- 切换数据库</span><br><span class="line">use test;</span><br><span class="line"></span><br><span class="line">-- 显示数据库中的所有表</span><br><span class="line">show tables;</span><br><span class="line"></span><br><span class="line">-- 创建数据表</span><br><span class="line">CREATE TABLE pet (</span><br><span class="line">    name VARCHAR(20),</span><br><span class="line">    owner VARCHAR(20),</span><br><span class="line">    species VARCHAR(20),</span><br><span class="line">    sex CHAR(1),</span><br><span class="line">    birth DATE,</span><br><span class="line">    death DATE</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line">-- 查看数据表结构</span><br><span class="line">-- describe pet;</span><br><span class="line">desc pet;</span><br><span class="line"></span><br><span class="line">-- 查询表</span><br><span class="line">SELECT * from pet;</span><br><span class="line"></span><br><span class="line">-- 插入数据</span><br><span class="line">INSERT INTO pet VALUES (&#39;puffball&#39;, &#39;Diane&#39;, &#39;hamster&#39;, &#39;f&#39;, &#39;1990-03-30&#39;, NULL);</span><br><span class="line"></span><br><span class="line">-- 修改数据</span><br><span class="line">UPDATE pet SET name &#x3D; &#39;squirrel&#39; where owner &#x3D; &#39;Diane&#39;;</span><br><span class="line"></span><br><span class="line">-- 删除数据</span><br><span class="line">DELETE FROM pet where name &#x3D; &#39;squirrel&#39;;</span><br><span class="line"></span><br><span class="line">-- 删除表</span><br><span class="line">DROP TABLE myorder;</span><br></pre></td></tr></table></figure><br><br><h3 id="mysql-建表约束"><a href="#mysql-建表约束" class="headerlink" title="mysql 建表约束"></a>mysql 建表约束</h3><h4 id="主键约束："><a href="#主键约束：" class="headerlink" title="主键约束："></a>主键约束：</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br></pre></td><td class="code"><pre><span class="line">-- 主键约束</span><br><span class="line">-- 使某个字段不重复且不得为空，确保表内所有数据的唯一性。</span><br><span class="line">CREATE TABLE user (</span><br><span class="line">    id INT PRIMARY KEY,</span><br><span class="line">    name VARCHAR(20)</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line">mysql&gt; desc user;</span><br><span class="line">+-------+-------------+------+-----+---------+-------+</span><br><span class="line">| Field | Type        | Null | Key | Default | Extra |</span><br><span class="line">+-------+-------------+------+-----+---------+-------+</span><br><span class="line">| id    | int(11)     | NO   | PRI | NULL    |       |</span><br><span class="line">| name  | varchar(20) | YES  |     | NULL    |       |</span><br><span class="line">+-------+-------------+------+-----+---------+-------+</span><br><span class="line"></span><br><span class="line">-- 联合主键</span><br><span class="line">-- 联合主键中的每个字段都不能为空，并且*加起来*不能和已设置的联合主键重复即可。</span><br><span class="line">CREATE TABLE user2 (</span><br><span class="line">    id INT,</span><br><span class="line">    name VARCHAR(20),</span><br><span class="line">    password VARCHAR(20),</span><br><span class="line">    PRIMARY KEY(id, name)</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line">mysql&gt; desc user2;</span><br><span class="line">+----------+-------------+------+-----+---------+-------+</span><br><span class="line">| Field    | Type        | Null | Key | Default | Extra |</span><br><span class="line">+----------+-------------+------+-----+---------+-------+</span><br><span class="line">| id       | int(11)     | NO   | PRI | NULL    |       |</span><br><span class="line">| name     | varchar(20) | NO   | PRI | NULL    |       |</span><br><span class="line">| password | varchar(20) | YES  |     | NULL    |       |</span><br><span class="line">+----------+-------------+------+-----+---------+-------+</span><br><span class="line"></span><br><span class="line">-- 自增约束：auto_increment</span><br><span class="line">-- 自增约束的主键由系统自动递增分配。</span><br><span class="line">create table user3(</span><br><span class="line">  id int primary key auto_increment,</span><br><span class="line">  name varchar(20)</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line">mysql&gt; desc user3;</span><br><span class="line">+-------+-------------+------+-----+---------+----------------+</span><br><span class="line">| Field | Type        | Null | Key | Default | Extra          |</span><br><span class="line">+-------+-------------+------+-----+---------+----------------+</span><br><span class="line">| id    | int(11)     | NO   | PRI | NULL    | auto_increment |</span><br><span class="line">| name  | varchar(20) | YES  |     | NULL    |                |</span><br><span class="line">+-------+-------------+------+-----+---------+----------------+</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">insert into user3 (name) values (&#39;zhangsan&#39;);</span><br><span class="line"></span><br><span class="line">mysql&gt; select * from user3;</span><br><span class="line">+----+----------+</span><br><span class="line">| id | name     |</span><br><span class="line">+----+----------+</span><br><span class="line">|  1 | zhangsan |</span><br><span class="line">+----+----------+</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- 添加主键约束</span><br><span class="line">-- 如果忘记设置主键，还可以通过SQL语句设置（两种方式）：</span><br><span class="line">ALTER TABLE user ADD PRIMARY KEY(id);</span><br><span class="line">ALTER TABLE user MODIFY id INT PRIMARY KEY;</span><br><span class="line"></span><br><span class="line">-- 删除主键</span><br><span class="line">ALTER TABLE user drop PRIMARY KEY;</span><br></pre></td></tr></table></figure><br><h4 id="唯一约束："><a href="#唯一约束：" class="headerlink" title="唯一约束："></a>唯一约束：</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">-- 建表时创建唯一字段</span><br><span class="line">CREATE TABLE user5 (</span><br><span class="line">    id INT,</span><br><span class="line">    name VARCHAR(20),</span><br><span class="line">    UNIQUE(name)</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line">#表示(id,name)合在一起不同即可</span><br><span class="line">CREATE TABLE user6 (</span><br><span class="line">    id INT,</span><br><span class="line">    name VARCHAR(20),</span><br><span class="line">    UNIQUE(id,name)</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line">-- 添加唯一约束</span><br><span class="line">-- 如果建表时没有设置唯一约束，还可以通过SQL语句设置（两种方式）：</span><br><span class="line">ALTER TABLE user ADD UNIQUE(name);</span><br><span class="line">ALTER TABLE user MODIFY name VARCHAR(20) UNIQUE;</span><br><span class="line"></span><br><span class="line">-- 删除唯一约束</span><br><span class="line">ALTER TABLE user DROP INDEX name;</span><br></pre></td></tr></table></figure><br><h4 id="非空约束："><a href="#非空约束：" class="headerlink" title="非空约束："></a>非空约束：</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">-- 建表时添加非空约束</span><br><span class="line">-- 约束某个字段不能为空</span><br><span class="line">CREATE TABLE user7 (</span><br><span class="line">    id INT,</span><br><span class="line">    name VARCHAR(20) NOT NULL</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line">mysql&gt; desc user7;</span><br><span class="line">+-------+-------------+------+-----+---------+-------+</span><br><span class="line">| Field | Type        | Null | Key | Default | Extra |</span><br><span class="line">+-------+-------------+------+-----+---------+-------+</span><br><span class="line">| id    | int(11)     | YES  |     | NULL    |       |</span><br><span class="line">| name  | varchar(20) | NO   |     | NULL    |       |</span><br><span class="line">+-------+-------------+------+-----+---------+-------+</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- 移除非空约束</span><br><span class="line">ALTER TABLE user MODIFY name VARCHAR(20);</span><br></pre></td></tr></table></figure><br><h4 id="默认约束："><a href="#默认约束：" class="headerlink" title="默认约束："></a>默认约束：</h4><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></pre></td><td class="code"><pre><span class="line">-- 建表时添加默认约束</span><br><span class="line">-- 约束某个字段的默认值</span><br><span class="line">CREATE TABLE user9 (</span><br><span class="line">    id INT,</span><br><span class="line">    name VARCHAR(20),</span><br><span class="line">    age INT DEFAULT 10</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line">mysql&gt; desc user9;</span><br><span class="line">+-------+-------------+------+-----+---------+-------+</span><br><span class="line">| Field | Type        | Null | Key | Default | Extra |</span><br><span class="line">+-------+-------------+------+-----+---------+-------+</span><br><span class="line">| id    | int(11)     | YES  |     | NULL    |       |</span><br><span class="line">| name  | varchar(20) | YES  |     | NULL    |       |</span><br><span class="line">| age   | int(11)     | YES  |     | 10      |       |</span><br><span class="line">+-------+-------------+------+-----+---------+-------+</span><br></pre></td></tr></table></figure><br><h4 id="外键约束："><a href="#外键约束：" class="headerlink" title="外键约束："></a>外键约束：</h4><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></pre></td><td class="code"><pre><span class="line">-- 外键约束</span><br><span class="line">-- 涉及两个表：主表，副表</span><br><span class="line"></span><br><span class="line">-- 班级表 </span><br><span class="line">create table class(</span><br><span class="line">  id int primary key,</span><br><span class="line">  name varchar(20)</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line">mysql&gt; desc class;</span><br><span class="line">+-------+-------------+------+-----+---------+-------+</span><br><span class="line">| Field | Type        | Null | Key | Default | Extra |</span><br><span class="line">+-------+-------------+------+-----+---------+-------+</span><br><span class="line">| id    | int(11)     | NO   | PRI | NULL    |       |</span><br><span class="line">| name  | varchar(20) | YES  |     | NULL    |       |</span><br><span class="line">+-------+-------------+------+-----+---------+-------+</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- 学生表 </span><br><span class="line">create table student(</span><br><span class="line">  id int primary key,</span><br><span class="line">  name varchar(20),</span><br><span class="line">  -- 这里的 class_id 要和 classes 中的 id 字段相关联</span><br><span class="line">  class_id int,</span><br><span class="line">  -- 表示 class_id 的值必须来自于 classes 中的 id 字段值</span><br><span class="line">  foreign key(class_id) references class(id)</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line">mysql&gt; desc student;</span><br><span class="line">+----------+-------------+------+-----+---------+-------+</span><br><span class="line">| Field    | Type        | Null | Key | Default | Extra |</span><br><span class="line">+----------+-------------+------+-----+---------+-------+</span><br><span class="line">| id       | int(11)     | NO   | PRI | NULL    |       |</span><br><span class="line">| name     | varchar(20) | YES  |     | NULL    |       |</span><br><span class="line">| class_id | int(11)     | YES  | MUL | NULL    |       |</span><br><span class="line">+----------+-------------+------+-----+---------+-------+</span><br><span class="line">-- 注意：</span><br><span class="line">-- 1.主表（class）中没有的数据值，在副表（student）中不能使用；</span><br><span class="line">-- 2.主表中的记录被副表引用，不不可以删除的；</span><br></pre></td></tr></table></figure><br><br><h3 id="数据表设计-三大范式"><a href="#数据表设计-三大范式" class="headerlink" title="数据表设计-三大范式"></a>数据表设计-三大范式</h3><h4 id="1NF"><a href="#1NF" class="headerlink" title="1NF"></a>1NF</h4><p><strong>只要字段值还可以继续拆分，就不满足第一范式。</strong></p><p>范式设计得越详细，对某些实际操作可能会更好，但并非都有好处，需要对项目的实际情况进行设定。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">address&gt;&gt;-  country | province | city | details |</span><br></pre></td></tr></table></figure><br><h4 id="2NF"><a href="#2NF" class="headerlink" title="2NF"></a>2NF</h4><p><strong>在满足第一范式的前提下，其他列都必须完全依赖于主键列。</strong>如果出现不完全依赖，只可能发生在联合主键的情况下：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">-- 订单表</span><br><span class="line">CREATE TABLE myorder (</span><br><span class="line">    product_id INT,</span><br><span class="line">    customer_id INT,</span><br><span class="line">    product_name VARCHAR(20),</span><br><span class="line">    customer_name VARCHAR(20),</span><br><span class="line">    PRIMARY KEY (product_id, customer_id)</span><br><span class="line">);</span><br></pre></td></tr></table></figure><p>实际上，在这张订单表中，<code>product_name</code> 只依赖于 <code>product_id</code> ，<code>customer_name</code> 只依赖于 <code>customer_id</code> 。也就是说，<code>product_name</code>和 <code>customer_id</code> 是没用关系的，<code>customer_name</code> 和 <code>product_id</code> 也是没有关系的。</p><p>这就不满足第二范式：其他列都必须完全依赖于主键列！–&gt;拆分！</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">CREATE TABLE myorder (</span><br><span class="line">    order_id INT PRIMARY KEY,</span><br><span class="line">    product_id INT,</span><br><span class="line">    customer_id INT</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line">CREATE TABLE product (</span><br><span class="line">    id INT PRIMARY KEY,</span><br><span class="line">    name VARCHAR(20)</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line">CREATE TABLE customer (</span><br><span class="line">    id INT PRIMARY KEY,</span><br><span class="line">    name VARCHAR(20)</span><br><span class="line">);</span><br></pre></td></tr></table></figure><p>拆分之后，<code>myorder</code> 表中的 <code>product_id</code> 和 <code>customer_id</code> 完全依赖于 <code>order_id</code> 主键，而 <code>product</code> 和 <code>customer</code> 表中的其他字段又完全依赖于主键。满足了第二范式的设计！</p><br><h4 id="3NF"><a href="#3NF" class="headerlink" title="3NF"></a>3NF</h4><p><strong>在满足第二范式的前提下，除了主键列之外，其他列之间不能有传递依赖关系。</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">CREATE TABLE myorder (</span><br><span class="line">    order_id INT PRIMARY KEY,</span><br><span class="line">    product_id INT,</span><br><span class="line">    customer_id INT,</span><br><span class="line">    customer_phone VARCHAR(15)</span><br><span class="line">);</span><br></pre></td></tr></table></figure><p>表中的 <code>customer_phone</code> 有可能依赖于除了 <code>customer_id</code> 之外的 <code>order_id</code> 列，也就不满足了第三范式的设计：除了主键列之外，其他列之间不能有传递依赖关系。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">CREATE TABLE myorder (</span><br><span class="line">    order_id INT PRIMARY KEY,</span><br><span class="line">    product_id INT,</span><br><span class="line">    customer_id INT</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line">CREATE TABLE customer (</span><br><span class="line">    id INT PRIMARY KEY,</span><br><span class="line">    name VARCHAR(20),</span><br><span class="line">    phone VARCHAR(15)</span><br><span class="line">);</span><br></pre></td></tr></table></figure><p><strong>修改后就不存在其他列之间的传递依赖关系，其他列都只依赖于主键列，满足了第三范式的设计！</strong></p><br><br><h3 id="mysql查询练习"><a href="#mysql查询练习" class="headerlink" title="mysql查询练习"></a>mysql查询练习</h3><h4 id="准备数据"><a href="#准备数据" class="headerlink" title="准备数据"></a>准备数据</h4><p><strong>创建表：</strong>学生表(student)、教师表(teacher)、成绩表(score)、课程表(course)</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><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></td><td class="code"><pre><span class="line">-- 创建学生表</span><br><span class="line">-- 学号</span><br><span class="line">-- 姓名</span><br><span class="line">-- 性别</span><br><span class="line">-- 生日</span><br><span class="line">-- 班级</span><br><span class="line">CREATE TABLE student (</span><br><span class="line">    no VARCHAR(20) PRIMARY KEY,</span><br><span class="line">    name VARCHAR(20) NOT NULL,</span><br><span class="line">    sex VARCHAR(10) NOT NULL,</span><br><span class="line">    birthday DATE, -- 生日</span><br><span class="line">    class VARCHAR(20) -- 所在班级</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- 创建教师表</span><br><span class="line">-- 编号 </span><br><span class="line">-- 姓名</span><br><span class="line">-- 性别</span><br><span class="line">-- 生日</span><br><span class="line">-- 职称</span><br><span class="line">-- 部门 </span><br><span class="line">CREATE TABLE teacher (</span><br><span class="line">    no VARCHAR(20) PRIMARY KEY,</span><br><span class="line">    name VARCHAR(20) NOT NULL,</span><br><span class="line">    sex VARCHAR(10) NOT NULL,</span><br><span class="line">    birthday DATE,</span><br><span class="line">    profession VARCHAR(20) NOT NULL, -- 职称</span><br><span class="line">    department VARCHAR(20) NOT NULL -- 部门</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- 创建课程表</span><br><span class="line">-- 课程编号</span><br><span class="line">-- 教师名称</span><br><span class="line">-- 教师编号</span><br><span class="line">CREATE TABLE course (</span><br><span class="line">    no VARCHAR(20) PRIMARY KEY,</span><br><span class="line">    name VARCHAR(20) NOT NULL,</span><br><span class="line">    t_no VARCHAR(20) NOT NULL, -- 教师编号</span><br><span class="line">    -- 外键：表示该 tno 来自于 teacher 表中的 no 字段值</span><br><span class="line">    FOREIGN KEY(t_no) REFERENCES teacher(no) </span><br><span class="line">);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- 成绩表</span><br><span class="line">-- 学生编号</span><br><span class="line">-- 课程编号</span><br><span class="line">-- 成绩</span><br><span class="line">CREATE TABLE score (</span><br><span class="line">    s_no VARCHAR(20) NOT NULL, -- 学生编号</span><br><span class="line">    c_no VARCHAR(20) NOT NULL, -- 课程号</span><br><span class="line">    degree DECIMAL,-- 成绩</span><br><span class="line">    -- 外键：表示该 s_no, c_no 分别来自于 student, course 表中的 no 字段值</span><br><span class="line">    FOREIGN KEY(s_no) REFERENCES student(no),</span><br><span class="line">    FOREIGN KEY(c_no) REFERENCES course(no),</span><br><span class="line">    -- 设置 s_no, c_no 为联合主键</span><br><span class="line">    PRIMARY KEY(s_no, c_no)</span><br><span class="line">);</span><br></pre></td></tr></table></figure><p><strong>添加数据：</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><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><br><span class="line">INSERT INTO student VALUES(&#39;101&#39;, &#39;曾华&#39;, &#39;男&#39;, &#39;1977-09-01&#39;, &#39;95033&#39;);</span><br><span class="line">INSERT INTO student VALUES(&#39;102&#39;, &#39;匡明&#39;, &#39;男&#39;, &#39;1975-10-02&#39;, &#39;95031&#39;);</span><br><span class="line">INSERT INTO student VALUES(&#39;103&#39;, &#39;王丽&#39;, &#39;女&#39;, &#39;1976-01-23&#39;, &#39;95033&#39;);</span><br><span class="line">INSERT INTO student VALUES(&#39;104&#39;, &#39;李军&#39;, &#39;男&#39;, &#39;1976-02-20&#39;, &#39;95033&#39;);</span><br><span class="line">INSERT INTO student VALUES(&#39;105&#39;, &#39;王芳&#39;, &#39;女&#39;, &#39;1975-02-10&#39;, &#39;95031&#39;);</span><br><span class="line">INSERT INTO student VALUES(&#39;106&#39;, &#39;陆军&#39;, &#39;男&#39;, &#39;1974-06-03&#39;, &#39;95031&#39;);</span><br><span class="line">INSERT INTO student VALUES(&#39;107&#39;, &#39;王尼玛&#39;, &#39;男&#39;, &#39;1976-02-20&#39;, &#39;95033&#39;);</span><br><span class="line">INSERT INTO student VALUES(&#39;108&#39;, &#39;张全蛋&#39;, &#39;男&#39;, &#39;1975-02-10&#39;, &#39;95031&#39;);</span><br><span class="line">INSERT INTO student VALUES(&#39;109&#39;, &#39;赵铁柱&#39;, &#39;男&#39;, &#39;1974-06-03&#39;, &#39;95031&#39;);</span><br><span class="line"></span><br><span class="line">-- 添加教师表数据</span><br><span class="line">INSERT INTO teacher VALUES(&#39;804&#39;, &#39;李诚&#39;, &#39;男&#39;, &#39;1958-12-02&#39;, &#39;副教授&#39;, &#39;计算机系&#39;);</span><br><span class="line">INSERT INTO teacher VALUES(&#39;856&#39;, &#39;张旭&#39;, &#39;男&#39;, &#39;1969-03-12&#39;, &#39;讲师&#39;, &#39;电子工程系&#39;);</span><br><span class="line">INSERT INTO teacher VALUES(&#39;825&#39;, &#39;王萍&#39;, &#39;女&#39;, &#39;1972-05-05&#39;, &#39;助教&#39;, &#39;计算机系&#39;);</span><br><span class="line">INSERT INTO teacher VALUES(&#39;831&#39;, &#39;刘冰&#39;, &#39;女&#39;, &#39;1977-08-14&#39;, &#39;助教&#39;, &#39;电子工程系&#39;);</span><br><span class="line"></span><br><span class="line">-- 添加课程表数据</span><br><span class="line">INSERT INTO course VALUES(&#39;3-105&#39;, &#39;计算机导论&#39;, &#39;825&#39;);</span><br><span class="line">INSERT INTO course VALUES(&#39;3-245&#39;, &#39;操作系统&#39;, &#39;804&#39;);</span><br><span class="line">INSERT INTO course VALUES(&#39;6-166&#39;, &#39;数字电路&#39;, &#39;856&#39;);</span><br><span class="line">INSERT INTO course VALUES(&#39;9-888&#39;, &#39;高等数学&#39;, &#39;831&#39;);</span><br><span class="line"></span><br><span class="line">-- 添加添加成绩表数据</span><br><span class="line">INSERT INTO score VALUES(&#39;103&#39;, &#39;3-105&#39;, &#39;92&#39;);</span><br><span class="line">INSERT INTO score VALUES(&#39;103&#39;, &#39;3-245&#39;, &#39;86&#39;);</span><br><span class="line">INSERT INTO score VALUES(&#39;103&#39;, &#39;6-166&#39;, &#39;85&#39;);</span><br><span class="line">INSERT INTO score VALUES(&#39;105&#39;, &#39;3-105&#39;, &#39;88&#39;);</span><br><span class="line">INSERT INTO score VALUES(&#39;105&#39;, &#39;3-245&#39;, &#39;75&#39;);</span><br><span class="line">INSERT INTO score VALUES(&#39;105&#39;, &#39;6-166&#39;, &#39;79&#39;);</span><br><span class="line">INSERT INTO score VALUES(&#39;109&#39;, &#39;3-105&#39;, &#39;76&#39;);</span><br><span class="line">INSERT INTO score VALUES(&#39;109&#39;, &#39;3-245&#39;, &#39;68&#39;);</span><br><span class="line">INSERT INTO score VALUES(&#39;109&#39;, &#39;6-166&#39;, &#39;81&#39;);</span><br><span class="line"></span><br><span class="line">-- 查看表结构</span><br><span class="line">SELECT * FROM course;</span><br><span class="line">SELECT * FROM score;</span><br><span class="line">SELECT * FROM student;</span><br><span class="line">SELECT * FROM teacher;</span><br></pre></td></tr></table></figure><br><h4 id="十道练习题"><a href="#十道练习题" class="headerlink" title="十道练习题"></a>十道练习题</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><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></pre></td><td class="code"><pre><span class="line">-- 1.查询student表中所有记录</span><br><span class="line">select * from student;</span><br><span class="line"></span><br><span class="line">mysql&gt; select * from student;</span><br><span class="line">+-----+-----------+-----+------------+-------+</span><br><span class="line">| no  | name      | sex | birthday   | class |</span><br><span class="line">+-----+-----------+-----+------------+-------+</span><br><span class="line">| 101 | 曾华      | 男  | 1977-09-01 | 95033 |</span><br><span class="line">| 102 | 匡明      | 男  | 1975-10-02 | 95031 |</span><br><span class="line">| 103 | 王丽      | 女  | 1976-01-23 | 95033 |</span><br><span class="line">| 104 | 李军      | 男  | 1976-02-20 | 95033 |</span><br><span class="line">| 105 | 王芳      | 女  | 1975-02-10 | 95031 |</span><br><span class="line">| 106 | 陆军      | 男  | 1974-06-03 | 95031 |</span><br><span class="line">| 107 | 王尼玛    | 男  | 1976-02-20 | 95033 |</span><br><span class="line">| 108 | 张全蛋    | 男  | 1975-02-10 | 95031 |</span><br><span class="line">| 109 | 赵铁柱    | 男  | 1974-06-03 | 95031 |</span><br><span class="line">+-----+-----------+-----+------------+-------+</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- 2.查询 student 表中的 name、sex 和 class 字段的所有行</span><br><span class="line">select name, sex, class from student;</span><br><span class="line"></span><br><span class="line">mysql&gt; select name, sex, class from student;</span><br><span class="line">+-----------+-----+-------+</span><br><span class="line">| name      | sex | class |</span><br><span class="line">+-----------+-----+-------+</span><br><span class="line">| 曾华      | 男  | 95033 |</span><br><span class="line">| 匡明      | 男  | 95031 |</span><br><span class="line">| 王丽      | 女  | 95033 |</span><br><span class="line">| 李军      | 男  | 95033 |</span><br><span class="line">| 王芳      | 女  | 95031 |</span><br><span class="line">| 陆军      | 男  | 95031 |</span><br><span class="line">| 王尼玛    | 男  | 95033 |</span><br><span class="line">| 张全蛋    | 男  | 95031 |</span><br><span class="line">| 赵铁柱    | 男  | 95031 |</span><br><span class="line">+-----------+-----+-------+</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- 3.查询 teacher 表中不重复的 department 列</span><br><span class="line">--   distinct: 去重查询</span><br><span class="line">select distinct department from teacher;</span><br><span class="line"></span><br><span class="line">mysql&gt; select distinct department from teacher;</span><br><span class="line">+-----------------+</span><br><span class="line">| department      |</span><br><span class="line">+-----------------+</span><br><span class="line">| 计算机系        |</span><br><span class="line">| 电子工程系      |</span><br><span class="line">+-----------------+</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- 4.查询 score 表中成绩在60-80之间的所有行（区间查询和运算符查询）</span><br><span class="line">--   BETWEEN xx AND xx: 查询区间, AND 表示 &quot;并且&quot;</span><br><span class="line">select * from score where degree between 60 and 80;</span><br><span class="line">select * from score where degree &gt; 60 and degree &lt; 80;</span><br><span class="line"></span><br><span class="line">mysql&gt; select * from score where degree between 60 and 80;</span><br><span class="line">mysql&gt; select * from score where degree &gt; 60 and degree &lt; 80;</span><br><span class="line">+------+-------+--------+</span><br><span class="line">| s_no | c_no  | degree |</span><br><span class="line">+------+-------+--------+</span><br><span class="line">| 105  | 3-245 |     75 |</span><br><span class="line">| 105  | 6-166 |     79 |</span><br><span class="line">| 109  | 3-105 |     76 |</span><br><span class="line">| 109  | 3-245 |     68 |</span><br><span class="line">+------+-------+--------+</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- 5.查询 score 表中成绩为 85, 86 或 88 的行</span><br><span class="line">--   IN: 查询规定中的多个值</span><br><span class="line">select * from score where degree in (85,86,88);</span><br><span class="line"></span><br><span class="line">mysql&gt; select * from score where degree in (85,86,88);</span><br><span class="line">+------+-------+--------+</span><br><span class="line">| s_no | c_no  | degree |</span><br><span class="line">+------+-------+--------+</span><br><span class="line">| 103  | 3-245 |     86 |</span><br><span class="line">| 103  | 6-166 |     85 |</span><br><span class="line">| 105  | 3-105 |     88 |</span><br><span class="line">+------+-------+--------+</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- 6.查询 student 表中 &#39;95031&#39; 班或性别为 &#39;女&#39; 的所有行</span><br><span class="line">--   or: 表示或者关系</span><br><span class="line">select * from student where class &#x3D; &#39;95031&#39; or sex &#x3D; &#39;女&#39;;</span><br><span class="line"></span><br><span class="line">mysql&gt; select * from student where class &#x3D; &#39;95031&#39; or sex &#x3D; &#39;女&#39;;</span><br><span class="line">+-----+-----------+-----+------------+-------+</span><br><span class="line">| no  | name      | sex | birthday   | class |</span><br><span class="line">+-----+-----------+-----+------------+-------+</span><br><span class="line">| 102 | 匡明      | 男  | 1975-10-02 | 95031 |</span><br><span class="line">| 103 | 王丽      | 女  | 1976-01-23 | 95033 |</span><br><span class="line">| 105 | 王芳      | 女  | 1975-02-10 | 95031 |</span><br><span class="line">| 106 | 陆军      | 男  | 1974-06-03 | 95031 |</span><br><span class="line">| 108 | 张全蛋    | 男  | 1975-02-10 | 95031 |</span><br><span class="line">| 109 | 赵铁柱    | 男  | 1974-06-03 | 95031 |</span><br><span class="line">+-----+-----------+-----+------------+-------+</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- 7.以 class 降序的方式查询 student 表的所有行</span><br><span class="line">--   DESC: 降序，从高到低</span><br><span class="line">--   ASC（默认）: 升序，从低到高</span><br><span class="line">select * from student order by class desc;</span><br><span class="line">select * from student order by class; (asc)</span><br><span class="line"></span><br><span class="line">mysql&gt; select * from student order by class desc;</span><br><span class="line">+-----+-----------+-----+------------+-------+</span><br><span class="line">| no  | name      | sex | birthday   | class |</span><br><span class="line">+-----+-----------+-----+------------+-------+</span><br><span class="line">| 101 | 曾华      | 男  | 1977-09-01 | 95033 |</span><br><span class="line">| 103 | 王丽      | 女  | 1976-01-23 | 95033 |</span><br><span class="line">| 104 | 李军      | 男  | 1976-02-20 | 95033 |</span><br><span class="line">| 107 | 王尼玛    | 男  | 1976-02-20 | 95033 |</span><br><span class="line">| 102 | 匡明      | 男  | 1975-10-02 | 95031 |</span><br><span class="line">| 105 | 王芳      | 女  | 1975-02-10 | 95031 |</span><br><span class="line">| 106 | 陆军      | 男  | 1974-06-03 | 95031 |</span><br><span class="line">| 108 | 张全蛋    | 男  | 1975-02-10 | 95031 |</span><br><span class="line">| 109 | 赵铁柱    | 男  | 1974-06-03 | 95031 |</span><br><span class="line">+-----+-----------+-----+------------+-------+</span><br><span class="line"></span><br><span class="line">mysql&gt; select * from student order by class;</span><br><span class="line">+-----+-----------+-----+------------+-------+</span><br><span class="line">| no  | name      | sex | birthday   | class |</span><br><span class="line">+-----+-----------+-----+------------+-------+</span><br><span class="line">| 102 | 匡明      | 男  | 1975-10-02 | 95031 |</span><br><span class="line">| 105 | 王芳      | 女  | 1975-02-10 | 95031 |</span><br><span class="line">| 106 | 陆军      | 男  | 1974-06-03 | 95031 |</span><br><span class="line">| 108 | 张全蛋    | 男  | 1975-02-10 | 95031 |</span><br><span class="line">| 109 | 赵铁柱    | 男  | 1974-06-03 | 95031 |</span><br><span class="line">| 101 | 曾华      | 男  | 1977-09-01 | 95033 |</span><br><span class="line">| 103 | 王丽      | 女  | 1976-01-23 | 95033 |</span><br><span class="line">| 104 | 李军      | 男  | 1976-02-20 | 95033 |</span><br><span class="line">| 107 | 王尼玛    | 男  | 1976-02-20 | 95033 |</span><br><span class="line">+-----+-----------+-----+------------+-------+</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- 8.以 c_no 升序、degree 降序查询 score 表的所有行</span><br><span class="line">--   先以c_no升、再以score降序</span><br><span class="line">select * from score order by c_no , degree desc;</span><br><span class="line"></span><br><span class="line">mysql&gt; select * from score order by c_no , degree desc;</span><br><span class="line">+------+-------+--------+</span><br><span class="line">| s_no | c_no  | degree |</span><br><span class="line">+------+-------+--------+</span><br><span class="line">| 103  | 3-105 |     92 |</span><br><span class="line">| 105  | 3-105 |     88 |</span><br><span class="line">| 109  | 3-105 |     76 |</span><br><span class="line">| 103  | 3-245 |     86 |</span><br><span class="line">| 105  | 3-245 |     75 |</span><br><span class="line">| 109  | 3-245 |     68 |</span><br><span class="line">| 103  | 6-166 |     85 |</span><br><span class="line">| 109  | 6-166 |     81 |</span><br><span class="line">| 105  | 6-166 |     79 |</span><br><span class="line">+------+-------+--------+</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- 9.查询 &quot;95031&quot; 班的学生人数</span><br><span class="line">--   COUNT: 统计</span><br><span class="line">select count(*) from student where class &#x3D; &#39;95031&#39;;</span><br><span class="line"></span><br><span class="line">mysql&gt; select count(*) from student where class &#x3D; &#39;95031&#39;;</span><br><span class="line">+----------+</span><br><span class="line">| count(*) |</span><br><span class="line">+----------+</span><br><span class="line">|        5 |</span><br><span class="line">+----------+</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- 10.查询 score 表中的最高分的学生学号和课程编号（子查询或排序查询）。</span><br><span class="line">--    (SELECT MAX(degree) FROM score): 子查询，算出最高分</span><br><span class="line">select s_no, c_no from score where degree &#x3D; (select max(degree) from score);</span><br><span class="line"></span><br><span class="line">mysql&gt; select s_no, c_no from score where degree &#x3D; (select max(degree) from score);</span><br><span class="line">+------+-------+</span><br><span class="line">| s_no | c_no  |</span><br><span class="line">+------+-------+</span><br><span class="line">| 103  | 3-105 |</span><br><span class="line">+------+-------+</span><br><span class="line"></span><br><span class="line">--    排序方式</span><br><span class="line">--    limit num1,num2</span><br><span class="line">--    num1:表示从第 num1 条记录开始取；</span><br><span class="line">--    num2:表示取 num2 条记录；</span><br><span class="line">select s_no, c_no from score order by degree desc limit 0,1;</span><br><span class="line"></span><br><span class="line">mysql&gt; select s_no, c_no from score order by degree desc limit 0,1;</span><br><span class="line">+------+-------+</span><br><span class="line">| s_no | c_no  |</span><br><span class="line">+------+-------+</span><br><span class="line">| 103  | 3-105 |</span><br><span class="line">+------+-------+</span><br></pre></td></tr></table></figure><br><h4 id="分组计算平均成绩"><a href="#分组计算平均成绩" class="headerlink" title="分组计算平均成绩"></a>分组计算平均成绩</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">-- 查询每门课的平均成绩</span><br><span class="line">-- AVG: 平均值</span><br><span class="line">select avg(degree) from score where c_no &#x3D; &#39;3-105&#39;;</span><br><span class="line"></span><br><span class="line">mysql&gt; select avg(degree) from score where c_no &#x3D; &#39;3-105&#39;;</span><br><span class="line">+-------------+</span><br><span class="line">| avg(degree) |</span><br><span class="line">+-------------+</span><br><span class="line">|     85.3333 |</span><br><span class="line">+-------------+</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- GROUP BY: 分组查询</span><br><span class="line">SELECT c_no, AVG(degree) FROM score GROUP BY c_no;</span><br><span class="line"></span><br><span class="line">mysql&gt; SELECT c_no, AVG(degree) FROM score GROUP BY c_no;</span><br><span class="line">+-------+-------------+</span><br><span class="line">| c_no  | AVG(degree) |</span><br><span class="line">+-------+-------------+</span><br><span class="line">| 3-105 |     85.3333 |</span><br><span class="line">| 3-245 |     76.3333 |</span><br><span class="line">| 6-166 |     81.6667 |</span><br><span class="line">+-------+-------------+</span><br></pre></td></tr></table></figure><br><h4 id="分组条件与模糊查询"><a href="#分组条件与模糊查询" class="headerlink" title="分组条件与模糊查询"></a>分组条件与模糊查询</h4><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></pre></td><td class="code"><pre><span class="line">-- 查询 score 表中至少有 2 名学生选修，并以 3 开头的课程的平均分数</span><br><span class="line"></span><br><span class="line">-- 查询出至少有 2 名学生选修的课程</span><br><span class="line">-- HAVING: 表示持有</span><br><span class="line">HAVING COUNT(c_no) &gt;&#x3D; 2</span><br><span class="line"></span><br><span class="line">-- 并且是以 3 开头的课程</span><br><span class="line">-- LIKE 表示模糊查询，&quot;%&quot; 是一个通配符，匹配 &quot;3&quot; 后面的任意字符。</span><br><span class="line">AND c_no LIKE &#39;3%&#39;</span><br><span class="line"></span><br><span class="line">-- 最终语句</span><br><span class="line">select c_no, avg(degree), count(c_no) from score GROUP BY c_no</span><br><span class="line">HAVING COUNT(c_no) &gt;&#x3D; 2 and </span><br><span class="line">c_no LIKE &#39;3%&#39;;</span><br><span class="line"></span><br><span class="line">mysql&gt; select c_no, avg(degree), count(c_no) from score GROUP BY c_no</span><br><span class="line">    -&gt; HAVING COUNT(c_no) &gt;&#x3D; 2 and</span><br><span class="line">    -&gt; c_no LIKE &#39;3%&#39;;</span><br><span class="line">+-------+-------------+-------------+</span><br><span class="line">| c_no  | avg(degree) | count(c_no) |</span><br><span class="line">+-------+-------------+-------------+</span><br><span class="line">| 3-105 |     85.3333 |           3 |</span><br><span class="line">| 3-245 |     76.3333 |           3 |</span><br><span class="line">+-------+-------------+-------------+</span><br></pre></td></tr></table></figure><br><h4 id="多表查询"><a href="#多表查询" class="headerlink" title="多表查询"></a>多表查询</h4><p>查询所有学生的 name，以及该学生在 score 表中对应的 c_no 和 degree :</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">-- SELECT no, name FROM student;</span><br><span class="line">mysql&gt; SELECT no, name FROM student;</span><br><span class="line">+-----+-----------+</span><br><span class="line">| no  | name      |</span><br><span class="line">+-----+-----------+</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">+-----+-----------+</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- SELECT s_no, c_no, degree FROM score;</span><br><span class="line"></span><br><span class="line">mysql&gt; SELECT s_no, c_no, degree FROM score;</span><br><span class="line">+------+-------+--------+</span><br><span class="line">| s_no | c_no  | degree |</span><br><span class="line">+------+-------+--------+</span><br><span class="line">| 103  | 3-105 |     92 |</span><br><span class="line">| 103  | 3-245 |     86 |</span><br><span class="line">| 103  | 6-166 |     85 |</span><br><span class="line">| 105  | 3-105 |     88 |</span><br><span class="line">| 105  | 3-245 |     75 |</span><br><span class="line">| 105  | 6-166 |     79 |</span><br><span class="line">| 109  | 3-105 |     76 |</span><br><span class="line">| 109  | 3-245 |     68 |</span><br><span class="line">| 109  | 6-166 |     81 |</span><br><span class="line">+------+-------+--------+</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- 查询所有学生的 name，以及该学生在 score 表中对应的 c_no 和 degree </span><br><span class="line">select name, c_no, degree from student, score</span><br><span class="line">where student.no &#x3D; score.s_no;</span><br><span class="line"></span><br><span class="line">mysql&gt; select name, c_no, degree from student, score</span><br><span class="line">    -&gt; where student.no &#x3D; score.s_no;</span><br><span class="line">+-----------+-------+--------+</span><br><span class="line">| name      | c_no  | degree |</span><br><span class="line">+-----------+-------+--------+</span><br><span class="line">| 王丽      | 3-105 |     92 |</span><br><span class="line">| 王丽      | 3-245 |     86 |</span><br><span class="line">| 王丽      | 6-166 |     85 |</span><br><span class="line">| 王芳      | 3-105 |     88 |</span><br><span class="line">| 王芳      | 3-245 |     75 |</span><br><span class="line">| 王芳      | 6-166 |     79 |</span><br><span class="line">| 赵铁柱    | 3-105 |     76 |</span><br><span class="line">| 赵铁柱    | 3-245 |     68 |</span><br><span class="line">| 赵铁柱    | 6-166 |     81 |</span><br><span class="line">+-----------+-------+--------+</span><br></pre></td></tr></table></figure><p>查询所有学生的 no 、课程名称 ( course 表中的 name ) 和成绩 ( score 表中的 degree ) 列：</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></pre></td><td class="code"><pre><span class="line">-- 查询所有学生的 no 、课程名称 ( course 表中的 name ) 和成绩 ( score 表中的 degree ) 列</span><br><span class="line">select s_no, name, degree from course, score </span><br><span class="line">where course.no &#x3D; score.c_no;</span><br><span class="line"></span><br><span class="line">mysql&gt; select s_no, name, degree from course, score</span><br><span class="line">    -&gt; where course.no &#x3D; score.c_no;</span><br><span class="line">+------+-----------------+--------+</span><br><span class="line">| s_no | name            | degree |</span><br><span class="line">+------+-----------------+--------+</span><br><span class="line">| 103  | 计算机导论      |     92 |</span><br><span class="line">| 103  | 操作系统        |     86 |</span><br><span class="line">| 103  | 数字电路        |     85 |</span><br><span class="line">| 105  | 计算机导论      |     88 |</span><br><span class="line">| 105  | 操作系统        |     75 |</span><br><span class="line">| 105  | 数字电路        |     79 |</span><br><span class="line">| 109  | 计算机导论      |     76 |</span><br><span class="line">| 109  | 操作系统        |     68 |</span><br><span class="line">| 109  | 数字电路        |     81 |</span><br><span class="line">+------+-----------------+--------+</span><br><span class="line"></span><br><span class="line">-- as 表示取一个该字段的别名。</span><br><span class="line">select s_no, name as c_name, degree from course, score </span><br><span class="line">where course.no &#x3D; score.c_no;</span><br><span class="line"></span><br><span class="line">mysql&gt; select s_no, name as c_name, degree from course, score</span><br><span class="line">    -&gt; where course.no &#x3D; score.c_no;</span><br><span class="line">+------+-----------------+--------+</span><br><span class="line">| s_no | c_name          | degree |</span><br><span class="line">+------+-----------------+--------+</span><br><span class="line">| 103  | 计算机导论      |     92 |</span><br><span class="line">| 103  | 操作系统        |     86 |</span><br><span class="line">| 103  | 数字电路        |     85 |</span><br><span class="line">| 105  | 计算机导论      |     88 |</span><br><span class="line">| 105  | 操作系统        |     75 |</span><br><span class="line">| 105  | 数字电路        |     79 |</span><br><span class="line">| 109  | 计算机导论      |     76 |</span><br><span class="line">| 109  | 操作系统        |     68 |</span><br><span class="line">| 109  | 数字电路        |     81 |</span><br><span class="line">+------+-----------------+--------+</span><br></pre></td></tr></table></figure><br><h4 id="三表关联查询"><a href="#三表关联查询" class="headerlink" title="三表关联查询"></a>三表关联查询</h4><p>查询所有学生的 <code>name</code> 、课程名 ( <code>course</code> 表中的 <code>name</code> ) 和 <code>degree</code> ：</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></pre></td><td class="code"><pre><span class="line">-- 查询所有学生的 &#96;name&#96; 、课程名 ( &#96;course&#96; 表中的 &#96;name&#96; ) 和 &#96;degree&#96; </span><br><span class="line">-- name --&gt; student表</span><br><span class="line">-- c_name --&gt; course表</span><br><span class="line">-- degree --&gt; score表</span><br><span class="line">-- 只有 score 表中关联学生的学号和课堂号，我们只要围绕着 score 这张表查询就好了</span><br><span class="line"></span><br><span class="line">-- 由于字段名存在重复，使用 &quot;表名.字段名 as 别名&quot; 代替。</span><br><span class="line">select student.name, course.name as c_name, degree </span><br><span class="line">from student, course, score </span><br><span class="line">where student.no &#x3D; score.s_no and </span><br><span class="line">course.no &#x3D; score.c_no;</span><br><span class="line"></span><br><span class="line">mysql&gt; select student.name, course.name as c_name, degree</span><br><span class="line">    -&gt; from student, course, score</span><br><span class="line">    -&gt; where student.no &#x3D; score.s_no and</span><br><span class="line">    -&gt; course.no &#x3D; score.c_no;</span><br><span class="line">+-----------+-----------------+--------+</span><br><span class="line">| name      | c_name          | degree |</span><br><span class="line">+-----------+-----------------+--------+</span><br><span class="line">| 王丽      | 计算机导论      |     92 |</span><br><span class="line">| 王丽      | 操作系统        |     86 |</span><br><span class="line">| 王丽      | 数字电路        |     85 |</span><br><span class="line">| 王芳      | 计算机导论      |     88 |</span><br><span class="line">| 王芳      | 操作系统        |     75 |</span><br><span class="line">| 王芳      | 数字电路        |     79 |</span><br><span class="line">| 赵铁柱    | 计算机导论      |     76 |</span><br><span class="line">| 赵铁柱    | 操作系统        |     68 |</span><br><span class="line">| 赵铁柱    | 数字电路        |     81 |</span><br><span class="line">+-----------+-----------------+--------+</span><br></pre></td></tr></table></figure><br><h4 id="子查询加分组求平均分"><a href="#子查询加分组求平均分" class="headerlink" title="子查询加分组求平均分"></a>子查询加分组求平均分</h4><p>查询 95031 班学生每门课程的平均成绩：</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><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></pre></td><td class="code"><pre><span class="line">-- 查询 95031 班学生每门课程的平均成绩</span><br><span class="line">-- 1.查询 95031 班的学生学号作为条件</span><br><span class="line">select no from student where class &#x3D; &#39;95031&#39;</span><br><span class="line"></span><br><span class="line">mysql&gt; select no from student where class &#x3D; &#39;95031&#39;;</span><br><span class="line">+-----+</span><br><span class="line">| no  |</span><br><span class="line">+-----+</span><br><span class="line">| 102 |</span><br><span class="line">| 105 |</span><br><span class="line">| 106 |</span><br><span class="line">| 108 |</span><br><span class="line">| 109 |</span><br><span class="line">+-----+</span><br><span class="line"></span><br><span class="line">-- 2.IN (..): 将筛选出的学生号当做 s_no 的条件查询</span><br><span class="line">select s_no, c_no, degree from score </span><br><span class="line">where s_no in (select no from student where class &#x3D; &#39;95031&#39;);</span><br><span class="line"></span><br><span class="line">mysql&gt; select s_no, c_no, degree from score</span><br><span class="line">    -&gt; where s_no in (select no from student where class &#x3D; &#39;95031&#39;);</span><br><span class="line">+------+-------+--------+</span><br><span class="line">| s_no | c_no  | degree |</span><br><span class="line">+------+-------+--------+</span><br><span class="line">| 105  | 3-105 |     88 |</span><br><span class="line">| 105  | 3-245 |     75 |</span><br><span class="line">| 105  | 6-166 |     79 |</span><br><span class="line">| 109  | 3-105 |     76 |</span><br><span class="line">| 109  | 3-245 |     68 |</span><br><span class="line">| 109  | 6-166 |     81 |</span><br><span class="line">+------+-------+--------+</span><br><span class="line"></span><br><span class="line">-- 按课程号分组求平均：group by c_no</span><br><span class="line">select c_no, avg(degree) </span><br><span class="line">from score </span><br><span class="line">where s_no in (select no from student where class &#x3D; &#39;95031&#39;) </span><br><span class="line">group by c_no;</span><br><span class="line"></span><br><span class="line">mysql&gt; select c_no, avg(degree)</span><br><span class="line">    -&gt; from score</span><br><span class="line">    -&gt; where s_no in (select no from student where class &#x3D; &#39;95031&#39;)</span><br><span class="line">    -&gt; group by c_no;</span><br><span class="line">+-------+-------------+</span><br><span class="line">| c_no  | avg(degree) |</span><br><span class="line">+-------+-------------+</span><br><span class="line">| 3-105 |     82.0000 |</span><br><span class="line">| 3-245 |     71.5000 |</span><br><span class="line">| 6-166 |     80.0000 |</span><br><span class="line">+-------+-------------+</span><br><span class="line"></span><br><span class="line">-- 将课程编号换成课程名</span><br><span class="line">select name as c_name, avg(degree) </span><br><span class="line">from score, course</span><br><span class="line">where s_no in (select no from student where class &#x3D; &#39;95031&#39;)   </span><br><span class="line">and course.no &#x3D; score.c_no</span><br><span class="line">group by c_no;</span><br><span class="line"></span><br><span class="line">mysql&gt; select name as c_name, avg(degree)</span><br><span class="line">    -&gt; from score, course</span><br><span class="line">    -&gt; where s_no in (select no from student where class &#x3D; &#39;95031&#39;)</span><br><span class="line">    -&gt; and course.no &#x3D; score.c_no</span><br><span class="line">    -&gt; group by c_no;</span><br><span class="line">+-----------------+-------------+</span><br><span class="line">| c_name          | avg(degree) |</span><br><span class="line">+-----------------+-------------+</span><br><span class="line">| 计算机导论      |     82.0000 |</span><br><span class="line">| 操作系统        |     71.5000 |</span><br><span class="line">| 数字电路        |     80.0000 |</span><br><span class="line">+-----------------+-------------+</span><br></pre></td></tr></table></figure><br><h4 id="子查询"><a href="#子查询" class="headerlink" title="子查询"></a>子查询</h4><p>查询在 3-105 课程中，所有成绩高于 109 号同学的记录：</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><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line">-- 查询在 3-105 课程中，所有成绩高于 109 号同学的记录</span><br><span class="line">-- 1.首先筛选出课堂号为 3-105</span><br><span class="line">select s_no, c_no from score where c_no &#x3D; &#39;3-105&#39;;</span><br><span class="line"></span><br><span class="line">mysql&gt; select s_no, c_no from score where c_no &#x3D; &#39;3-105&#39;;</span><br><span class="line">+------+-------+</span><br><span class="line">| s_no | c_no  |</span><br><span class="line">+------+-------+</span><br><span class="line">| 103  | 3-105 |</span><br><span class="line">| 105  | 3-105 |</span><br><span class="line">| 109  | 3-105 |</span><br><span class="line">+------+-------+</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- 2.找到 109 同学的 3-105 成绩</span><br><span class="line">select degree from score where s_no &#x3D; &#39;109&#39; and c_no &#x3D;&#39;3-105&#39;;</span><br><span class="line"></span><br><span class="line">mysql&gt; select degree from score where s_no &#x3D; &#39;109&#39; and c_no &#x3D;&#39;3-105&#39;;</span><br><span class="line">+--------+</span><br><span class="line">| degree |</span><br><span class="line">+--------+</span><br><span class="line">|     76 |</span><br><span class="line">+--------+</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- 3.最终语句</span><br><span class="line">select * from score </span><br><span class="line">where c_no &#x3D; &#39;3-105&#39; </span><br><span class="line">and degree &gt; (select degree from score where s_no &#x3D; &#39;109&#39; and c_no &#x3D;&#39;3-105&#39;);</span><br><span class="line"></span><br><span class="line">mysql&gt; select * from score</span><br><span class="line">    -&gt; where c_no &#x3D; &#39;3-105&#39;</span><br><span class="line">    -&gt; and degree &gt; (select degree from score where s_no &#x3D; &#39;109&#39; and c_no &#x3D;&#39;3-105&#39;);</span><br><span class="line">+------+-------+--------+</span><br><span class="line">| s_no | c_no  | degree |</span><br><span class="line">+------+-------+--------+</span><br><span class="line">| 103  | 3-105 |     92 |</span><br><span class="line">| 105  | 3-105 |     88 |</span><br><span class="line">+------+-------+--------+</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- 查询所有成绩高于 109 号同学的 3-105 课程成绩的所有记录。</span><br><span class="line">select * from score </span><br><span class="line">where degree &gt; (select degree from score where s_no &#x3D; &#39;109&#39; and c_no &#x3D;&#39;3-105&#39;);</span><br><span class="line">mysql&gt; select * from score</span><br><span class="line">    -&gt; where degree &gt; (select degree from score where s_no &#x3D; &#39;109&#39; and c_no &#x3D;&#39;3-105&#39;);</span><br><span class="line">+------+-------+--------+</span><br><span class="line">| s_no | c_no  | degree |</span><br><span class="line">+------+-------+--------+</span><br><span class="line">| 103  | 3-105 |     92 |</span><br><span class="line">| 103  | 3-245 |     86 |</span><br><span class="line">| 103  | 6-166 |     85 |</span><br><span class="line">| 105  | 3-105 |     88 |</span><br><span class="line">| 105  | 6-166 |     79 |</span><br><span class="line">| 109  | 6-166 |     81 |</span><br><span class="line">+------+-------+--------+</span><br></pre></td></tr></table></figure><br><h4 id="YEAR-函数与带-IN-关键字查询"><a href="#YEAR-函数与带-IN-关键字查询" class="headerlink" title="YEAR 函数与带 IN 关键字查询"></a>YEAR 函数与带 IN 关键字查询</h4><p>查询所有和 <code>101</code> 、<code>108</code> 号学生同年出生的 <code>no</code> 、<code>name</code> 、<code>birthday</code> 列</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></pre></td><td class="code"><pre><span class="line">-- 查询所有和 &#96;101&#96; 、&#96;108&#96; 号学生同年出生的 &#96;no&#96; 、&#96;name&#96; 、&#96;birthday&#96; 列</span><br><span class="line">select * from student where no in (&#39;101&#39;, &#39;108&#39;);</span><br><span class="line"></span><br><span class="line">mysql&gt; select * from student where no in (&#39;101&#39;, &#39;108&#39;);</span><br><span class="line">+-----+-----------+-----+------------+-------+</span><br><span class="line">| no  | name      | sex | birthday   | class |</span><br><span class="line">+-----+-----------+-----+------------+-------+</span><br><span class="line">| 101 | 曾华      | 男  | 1977-09-01 | 95033 |</span><br><span class="line">| 108 | 张全蛋    | 男  | 1975-02-10 | 95031 |</span><br><span class="line">+-----+-----------+-----+------------+-------+</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- 查询年份 year</span><br><span class="line">select year(birthday) from student where no in (&#39;101&#39;, &#39;108&#39;);</span><br><span class="line"></span><br><span class="line">mysql&gt; select year(birthday) from student where no in (&#39;101&#39;, &#39;108&#39;);</span><br><span class="line">+----------------+</span><br><span class="line">| year(birthday) |</span><br><span class="line">+----------------+</span><br><span class="line">|           1977 |</span><br><span class="line">|           1975 |</span><br><span class="line">+----------------+</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- 最终语句</span><br><span class="line">select no, name, birthday from student </span><br><span class="line">where year(birthday) </span><br><span class="line">in ( select year(birthday) from student where no in (&#39;101&#39;, &#39;108&#39;) );</span><br><span class="line"></span><br><span class="line">mysql&gt; select no, name, birthday from student</span><br><span class="line">    -&gt; where year(birthday)</span><br><span class="line">    -&gt; in ( select year(birthday) from student where no in (&#39;101&#39;, &#39;108&#39;) );</span><br><span class="line">+-----+-----------+------------+</span><br><span class="line">| no  | name      | birthday   |</span><br><span class="line">+-----+-----------+------------+</span><br><span class="line">| 101 | 曾华      | 1977-09-01 |</span><br><span class="line">| 102 | 匡明      | 1975-10-02 |</span><br><span class="line">| 105 | 王芳      | 1975-02-10 |</span><br><span class="line">| 108 | 张全蛋    | 1975-02-10 |</span><br><span class="line">+-----+-----------+------------+</span><br></pre></td></tr></table></figure><br><h4 id="多层嵌套子查询"><a href="#多层嵌套子查询" class="headerlink" title="多层嵌套子查询"></a>多层嵌套子查询</h4><p>查询 <code>&#39;张旭&#39;</code> 教师任课的学生成绩表</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></pre></td><td class="code"><pre><span class="line">-- 查询 &#39;张旭&#39; 教师任课的学生成绩表</span><br><span class="line"></span><br><span class="line">-- 查找对应教师的编号</span><br><span class="line">select no from teacher where name &#x3D; &#39;张旭&#39;;</span><br><span class="line"></span><br><span class="line">mysql&gt; select no from teacher where name &#x3D; &#39;张旭&#39;;</span><br><span class="line">+-----+</span><br><span class="line">| no  |</span><br><span class="line">+-----+</span><br><span class="line">| 856 |</span><br><span class="line">+-----+</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- 2.通过教师编号查找对应的课程</span><br><span class="line">select * from course where t_no &#x3D; (select no from teacher where name &#x3D; &#39;张旭&#39;);</span><br><span class="line"></span><br><span class="line">mysql&gt; select * from course where t_no &#x3D; (select no from teacher where name &#x3D; &#39;张旭&#39;);</span><br><span class="line">+-------+--------------+------+</span><br><span class="line">| no    | name         | t_no |</span><br><span class="line">+-------+--------------+------+</span><br><span class="line">| 6-166 | 数字电路     | 856  |</span><br><span class="line">+-------+--------------+------+</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- 3.通过课程编号查找学生成绩表</span><br><span class="line">select * from score </span><br><span class="line">where c_no &#x3D; </span><br><span class="line">(select no from course where t_no &#x3D; (select no from teacher where name &#x3D; &#39;张旭&#39;));</span><br><span class="line"></span><br><span class="line">mysql&gt; select * from score</span><br><span class="line">    -&gt; where c_no &#x3D;</span><br><span class="line">    -&gt; (select no from course where t_no &#x3D; (select no from teacher where name &#x3D; &#39;张旭&#39;));</span><br><span class="line">+------+-------+--------+</span><br><span class="line">| s_no | c_no  | degree |</span><br><span class="line">+------+-------+--------+</span><br><span class="line">| 103  | 6-166 |     85 |</span><br><span class="line">| 105  | 6-166 |     79 |</span><br><span class="line">| 109  | 6-166 |     81 |</span><br><span class="line">+------+-------+--------+</span><br></pre></td></tr></table></figure><br><h4 id="多表查询-1"><a href="#多表查询-1" class="headerlink" title="多表查询"></a>多表查询</h4><p>查询某选修课程多于5个同学的教师姓名</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></pre></td><td class="code"><pre><span class="line">-- 查询某选修课程多于5个同学的教师姓名</span><br><span class="line"></span><br><span class="line">-- 1.找到选修课程大于5个同学的课程</span><br><span class="line">select c_no from score group by c_no having count(c_no)&gt;5;</span><br><span class="line"></span><br><span class="line">mysql&gt; select c_no from score group by c_no having count(c_no)&gt;5;</span><br><span class="line">+-------+</span><br><span class="line">| c_no  |</span><br><span class="line">+-------+</span><br><span class="line">| 3-105 |</span><br><span class="line">+-------+</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- 2.找到该课程对应的教师编号</span><br><span class="line">select t_no from course </span><br><span class="line">where no in (select c_no from score group by c_no having count(c_no)&gt;5);</span><br><span class="line"></span><br><span class="line">mysql&gt; select t_no from course</span><br><span class="line">    -&gt; where no in (select c_no from score group by c_no having count(c_no)&gt;5);</span><br><span class="line">+------+</span><br><span class="line">| t_no |</span><br><span class="line">+------+</span><br><span class="line">| 825  |</span><br><span class="line">+------+</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- 3.根据教师编号找到对应的教师姓名</span><br><span class="line">select name from teacher </span><br><span class="line">where no in (select t_no from course </span><br><span class="line">where no in (select c_no from score group by c_no having count(c_no)&gt;5));</span><br><span class="line">             </span><br><span class="line">mysql&gt; select name from teacher</span><br><span class="line">    -&gt; where no in (select t_no from course</span><br><span class="line">    -&gt; where no in (select c_no from score group by c_no having count(c_no)&gt;5));</span><br><span class="line">+--------+</span><br><span class="line">| name   |</span><br><span class="line">+--------+</span><br><span class="line">| 王萍   |</span><br><span class="line">+--------+</span><br></pre></td></tr></table></figure><br><h4 id="子查询-2"><a href="#子查询-2" class="headerlink" title="子查询-2"></a>子查询-2</h4><p>查询计算机系所有老师的上的课的成绩表</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><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></pre></td><td class="code"><pre><span class="line">-- 查询计算机系所有老师的上的课的成绩表</span><br><span class="line"></span><br><span class="line">-- 1.查询所有计算机系的老师</span><br><span class="line">select * from teacher where department &#x3D; &#39;计算机系&#39;;</span><br><span class="line"></span><br><span class="line">mysql&gt; select * from teacher where department &#x3D; &#39;计算机系&#39;;</span><br><span class="line">+-----+--------+-----+------------+------------+--------------+</span><br><span class="line">| no  | name   | sex | birthday   | profession | department   |</span><br><span class="line">+-----+--------+-----+------------+------------+--------------+</span><br><span class="line">| 804 | 李诚   | 男  | 1958-12-02 | 副教授     | 计算机系     |</span><br><span class="line">| 825 | 王萍   | 女  | 1972-05-05 | 助教       | 计算机系     |</span><br><span class="line">+-----+--------+-----+------------+------------+--------------+</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- 2.根据教师编号，查询计算机系老师上的课</span><br><span class="line">select * from course </span><br><span class="line">where t_no in (select no from teacher where department &#x3D; &#39;计算机系&#39;);</span><br><span class="line"></span><br><span class="line">mysql&gt; select * from course</span><br><span class="line">    -&gt; where t_no in (select no from teacher where department &#x3D; &#39;计算机系&#39;);</span><br><span class="line">+-------+-----------------+------+</span><br><span class="line">| no    | name            | t_no |</span><br><span class="line">+-------+-----------------+------+</span><br><span class="line">| 3-245 | 操作系统        | 804  |</span><br><span class="line">| 3-105 | 计算机导论      | 825  |</span><br><span class="line">+-------+-----------------+------+</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- 3.根据课程编号，查询对应课程的成绩表</span><br><span class="line">select * from score</span><br><span class="line">where c_no in (select no from course </span><br><span class="line">where t_no in (select no from teacher where department &#x3D; &#39;计算机系&#39;));</span><br><span class="line"></span><br><span class="line">mysql&gt; select * from score</span><br><span class="line">    -&gt; where c_no in (select no from course</span><br><span class="line">    -&gt; where t_no in (select no from teacher where department &#x3D; &#39;计算机系&#39;));</span><br><span class="line">+------+-------+--------+</span><br><span class="line">| s_no | c_no  | degree |</span><br><span class="line">+------+-------+--------+</span><br><span class="line">| 103  | 3-245 |     86 |</span><br><span class="line">| 105  | 3-245 |     75 |</span><br><span class="line">| 109  | 3-245 |     68 |</span><br><span class="line">| 101  | 3-105 |     90 |</span><br><span class="line">| 102  | 3-105 |     91 |</span><br><span class="line">| 103  | 3-105 |     92 |</span><br><span class="line">| 104  | 3-105 |     89 |</span><br><span class="line">| 105  | 3-105 |     88 |</span><br><span class="line">| 109  | 3-105 |     76 |</span><br><span class="line">+------+-------+--------+</span><br></pre></td></tr></table></figure><br><h4 id="UNION-和-NOT-IN-的使用"><a href="#UNION-和-NOT-IN-的使用" class="headerlink" title="UNION 和 NOT IN 的使用"></a>UNION 和 NOT IN 的使用</h4><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></pre></td><td class="code"><pre><span class="line">-- 查询 计算机系 与 电子工程系 中的不同职称的教师</span><br><span class="line">-- -- NOT: 代表逻辑非</span><br><span class="line">-- -- UNION：求并集</span><br><span class="line"></span><br><span class="line">-- 查询 计算机系 教师的职称</span><br><span class="line">select profession from teacher where department &#x3D; &#39;计算机系&#39;;</span><br><span class="line"></span><br><span class="line">-- 查询 电子工程系 教师的职称</span><br><span class="line">select profession from teacher where department &#x3D; &#39;电子工程系&#39;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- 查询 计算机系 中，职称在电子工程系没有的教师</span><br><span class="line">select * from teacher </span><br><span class="line">where department &#x3D; &#39;计算机系&#39; </span><br><span class="line">and profession not in (select profession from teacher where department &#x3D; &#39;电子工程系&#39;);</span><br><span class="line"></span><br><span class="line">+-----+--------+-----+------------+------------+--------------+</span><br><span class="line">| no  | name   | sex | birthday   | profession | department   |</span><br><span class="line">+-----+--------+-----+------------+------------+--------------+</span><br><span class="line">| 804 | 李诚   | 男  | 1958-12-02 | 副教授     | 计算机系     |</span><br><span class="line">+-----+--------+-----+------------+------------+--------------+</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- 查询 电子工程系 中，职称在计算机系没有的教师</span><br><span class="line">select * from teacher </span><br><span class="line">where department &#x3D; &#39;电子工程系&#39; </span><br><span class="line">and profession not in (select profession from teacher where department &#x3D; &#39;计算机系&#39;);</span><br><span class="line"></span><br><span class="line">+-----+--------+-----+------------+------------+-----------------+</span><br><span class="line">| no  | name   | sex | birthday   | profession | department      |</span><br><span class="line">+-----+--------+-----+------------+------------+-----------------+</span><br><span class="line">| 856 | 张旭   | 男  | 1969-03-12 | 讲师       | 电子工程系      |</span><br><span class="line">+-----+--------+-----+------------+------------+-----------------+</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- 最终语句：用 UNION 将两个语句合起来</span><br><span class="line">select * from teacher </span><br><span class="line">where department &#x3D; &#39;计算机系&#39; </span><br><span class="line">and profession not in (select profession from teacher where department &#x3D; &#39;电子工程系&#39;)</span><br><span class="line">union</span><br><span class="line">select * from teacher </span><br><span class="line">where department &#x3D; &#39;电子工程系&#39; </span><br><span class="line">and profession not in (select profession from teacher where department &#x3D; &#39;计算机系&#39;);</span><br><span class="line"></span><br><span class="line">+-----+--------+-----+------------+------------+-----------------+</span><br><span class="line">| no  | name   | sex | birthday   | profession | department      |</span><br><span class="line">+-----+--------+-----+------------+------------+-----------------+</span><br><span class="line">| 804 | 李诚   | 男  | 1958-12-02 | 副教授     | 计算机系        |</span><br><span class="line">| 856 | 张旭   | 男  | 1969-03-12 | 讲师       | 电子工程系      |</span><br><span class="line">+-----+--------+-----+------------+------------+-----------------+</span><br></pre></td></tr></table></figure><br><h4 id="ANY-表示至少一个-DESC-降序"><a href="#ANY-表示至少一个-DESC-降序" class="headerlink" title="ANY 表示至少一个 - DESC ( 降序 )"></a>ANY 表示至少一个 - DESC ( 降序 )</h4><p>查询课程 <code>3-105</code> 且成绩 至少 高于 <code>3-245</code> 的 <code>score</code> 表(大于 <code>3-245</code> 的最小值)</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">-- 查询课程 &#96;3-105&#96; 且成绩 至少 高于 &#96;3-245&#96; 的 &#96;score&#96; 表</span><br><span class="line">select * from score </span><br><span class="line">where c_no &#x3D; &#39;3-105&#39; and degree &gt; any(select degree from score where c_no &#x3D; &#39;3-245&#39;)</span><br><span class="line">order by degree desc;</span><br><span class="line"></span><br><span class="line">mysql&gt; select * from score</span><br><span class="line">    -&gt; where c_no &#x3D; &#39;3-105&#39; and degree &gt; any(select degree from score where c_no &#x3D; &#39;3-245&#39;)</span><br><span class="line">    -&gt; order by degree desc;</span><br><span class="line">+------+-------+--------+</span><br><span class="line">| s_no | c_no  | degree |</span><br><span class="line">+------+-------+--------+</span><br><span class="line">| 103  | 3-105 |     92 |</span><br><span class="line">| 102  | 3-105 |     91 |</span><br><span class="line">| 101  | 3-105 |     90 |</span><br><span class="line">| 104  | 3-105 |     89 |</span><br><span class="line">| 105  | 3-105 |     88 |</span><br><span class="line">| 109  | 3-105 |     76 |</span><br><span class="line">+------+-------+--------+</span><br></pre></td></tr></table></figure><br><h4 id="表示所有的-ALL"><a href="#表示所有的-ALL" class="headerlink" title="表示所有的 ALL"></a>表示所有的 ALL</h4><p>查询课程 3-105 且成绩高于 3-245 的 score 表</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">-- 查询课程 3-105 且成绩高于 3-245 的 score 表</span><br><span class="line">-- all</span><br><span class="line">select * from score </span><br><span class="line">where c_no &#x3D; &#39;3-105&#39; and degree &gt; all(select degree from score where c_no &#x3D; &#39;3-245&#39;)</span><br><span class="line">order by degree desc;</span><br><span class="line"></span><br><span class="line">mysql&gt; select * from score</span><br><span class="line">    -&gt; where c_no &#x3D; &#39;3-105&#39; and degree &gt; all(select degree from score where c_no &#x3D; &#39;3-245&#39;)</span><br><span class="line">    -&gt; order by degree desc;</span><br><span class="line">+------+-------+--------+</span><br><span class="line">| s_no | c_no  | degree |</span><br><span class="line">+------+-------+--------+</span><br><span class="line">| 103  | 3-105 |     92 |</span><br><span class="line">| 102  | 3-105 |     91 |</span><br><span class="line">| 101  | 3-105 |     90 |</span><br><span class="line">| 104  | 3-105 |     89 |</span><br><span class="line">| 105  | 3-105 |     88 |</span><br><span class="line">+------+-------+--------+</span><br></pre></td></tr></table></figure><br><h4 id="复制表的数据作为条件查询"><a href="#复制表的数据作为条件查询" class="headerlink" title="复制表的数据作为条件查询"></a>复制表的数据作为条件查询</h4><p>查询某课程成绩比该课程平均成绩低的 <code>score</code> 表</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></pre></td><td class="code"><pre><span class="line">-- 查询某课程成绩比该课程平均成绩低的 &#96;score&#96; 表</span><br><span class="line">-- 查询平均分</span><br><span class="line">SELECT c_no, AVG(degree) FROM score GROUP BY c_no;</span><br><span class="line"></span><br><span class="line">mysql&gt; SELECT c_no, AVG(degree) FROM score GROUP BY c_no;</span><br><span class="line">+-------+-------------+</span><br><span class="line">| c_no  | AVG(degree) |</span><br><span class="line">+-------+-------------+</span><br><span class="line">| 3-105 |     87.6667 |</span><br><span class="line">| 3-245 |     76.3333 |</span><br><span class="line">| 6-166 |     81.6667 |</span><br><span class="line">+-------+-------------+</span><br><span class="line"></span><br><span class="line">-- 将表 b 作用于表 a 中查询数据</span><br><span class="line">-- score a (b): 将表声明为 a (b)，</span><br><span class="line">-- 如此就能用 a.c_no &#x3D; b.c_no 作为条件执行查询了</span><br><span class="line">select * from score a</span><br><span class="line">where degree &lt; (SELECT AVG(degree) FROM score b where a.c_no &#x3D; b.c_no);</span><br><span class="line"></span><br><span class="line">mysql&gt; select * from score a</span><br><span class="line">    -&gt; where degree &lt; (SELECT AVG(degree) FROM score b where a.c_no &#x3D; b.c_no);</span><br><span class="line">+------+-------+--------+</span><br><span class="line">| s_no | c_no  | degree |</span><br><span class="line">+------+-------+--------+</span><br><span class="line">| 105  | 3-245 |     75 |</span><br><span class="line">| 105  | 6-166 |     79 |</span><br><span class="line">| 109  | 3-105 |     76 |</span><br><span class="line">| 109  | 3-245 |     68 |</span><br><span class="line">| 109  | 6-166 |     81 |</span><br><span class="line">+------+-------+--------+</span><br></pre></td></tr></table></figure><br><h4 id="子查询-4"><a href="#子查询-4" class="headerlink" title="子查询 - 4"></a>子查询 - 4</h4><p>查询所有任课 ( 在 <code>course</code> 表里有课程 ) 教师的 <code>name</code> 和 <code>department</code> </p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">-- 查询所有任课 ( 在 &#96;course&#96; 表里有课程 ) 教师的 &#96;name&#96; 和 &#96;department&#96; </span><br><span class="line">select name, department from teacher </span><br><span class="line">where no in (select t_no from course);</span><br><span class="line"></span><br><span class="line">mysql&gt; select name, department from teacher</span><br><span class="line">    -&gt; where no in (select t_no from course);</span><br><span class="line">+--------+-----------------+</span><br><span class="line">| name   | department      |</span><br><span class="line">+--------+-----------------+</span><br><span class="line">| 李诚   | 计算机系        |</span><br><span class="line">| 王萍   | 计算机系        |</span><br><span class="line">| 刘冰   | 电子工程系      |</span><br><span class="line">| 张旭   | 电子工程系      |</span><br><span class="line">+--------+-----------------+</span><br></pre></td></tr></table></figure><br><h4 id="条件加组筛选"><a href="#条件加组筛选" class="headerlink" title="条件加组筛选"></a>条件加组筛选</h4><p>查询 <code>student</code> 表中至少有 2 名男生的 <code>class</code> </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></pre></td><td class="code"><pre><span class="line">-- 查询 &#96;student&#96; 表中至少有 2 名男生的 &#96;class&#96; </span><br><span class="line">select * from student;</span><br><span class="line"></span><br><span class="line">mysql&gt; select * from student;</span><br><span class="line">+-----+-----------+-----+------------+-------+</span><br><span class="line">| no  | name      | sex | birthday   | class |</span><br><span class="line">+-----+-----------+-----+------------+-------+</span><br><span class="line">| 101 | 曾华      | 男  | 1977-09-01 | 95033 |</span><br><span class="line">| 102 | 匡明      | 男  | 1975-10-02 | 95031 |</span><br><span class="line">| 103 | 王丽      | 女  | 1976-01-23 | 95033 |</span><br><span class="line">| 104 | 李军      | 男  | 1976-02-20 | 95033 |</span><br><span class="line">| 105 | 王芳      | 女  | 1975-02-10 | 95031 |</span><br><span class="line">| 106 | 陆军      | 男  | 1974-06-03 | 95031 |</span><br><span class="line">| 107 | 王尼玛    | 男  | 1976-02-20 | 95033 |</span><br><span class="line">| 108 | 张全蛋    | 男  | 1975-02-10 | 95031 |</span><br><span class="line">| 109 | 赵铁柱    | 男  | 1974-06-03 | 95031 |</span><br><span class="line">| 200 | 王喜全    | 男  | 1974-06-03 | 95038 |</span><br><span class="line">+-----+-----------+-----+------------+-------+</span><br><span class="line"></span><br><span class="line">select class from student </span><br><span class="line">WHERE sex &#x3D; &#39;男&#39;</span><br><span class="line">group by class having count(sex) &gt; 1;</span><br><span class="line"></span><br><span class="line">mysql&gt; select class from student</span><br><span class="line">    -&gt; WHERE sex &#x3D; &#39;男&#39;</span><br><span class="line">    -&gt; group by class having count(sex) &gt; 1;</span><br><span class="line">+-------+</span><br><span class="line">| class |</span><br><span class="line">+-------+</span><br><span class="line">| 95031 |</span><br><span class="line">| 95033 |</span><br><span class="line">+-------+</span><br></pre></td></tr></table></figure><br><h4 id="NOTLIKE-模糊查询取反"><a href="#NOTLIKE-模糊查询取反" class="headerlink" title="NOTLIKE 模糊查询取反"></a>NOTLIKE 模糊查询取反</h4><p>查询 <code>student</code> 表中不姓 “王” 的同学记录</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">-- NOT: 取反</span><br><span class="line">-- LIKE: 模糊查询</span><br><span class="line">select * from student where name not like &#39;王%&#39;;</span><br><span class="line"></span><br><span class="line">mysql&gt; select * from student where name not like &#39;王%&#39;;</span><br><span class="line">+-----+-----------+-----+------------+-------+</span><br><span class="line">| no  | name      | sex | birthday   | class |</span><br><span class="line">+-----+-----------+-----+------------+-------+</span><br><span class="line">| 101 | 曾华      | 男  | 1977-09-01 | 95033 |</span><br><span class="line">| 102 | 匡明      | 男  | 1975-10-02 | 95031 |</span><br><span class="line">| 104 | 李军      | 男  | 1976-02-20 | 95033 |</span><br><span class="line">| 106 | 陆军      | 男  | 1974-06-03 | 95031 |</span><br><span class="line">| 108 | 张全蛋    | 男  | 1975-02-10 | 95031 |</span><br><span class="line">| 109 | 赵铁柱    | 男  | 1974-06-03 | 95031 |</span><br><span class="line">+-----+-----------+-----+------------+-------+</span><br></pre></td></tr></table></figure><br><h4 id="YEAR-与-NOW-函数"><a href="#YEAR-与-NOW-函数" class="headerlink" title="YEAR 与 NOW 函数"></a>YEAR 与 NOW 函数</h4><p>查询 <code>student</code> 表中每个学生的姓名和年龄</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></pre></td><td class="code"><pre><span class="line">-- 查询 &#96;student&#96; 表中每个学生的姓名和年龄</span><br><span class="line">-- select year(now())查询当前年份</span><br><span class="line">select year(now()); -- 查询当前年份</span><br><span class="line"></span><br><span class="line">mysql&gt; select year(now());</span><br><span class="line">+-------------+</span><br><span class="line">| year(now()) |</span><br><span class="line">+-------------+</span><br><span class="line">|        2020 |</span><br><span class="line">+-------------+</span><br><span class="line"></span><br><span class="line">-- 查询姓名，年龄</span><br><span class="line">select name, year(now())-year(birthday) as &#39;年龄&#39; from student;</span><br><span class="line"></span><br><span class="line">mysql&gt; select name, year(now())-year(birthday) as &#39;年龄&#39; from student;</span><br><span class="line">+-----------+--------+</span><br><span class="line">| name      | 年龄   |</span><br><span class="line">+-----------+--------+</span><br><span class="line">| 曾华      |     43 |</span><br><span class="line">| 匡明      |     45 |</span><br><span class="line">| 王丽      |     44 |</span><br><span class="line">| 李军      |     44 |</span><br><span class="line">| 王芳      |     45 |</span><br><span class="line">| 陆军      |     46 |</span><br><span class="line">| 王尼玛    |     44 |</span><br><span class="line">| 张全蛋    |     45 |</span><br><span class="line">| 赵铁柱    |     46 |</span><br><span class="line">| 王喜全    |     46 |</span><br><span class="line">+-----------+--------+</span><br></pre></td></tr></table></figure><br><h4 id="MAX-与-MIN-函数"><a href="#MAX-与-MIN-函数" class="headerlink" title="MAX 与 MIN 函数"></a>MAX 与 MIN 函数</h4><p>查询 <code>student</code> 表中最大和最小的 <code>birthday</code> 值</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">-- 查询 &#96;student&#96; 表中最大和最小的 &#96;birthday&#96; 值</span><br><span class="line">select max(birthday), min(birthday) from student; -- 根据年份数值的大小</span><br><span class="line"></span><br><span class="line">mysql&gt; select max(birthday), min(birthday) from student;</span><br><span class="line">+---------------+---------------+</span><br><span class="line">| max(birthday) | min(birthday) |</span><br><span class="line">+---------------+---------------+</span><br><span class="line">| 1977-09-01    | 1974-06-03    |</span><br><span class="line">+---------------+---------------+</span><br></pre></td></tr></table></figure><br><h4 id="多段排序"><a href="#多段排序" class="headerlink" title="多段排序"></a>多段排序</h4><p>以 <code>class</code> 和 <code>birthday</code> 从大到小的顺序查询 <code>student</code> 表</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">-- 以 &#96;class&#96; 和 &#96;birthday&#96; 从大到小的顺序查询 &#96;student&#96; 表</span><br><span class="line">select * from student order by class desc, birthday;</span><br><span class="line"></span><br><span class="line">mysql&gt; select * from student order by class desc, birthday;</span><br><span class="line">+-----+-----------+-----+------------+-------+</span><br><span class="line">| no  | name      | sex | birthday   | class |</span><br><span class="line">+-----+-----------+-----+------------+-------+</span><br><span class="line">| 200 | 王喜全    | 男  | 1974-06-03 | 95038 |</span><br><span class="line">| 103 | 王丽      | 女  | 1976-01-23 | 95033 |</span><br><span class="line">| 104 | 李军      | 男  | 1976-02-20 | 95033 |</span><br><span class="line">| 107 | 王尼玛    | 男  | 1976-02-20 | 95033 |</span><br><span class="line">| 101 | 曾华      | 男  | 1977-09-01 | 95033 |</span><br><span class="line">| 106 | 陆军      | 男  | 1974-06-03 | 95031 |</span><br><span class="line">| 109 | 赵铁柱    | 男  | 1974-06-03 | 95031 |</span><br><span class="line">| 105 | 王芳      | 女  | 1975-02-10 | 95031 |</span><br><span class="line">| 108 | 张全蛋    | 男  | 1975-02-10 | 95031 |</span><br><span class="line">| 102 | 匡明      | 男  | 1975-10-02 | 95031 |</span><br><span class="line">+-----+-----------+-----+------------+-------+</span><br></pre></td></tr></table></figure><br><h4 id="子查询-5"><a href="#子查询-5" class="headerlink" title="子查询 - 5"></a>子查询 - 5</h4><p>查询 “男” 教师及其所上的课程</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><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></pre></td><td class="code"><pre><span class="line">-- 查询 &quot;男&quot; 教师及其所上的课程</span><br><span class="line">select * from teacher where sex &#x3D; &#39;男&#39;;</span><br><span class="line"></span><br><span class="line">mysql&gt; select * from teacher where sex &#x3D; &#39;男&#39;;</span><br><span class="line">+-----+--------+-----+------------+------------+-----------------+</span><br><span class="line">| no  | name   | sex | birthday   | profession | department      |</span><br><span class="line">+-----+--------+-----+------------+------------+-----------------+</span><br><span class="line">| 804 | 李诚   | 男  | 1958-12-02 | 副教授     | 计算机系        |</span><br><span class="line">| 856 | 张旭   | 男  | 1969-03-12 | 讲师       | 电子工程系      |</span><br><span class="line">+-----+--------+-----+------------+------------+-----------------+</span><br><span class="line"></span><br><span class="line">-- 查询课程</span><br><span class="line">select * from course </span><br><span class="line">where t_no in (select no from teacher where sex &#x3D; &#39;男&#39;);</span><br><span class="line"></span><br><span class="line">mysql&gt; select * from course</span><br><span class="line">    -&gt; where t_no in (select no from teacher where sex &#x3D; &#39;男&#39;);</span><br><span class="line">+-------+--------------+------+</span><br><span class="line">| no    | name         | t_no |</span><br><span class="line">+-------+--------------+------+</span><br><span class="line">| 3-245 | 操作系统     | 804  |</span><br><span class="line">| 6-166 | 数字电路     | 856  |</span><br><span class="line">+-------+--------------+------+</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- 显示教师姓名</span><br><span class="line">select teacher.name, course.name </span><br><span class="line">from teacher,course </span><br><span class="line">where t_no in (select no from teacher where sex &#x3D; &#39;男&#39;) </span><br><span class="line">and teacher.no &#x3D; course.t_no;</span><br><span class="line"></span><br><span class="line">mysql&gt; select teacher.name, course.name</span><br><span class="line">    -&gt; from teacher,course</span><br><span class="line">    -&gt; where t_no in (select no from teacher where sex &#x3D; &#39;男&#39;)</span><br><span class="line">    -&gt; and teacher.no &#x3D; course.t_no;</span><br><span class="line">+--------+--------------+</span><br><span class="line">| name   | name         |</span><br><span class="line">+--------+--------------+</span><br><span class="line">| 李诚   | 操作系统     |</span><br><span class="line">| 张旭   | 数字电路     |</span><br><span class="line">+--------+--------------+</span><br></pre></td></tr></table></figure><br><h4 id="MAX-函数与子查询"><a href="#MAX-函数与子查询" class="headerlink" title="MAX 函数与子查询"></a>MAX 函数与子查询</h4><p>查询最高分同学的 <code>score</code> </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></pre></td><td class="code"><pre><span class="line">-- 查询最高分同学的 &#96;score&#96; </span><br><span class="line">-- 查询最高成绩</span><br><span class="line">select max(degree) from score;</span><br><span class="line"></span><br><span class="line">mysql&gt; select max(degree) from score;</span><br><span class="line">+-------------+</span><br><span class="line">| max(degree) |</span><br><span class="line">+-------------+</span><br><span class="line">|          92 |</span><br><span class="line">+-------------+</span><br><span class="line"></span><br><span class="line">-- 查询学生</span><br><span class="line">select * from score </span><br><span class="line">where degree &#x3D; (select max(degree) from score);</span><br><span class="line"></span><br><span class="line">mysql&gt; select * from score</span><br><span class="line">    -&gt; where degree &#x3D; (select max(degree) from score);</span><br><span class="line">+------+-------+--------+</span><br><span class="line">| s_no | c_no  | degree |</span><br><span class="line">+------+-------+--------+</span><br><span class="line">| 103  | 3-105 |     92 |</span><br><span class="line">+------+-------+--------+</span><br><span class="line"></span><br><span class="line">-- 多表查询</span><br><span class="line">select student.name, score.s_no, degree </span><br><span class="line">from student,score </span><br><span class="line">where degree &#x3D; (select max(degree) from score)</span><br><span class="line">and student.no &#x3D; score.s_no;</span><br><span class="line"></span><br><span class="line">mysql&gt; select student.name, score.s_no, degree</span><br><span class="line">    -&gt; from student,score</span><br><span class="line">    -&gt; where degree &#x3D; (select max(degree) from score)</span><br><span class="line">    -&gt; and student.no &#x3D; score.s_no;</span><br><span class="line">+--------+------+--------+</span><br><span class="line">| name   | s_no | degree |</span><br><span class="line">+--------+------+--------+</span><br><span class="line">| 王丽   | 103  |     92 |</span><br><span class="line">+--------+------+--------+</span><br></pre></td></tr></table></figure><br><h4 id="子查询-6"><a href="#子查询-6" class="headerlink" title="子查询 - 6"></a>子查询 - 6</h4><p>查询和 “李军” 同性别的所有同学 <code>name</code> </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></pre></td><td class="code"><pre><span class="line">-- 查询和 &quot;李军&quot; 同性别的所有同学 &#96;name&#96; </span><br><span class="line"></span><br><span class="line">-- 查询李军性别</span><br><span class="line">select sex from student where name &#x3D; &#39;李军&#39;;</span><br><span class="line"></span><br><span class="line">mysql&gt; select sex from student where name &#x3D; &#39;李军&#39;;</span><br><span class="line">+-----+</span><br><span class="line">| sex |</span><br><span class="line">+-----+</span><br><span class="line">| 男  |</span><br><span class="line">+-----+</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- 查询同性别</span><br><span class="line">select name from student </span><br><span class="line">where sex &#x3D; (select sex from student where name &#x3D; &#39;李军&#39;);</span><br><span class="line"></span><br><span class="line">mysql&gt; select name from student</span><br><span class="line">    -&gt; where sex &#x3D; (select sex from student where name &#x3D; &#39;李军&#39;);</span><br><span class="line">+-----------+</span><br><span class="line">| name      |</span><br><span class="line">+-----------+</span><br><span class="line">| 曾华      |</span><br><span class="line">| 匡明      |</span><br><span class="line">| 李军      |</span><br><span class="line">| 陆军      |</span><br><span class="line">| 王尼玛    |</span><br><span class="line">| 张全蛋    |</span><br><span class="line">| 赵铁柱    |</span><br><span class="line">| 王喜全    |</span><br><span class="line">+-----------+</span><br></pre></td></tr></table></figure><br><h4 id="子查询-7"><a href="#子查询-7" class="headerlink" title="子查询 - 7"></a>子查询 - 7</h4><p>查询和 “李军” 同性别且同班的同学 <code>name</code></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">-- 查询和 &quot;李军&quot; 同性别且同班的同学 &#96;name&#96;</span><br><span class="line">select name, class from student </span><br><span class="line">where sex &#x3D; (select sex from student where name &#x3D; &#39;李军&#39;)</span><br><span class="line">and class &#x3D; (select class from student where name &#x3D; &#39;李军&#39;);</span><br><span class="line"></span><br><span class="line">mysql&gt; select name, class from student</span><br><span class="line">    -&gt; where sex &#x3D; (select sex from student where name &#x3D; &#39;李军&#39;)</span><br><span class="line">    -&gt; and class &#x3D; (select class from student where name &#x3D; &#39;李军&#39;);</span><br><span class="line">+-----------+-------+</span><br><span class="line">| name      | class |</span><br><span class="line">+-----------+-------+</span><br><span class="line">| 曾华      | 95033 |</span><br><span class="line">| 李军      | 95033 |</span><br><span class="line">| 王尼玛    | 95033 |</span><br><span class="line">+-----------+-------+</span><br></pre></td></tr></table></figure><br><h4 id="子查询-8"><a href="#子查询-8" class="headerlink" title="子查询 - 8"></a>子查询 - 8</h4><p>查询所有选修 “计算机导论” 课程的 “男” 同学成绩表</p><p>需要的 “计算机导论” 和性别为 “男” 的编号可以在 <code>course</code> 和 <code>student</code> 表中找到</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></pre></td><td class="code"><pre><span class="line">-- 查询所有选修 &quot;计算机导论&quot; 课程的 &quot;男&quot; 同学成绩表</span><br><span class="line"></span><br><span class="line">-- 查询计算机导论</span><br><span class="line">select * from course where name &#x3D; &#39;计算机导论&#39;;</span><br><span class="line"></span><br><span class="line">mysql&gt; select * from course where name &#x3D; &#39;计算机导论&#39;;</span><br><span class="line">+-------+-----------------+------+</span><br><span class="line">| no    | name            | t_no |</span><br><span class="line">+-------+-----------------+------+</span><br><span class="line">| 3-105 | 计算机导论      | 825  |</span><br><span class="line">+-------+-----------------+------+</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- 查询性别为男</span><br><span class="line">select * from student where sex &#x3D; &#39;男&#39;;</span><br><span class="line"></span><br><span class="line">mysql&gt; select * from student where sex &#x3D; &#39;男&#39;;</span><br><span class="line">+-----+-----------+-----+------------+-------+</span><br><span class="line">| no  | name      | sex | birthday   | class |</span><br><span class="line">+-----+-----------+-----+------------+-------+</span><br><span class="line">| 101 | 曾华      | 男  | 1977-09-01 | 95033 |</span><br><span class="line">| 102 | 匡明      | 男  | 1975-10-02 | 95031 |</span><br><span class="line">| 104 | 李军      | 男  | 1976-02-20 | 95033 |</span><br><span class="line">| 106 | 陆军      | 男  | 1974-06-03 | 95031 |</span><br><span class="line">| 107 | 王尼玛    | 男  | 1976-02-20 | 95033 |</span><br><span class="line">| 108 | 张全蛋    | 男  | 1975-02-10 | 95031 |</span><br><span class="line">| 109 | 赵铁柱    | 男  | 1974-06-03 | 95031 |</span><br><span class="line">| 200 | 王喜全    | 男  | 1974-06-03 | 95038 |</span><br><span class="line">+-----+-----------+-----+------------+-------+</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- 查询成绩表</span><br><span class="line">select * from score </span><br><span class="line">where c_no &#x3D; (select no from course where name &#x3D; &#39;计算机导论&#39;)</span><br><span class="line">and s_no in (select no from student where sex &#x3D; &#39;男&#39;);</span><br><span class="line"></span><br><span class="line">mysql&gt; select * from score</span><br><span class="line">    -&gt; where c_no &#x3D; (select no from course where name &#x3D; &#39;计算机导论&#39;)</span><br><span class="line">    -&gt; and s_no in (select no from student where sex &#x3D; &#39;男&#39;);</span><br><span class="line">+------+-------+--------+</span><br><span class="line">| s_no | c_no  | degree |</span><br><span class="line">+------+-------+--------+</span><br><span class="line">| 101  | 3-105 |     90 |</span><br><span class="line">| 102  | 3-105 |     91 |</span><br><span class="line">| 104  | 3-105 |     89 |</span><br><span class="line">| 109  | 3-105 |     76 |</span><br><span class="line">+------+-------+--------+</span><br></pre></td></tr></table></figure><br><h4 id="按等级查询"><a href="#按等级查询" class="headerlink" title="按等级查询"></a>按等级查询</h4><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></pre></td><td class="code"><pre><span class="line">-- 建立一个 &#96;grade&#96; 表代表学生的成绩等级，并插入数据</span><br><span class="line">create table grade(</span><br><span class="line">  low int(5),</span><br><span class="line">  top int(5),</span><br><span class="line">  grade char(1) </span><br><span class="line">);</span><br><span class="line"></span><br><span class="line">insert into grade values(90, 100, &#39;A&#39;);</span><br><span class="line">INSERT INTO grade VALUES (80, 89, &#39;B&#39;);</span><br><span class="line">INSERT INTO grade VALUES (70, 79, &#39;C&#39;);</span><br><span class="line">INSERT INTO grade VALUES (60, 69, &#39;D&#39;);</span><br><span class="line">INSERT INTO grade VALUES (0, 59, &#39;E&#39;);</span><br><span class="line"></span><br><span class="line">mysql&gt; select * from grade;</span><br><span class="line">+------+------+-------+</span><br><span class="line">| low  | top  | grade |</span><br><span class="line">+------+------+-------+</span><br><span class="line">|   90 |  100 | A     |</span><br><span class="line">|   80 |   89 | B     |</span><br><span class="line">|   70 |   79 | C     |</span><br><span class="line">|   60 |   69 | D     |</span><br><span class="line">|    0 |   59 | E     |</span><br><span class="line">+------+------+-------+</span><br><span class="line"></span><br><span class="line">-- 查询所有学生的degree  s_no 、c_no 和 grade 列</span><br><span class="line">select score.degree, score.s_no, score.c_no, grade </span><br><span class="line">from score, grade </span><br><span class="line">where degree between low and top;</span><br><span class="line"></span><br><span class="line">ysql&gt; select score.degree, score.s_no, score.c_no, grade</span><br><span class="line">    -&gt; from score, grade</span><br><span class="line">    -&gt; where degree between low and top;</span><br><span class="line">+--------+------+-------+-------+</span><br><span class="line">| degree | s_no | c_no  | grade |</span><br><span class="line">+--------+------+-------+-------+</span><br><span class="line">|     90 | 101  | 3-105 | A     |</span><br><span class="line">|     91 | 102  | 3-105 | A     |</span><br><span class="line">|     92 | 103  | 3-105 | A     |</span><br><span class="line">|     86 | 103  | 3-245 | B     |</span><br><span class="line">|     85 | 103  | 6-166 | B     |</span><br><span class="line">|     89 | 104  | 3-105 | B     |</span><br><span class="line">|     88 | 105  | 3-105 | B     |</span><br><span class="line">|     75 | 105  | 3-245 | C     |</span><br><span class="line">|     79 | 105  | 6-166 | C     |</span><br><span class="line">|     76 | 109  | 3-105 | C     |</span><br><span class="line">|     68 | 109  | 3-245 | D     |</span><br><span class="line">|     81 | 109  | 6-166 | B     |</span><br><span class="line">+--------+------+-------+-------+</span><br></pre></td></tr></table></figure><br><br><h3 id="mysql连接查询"><a href="#mysql连接查询" class="headerlink" title="mysql连接查询"></a>mysql连接查询</h3><p><img src="/2020/06/26/mysql%E6%95%B0%E6%8D%AE%E5%BA%93/mysql%E8%BF%9E%E6%8E%A5%E6%9F%A5%E8%AF%A2.png" alt="mysql连接查询"></p><h4 id="准备数据："><a href="#准备数据：" class="headerlink" title="准备数据："></a><strong>准备数据：</strong></h4><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></pre></td><td class="code"><pre><span class="line">CREATE DATABASE testJoin;</span><br><span class="line"></span><br><span class="line">CREATE TABLE person (</span><br><span class="line">    id INT,</span><br><span class="line">    name VARCHAR(20),</span><br><span class="line">    cardId INT</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line">CREATE TABLE card (</span><br><span class="line">    id INT,</span><br><span class="line">    name VARCHAR(20)</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line">INSERT INTO card VALUES (1, &#39;饭卡&#39;), (2, &#39;建行卡&#39;), (3, &#39;农行卡&#39;), (4, &#39;工商卡&#39;), (5, &#39;邮政卡&#39;);</span><br><span class="line"></span><br><span class="line">SELECT * FROM card;</span><br><span class="line">+------+-----------+</span><br><span class="line">| id   | name      |</span><br><span class="line">+------+-----------+</span><br><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">+------+-----------+</span><br><span class="line"></span><br><span class="line">INSERT INTO person VALUES (1, &#39;张三&#39;, 1), (2, &#39;李四&#39;, 3), (3, &#39;王五&#39;, 6);</span><br><span class="line"></span><br><span class="line">SELECT * FROM person;</span><br><span class="line">+------+--------+--------+</span><br><span class="line">| id   | name   | cardId |</span><br><span class="line">+------+--------+--------+</span><br><span class="line">|    1 | 张三   |      1 |</span><br><span class="line">|    2 | 李四   |      3 |</span><br><span class="line">|    3 | 王五   |      6 |</span><br><span class="line">+------+--------+--------+</span><br></pre></td></tr></table></figure><p>分析两张表发现，<code>person</code> 表并没有为 <code>cardId</code> 字段设置一个在 <code>card</code> 表中对应的 <code>id</code> 外键。如果设置了的话，<code>person</code> 中 <code>cardId</code> 字段值为 <code>6</code> 的行就插不进去，因为该 <code>cardId</code> 值在 <code>card</code> 表中并没有</p><h4 id="内连接"><a href="#内连接" class="headerlink" title="内连接"></a>内连接</h4><p>inner join 或者 join</p><p>要查询这两张表中有关系的数据，可以使用 <code>INNER JOIN</code> ( 内连接 ) 将它们连接在一起</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></pre></td><td class="code"><pre><span class="line">select * from person inner join card on person.cardId &#x3D; card.id;</span><br><span class="line"></span><br><span class="line">mysql&gt; select * from person inner join card on person.cardId &#x3D; card.id;</span><br><span class="line">+------+--------+--------+------+-----------+</span><br><span class="line">| id   | name   | cardId | id   | name      |</span><br><span class="line">+------+--------+--------+------+-----------+</span><br><span class="line">|    1 | 张三   |      1 |    1 | 饭卡      |</span><br><span class="line">|    2 | 李四   |      3 |    3 | 农行卡    |</span><br><span class="line">+------+--------+--------+------+-----------+</span><br><span class="line"></span><br><span class="line">-- 将 INNER 关键字省略掉，结果也是一样的</span><br><span class="line">-- SELECT * FROM person JOIN card on person.cardId &#x3D; card.id;</span><br></pre></td></tr></table></figure><p><strong>注意：</strong><code>card</code> 的整张表被连接到了右边</p><br><h4 id="外链接"><a href="#外链接" class="headerlink" title="外链接"></a>外链接</h4><p><strong>左外连接：</strong>left join 或者 left outer join</p><p>完整显示左边的表 ( <code>person</code> ) ，右边的表如果符合条件就显示，不符合则补 <code>NULL</code></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></pre></td><td class="code"><pre><span class="line">select * from person left join card on person.cardId &#x3D; card.id;</span><br><span class="line"></span><br><span class="line">mysql&gt; select * from person left join card on person.cardId &#x3D; card.id;</span><br><span class="line">+------+--------+--------+------+-----------+</span><br><span class="line">| id   | name   | cardId | id   | name      |</span><br><span class="line">+------+--------+--------+------+-----------+</span><br><span class="line">|    1 | 张三   |      1 |    1 | 饭卡      |</span><br><span class="line">|    2 | 李四   |      3 |    3 | 农行卡    |</span><br><span class="line">|    3 | 王五   |      6 | NULL | NULL      |</span><br><span class="line">+------+--------+--------+------+-----------+</span><br><span class="line"></span><br><span class="line">--  left outer join，结果也是一样的</span><br></pre></td></tr></table></figure><br><p><strong>右外连接：</strong>right join 或者 right outer join</p><p>完整显示右边的表 ( <code>card</code> ) ，左边的表如果符合条件就显示，不符合则补 <code>NULL</code></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">select * from person right join card on person.cardId &#x3D; card.id;</span><br><span class="line"></span><br><span class="line">mysql&gt; select * from person right join card on person.cardId &#x3D; card.id;</span><br><span class="line">+------+--------+--------+------+-----------+</span><br><span class="line">| id   | name   | cardId | id   | name      |</span><br><span class="line">+------+--------+--------+------+-----------+</span><br><span class="line">|    1 | 张三   |      1 |    1 | 饭卡      |</span><br><span class="line">|    2 | 李四   |      3 |    3 | 农行卡    |</span><br><span class="line">| NULL | NULL   |   NULL |    2 | 建行卡    |</span><br><span class="line">| NULL | NULL   |   NULL |    4 | 工商卡    |</span><br><span class="line">| NULL | NULL   |   NULL |    5 | 邮政卡    |</span><br><span class="line">+------+--------+--------+------+-----------+</span><br><span class="line"></span><br><span class="line">--  right outer join，结果也是一样的</span><br></pre></td></tr></table></figure><br><p><strong>完全连接：</strong>full join 或者 full outer join</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">-- mysql 不支持全连接语法</span><br><span class="line">-- SELECT * FROM person FULL JOIN card on person.cardId &#x3D; card.id;</span><br><span class="line">-- ERROR 1054 (42S22): Unknown column &#39;person.cardId&#39; in &#39;on clause&#39;</span><br><span class="line"></span><br><span class="line">-- 使用union</span><br><span class="line">select * from person left join card on person.cardId &#x3D; card.id</span><br><span class="line">union</span><br><span class="line">select * from person right join card on person.cardId &#x3D; card.id;</span><br><span class="line"></span><br><span class="line">mysql&gt; select * from person left join card on person.cardId &#x3D; card.id</span><br><span class="line">    -&gt; union</span><br><span class="line">    -&gt; select * from person right join card on person.cardId &#x3D; card.id;</span><br><span class="line">+------+--------+--------+------+-----------+</span><br><span class="line">| id   | name   | cardId | id   | name      |</span><br><span class="line">+------+--------+--------+------+-----------+</span><br><span class="line">|    1 | 张三   |      1 |    1 | 饭卡      |</span><br><span class="line">|    2 | 李四   |      3 |    3 | 农行卡    |</span><br><span class="line">|    3 | 王五   |      6 | NULL | NULL      |</span><br><span class="line">| NULL | NULL   |   NULL |    2 | 建行卡    |</span><br><span class="line">| NULL | NULL   |   NULL |    4 | 工商卡    |</span><br><span class="line">| NULL | NULL   |   NULL |    5 | 邮政卡    |</span><br><span class="line">+------+--------+--------+------+-----------+</span><br></pre></td></tr></table></figure><p><br><br></p><h3 id="事务"><a href="#事务" class="headerlink" title="事务"></a>事务</h3><p>在 MySQL 中，事务其实是一个最小的不可分割的工作单元。事务能够<strong>保证一个业务的完整性</strong>。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">-- 比如我们的银行转账：</span><br><span class="line">-- a -&gt; -100</span><br><span class="line">UPDATE user set money &#x3D; money - 100 WHERE name &#x3D; &#39;a&#39;;</span><br><span class="line"></span><br><span class="line">-- b -&gt; +100</span><br><span class="line">UPDATE user set money &#x3D; money + 100 WHERE name &#x3D; &#39;b&#39;;</span><br></pre></td></tr></table></figure><p>在实际项目中，假设只有一条 SQL 语句执行成功，而另外一条执行失败了，就会出现数据前后不一致。</p><p>因此，在执行多条有关联 SQL 语句时，<strong>事务</strong>会要求这些 SQL 语句要么同时执行成功，要么就都执行失败。</p><br><h4 id="如何控制事务-COMMIT-ROLLBACK"><a href="#如何控制事务-COMMIT-ROLLBACK" class="headerlink" title="如何控制事务 - COMMIT / ROLLBACK"></a>如何控制事务 - COMMIT / ROLLBACK</h4><p>在 MySQL 中，事务的<strong>自动提交</strong>状态默认是开启的</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">-- 查询事务的自动提交状态</span><br><span class="line">SELECT @@AUTOCOMMIT;</span><br><span class="line"></span><br><span class="line">mysql&gt; SELECT @@AUTOCOMMIT;</span><br><span class="line">+--------------+</span><br><span class="line">| @@AUTOCOMMIT |</span><br><span class="line">+--------------+</span><br><span class="line">|            1 |</span><br><span class="line">+--------------+</span><br></pre></td></tr></table></figure><p><strong>自动提交的作用</strong>：当我们执行一条 SQL 语句的时候，其产生的效果就会立即体现出来，且不能<strong>回滚</strong>。</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><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">CREATE DATABASE bank;</span><br><span class="line"></span><br><span class="line">CREATE TABLE user (</span><br><span class="line">    id INT PRIMARY KEY,</span><br><span class="line">    name VARCHAR(20),</span><br><span class="line">    money INT</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line">-- 插入数据</span><br><span class="line">INSERT INTO user VALUES (1, &#39;a&#39;, 1000);</span><br><span class="line"></span><br><span class="line">SELECT * FROM user;</span><br><span class="line">+----+------+-------+</span><br><span class="line">| id | name | money |</span><br><span class="line">+----+------+-------+</span><br><span class="line">|  1 | a    |  1000 |</span><br><span class="line">+----+------+-------+</span><br></pre></td></tr></table></figure><p>可以看到，在执行插入语句后数据立刻生效，原因是 MySQL 中的事务自动将它<strong>提交</strong>到了数据库中。那么所谓<strong>回滚</strong>的意思就是，撤销执行过的所有 SQL 语句，使其回滚到<strong>最后一次提交</strong>数据时的状态。</p><p>在 MySQL 中使用 <code>ROLLBACK</code> 执行回滚：</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></pre></td><td class="code"><pre><span class="line">-- 回滚到最后一次提交</span><br><span class="line">rollback;</span><br><span class="line"></span><br><span class="line">mysql&gt; rollback;</span><br><span class="line">Query OK, 0 rows affected (0.00 sec)</span><br><span class="line"></span><br><span class="line">mysql&gt; SELECT * FROM user;</span><br><span class="line">+----+------+-------+</span><br><span class="line">| id | name | money |</span><br><span class="line">+----+------+-------+</span><br><span class="line">|  1 | a    |  1000 |</span><br><span class="line">+----+------+-------+</span><br></pre></td></tr></table></figure><p>由于所有执行过的 SQL 语句都已经被提交过了，所以数据并没有发生回滚。那如何让数据可以发生回滚： 设置AUTOCOMMIT = 0；</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><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></pre></td><td class="code"><pre><span class="line">-- 关闭自动提交</span><br><span class="line">-- 关闭 AUTOCOMMIT 后，数据的变化是在一张虚拟的临时数据表中展示，</span><br><span class="line">-- 发生变化的数据并没有真正插入到数据表中。</span><br><span class="line">SET AUTOCOMMIT &#x3D; 0;</span><br><span class="line"></span><br><span class="line">mysql&gt; SET AUTOCOMMIT &#x3D; 0;</span><br><span class="line">Query OK, 0 rows affected (0.00 sec)</span><br><span class="line"></span><br><span class="line">mysql&gt; select @@autocommit;</span><br><span class="line">+--------------+</span><br><span class="line">| @@autocommit |</span><br><span class="line">+--------------+</span><br><span class="line">|            0 |</span><br><span class="line">+--------------+</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- 测试回滚</span><br><span class="line">INSERT INTO user VALUES (2, &#39;b&#39;, 1000);</span><br><span class="line"></span><br><span class="line">mysql&gt; INSERT INTO user VALUES (2, &#39;b&#39;, 1000);</span><br><span class="line">Query OK, 1 row affected (0.00 sec)</span><br><span class="line"></span><br><span class="line">mysql&gt; SELECT * FROM user;</span><br><span class="line">+----+------+-------+</span><br><span class="line">| id | name | money |</span><br><span class="line">+----+------+-------+</span><br><span class="line">|  1 | a    |  1000 |</span><br><span class="line">|  2 | b    |  1000 |</span><br><span class="line">+----+------+-------+</span><br><span class="line"></span><br><span class="line">mysql&gt; rollback;</span><br><span class="line">Query OK, 0 rows affected (0.00 sec)</span><br><span class="line"></span><br><span class="line">mysql&gt; SELECT * FROM user;</span><br><span class="line">+----+------+-------+</span><br><span class="line">| id | name | money |</span><br><span class="line">+----+------+-------+</span><br><span class="line">|  1 | a    |  1000 |</span><br><span class="line">+----+------+-------+</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- 手动提交数据（持久性），</span><br><span class="line">-- 将数据真正提交到数据库中，执行后不能再回滚提交过的数据</span><br><span class="line">commit;</span><br><span class="line"></span><br><span class="line">mysql&gt; INSERT INTO user VALUES (2, &#39;b&#39;, 1000);</span><br><span class="line">Query OK, 1 row affected (0.00 sec)</span><br><span class="line"></span><br><span class="line">mysql&gt; commit;</span><br><span class="line">Query OK, 0 rows affected (0.00 sec)</span><br><span class="line"></span><br><span class="line">mysql&gt; rollback;</span><br><span class="line">Query OK, 0 rows affected (0.00 sec)</span><br><span class="line"></span><br><span class="line">mysql&gt; SELECT * FROM user;</span><br><span class="line">+----+------+-------+</span><br><span class="line">| id | name | money |</span><br><span class="line">+----+------+-------+</span><br><span class="line">|  1 | a    |  1000 |</span><br><span class="line">|  2 | b    |  1000 |</span><br><span class="line">+----+------+-------+</span><br><span class="line">-- 发现回滚无效</span><br></pre></td></tr></table></figure><p><strong>总结：</strong></p><ol><li><p><strong>自动提交</strong></p><ul><li>查看自动提交状态：<code>SELECT @@AUTOCOMMIT</code> ；</li><li>设置自动提交状态：<code>SET AUTOCOMMIT = 0</code> 。</li></ul></li><li><p><strong>手动提交</strong></p><p> <code>@@AUTOCOMMIT = 0</code> 时，使用 <code>COMMIT</code> 命令提交事务。</p></li><li><p><strong>事务回滚</strong></p><p> <code>@@AUTOCOMMIT = 0</code> 时，使用 <code>ROLLBACK</code> 命令回滚事务。</p></li></ol><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></pre></td><td class="code"><pre><span class="line">-- 测试银行转账</span><br><span class="line">update user set money &#x3D; money - 100 where id &#x3D; 1;</span><br><span class="line">update user set money &#x3D; money + 100 where id &#x3D; 2;</span><br><span class="line"></span><br><span class="line">mysql&gt; select * from user;</span><br><span class="line">+----+------+-------+</span><br><span class="line">| id | name | money |</span><br><span class="line">+----+------+-------+</span><br><span class="line">|  1 | a    |   900 |</span><br><span class="line">|  2 | b    |  1100 |</span><br><span class="line">+----+------+-------+</span><br><span class="line"></span><br><span class="line">-- 回滚：假设转账发生了意外，需要回滚</span><br><span class="line">rollback;</span><br><span class="line"></span><br><span class="line">mysql&gt; rollback;</span><br><span class="line">Query OK, 0 rows affected (0.00 sec)</span><br><span class="line"></span><br><span class="line">mysql&gt; select * from user;</span><br><span class="line">+----+------+-------+</span><br><span class="line">| id | name | money |</span><br><span class="line">+----+------+-------+</span><br><span class="line">|  1 | a    |  1000 |</span><br><span class="line">|  2 | b    |  1000 |</span><br><span class="line">+----+------+-------+</span><br></pre></td></tr></table></figure><p>这时我们又回到了发生意外之前的状态，也就是说，事务给我们提供了一个可以反悔的机会。假设数据没有发生意外，这时可以手动将数据真正提交到数据表中：<code>COMMIT</code> </p><br><h4 id="手动开启事务-BEGIN-START-TRANSACTION"><a href="#手动开启事务-BEGIN-START-TRANSACTION" class="headerlink" title="手动开启事务 - BEGIN / START TRANSACTION"></a>手动开启事务 - BEGIN / START TRANSACTION</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">-- 设置为自动提交</span><br><span class="line">set autocommit &#x3D; 1;</span><br><span class="line"></span><br><span class="line">select @@autocommit;</span><br><span class="line"></span><br><span class="line">mysql&gt; select @@autocommit;</span><br><span class="line">+--------------+</span><br><span class="line">| @@autocommit |</span><br><span class="line">+--------------+</span><br><span class="line">|            1 |</span><br><span class="line">+--------------+</span><br></pre></td></tr></table></figure><p>事务的默认提交被开启 ( <code>@@AUTOCOMMIT = 1</code> ) 后，此时就不能使用事务回滚了。但是我们还可以手动开启一个事务处理事件，使其可以发生回滚：</p><p><strong>使用 BEGIN 或者 START TRANSACTION 手动开启一个事务:</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><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">-- 使用 BEGIN 或者 START TRANSACTION 手动开启一个事务</span><br><span class="line">begin;</span><br><span class="line">update user set money &#x3D; money - 100 where id &#x3D; 1;</span><br><span class="line">update user set money &#x3D; money + 100 where id &#x3D; 2;</span><br><span class="line"></span><br><span class="line">mysql&gt; select * from user;</span><br><span class="line">+----+------+-------+</span><br><span class="line">| id | name | money |</span><br><span class="line">+----+------+-------+</span><br><span class="line">|  1 | a    |   900 |</span><br><span class="line">|  2 | b    |  1100 |</span><br><span class="line">+----+------+-------+</span><br><span class="line"></span><br><span class="line">-- 回滚</span><br><span class="line">rollback;</span><br><span class="line"></span><br><span class="line">mysql&gt; rollback;</span><br><span class="line">Query OK, 0 rows affected (0.00 sec)</span><br><span class="line"></span><br><span class="line">mysql&gt; select * from user;</span><br><span class="line">+----+------+-------+</span><br><span class="line">| id | name | money |</span><br><span class="line">+----+------+-------+</span><br><span class="line">|  1 | a    |  1000 |</span><br><span class="line">|  2 | b    |  1000 |</span><br><span class="line">+----+------+-------+</span><br><span class="line"></span><br><span class="line">-- 用commit提交事务</span><br></pre></td></tr></table></figure><br><h4 id="事务的-ACID-特征与使用"><a href="#事务的-ACID-特征与使用" class="headerlink" title="事务的 ACID 特征与使用"></a>事务的 ACID 特征与使用</h4><p>事务的四大特征：</p><p>A(Atomicity)：原子性：事务是最小的单位，不可以再分割；</p><p>C(Consistency)：一致性：要求同一事务中的 SQL 语句，必须保证同时成功或者失败；</p><p>I(Isolation)： 隔离性：事务1 和 事务2 之间是具有隔离性的；</p><p>D(Durability)：持久性：事务一旦结束 ( <code>COMMIT</code> ) ，就不可以再返回了 ( <code>ROLLBACK</code> ) ；</p><br><p><strong>事务的隔离性可分为四种 ( 性能从低到高 )</strong> ：</p><ol><li><p><strong>READ - UNCOMMITTED ( 读取未提交 )</strong></p><p> 如果有多个事务，那么任意事务都可以看见其他事务的<strong>未提交数据</strong>。</p></li><li><p><strong>READ - COMMITTED ( 读取已提交 )</strong></p><p> 只能读取到其他事务<strong>已经提交的数据</strong>。</p></li><li><p><strong>REPEATABLE - READ ( 可被重复读 )</strong></p><p> 如果有多个连接都开启了事务，那么事务之间不能共享数据记录，否则只能共享已提交的记录。</p></li><li><p><strong>SERIALIZABLE ( 串行化 )</strong></p><p> 所有的事务都会按照<strong>固定顺序执行</strong>，执行完一个事务后再继续执行下一个事务的<strong>写入操作</strong>。</p></li></ol><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></pre></td><td class="code"><pre><span class="line">-- 查看当前数据库的默认隔离级别：</span><br><span class="line">-- MySQL 8.x, GLOBAL 表示系统级别，不加表示会话级别。</span><br><span class="line">SELECT @@GLOBAL.TRANSACTION_ISOLATION;</span><br><span class="line">SELECT @@TRANSACTION_ISOLATION;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- MySQL 5.x</span><br><span class="line">mysql&gt; SELECT @@GLOBAL.TX_ISOLATION;</span><br><span class="line">+-----------------------+</span><br><span class="line">| @@GLOBAL.TX_ISOLATION |</span><br><span class="line">+-----------------------+</span><br><span class="line">| REPEATABLE-READ       | -- MySQL的默认隔离级别，可以重复读。</span><br><span class="line">+-----------------------+</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- 设置系统隔离级别，LEVEL 后面表示要设置的隔离级别 (READ UNCOMMITTED)</span><br><span class="line">set global transaction isolation level READ COMMITTED;</span><br><span class="line"></span><br><span class="line">mysql&gt; set global transaction isolation level READ COMMITTED;</span><br><span class="line">Query OK, 0 rows affected (0.01 sec)</span><br><span class="line"></span><br><span class="line">mysql&gt; SELECT @@GLOBAL.TX_ISOLATION;</span><br><span class="line">+-----------------------+</span><br><span class="line">| @@GLOBAL.TX_ISOLATION |</span><br><span class="line">+-----------------------+</span><br><span class="line">| READ-COMMITTED        |</span><br><span class="line">+-----------------------+</span><br></pre></td></tr></table></figure><br><p><strong>脏读：</strong>READ UNCOMMITTED ( 读取未提交 )</p><p>一个事务读取到另外一个事务还未提交的数据。这在实际开发中是不允许出现的；</p><p>如果此时 rollback ，之前操作的数据就会失效</p><br><p><strong>不可重复读：</strong>读取已提交：READ - COMMITTED ( 读取已提交 )</p><p>虽然 READ COMMITTED 让我们只能读取到其他事务已经提交的数据，但还是会出现问题，就是在读取同一个表的数据时，可能会发生前后不一致的情况。这被称为不可重复读现象 ( READ COMMITTED ) </p><br><p><strong>幻读：</strong>REPEATABLE - READ ( 可被重复读 )</p><p>当前事务开启后，没提交之前，查询不到，提交后可以被查询到。但是，在提交之前其他事务被开启了，那么在这条事务线上，就不会查询到当前有操作事务的连接。相当于开辟出一条单独的线程。</p><p>无论小张是否执行过 <code>COMMIT</code> ，在小王这边，都不会查询到小张的事务记录，而是只会查询到自己所处事务的记录</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">-- 小张 - 成都</span><br><span class="line">START TRANSACTION;</span><br><span class="line">INSERT INTO user VALUES (6, &#39;d&#39;, 1000);</span><br><span class="line"></span><br><span class="line">-- 小王 - 北京</span><br><span class="line">START TRANSACTION;</span><br><span class="line"></span><br><span class="line">-- 小张 - 成都</span><br><span class="line">COMMIT;</span><br><span class="line"></span><br><span class="line">SELECT * FROM user;</span><br><span class="line">+----+-----------+-------+</span><br><span class="line">| id | name      | money |</span><br><span class="line">+----+-----------+-------+</span><br><span class="line">|  1 | a         |   900 |</span><br><span class="line">|  2 | b         |  1100 |</span><br><span class="line">|  3 | 小明      |  1000 |</span><br><span class="line">|  4 | 淘宝店    |  1000 |</span><br><span class="line">|  5 | c         |   100 |</span><br><span class="line">+----+-----------+-------+</span><br></pre></td></tr></table></figure><p>这是因为<strong>小王在此之前开启了一个新的事务 ( <code>START TRANSACTION</code> )</strong> ，那么在他的这条新事务的线上，跟其他事务是没有联系的，也就是说，此时如果其他事务正在操作数据，它是不知道的。</p><p>然而事实是，在真实的数据表中，小张已经插入了一条数据</p><br><p><strong>串行化：</strong>SERIALIZABLE ( 串行化 ) </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></pre></td><td class="code"><pre><span class="line">-- 设置隔离级别</span><br><span class="line">set global transaction isolation level SERIALIZABLE;</span><br><span class="line"></span><br><span class="line">mysql&gt; set global transaction isolation level SERIALIZABLE;</span><br><span class="line">Query OK, 0 rows affected (0.00 sec)</span><br><span class="line"></span><br><span class="line">mysql&gt; SELECT @@GLOBAL.TX_ISOLATION;</span><br><span class="line">+-----------------------+</span><br><span class="line">| @@GLOBAL.TX_ISOLATION |</span><br><span class="line">+-----------------------+</span><br><span class="line">| SERIALIZABLE          |</span><br><span class="line">+-----------------------+</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">-- 小张插入数据</span><br><span class="line">INSERT INTO user VALUES (7, &#39;hhh&#39;, 1000);</span><br><span class="line"></span><br><span class="line">mysql&gt; commit;</span><br><span class="line">Query OK, 0 rows affected (0.00 sec)</span><br><span class="line"></span><br><span class="line">mysql&gt; select * from user;</span><br><span class="line">+----+------+-------+</span><br><span class="line">| id | name | money |</span><br><span class="line">+----+------+-------+</span><br><span class="line">|  1 | a    |  1000 |</span><br><span class="line">|  2 | b    |  1000 |</span><br><span class="line">|  7 | hhh  |  1000 |</span><br><span class="line">+----+------+-------+</span><br><span class="line"></span><br><span class="line">-- 小王查询</span><br><span class="line">mysql&gt; select * from user;</span><br><span class="line">+----+------+-------+</span><br><span class="line">| id | name | money |</span><br><span class="line">+----+------+-------+</span><br><span class="line">|  1 | a    |  1000 |</span><br><span class="line">|  2 | b    |  1000 |</span><br><span class="line">|  7 | hhh  |  1000 |</span><br><span class="line">+----+------+-------+</span><br></pre></td></tr></table></figure><p>此时会发生什么呢？由于现在的隔离级别是 <strong>SERIALIZABLE ( 串行化 )</strong> ，串行化的意思就是：假设把所有的事务都放在一个串行的队列中，那么所有的事务都会按照<strong>固定顺序执行</strong>，执行完一个事务后再继续执行下一个事务的<strong>写入操作</strong> ( <strong>这意味着队列中同时只能执行一个事务的写入操作</strong> ) 。</p><p>根据这个解释，小王在插入数据时，会出现等待状态，<strong>直到小张执行 <code>COMMIT</code> 结束它所处的事务，或者出现等待超时。</strong> <strong>所以性能较差</strong></p>]]></content>
    
    <summary type="html">
    
      &lt;h3 id=&quot;登录和退出MySQL服务器&quot;&gt;&lt;a href=&quot;#登录和退出MySQL服务器&quot; class=&quot;headerlink&quot; title=&quot;登录和退出MySQL服务器&quot;&gt;&lt;/a&gt;登录和退出MySQL服务器&lt;/h3&gt;&lt;figure class=&quot;highlight plain&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;3&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;4&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;#登陆&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;mysql -uroot -p12345612;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;#退出&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;exit;&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;

&lt;br&gt;

&lt;p&gt;&lt;br&gt;&lt;/p&gt;
    
    </summary>
    
    
      <category term="mysql" scheme="https://chrisxb1996.github.io/categories/mysql/"/>
    
    
      <category term="mysql" scheme="https://chrisxb1996.github.io/tags/mysql/"/>
    
      <category term="数据库" scheme="https://chrisxb1996.github.io/tags/%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
    
  </entry>
  
  <entry>
    <title>常用数据结构和算法</title>
    <link href="https://chrisxb1996.github.io/2020/06/25/%E5%B8%B8%E7%94%A8%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/"/>
    <id>https://chrisxb1996.github.io/2020/06/25/%E5%B8%B8%E7%94%A8%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/</id>
    <published>2020-06-25T14:06:27.000Z</published>
    <updated>2020-08-07T04:20:13.034Z</updated>
    
    <content type="html"><![CDATA[<h3 id="排序算法"><a href="#排序算法" class="headerlink" title="排序算法"></a>排序算法</h3><h4 id="冒泡排序"><a href="#冒泡排序" class="headerlink" title="冒泡排序"></a><strong>冒泡排序</strong></h4><ul><li>需要 array.length-1 轮的比较，可以通过优化标识来减少比较的次数，时间复杂度O(n^2)</li></ul><p><img src="/2020/06/25/%E5%B8%B8%E7%94%A8%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/%E5%86%92%E6%B3%A1%E6%8E%92%E5%BA%8F.png" alt="冒泡排序"><a id="more"></a></p><figure class="highlight java"><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="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">bubbleSort</span><span class="params">(<span class="keyword">int</span>[] array)</span></span>&#123;</span><br><span class="line">  <span class="keyword">int</span> temp = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">boolean</span> flag = <span class="keyword">false</span>;<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;array.length - <span class="number">1</span>; j++)&#123;</span><br><span class="line">    <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i&lt;array.length - (j+<span class="number">1</span>); i++)&#123;</span><br><span class="line">      <span class="keyword">if</span>(array[i] &gt; array[i+<span class="number">1</span>])&#123;</span><br><span class="line">        flag = <span class="keyword">true</span>;</span><br><span class="line">        temp = array[i];</span><br><span class="line">        array[i] = array[i+<span class="number">1</span>];</span><br><span class="line">        array[i+<span class="number">1</span>] = temp;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span>(flag)&#123;<span class="comment">//发生过交换</span></span><br><span class="line">      flag = <span class="keyword">false</span>;</span><br><span class="line">    &#125;<span class="keyword">else</span>&#123;</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">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="快速排序"><a href="#快速排序" class="headerlink" title="快速排序"></a>快速排序</h4><p>思路：</p><ul><li>1．先从数列中取出一个数作为基准数。</li><li>2．分区过程，将比这个数大的数全放到它的右边，小于或等于它的数全放到它的左边。</li><li>3．再对左右区间重复第二步，直到各区间只有一个数。 </li></ul><p><img src="/2020/06/25/%E5%B8%B8%E7%94%A8%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/quickSort.png" alt="quickSort"></p><figure class="highlight java"><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="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">quickSort</span><span class="params">(<span class="keyword">int</span>[] array, <span class="keyword">int</span> i, <span class="keyword">int</span> j)</span></span>&#123;</span><br><span class="line">  <span class="keyword">if</span>(i &gt; j) &#123;</span><br><span class="line">    <span class="keyword">return</span>;</span><br><span class="line">  &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">    <span class="keyword">int</span> index = getPosition(array, i, j);</span><br><span class="line">    quickSort(array, i, index-<span class="number">1</span>);</span><br><span class="line">    quickSort(array, index+<span class="number">1</span>, j);</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">//1.找到基准对应的索引</span></span><br><span class="line"><span class="comment">//2.对数据分成两部分，大于基准在右侧；小于基准在左侧</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getPosition</span><span class="params">(<span class="keyword">int</span>[] array, <span class="keyword">int</span> i, <span class="keyword">int</span> j)</span></span>&#123;</span><br><span class="line">  <span class="keyword">int</span> temp = array[j];</span><br><span class="line">  <span class="keyword">while</span>(i &lt; j)&#123;</span><br><span class="line">    <span class="keyword">while</span>(array[i] &lt;= temp &amp;&amp; i &lt; j)&#123;</span><br><span class="line">      i++;</span><br><span class="line">    &#125;</span><br><span class="line">    array[j] = array[i];</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">while</span>(array[j] &gt; temp &amp;&amp; i &lt; j)&#123;</span><br><span class="line">      j--;</span><br><span class="line">    &#125;</span><br><span class="line">    array[i] = array[j];</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">// 跳出循环时low和high相等,此时的low或high就是tmp的正确索引位置</span></span><br><span class="line">  array[i] = temp;</span><br><span class="line">  <span class="keyword">return</span> i;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h3 id="查找算法"><a href="#查找算法" class="headerlink" title="查找算法"></a>查找算法</h3><h4 id="二分查找"><a href="#二分查找" class="headerlink" title="二分查找"></a>二分查找</h4><p><strong>必须是有序数组</strong></p><figure class="highlight java"><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="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">binarySearch</span><span class="params">(<span class="keyword">int</span>[] array, <span class="keyword">int</span> target)</span></span>&#123;</span><br><span class="line">  <span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">int</span> j = array.length-<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>(i &lt;= j)&#123;</span><br><span class="line">    mid = i + (j-i)/<span class="number">2</span>;</span><br><span class="line">    <span class="keyword">if</span>(array[mid] == target)&#123;</span><br><span class="line">      <span class="keyword">return</span> mid;</span><br><span class="line">    &#125;<span class="keyword">else</span> <span class="keyword">if</span>(array[mid] &lt; target)&#123;</span><br><span class="line">      i = mid + <span class="number">1</span>;</span><br><span class="line">    &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">      j = 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></pre></td></tr></table></figure><br><p><strong>变种：二分查找找最左</strong></p><p>可以用来查找相同元素的个数</p><p><img src="/2020/06/25/%E5%B8%B8%E7%94%A8%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%88%86%E6%89%BE%E6%9C%80%E5%B7%A6.png" alt="二分找最左"></p><figure class="highlight java"><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="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">binarySearchForLeft</span><span class="params">(<span class="keyword">int</span>[] array, <span class="keyword">int</span> target)</span></span>&#123;</span><br><span class="line">  <span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">int</span> j = array.length-<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><br><span class="line">  <span class="keyword">while</span>(i &lt; j)&#123;</span><br><span class="line">    mid = i + (j-i)/<span class="number">2</span>;</span><br><span class="line">    <span class="keyword">if</span>(array[mid] &gt;= target)&#123;</span><br><span class="line">      j = mid;</span><br><span class="line">    &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">      i = 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> i;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>注意：</strong>为了验证有没有查找到，需要在调用端判断一下返回位置上的值和 key 是否相等</p>]]></content>
    
    <summary type="html">
    
      &lt;h3 id=&quot;排序算法&quot;&gt;&lt;a href=&quot;#排序算法&quot; class=&quot;headerlink&quot; title=&quot;排序算法&quot;&gt;&lt;/a&gt;排序算法&lt;/h3&gt;&lt;h4 id=&quot;冒泡排序&quot;&gt;&lt;a href=&quot;#冒泡排序&quot; class=&quot;headerlink&quot; title=&quot;冒泡排序&quot;&gt;&lt;/a&gt;&lt;strong&gt;冒泡排序&lt;/strong&gt;&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;需要 array.length-1 轮的比较，可以通过优化标识来减少比较的次数，时间复杂度O(n^2)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/2020/06/25/%E5%B8%B8%E7%94%A8%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/%E5%86%92%E6%B3%A1%E6%8E%92%E5%BA%8F.png&quot; alt=&quot;冒泡排序&quot;&gt;&lt;/p&gt;
    
    </summary>
    
    
      <category term="数据结构和算法" scheme="https://chrisxb1996.github.io/categories/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/"/>
    
    
      <category term="数据结构和算法" scheme="https://chrisxb1996.github.io/tags/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/"/>
    
  </entry>
  
  <entry>
    <title>剑指offer-较难篇</title>
    <link href="https://chrisxb1996.github.io/2020/06/25/%E5%89%91%E6%8C%87offer/%E5%89%91%E6%8C%87offer-%E8%BE%83%E9%9A%BE%E7%AF%87/"/>
    <id>https://chrisxb1996.github.io/2020/06/25/%E5%89%91%E6%8C%87offer/%E5%89%91%E6%8C%87offer-%E8%BE%83%E9%9A%BE%E7%AF%87/</id>
    <published>2020-06-25T04:56:22.000Z</published>
    <updated>2020-08-07T08:10:22.788Z</updated>
    
    <content type="html"><![CDATA[<h4 id="滑动窗口的最大值"><a href="#滑动窗口的最大值" class="headerlink" title="滑动窗口的最大值"></a>滑动窗口的最大值</h4><p><strong>题目描述：</strong>给定一个数组和滑动窗口的大小，找出所有滑动窗口里数值的最大值。例如，如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3，那么一共存在6个滑动窗口，他们的最大值分别为{4,4,6,6,6,5}； 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个： {[2,3,4],2,6,2,5,1}， {2,[3,4,2],6,2,5,1}， {2,3,[4,2,6],2,5,1}， {2,3,4,[2,6,2],5,1}， {2,3,4,2,[6,2,5],1}， {2,3,4,2,6,[2,5,1]}。</p><p><u>思路</u>：<img src="/2020/06/25/%E5%89%91%E6%8C%87offer/%E5%89%91%E6%8C%87offer-%E8%BE%83%E9%9A%BE%E7%AF%87/%E6%BB%91%E5%8A%A8%E7%AA%97%E5%8F%A3%E7%9A%84%E6%9C%80%E5%A4%A7%E5%80%BC.png" alt="滑动窗口的最大值"> <a id="more"></a></p><figure class="highlight java"><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">public</span> ArrayList&lt;Integer&gt; <span class="title">maxInWindows</span><span class="params">(<span class="keyword">int</span> [] num, <span class="keyword">int</span> size)</span></span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (num == <span class="keyword">null</span> || num.length == <span class="number">0</span> || size &lt;= <span class="number">0</span> || num.length &lt; size) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> ArrayList&lt;Integer&gt;();</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  ArrayList&lt;Integer&gt; res = <span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">  LinkedList&lt;Integer&gt; queue = <span class="keyword">new</span> LinkedList&lt;&gt;();</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; num.length; i++)&#123;</span><br><span class="line">    <span class="keyword">while</span>(!queue.isEmpty() &amp;&amp; num[queue.peekLast()] &lt; num[i])&#123;</span><br><span class="line">      queue.pollLast();</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    queue.addLast(i);</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//判断头索引是否超出size</span></span><br><span class="line">    <span class="keyword">if</span>(queue.peekFirst() &lt;= i - size)&#123;</span><br><span class="line">      queue.pollFirst();</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">if</span>(i &gt;= size-<span class="number">1</span>)&#123;</span><br><span class="line">      res.add(num[queue.peekFirst()]);</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></pre></td></tr></table></figure><br><br><h4 id="二叉搜索树的第k个结点"><a href="#二叉搜索树的第k个结点" class="headerlink" title="二叉搜索树的第k个结点"></a>二叉搜索树的第k个结点</h4><p><strong>题目描述：</strong>给定一棵二叉搜索树，请找出其中的第k小的结点。例如， （5，3，7，2，4，6，8）  中，按结点数值大小顺序第三小结点的值为4。</p><p><u>思路</u>：中序遍历第K个节点即可</p><figure class="highlight java"><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="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Solution</span> </span>&#123;</span><br><span class="line">  <span class="keyword">private</span> TreeNode res;</span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">int</span> index = <span class="number">0</span>;<span class="comment">//计数器</span></span><br><span class="line">  </span><br><span class="line">  <span class="function">TreeNode <span class="title">KthNode</span><span class="params">(TreeNode pRoot, <span class="keyword">int</span> k)</span></span>&#123;</span><br><span class="line">inOrder(pRoot, k);</span><br><span class="line">    <span class="keyword">return</span> res;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">inOrder</span><span class="params">(TreeNode root, <span class="keyword">int</span> k)</span></span>&#123;</span><br><span class="line">    <span class="keyword">if</span>(root == <span class="keyword">null</span>)&#123;</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    inOrder(root.left, k);</span><br><span class="line">    </span><br><span class="line">    index++;</span><br><span class="line">    <span class="keyword">if</span>(index == k)&#123;</span><br><span class="line">      res = root;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    inOrder(root.right, k);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="序列化二叉树"><a href="#序列化二叉树" class="headerlink" title="序列化二叉树"></a>序列化二叉树</h4><p><strong>题目描述：</strong>请实现两个函数，分别用来序列化和反序列化二叉树 </p><p>二叉树的序列化是指：把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串，从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树遍历方式来进行修改，序列化的结果是一个字符串，序列化时通过 某种符号表示空节点（#），以 ！ 表示一个结点值的结束（value!）。</p><p>二叉树的反序列化是指：根据某种遍历顺序得到的序列化字符串结果str，重构二叉树。</p><p>例如，我们可以把一个只有根节点为1的二叉树序列化为”1,”，然后通过自己的函数来解析回这个二叉树</p><p><u>思路</u>：递归</p><figure class="highlight java"><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="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Solution</span> </span>&#123;</span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">int</span> index = -<span class="number">1</span>;</span><br><span class="line">  <span class="function">String <span class="title">Serialize</span><span class="params">(TreeNode root)</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span>(root == <span class="keyword">null</span>)&#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="string">"#"</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> root.val + <span class="string">","</span> + Serialize(root.left) + <span class="string">","</span> + Serialize(root.right);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">  <span class="function">TreeNode <span class="title">Deserialize</span><span class="params">(String str)</span> </span>&#123;</span><br><span class="line">    index++;    </span><br><span class="line">    String[] strr = str.split(<span class="string">","</span>);</span><br><span class="line">    TreeNode node = <span class="keyword">null</span>;</span><br><span class="line">    <span class="keyword">if</span>(!strr[index].equals(<span class="string">"#"</span>))&#123;</span><br><span class="line">      node = <span class="keyword">new</span> TreeNode(Integer.valueOf(strr[index]));</span><br><span class="line">      node.left = Deserialize(str);</span><br><span class="line">      node.right = Deserialize(str);</span><br><span class="line">    &#125;</span><br><span class="line"></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><br><br><h4 id="按之字形顺序打印二叉树"><a href="#按之字形顺序打印二叉树" class="headerlink" title="按之字形顺序打印二叉树"></a>按之字形顺序打印二叉树</h4><p><strong>题目描述：</strong>请实现一个函数按照之字形打印二叉树，即第一行按照从左到右的顺序打印，第二层按照从右至左的顺序打印，第三行按照从左到右的顺序打印，其他行以此类推。</p><p><u>思路</u>：使用队列</p><figure class="highlight java"><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="keyword">public</span> ArrayList&lt;ArrayList&lt;Integer&gt; &gt; Print(TreeNode pRoot) &#123;</span><br><span class="line">  <span class="keyword">if</span>(pRoot == <span class="keyword">null</span>) <span class="keyword">return</span> <span class="keyword">new</span> ArrayList();</span><br><span class="line">  </span><br><span class="line">  ArrayList&lt;ArrayList&lt;Integer&gt; &gt; res = <span class="keyword">new</span> ArrayList&lt;ArrayList&lt;Integer&gt; &gt;();</span><br><span class="line">  Queue&lt;TreeNode&gt; queue = <span class="keyword">new</span> LinkedList&lt;&gt;();</span><br><span class="line">  queue.add(pRoot);</span><br><span class="line">  <span class="keyword">int</span> count = <span class="number">1</span>;<span class="comment">//记录行数</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">while</span>(!queue.isEmpty())&#123;</span><br><span class="line">    <span class="keyword">int</span> n = queue.size();</span><br><span class="line">    ArrayList&lt;Integer&gt; list = <span class="keyword">new</span> ArrayList&lt;Integer&gt;();</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">      TreeNode node = queue.poll();</span><br><span class="line">      list.add(node.val);</span><br><span class="line">      <span class="keyword">if</span>(node.left != <span class="keyword">null</span>) queue.add(node.left);</span><br><span class="line">      <span class="keyword">if</span>(node.right != <span class="keyword">null</span>) queue.add(node.right);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span>(count % <span class="number">2</span> == <span class="number">1</span>)&#123;<span class="comment">//奇数行</span></span><br><span class="line">      res.add(list);</span><br><span class="line">      count++;</span><br><span class="line">    &#125;<span class="keyword">else</span>&#123;<span class="comment">//偶数行</span></span><br><span class="line">      Collections.reverse(list);</span><br><span class="line">      res.add(list);</span><br><span class="line">      count++;</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></pre></td></tr></table></figure><br><br><h4 id="删除链表中重复的结点"><a href="#删除链表中重复的结点" class="headerlink" title="删除链表中重复的结点"></a>删除链表中重复的结点</h4><p><strong>题目描述：</strong>在一个排序的链表中，存在重复的结点，请删除该链表中重复的结点，重复的结点不保留，返回链表头指针。 例如，链表1-&gt;2-&gt;3-&gt;3-&gt;4-&gt;4-&gt;5 处理后为 1-&gt;2-&gt;5</p><p><u>思路</u>：三指针</p><p><img src="/2020/06/25/%E5%89%91%E6%8C%87offer/%E5%89%91%E6%8C%87offer-%E8%BE%83%E9%9A%BE%E7%AF%87/%E5%88%A0%E9%99%A4%E9%93%BE%E8%A1%A8%E4%B8%AD%E9%87%8D%E5%A4%8D%E7%9A%84%E7%BB%93%E7%82%B9.png" alt="删除链表中重复的结点"></p><figure class="highlight java"><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="function"><span class="keyword">public</span> ListNode <span class="title">deleteDuplication</span><span class="params">(ListNode pHead)</span></span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (pHead==<span class="keyword">null</span> || pHead.next==<span class="keyword">null</span>) <span class="keyword">return</span> pHead;</span><br><span class="line">  ListNode newHead = <span class="keyword">new</span> ListNode(-<span class="number">1</span>);</span><br><span class="line">  newHead.next = pHead;</span><br><span class="line">  ListNode pre = newHead;</span><br><span class="line">  ListNode last = newHead.next;</span><br><span class="line">  <span class="keyword">while</span>(last != <span class="keyword">null</span>)&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (last.next != <span class="keyword">null</span> &amp;&amp; last.val == last.next.val)&#123;</span><br><span class="line">      <span class="keyword">while</span>(last.next != <span class="keyword">null</span> &amp;&amp; last.val == last.next.val) &#123;</span><br><span class="line">        last = last.next;</span><br><span class="line">      &#125;</span><br><span class="line">      pre.next = last.next;</span><br><span class="line">      last = last.next;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      pre = pre.next;</span><br><span class="line">      last = last.next;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> newHead.next;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="把字符串转换成整数"><a href="#把字符串转换成整数" class="headerlink" title="把字符串转换成整数"></a>把字符串转换成整数</h4><p><strong>题目描述：</strong>将一个字符串转换成一个整数，要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0</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><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">输入一个字符串,包括数字字母符号,可以为空</span><br><span class="line">例：</span><br><span class="line">+2147483647</span><br><span class="line">1a33</span><br></pre></td></tr></table></figure><p>输出描述:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">如果是合法的数值表达则返回该数字，否则返回0</span><br><span class="line">例：</span><br><span class="line">2147483647</span><br><span class="line">0</span><br></pre></td></tr></table></figure><p><u>思路</u>：</p><figure class="highlight java"><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="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">StrToInt</span><span class="params">(String str)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">if</span>(str.length() == <span class="number">0</span> || str == <span class="keyword">null</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> 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;str.length(); i++)&#123;</span><br><span class="line">    <span class="keyword">char</span> c = str.charAt(i);</span><br><span class="line">    <span class="keyword">if</span>(c == <span class="string">'0'</span> || c == <span class="string">'+'</span> || c == <span class="string">'-'</span>)&#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>(c &lt; <span class="string">'0'</span> || c &gt; <span class="string">'9'</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><br><span class="line">    res = res*<span class="number">10</span> +(c-<span class="string">'0'</span>);</span><br><span class="line"></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> str.charAt(<span class="number">0</span>) == <span class="string">'-'</span> ? -res : res;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="翻转单词顺序列"><a href="#翻转单词顺序列" class="headerlink" title="翻转单词顺序列"></a>翻转单词顺序列</h4><p><strong>题目描述：</strong>将一个字符串转换成一个整数，要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0</p><p><u>思路</u>：先反转每个单词，再反转整个句子;</p><figure class="highlight java"><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">public</span> String <span class="title">ReverseSentence</span><span class="params">(String str)</span> </span>&#123;</span><br><span class="line">  <span class="comment">//先反转每个单词，再反转整个句子</span></span><br><span class="line">  <span class="keyword">char</span>[] chars = str.toCharArray();</span><br><span class="line">  <span class="keyword">int</span> n = chars.length;</span><br><span class="line">  <span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">int</span> j = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">while</span>(j &lt;= n)&#123;</span><br><span class="line">    <span class="keyword">if</span>(j == n || chars[j] == <span class="string">' '</span>)&#123; <span class="comment">// 利用短路特性，否则会报数组越界</span></span><br><span class="line">      reverse(chars, i, j-<span class="number">1</span>);</span><br><span class="line">      i = j+<span class="number">1</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    j++;</span><br><span class="line">  &#125;</span><br><span class="line">  reverse(chars, <span class="number">0</span>, n-<span class="number">1</span>);</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">new</span> String(chars);</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="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">reverse</span><span class="params">(<span class="keyword">char</span>[] chars, <span class="keyword">int</span> i, <span class="keyword">int</span> j)</span></span>&#123;</span><br><span class="line">  <span class="keyword">while</span>(i &lt; j)&#123;</span><br><span class="line">    <span class="keyword">char</span> temp = chars[i];</span><br><span class="line">    chars[i] = chars[j];</span><br><span class="line">    chars[j] = temp;</span><br><span class="line">    i++;</span><br><span class="line">    j--;</span><br><span class="line">  &#125;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="把数组排成最小的数"><a href="#把数组排成最小的数" class="headerlink" title="把数组排成最小的数"></a>把数组排成最小的数</h4><p><strong>题目描述：</strong>输入一个正整数数组，把数组里所有数字拼接起来排成一个数，打印能拼接出的所有数字中最小的一个。例如输入数组{3，32，321}，则打印出这三个数字能排成的最小数字为321323。</p><p><u>思路</u>：可以看成是一个排序问题，在比较两个字符串 S1 和 S2 的大小时，应该比较的是 S1+S2 和 S2+S1 的大小，如果 S1+S2 &lt; S2+S1，那么应该把 S1 排在前面，否则应该把 S2 排在前面。</p><p><strong>补充：</strong></p><p><strong>Comparator：</strong>对任意类型集合对象进行整体排序，排序时将此接口的实现传递给Collections.sort方法或者Arrays.sort方法排序.<br>实现int compare(T o1, T o2);方法，返回正数，零，负数各代表大于，等于，小于。</p><p><strong>compareTo()：</strong>的返回值是整型，它是先比较对应字符的大小(ASCII码顺序)，如果第一个字符和参数的第一个字符不等,结束比较，返回他们之间的差值，如果第一个字符和参数的第一个字符相等，则以第二个字符和参数的第二个字符做比较,以此类推,直至比较的字符或被比较的字符有一方全比较完，这时就比较字符的长度. </p><figure class="highlight java"><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="function"><span class="keyword">public</span> String <span class="title">PrintMinNumber</span><span class="params">(<span class="keyword">int</span> [] numbers)</span> </span>&#123;</span><br><span class="line">  String[] str = <span class="keyword">new</span> String[numbers.length];</span><br><span class="line">  <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i&lt;numbers.length; i++)&#123;</span><br><span class="line">    str[i] = numbers[i]+<span class="string">""</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  StringBuilder res = <span class="keyword">new</span> StringBuilder();</span><br><span class="line"></span><br><span class="line">  Arrays.sort(str,<span class="keyword">new</span> Comparator&lt;String&gt;()&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">compare</span><span class="params">(String s1, String s2)</span> </span>&#123;</span><br><span class="line">      String c1 = s1 + s2;</span><br><span class="line">      String c2 = s2 + s1;</span><br><span class="line">      <span class="keyword">return</span> c1.compareTo(c2);</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> i = <span class="number">0</span>;i&lt;str.length;i++)&#123;</span><br><span class="line">    res.append(str[i]);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> res.toString();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="二叉树中和为某一值的路径"><a href="#二叉树中和为某一值的路径" class="headerlink" title="二叉树中和为某一值的路径"></a>二叉树中和为某一值的路径</h4><p><strong>题目描述：</strong>输入一颗二叉树的根节点和一个整数，按字典序打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。</p><p><u>思路</u>：深度遍历：</p><p><img src="/2020/06/25/%E5%89%91%E6%8C%87offer/%E5%89%91%E6%8C%87offer-%E8%BE%83%E9%9A%BE%E7%AF%87/%E4%BA%8C%E5%8F%89%E6%A0%91%E5%92%8C%E4%B8%BA%E6%9F%90%E4%B8%AA%E5%80%BC%E7%9A%84%E8%B7%AF%E5%BE%84.png" alt="二叉树和为某个值的路径"></p><p>以上面的树模拟先序遍历的过程</p><ul><li><p>10–&gt;5–&gt;4  已近到达叶子结点，不满足要求22，因此该路径访问结束，需要访问下一个路径</p><p>因为在访问节点的过程中，我们并不知道该路径是否满足要求，所以我们每访问一个节点就要记录该结点</p><p><strong>访问下有一个结点前，要先从结点4退回到结点5，再访问下一个结点7，因为4不在去往7的路径上，所以要在路径中将4删除</strong></p></li><li><p>10–&gt;5–&gt;7  满足要求，保存该路径</p><p>访问下一个结点，从结点7回到结点5再回到结点10</p></li><li><p>10–&gt;12，满足要求，保存该路径</p></li></ul><figure class="highlight java"><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="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Solution</span> </span>&#123;</span><br><span class="line">  ArrayList&lt;ArrayList&lt;Integer&gt;&gt; res = <span class="keyword">new</span> ArrayList&lt;ArrayList&lt;Integer&gt;&gt;();</span><br><span class="line">  ArrayList&lt;Integer&gt; list = <span class="keyword">new</span> ArrayList&lt;Integer&gt;();</span><br><span class="line">  <span class="keyword">public</span> ArrayList&lt;ArrayList&lt;Integer&gt;&gt; FindPath(TreeNode root,<span class="keyword">int</span> target) &#123;</span><br><span class="line">    <span class="keyword">if</span>(root == <span class="keyword">null</span>) &#123;</span><br><span class="line">      <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line">    target = target - root.val;</span><br><span class="line">    list.add(root.val);</span><br><span class="line">    <span class="keyword">if</span>(target == <span class="number">0</span> &amp;&amp; root.left == <span class="keyword">null</span> &amp;&amp; root.right == <span class="keyword">null</span>)&#123;</span><br><span class="line">      res.add(<span class="keyword">new</span> ArrayList(list));</span><br><span class="line">    &#125;</span><br><span class="line">    FindPath(root.left, target);</span><br><span class="line">    FindPath(root.right, target);</span><br><span class="line">    list.remove(list.size()-<span class="number">1</span>);<span class="comment">//回退</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></pre></td></tr></table></figure><br><br><h4 id="最小的K个数"><a href="#最小的K个数" class="headerlink" title="最小的K个数"></a>最小的K个数</h4><p><strong>题目描述：</strong>输入n个整数，找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字，则最小的4个数字是1,2,3,4,。</p><p><u>思路</u>：</p><figure class="highlight java"><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"><span class="function"><span class="keyword">public</span> ArrayList&lt;Integer&gt; <span class="title">GetLeastNumbers_Solution</span><span class="params">(<span class="keyword">int</span> [] input, <span class="keyword">int</span> k)</span> </span>&#123;</span><br><span class="line">  ArrayList&lt;Integer&gt; res = <span class="keyword">new</span> ArrayList&lt;Integer&gt;();</span><br><span class="line">  <span class="keyword">if</span>(k &gt; input.length) <span class="keyword">return</span> res;</span><br><span class="line">  Arrays.sort(input);</span><br><span class="line">  <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i&lt;k;i++)&#123;</span><br><span class="line">    res.add(input[i]);</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></pre></td></tr></table></figure><br><br><h4 id="二叉搜索树的后序遍历序列"><a href="#二叉搜索树的后序遍历序列" class="headerlink" title="二叉搜索树的后序遍历序列"></a>二叉搜索树的后序遍历序列</h4><p><strong>题目描述：</strong>输入一个整数数组，判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。</p><p><u>思路</u>：</p><figure class="highlight java"><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">public</span> <span class="keyword">boolean</span> <span class="title">VerifySquenceOfBST</span><span class="params">(<span class="keyword">int</span> [] sequence)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">if</span>(sequence.length == <span class="number">0</span>) <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">  <span class="keyword">return</span> judge(sequence, <span class="number">0</span>, sequence.length-<span class="number">1</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">judge</span><span class="params">(<span class="keyword">int</span> [] sequence, <span class="keyword">int</span> begin, <span class="keyword">int</span> end)</span></span>&#123;</span><br><span class="line">  <span class="keyword">if</span>(begin &gt;= end)&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">int</span> i = begin;</span><br><span class="line">  <span class="comment">//找到以end节点为根节点的左子树</span></span><br><span class="line">  <span class="keyword">while</span>(sequence[i] &lt; sequence[end])&#123;</span><br><span class="line">    i++;</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; j &lt; end; j++)&#123;</span><br><span class="line">    <span class="comment">//右子树如果有小于根节点的，则返回false</span></span><br><span class="line">    <span class="keyword">if</span>(sequence[j] &lt; sequence[end])&#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> judge(sequence, begin, i-<span class="number">1</span>) &amp;&amp; judge(sequence, i, end-<span class="number">1</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="二维数组中的查找"><a href="#二维数组中的查找" class="headerlink" title="二维数组中的查找"></a>二维数组中的查找</h4><p><strong>题目描述：</strong>在一个二维数组中（每个一维数组的长度相同），每一行都按照从左到右递增的顺序排序，每一列都按照从上到下递增的顺序排序。请完成一个函数，输入这样的一个二维数组和一个整数，判断数组中是否含有该整数。</p><p><u>思路</u>：从二维数组的右上角开始遍历，比当前值小的就在左边，比当前值大的就在下边</p><figure class="highlight java"><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="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">Find</span><span class="params">(<span class="keyword">int</span> target, <span class="keyword">int</span> [][] array)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">int</span> row = array.length;<span class="comment">//行数</span></span><br><span class="line">  <span class="keyword">int</span> col = array[<span class="number">0</span>].length;<span class="comment">//列数</span></span><br><span class="line">  <span class="comment">//从右上角开始搜索</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">int</span> j = col - <span class="number">1</span>;</span><br><span class="line">  <span class="keyword">while</span>(i &lt; row &amp;&amp; j &gt;= <span class="number">0</span>)&#123;</span><br><span class="line">    <span class="keyword">if</span>(array[i][j] == target)&#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    &#125;<span class="keyword">else</span> <span class="keyword">if</span>(array[i][j] &lt; target)&#123;</span><br><span class="line">      i++;</span><br><span class="line">    &#125;<span class="keyword">else</span>&#123;</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">return</span> <span class="keyword">false</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="替换空格"><a href="#替换空格" class="headerlink" title="替换空格"></a>替换空格</h4><p><strong>题目描述：</strong>请实现一个函数，将一个字符串中的每个空格替换成“%20”。例如，当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。</p><p><u>思路</u>：</p><figure class="highlight java"><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"><span class="function"><span class="keyword">public</span> String <span class="title">replaceSpace</span><span class="params">(StringBuffer str)</span> </span>&#123;</span><br><span class="line">  String strs = str.toString();</span><br><span class="line">  <span class="keyword">char</span>[] strChars = strs.toCharArray();</span><br><span class="line">  StringBuilder sb = <span class="keyword">new</span> StringBuilder();</span><br><span class="line">  <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i&lt;strChars.length; i++)&#123;</span><br><span class="line">    <span class="keyword">if</span>(strChars[i] == <span class="string">' '</span>)&#123;</span><br><span class="line">      sb.append(<span class="string">"%20"</span>);</span><br><span class="line">    &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">      sb.append(strChars[i]);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> sb.toString();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="从尾到头打印链表"><a href="#从尾到头打印链表" class="headerlink" title="从尾到头打印链表"></a>从尾到头打印链表</h4><p><strong>题目描述：</strong>输入一个链表，按链表从尾到头的顺序返回一个ArrayList。</p><p><u>思路</u>：利用栈，实现逆序打印</p><figure class="highlight java"><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="function"><span class="keyword">public</span> ArrayList&lt;Integer&gt; <span class="title">printListFromTailToHead</span><span class="params">(ListNode listNode)</span> </span>&#123;</span><br><span class="line">  ArrayList&lt;Integer&gt; res = <span class="keyword">new</span> ArrayList&lt;Integer&gt;();</span><br><span class="line">  Stack&lt;ListNode&gt; stack = <span class="keyword">new</span> Stack&lt;&gt;();</span><br><span class="line">  <span class="keyword">while</span>(listNode != <span class="keyword">null</span>)&#123;</span><br><span class="line">    stack.push(listNode);</span><br><span class="line">    listNode = listNode.next;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">while</span>(!stack.isEmpty())&#123;</span><br><span class="line">    ListNode node = stack.pop();</span><br><span class="line">    res.add(node.val);</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></pre></td></tr></table></figure><br><br><h4 id="调整数组顺序使奇数位于偶数前面"><a href="#调整数组顺序使奇数位于偶数前面" class="headerlink" title="调整数组顺序使奇数位于偶数前面"></a>调整数组顺序使奇数位于偶数前面</h4><p><strong>题目描述：</strong>输入一个整数数组，实现一个函数来调整该数组中数字的顺序，使得所有的奇数位于数组的前半部分，所有的偶数位于数组的后半部分，并保证奇数和奇数，偶数和偶数之间的相对位置不变。</p><p><u>思路</u>：统计原始数组中的奇数个数，利用拷贝数组，将原始数组进行位置调整</p><figure class="highlight java"><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="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">reOrderArray</span><span class="params">(<span class="keyword">int</span> [] array)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">int</span> count = <span class="number">0</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> num : array)&#123;</span><br><span class="line">    <span class="keyword">if</span>(num % <span class="number">2</span> == <span class="number">1</span>)&#123;</span><br><span class="line">      count++;</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="keyword">int</span>[] copy = <span class="keyword">new</span> <span class="keyword">int</span>[array.length];</span><br><span class="line">  <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i&lt;array.length; i++)&#123;</span><br><span class="line">    copy[i] = array[i];</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">int</span> i = <span class="number">0</span>;<span class="comment">//奇数索引</span></span><br><span class="line">  <span class="keyword">int</span> j = count;<span class="comment">//偶数索引</span></span><br><span class="line">  <span class="keyword">for</span>(<span class="keyword">int</span> num : copy)&#123;</span><br><span class="line">    <span class="keyword">if</span>(num % <span class="number">2</span> == <span class="number">1</span>)&#123;</span><br><span class="line">      array[i] = num;</span><br><span class="line">      i++;</span><br><span class="line">    &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">      array[count] = num;</span><br><span class="line">      count++;</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><br><br><h4 id="链表中倒数第k个结点"><a href="#链表中倒数第k个结点" class="headerlink" title="链表中倒数第k个结点"></a>链表中倒数第k个结点</h4><p><strong>题目描述：</strong>输入一个链表，输出该链表中倒数第k个结点。</p><p><u>思路</u>：创建两个指针，都指向头节点。第一个比第二个多走 k 个节点，然后两指针同时向后遍历，直到第一个指针遍历到结尾，返回第二个指针。</p><figure class="highlight java"><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="function"><span class="keyword">public</span> ListNode <span class="title">FindKthToTail</span><span class="params">(ListNode head,<span class="keyword">int</span> k)</span> </span>&#123;</span><br><span class="line">  ListNode p1 = head;</span><br><span class="line">  ListNode p2 = head;</span><br><span class="line">  <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i&lt;k; i++)&#123;</span><br><span class="line">    <span class="keyword">if</span>(p1 != <span class="keyword">null</span>)&#123;</span><br><span class="line">      p1 = p1.next;</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">null</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">while</span>(p1 != <span class="keyword">null</span>)&#123;</span><br><span class="line">    p1 = p1.next;</span><br><span class="line">    p2 = p2.next;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> p2;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="树的子结构"><a href="#树的子结构" class="headerlink" title="树的子结构"></a>树的子结构</h4><p><strong>题目描述：</strong>输入两棵二叉树A，B，判断B是不是A的子结构。（ps：我们约定空树不是任意一个树的子结构）</p><p><u>思路</u>：先编写方法 isSubTree() 判断B树与A树从根开始是有否相同的结构；再从头遍历A二叉树判断是否有和B树相同的结构</p><figure class="highlight java"><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="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Solution</span> </span>&#123;</span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">HasSubtree</span><span class="params">(TreeNode root1,TreeNode root2)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">if</span>(root1 == <span class="keyword">null</span> || root2 == <span class="keyword">null</span>) <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">    <span class="keyword">if</span>(isSubTree(root1, root2)) <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    <span class="keyword">return</span> HasSubtree(root1.left, root2) || HasSubtree(root1.right, root2);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isSubTree</span><span class="params">(TreeNode root1, TreeNode root2)</span></span>&#123;</span><br><span class="line">    <span class="keyword">if</span>(root2 == <span class="keyword">null</span>) <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    <span class="keyword">if</span>(root1 == <span class="keyword">null</span>) <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">    <span class="keyword">if</span>(root1.val != root2.val) <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">    <span class="keyword">return</span> isSubTree(root1.left, root2.left) &amp;&amp; isSubTree(root1.right, root2.right);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="顺时针打印矩阵"><a href="#顺时针打印矩阵" class="headerlink" title="顺时针打印矩阵"></a>顺时针打印矩阵</h4><p><strong>题目描述：</strong>输入一个矩阵，按照从外向里以顺时针的顺序依次打印出每一个数字，例如，如果输入如下4 X 4矩阵： 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.</p><p><u>思路</u>：创建四个指针，根据顺时针顺序进行顺序输出；注意条件：在添加最后一列和最后一行的时候增加判断条件：<code>r1 != r2</code>，<code>c1 != c2</code></p><figure class="highlight java"><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="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Solution</span> </span>&#123;</span><br><span class="line">  <span class="function"><span class="keyword">public</span> ArrayList&lt;Integer&gt; <span class="title">printMatrix</span><span class="params">(<span class="keyword">int</span> [][] matrix)</span> </span>&#123;</span><br><span class="line">    ArrayList&lt;Integer&gt; res = <span class="keyword">new</span> ArrayList&lt;Integer&gt;();</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">int</span> r1 = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">int</span> r2 = matrix.length-<span class="number">1</span>;</span><br><span class="line">    <span class="keyword">int</span> c1 = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">int</span> c2 = matrix[<span class="number">0</span>].length-<span class="number">1</span>;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">while</span>(r1 &lt;= r2 &amp;&amp; c1 &lt;= c2)&#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 = c1; i &lt;= c2; i++)&#123;</span><br><span class="line">        res.add(matrix[r1][i]);</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">for</span>(<span class="keyword">int</span> i = r1+<span class="number">1</span>; i &lt;= r2; i++)&#123;</span><br><span class="line">        res.add(matrix[i][c2]);</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">if</span> (r1 != r2)&#123;</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i = c2-<span class="number">1</span>; i &gt;= c1; i--)&#123;</span><br><span class="line">          res.add(matrix[r2][i]);</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="keyword">if</span>(c1 != c2)&#123;</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i = r2-<span class="number">1</span>; i &gt; r1; i--)&#123;</span><br><span class="line">        res.add(matrix[i][c1]);</span><br><span class="line">      &#125;</span><br><span class="line">      &#125;  </span><br><span class="line">      r1++;</span><br><span class="line">      r2--;</span><br><span class="line">      c1++;</span><br><span class="line">      c2--;</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><br><br><h4 id="二叉树中和为某一值的路径-1"><a href="#二叉树中和为某一值的路径-1" class="headerlink" title="二叉树中和为某一值的路径"></a>二叉树中和为某一值的路径</h4><p><strong>题目描述：</strong>输入一颗二叉树的根节点和一个整数，按字典序打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。</p><p><u>思路</u>：递归</p><figure class="highlight java"><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="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Solution</span> </span>&#123;</span><br><span class="line">  ArrayList&lt;ArrayList&lt;Integer&gt;&gt; res = <span class="keyword">new</span> ArrayList&lt;ArrayList&lt;Integer&gt;&gt;();</span><br><span class="line">  ArrayList&lt;Integer&gt; list = <span class="keyword">new</span> ArrayList&lt;Integer&gt;();</span><br><span class="line">  <span class="keyword">public</span> ArrayList&lt;ArrayList&lt;Integer&gt;&gt; FindPath(TreeNode root,<span class="keyword">int</span> target) &#123;</span><br><span class="line">    <span class="keyword">if</span>(root == <span class="keyword">null</span>) <span class="keyword">return</span> res;</span><br><span class="line">    target -= root.val;</span><br><span class="line">    list.add(root.val);</span><br><span class="line">    <span class="keyword">if</span>(target == <span class="number">0</span> &amp;&amp; root.left == <span class="keyword">null</span> &amp;&amp; root.right == <span class="keyword">null</span>)&#123;</span><br><span class="line">      res.add(<span class="keyword">new</span> ArrayList&lt;Integer&gt;(list));</span><br><span class="line">    &#125;</span><br><span class="line">    FindPath(root.left, target);</span><br><span class="line">    FindPath(root.right, target);</span><br><span class="line">    list.remove(list.size()-<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></pre></td></tr></table></figure><br><br><h4 id="复杂链表的复制"><a href="#复杂链表的复制" class="headerlink" title="复杂链表的复制"></a>复杂链表的复制</h4><p><strong>题目描述：</strong>输入一个复杂链表（每个节点中有节点值，以及两个指针，一个指向下一个节点，另一个特殊指针random指向一个随机节点），请对此链表进行深拷贝，并返回拷贝后的头结点。（注意，输出结果中请不要返回参数中的节点引用，否则判题程序会直接返回空）</p><p><u>思路</u>：第一步，在每个节点的后面插入复制的节点；第二步，建立 random 链接；第三步， 拆分；</p><p><img src="/2020/06/25/%E5%89%91%E6%8C%87offer/%E5%89%91%E6%8C%87offer-%E8%BE%83%E9%9A%BE%E7%AF%87/%E5%A4%8D%E6%9D%82%E9%93%BE%E8%A1%A8%E5%A4%8D%E5%88%B6.png" alt="复杂链表复制"></p><figure class="highlight java"><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="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Solution</span> </span>&#123;</span><br><span class="line">  <span class="function"><span class="keyword">public</span> RandomListNode <span class="title">Clone</span><span class="params">(RandomListNode pHead)</span></span>&#123;</span><br><span class="line"><span class="keyword">if</span>(pHead == <span class="keyword">null</span>) <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">    <span class="comment">//插入新节点</span></span><br><span class="line">    RandomListNode cur = pHead;</span><br><span class="line">    <span class="keyword">while</span>(cur != <span class="keyword">null</span>)&#123;</span><br><span class="line">      RandomListNode clone = <span class="keyword">new</span> RandomListNode(cur.label);</span><br><span class="line">      clone.next = cur.next;</span><br><span class="line">      cur.next = clone;</span><br><span class="line">      cur = clone.next;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//建立random连接</span></span><br><span class="line">    cur = pHead;</span><br><span class="line">    <span class="keyword">while</span>(cur != <span class="keyword">null</span>)&#123;</span><br><span class="line">      RandomListNode clone = cur.next;</span><br><span class="line">      <span class="keyword">if</span> (cur.random != <span class="keyword">null</span>)&#123;</span><br><span class="line">        clone.random = cur.random.next;</span><br><span class="line">      &#125;</span><br><span class="line">      cur = clone.next;</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">    cur = pHead;</span><br><span class="line">    RandomListNode cloneHead = cur.next;</span><br><span class="line">    <span class="keyword">while</span>(cur != <span class="keyword">null</span>)&#123;</span><br><span class="line">      RandomListNode next = cur.next;</span><br><span class="line">      cur.next = next.next;</span><br><span class="line">      cur = next;    </span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> cloneHead;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="把数组排成最小的数-1"><a href="#把数组排成最小的数-1" class="headerlink" title="把数组排成最小的数"></a>把数组排成最小的数</h4><p><strong>题目描述：</strong>输入一个正整数数组，把数组里所有数字拼接起来排成一个数，打印能拼接出的所有数字中最小的一个。例如输入数组{3，32，321}，则打印出这三个数字能排成的最小数字为321323。</p><p><u>思路</u>：Comparator的用法：<a href="https://blog.csdn.net/yongh701/article/details/44131051?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.compare&amp;depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.compare" target="_blank" rel="noopener">https://blog.csdn.net/yongh701/article/details/44131051?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.compare&amp;depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.compare</a></p><p>compareTo方法：<a href="https://www.iteye.com/blog/chenfeng0104-409754" target="_blank" rel="noopener">https://www.iteye.com/blog/chenfeng0104-409754</a></p><figure class="highlight java"><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="function"><span class="keyword">public</span> String <span class="title">PrintMinNumber</span><span class="params">(<span class="keyword">int</span> [] numbers)</span> </span>&#123;</span><br><span class="line">  String[] strs = <span class="keyword">new</span> String[numbers.length];</span><br><span class="line">  <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i&lt;numbers.length; i++)&#123;</span><br><span class="line">    strs[i] = numbers[i] + <span class="string">""</span>;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">//Collections也有类似的用法</span></span><br><span class="line">  Arrays.sort(strs, <span class="keyword">new</span> Comparator&lt;Object&gt;()&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">compare</span><span class="params">(Object s1, Object s2)</span></span>&#123;</span><br><span class="line">      String c1 = (String)s1+(String)s2;</span><br><span class="line">      String c2 = (String)s2+(String)s1;</span><br><span class="line">      <span class="keyword">return</span> c1.compareTo(c2);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;);</span><br><span class="line"></span><br><span class="line">  StringBuilder res = <span class="keyword">new</span> StringBuilder();</span><br><span class="line">  <span class="keyword">for</span>(String s : strs)&#123;</span><br><span class="line">    res.append(s);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> res.toString();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="丑数"><a href="#丑数" class="headerlink" title="丑数"></a>丑数</h4><p><strong>题目描述：</strong>把只包含质因子2、3和5的数称作丑数（Ugly Number）。例如6、8都是丑数，但14不是，因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。</p><p><u>思路</u>：</p><p><strong>我们没有必要维护三个队列，只需要记录三个指针显示到达哪一步；“|”表示指针,arr表示丑数数组；</strong></p><p><strong>（1）1</strong></p><p><strong>|2</strong></p><p><strong>|3</strong></p><p><strong>|5</strong></p><p><strong>目前指针指向0,0,0，队列头arr[0] * 2 = 2, arr[0] * 3 = 3, arr[0] * 5 = 5</strong></p><p><strong>（2）1 2</strong></p><p><strong>2 |4</strong></p><p><strong>|3 6</strong></p><p><strong>|5 10</strong></p><p><strong>目前指针指向1,0,0，队列头arr[1] * 2 = 4, arr[0] * 3 = 3, arr[0] * 5 = 5</strong></p><p><strong>（3）1 2 3</strong></p><p><strong>2| 4 6</strong></p><p><strong>3 |6 9</strong> </p><p><strong>|5 10 15</strong></p><p><strong>目前指针指向1,1,0，队列头arr[1] * 2 = 4, arr[1] * 3 = 6, arr[0] * 5 = 5</strong></p><p><strong>………………</strong></p><figure class="highlight java"><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="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">GetUglyNumber_Solution</span><span class="params">(<span class="keyword">int</span> N)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">if</span>(N &lt; <span class="number">7</span>) <span class="keyword">return</span> N;</span><br><span class="line">  <span class="keyword">int</span> i2 = <span class="number">0</span>;<span class="comment">//质因子为2的指针</span></span><br><span class="line">  <span class="keyword">int</span> i3 = <span class="number">0</span>;<span class="comment">//质因子为3的指针</span></span><br><span class="line">  <span class="keyword">int</span> i5 = <span class="number">0</span>;<span class="comment">//质因子为5的指针</span></span><br><span class="line">  <span class="keyword">int</span>[] dp = <span class="keyword">new</span> <span class="keyword">int</span>[N];<span class="comment">//丑数数组</span></span><br><span class="line">  dp[<span class="number">0</span>] = <span class="number">1</span>;</span><br><span class="line">  <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">1</span>; i&lt;N; i++)&#123;</span><br><span class="line">    <span class="keyword">int</span> next2 = dp[i2] * <span class="number">2</span>;</span><br><span class="line">    <span class="keyword">int</span> next3 = dp[i3] * <span class="number">3</span>;</span><br><span class="line">    <span class="keyword">int</span> next5 = dp[i5] * <span class="number">5</span>;</span><br><span class="line">    dp[i] = Math.min( next2,(Math.min(next3,next5)) );</span><br><span class="line">    <span class="keyword">if</span>(dp[i] == next2) i2++;</span><br><span class="line">    <span class="keyword">if</span>(dp[i] == next3) i3++;</span><br><span class="line">    <span class="keyword">if</span>(dp[i] == next5) i5++;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> dp[N-<span class="number">1</span>];</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="第一个只出现一次的字符"><a href="#第一个只出现一次的字符" class="headerlink" title="第一个只出现一次的字符"></a>第一个只出现一次的字符</h4><p><strong>题目描述：</strong>在一个字符串(0&lt;=字符串长度&lt;=10000，全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1（需要区分大小写）.（从0开始计数）</p><p><u>思路</u>：使用数组统计字符出现的次数</p><figure class="highlight java"><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="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">FirstNotRepeatingChar</span><span class="params">(String str)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">int</span>[] count = <span class="keyword">new</span> <span class="keyword">int</span>[<span class="number">256</span>];<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="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; str.length(); i++)&#123;</span><br><span class="line">    <span class="keyword">char</span> c = str.charAt(i);</span><br><span class="line">    count[c]++;</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">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; str.length(); i++)&#123;</span><br><span class="line">    <span class="keyword">char</span> c = str.charAt(i);</span><br><span class="line">    <span class="keyword">if</span>(count[c] == <span class="number">1</span>)&#123;</span><br><span class="line">      <span class="keyword">return</span> i;</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></pre></td></tr></table></figure><br><br><h4 id="机器人的运动范围"><a href="#机器人的运动范围" class="headerlink" title="机器人的运动范围"></a>机器人的运动范围</h4><p><strong>题目描述：</strong>地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动，每一次只能向左，右，上，下四个方向移动一格，但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如，当k为18时，机器人能够进入方格（35,37），因为3+5+3+7 = 18。但是，它不能进入方格（35,38），因为3+5+3+8 = 19。请问该机器人能够达到多少个格子？</p><p><u>思路</u>：递归回溯：</p><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Solution</span> </span>&#123;</span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">int</span> rows;</span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">int</span> cols;</span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">int</span> threshold;</span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">movingCount</span><span class="params">(<span class="keyword">int</span> threshold, <span class="keyword">int</span> rows, <span class="keyword">int</span> cols)</span></span>&#123;</span><br><span class="line">    <span class="keyword">this</span>.rows = rows;</span><br><span class="line">    <span class="keyword">this</span>.cols = cols;</span><br><span class="line">    <span class="keyword">this</span>.threshold = threshold;</span><br><span class="line">    <span class="keyword">boolean</span> isVisited[][] = <span class="keyword">new</span> <span class="keyword">boolean</span>[rows][cols];</span><br><span class="line">    <span class="keyword">int</span> count = dfs(<span class="number">0</span>, <span class="number">0</span>, isVisited);</span><br><span class="line">    <span class="keyword">return</span> count;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">private</span> <span class="keyword">int</span> <span class="title">dfs</span><span class="params">(<span class="keyword">int</span> i, <span class="keyword">int</span> j, <span class="keyword">boolean</span>[][] isVisited)</span></span>&#123;</span><br><span class="line">    <span class="keyword">if</span>(i &lt; <span class="number">0</span> || i &gt;= rows || j &lt; <span class="number">0</span> || j &gt;= cols ||</span><br><span class="line">       (numSum(i) + numSum(j)) &gt; threshold || isVisited[i][j])&#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">    isVisited[i][j] = <span class="keyword">true</span>;</span><br><span class="line">    <span class="keyword">return</span> dfs(i+<span class="number">0</span>, j+<span class="number">1</span>, isVisited)+</span><br><span class="line">      dfs(i+<span class="number">1</span>, j+<span class="number">0</span>, isVisited)+</span><br><span class="line">      dfs(i-<span class="number">1</span>, j+<span class="number">0</span>, isVisited)+</span><br><span class="line">      dfs(i+<span class="number">0</span>, j-<span class="number">1</span>, isVisited)+<span class="number">1</span>;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">private</span> <span class="keyword">int</span> <span class="title">numSum</span><span class="params">(<span class="keyword">int</span> threshold)</span></span>&#123;</span><br><span class="line">    <span class="keyword">int</span> sum = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">while</span>((threshold / <span class="number">10</span>) &gt; <span class="number">0</span>)&#123;</span><br><span class="line">      sum += threshold%<span class="number">10</span>;</span><br><span class="line">      threshold = threshold/<span class="number">10</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    sum = sum+threshold;</span><br><span class="line">    <span class="keyword">return</span> sum;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      &lt;h4 id=&quot;滑动窗口的最大值&quot;&gt;&lt;a href=&quot;#滑动窗口的最大值&quot; class=&quot;headerlink&quot; title=&quot;滑动窗口的最大值&quot;&gt;&lt;/a&gt;滑动窗口的最大值&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;题目描述：&lt;/strong&gt;给定一个数组和滑动窗口的大小，找出所有滑动窗口里数值的最大值。例如，如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3，那么一共存在6个滑动窗口，他们的最大值分别为{4,4,6,6,6,5}； 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个： {[2,3,4],2,6,2,5,1}， {2,[3,4,2],6,2,5,1}， {2,3,[4,2,6],2,5,1}， {2,3,4,[2,6,2],5,1}， {2,3,4,2,[6,2,5],1}， {2,3,4,2,6,[2,5,1]}。&lt;/p&gt;
&lt;p&gt;&lt;u&gt;思路&lt;/u&gt;：&lt;img src=&quot;/2020/06/25/%E5%89%91%E6%8C%87offer/%E5%89%91%E6%8C%87offer-%E8%BE%83%E9%9A%BE%E7%AF%87/%E6%BB%91%E5%8A%A8%E7%AA%97%E5%8F%A3%E7%9A%84%E6%9C%80%E5%A4%A7%E5%80%BC.png&quot; alt=&quot;滑动窗口的最大值&quot;&gt;&lt;/p&gt;
    
    </summary>
    
    
      <category term="剑指offer" scheme="https://chrisxb1996.github.io/categories/%E5%89%91%E6%8C%87offer/"/>
    
      <category term="数据结构和算法" scheme="https://chrisxb1996.github.io/categories/%E5%89%91%E6%8C%87offer/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/"/>
    
    
      <category term="数据结构和算法" scheme="https://chrisxb1996.github.io/tags/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/"/>
    
      <category term="剑指offer" scheme="https://chrisxb1996.github.io/tags/%E5%89%91%E6%8C%87offer/"/>
    
  </entry>
  
  <entry>
    <title>java-基础</title>
    <link href="https://chrisxb1996.github.io/2020/06/16/Java/Java-%E5%9F%BA%E7%A1%80/"/>
    <id>https://chrisxb1996.github.io/2020/06/16/Java/Java-%E5%9F%BA%E7%A1%80/</id>
    <published>2020-06-16T14:54:27.000Z</published>
    <updated>2020-06-25T09:07:37.556Z</updated>
    
    <content type="html"><![CDATA[<h2 id="Java面向对象"><a href="#Java面向对象" class="headerlink" title="Java面向对象"></a>Java面向对象</h2><ul><li><p><strong>面向对象：</strong>是一种程序设计的思想， 其基本思想是使用对象、类、封装、继承、多态等基本概念来进行程序设计。</p></li><li><p><strong>三大特性：</strong></p></li></ul><ol><li><p><strong>封装：</strong>封装性就是尽可能的隐藏对象内部细节，只保留一些对外的接口使其与外部发生联系。用户无需关心对象内部的细节，但可以通过对象对外提供的接口来访问该对象。</p><p>可以通过对类的成员设置一定的访问权限，实现类中成员的信息隐藏。<a id="more"></a></p><p><img src="/2020/06/16/Java/Java-%E5%9F%BA%E7%A1%80/%E8%AE%BF%E9%97%AE%E4%BF%AE%E9%A5%B0%E7%AC%A6.png" alt="访问修饰符"></p><p><strong>优点：</strong>1.实现了高内聚，低耦合；2.提高系统的可扩展性、可维护性</p></li><li><p><strong>继承：</strong> 子类的对象拥有父类的全部属性与方法，称作子类对父类的继承。</p><ul><li><p>Java中父类可以拥有多个子类，但是子类只能继承一个父类，称为单继承。继承<strong>实现了代码的复用</strong>。</p></li><li><p>Java中所有的类都是通过直接或间接地继承java.lang.Object类得到的。</p></li><li><p>子类不能继承父类中访问权限为private的成员变量和方法。</p></li><li><p>子类可以<strong>重写</strong>父类的方法，即命名与父类同名的成员变量。</p></li></ul></li><li><p><strong>多态：</strong>对象的多态性是指在父类中定义的属性或方法被子类继承之后，可以具有不同的数据类型或表现出不同的行为。</p><p>Java中多态体现在两个方面：</p><ul><li><p><strong>编译时多态：</strong>编译时多态主要指<strong>方法的重载</strong></p></li><li><p><strong>运行时多态：</strong>指的是<strong>方法的重写</strong>：产生运行时多态有三个条件：(1)继承；(2)方法重写；(3)父类引用指向子类对象；</p></li></ul></li></ol><br><br><h2 id="Java-和-C-的区别"><a href="#Java-和-C-的区别" class="headerlink" title="Java 和 C++ 的区别"></a>Java 和 C++ 的区别</h2><ul><li>Java 是纯粹的面向对象语言，所有的对象都继承自 java.lang.Object，C++ 为了兼容 C 即支持面向对象也支持面向过程。</li><li>Java 通过虚拟机(JVM)从而实现跨平台特性，但是 C++ 依赖于特定的平台。</li><li>Java 没有指针，它的引用可以理解为安全指针，而 C++ 具有和 C 一样的指针。</li><li>Java 支持自动垃圾回收，而 C++ 需要手动回收。</li><li>Java 不支持多重继承，只能通过实现多个接口来达到相同目的，而 C++ 支持多重继承。</li><li>Java 不支持操作符重载，虽然可以对两个 String 对象执行加法运算，但是这是语言内置支持的操作，不属于操作符重载，而 C++ 可以。</li><li>Java 的 goto 是保留字，但是不可用，C++ 可以使用 goto。</li></ul><br><br><h2 id="JDK-JRE-JVM"><a href="#JDK-JRE-JVM" class="headerlink" title="JDK/JRE/JVM"></a>JDK/JRE/JVM</h2><ul><li><strong>JVM：</strong>是java 虚拟机，当我们运行一个程序时，JVM 负责将Java源文件编译成能被Java虚拟机执行的字节码文件。除此之外，JVM 提供了内存管理/ 垃圾回收和安全机制等。</li><li><strong>JRE：</strong>Java Runtime Environment，Java 运行环境的简称，为 Java 的运行提供了所需的环境。它是一个 JVM 程序，主要包括了 JVM 的标准实现和一些 Java 基本类库。</li><li><strong>JDK：</strong>Java Development Kit，Java 开发工具包，提供了 Java 的开发及运行环境。JDK 是 Java 开发的核心，集成了 JRE 以及一些其它的工具，比如编译 Java 源码的编译器 javac 等。</li></ul><br><br><h2 id="Java数据类型以及自动拆箱-装箱"><a href="#Java数据类型以及自动拆箱-装箱" class="headerlink" title="Java数据类型以及自动拆箱/装箱"></a>Java数据类型以及自动拆箱/装箱</h2><p>Java语言支持的数据类型包括两种：</p><p>基本数据类型：</p><ul><li>byte：1字节(8位)</li><li>short(2)：2字节(16位)</li><li>char(2)：2字节(16位)</li><li>int(4)：4字节(32位)</li><li>float(4)：4字节(32位)</li><li>long(8)：8字节(64位)</li><li>double(8)：8字节(64位)</li><li>Boolean(1)：true、false，可以使用 1 位(bit) 来存储，但是具体大小没有明确规定。JVM 会在编译时期将 boolean 类型的数据转换为 int，使用 1 来表示 true，0 表示 false。JVM 支持 boolean 数组，但是是通过读写 byte 数组来实现的。</li></ul><p><strong>java采用Unicode编码，不论汉字、字母、数字，每个字符都占用2字节。</strong></p><p>自动装箱是Java编译器在基本数据类型和对应的对象包装类型之间做的一个转化。反之就是自动拆箱。自动装箱就是Java编译器在基本数据类型和对应的对象包装类型间的转化，即int转化为Integer,自动拆箱是Integer调用其方法将其转化为int的过程。</p><figure class="highlight java"><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">Integer x = <span class="number">2</span>;     <span class="comment">// 装箱 调用了 Integer.valueOf(2)</span></span><br><span class="line"><span class="keyword">int</span> y = x;         <span class="comment">// 拆箱 调用了 X.intValue()</span></span><br></pre></td></tr></table></figure><br><br><h2 id="Java容器"><a href="#Java容器" class="headerlink" title="Java容器"></a>Java容器</h2><p>容器主要包括 Collection 和 Map 两种，Collection 存储着对象的集合，而 Map 存储着键值对（两个对象）的映射表。</p><h3 id="Collection"><a href="#Collection" class="headerlink" title="Collection"></a>Collection</h3><p><img src="/2020/06/16/Java/Java-%E5%9F%BA%E7%A1%80/Collection.png" alt="Collection"></p><p>注：<strong>List是有序可重复元素集合，Set是无序不可重复元素集合；</strong></p><p><strong>Set</strong> </p><ul><li>TreeSet：基于红黑树实现，支持有序性操作，例如根据一个范围查找元素的操作。但是查找效率不如 HashSet，HashSet 查找的时间复杂度为 O(1)，TreeSet 则为 O(logN)。</li><li>HashSet：基于哈希表实现，支持快速查找，但不支持有序性操作。并且失去了元素的插入顺序信息，也就是说使用 Iterator 遍历 HashSet 得到的结果是不确定的。</li><li>LinkedHashSet：具有 HashSet 的查找效率，并且内部使用双向链表维护元素的插入顺序。</li></ul><p><strong>List</strong></p><ul><li>ArrayList：基于动态数组实现，支持随机访问。</li><li>Vector：和 ArrayList 类似，但它是线程安全的。</li><li>LinkedList：基于双向链表实现，只能顺序访问，但是可以快速地在链表中间插入和删除元素。不仅如此，LinkedList 还可以用作栈、队列和双向队列。</li></ul><p><strong>Queue</strong></p><ul><li>LinkedList：可以用它来实现双向队列。</li><li>PriorityQueue：基于堆结构实现，可以用它来实现<strong>优先队列</strong>。</li></ul><br><h3 id="Map"><a href="#Map" class="headerlink" title="Map"></a>Map</h3><p><img src="/2020/06/16/Java/Java-%E5%9F%BA%E7%A1%80/Map.png" alt="Map"></p><ul><li>TreeMap：基于红黑树实现。</li><li>HashMap：基于哈希表实现。</li><li>HashTable：和 HashMap 类似，但它是线程安全的，这意味着同一时刻多个线程同时写入 HashTable 不会导致数据不一致。它是遗留类，不应该去使用它，而是使用 ConcurrentHashMap 来支持线程安全，ConcurrentHashMap 的效率会更高，因为 ConcurrentHashMap 引入了分段锁。</li><li>LinkedHashMap：使用双向链表来维护元素的顺序，顺序为插入顺序或者最近最少使用（LRU）顺序。</li></ul><br><h3 id="迭代器模式"><a href="#迭代器模式" class="headerlink" title="迭代器模式"></a>迭代器模式</h3><p><img src="/2020/06/16/Java/Java-%E5%9F%BA%E7%A1%80/iterator.png" alt="iterator"></p><p>Collection 继承了 Iterable 接口，其中的 iterator() 方法能够产生一个 Iterator 对象，通过这个对象就可以迭代遍历 Collection 中的元素。</p><p>Java中的Iterator功能比较简单，并且只能单向移动：</p><p>(1) 使用方法iterator()要求容器返回一个Iterator。注意：iterator()方法是java.lang.Iterable接口的方法，被Collection继承。</p><p>(2) 使用hasNext()检查序列中是否还有元素。</p><p>(3) 使用next()获得序列中的下一个元素。</p><p>(4) 使用remove()将迭代器新返回的元素删除。</p><p>Iterator只能正向遍历集合，适用于获取移除元素。ListIterator继承自Iterator，专门针对List，可以从两个方向来遍历List，同时支持元素的修改(插入和删除)。从 JDK 1.5 之后可以使用 for each方法来遍历实现了 Iterable 接口的聚合对象。</p><br><h3 id="源码分析"><a href="#源码分析" class="headerlink" title="源码分析"></a>源码分析</h3><p><strong>ArrayList</strong></p><ul><li><p>ArrayList 是基于数组实现的，所以支持快速随机访问。</p></li><li><p>数组的默认大小为 10。</p>  <figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> DEFAULT_CAPACITY = <span class="number">10</span>;</span><br></pre></td></tr></table></figure></li><li><p><strong>扩容：</strong> <code>oldCapacity + (oldCapacity &gt;&gt; 1)</code>，为旧容量的 1.5 倍，扩容操作需要调用 <code>Arrays.copyOf()</code> 把原数组整个复制到新数组中，操作代价很高。</p></li><li><p><strong>删除元素：</strong>需要调用 System.arraycopy() 将 index+1 后面的元素都复制到 index 位置上，该操作的时间复杂度为 O(N)，可以看到 ArrayList 删除元素的代价是非常高的。</p></li></ul><p><strong>Vector</strong></p><ul><li><p><strong>同步：</strong>它的实现与 ArrayList 类似，但是使用了 synchronized 进行同步。</p></li><li><p><strong>与ArrayList比较：</strong><br>  （1）Vector 是同步的，因此开销就比 ArrayList 要大，访问速度更慢。最好使用 ArrayList 而不是 Vector，因为同步操作完全可以由程序员自己来控制；<br>  （2）Vector 每次扩容请求其大小的 2 倍（也可以通过构造函数设置增长的容量），而 ArrayList 是 1.5 倍。</p></li><li><p><strong>替代方案：</strong>可以使用 <code>Collections.synchronizedList();</code> 得到一个线程安全的 ArrayList。</p>  <figure class="highlight java"><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">List&lt;String&gt; list = <span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">List&lt;String&gt; synList = Collections.synchronizedList(list);</span><br></pre></td></tr></table></figure><p>  也可以使用 concurrent 并发包下的 CopyOnWriteArrayList 类。</p>  <figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">List&lt;String&gt; list = <span class="keyword">new</span> CopyOnWriteArrayList&lt;&gt;();</span><br></pre></td></tr></table></figure></li></ul><p><strong>CopyOnWriteArrayList</strong></p><ul><li><p><strong>读写分离：</strong>写操作在一个复制的数组上进行，读操作还是在原始数组中进行，读写分离，互不影响。</p><p>  写操作需要加锁，防止并发写入时导致写入数据丢失。<br>  写操作结束之后需要把原始数组指向新的复制数组。</p></li><li><p><strong>优缺点：</strong></p><p>  优点：CopyOnWriteArrayList 在写操作的同时允许读操作，大大提高了读操作的性能。<br>  缺点：</p><ul><li>内存占用：在写操作时需要复制一个新的数组，使得内存占用为原来的两倍左右；</li><li>数据不一致：读操作不能读取实时性的数据，因为部分写操作的数据还未同步到读数组中。</li></ul><p>  <strong>适用场景：适合读多写少的应用场景，不适合内存敏感以及对实时性要求很高的场景。</strong></p></li></ul><p><strong>LinkedList</strong></p><ul><li><p>ArrayList 基于动态数组实现，LinkedList 基于双向链表实现。ArrayList 和 LinkedList 的区别可以归结为数组和链表的区别：</p><p>  数组支持随机访问，但插入删除的代价很高，需要移动大量元素；<br>  链表不支持随机访问，但插入删除只需要改变指针。</p></li></ul><p><strong>HashMap</strong></p><ul><li>内部包含了一个 Entry 类型的数组 table。Entry 存储着键值对。它包含了四个字段，从 next 字段我们可以看出 Entry 是一个链表。即数组中的每个位置被当成一个桶，一个桶存放一个链表。HashMap 使用<strong>拉链法</strong>来解决冲突，同一个链表中存放哈希值和散列桶取模运算结果相同的 Entry。</li></ul><p><img src="/2020/06/16/Java/Java-%E5%9F%BA%E7%A1%80/HashMap.png" alt="HashMap"></p><ul><li><p><strong>拉链法</strong></p>  <figure class="highlight java"><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">HashMap&lt;String, String&gt; map = <span class="keyword">new</span> HashMap&lt;&gt;();</span><br><span class="line">map.put(<span class="string">"K1"</span>, <span class="string">"V1"</span>);</span><br><span class="line">map.put(<span class="string">"K2"</span>, <span class="string">"V2"</span>);</span><br><span class="line">map.put(<span class="string">"K3"</span>, <span class="string">"V3"</span>);</span><br></pre></td></tr></table></figure><p>  （1）新建一个 HashMap，默认大小为 16<br>  （2）插入 &lt;K1,V1&gt; 键值对，先计算 K1 的 hashCode 为 113，使用除留余数法得到所在的桶下标 113%16=1。<br>  （3）插入 &lt;K2,V2&gt; 键值对，先计算 K2 的 hashCode 为 120，使用除留余数法得到所在的桶下标 120%16=8。<br>  （4）插入 &lt;K3,V3&gt; 键值对，先计算 K3 的 hashCode 为 120，使用除留余数法得到所在的桶下标 120%16=8，插在 &lt;K2,V2&gt; 前面。<strong>（注意：头插法）</strong></p></li><li><p><strong>扩容</strong></p><p>  当需要扩容时，令 capacity 为原来的两倍。扩容使用 resize() 实现，需要注意的是，扩容操作同样需要把 oldTable 的所有键值对重新插入 newTable 中，因此这一步是很费时的。</p></li><li><p><strong>链表转红黑树</strong></p><p>  从 JDK 1.8 开始，一个桶存储的链表长度大于等于 8 时会将链表转换为红黑树。</p></li><li><p><strong>与HashTable比较</strong></p><p>  （1）Hashtable 使用 synchronized 来进行同步。<br>  （2）HashMap 可以插入键为 null 的 Entry。(HashMap 使用第 0 个桶存放键为 null 的键值对)<br>  （3）HashMap 的迭代器是 fail-fast 迭代器。<br>  （4）HashMap 不能保证随着时间的推移 Map 中的元素次序是不变的。</p></li></ul><p><strong>ConcurrentHashMap</strong></p><ul><li>ConcurrentHashMap 和 HashMap 实现上类似，最主要的差别是 ConcurrentHashMap 采用了<strong>分段锁（Segment）</strong>，每个分段锁维护着几个桶（HashEntry），多个线程可以同时访问不同分段锁上的桶，从而使其并发度更高（并发度就是 Segment 的个数）。</li><li><strong>size操作：</strong>ConcurrentHashMap 在执行 size 操作时先尝试不加锁，如果连续两次不加锁操作得到的结果一致，那么可以认为这个结果是正确的。</li><li><strong>JDK1.8后改动：</strong><ul><li>JDK 1.7 使用分段锁机制来实现并发更新操作，核心类为 Segment，它继承自重入锁 ReentrantLock，并发度与 Segment 数量相等。</li><li>JDK 1.8 使用了 CAS 操作来支持更高的并发度，在 CAS 操作失败时使用内置锁 synchronized。</li></ul></li></ul><br><br><h2 id="Java泛型"><a href="#Java泛型" class="headerlink" title="Java泛型"></a>Java泛型</h2><p>Java1.4或更早版本的开发背景的人都知道，在集合中存储对象并在使用前进行类型转换是多么的不方便。泛型防止了那种情况的发生。它提供了编译期的类型安全，确保你只能把正确类型的对象放入集合中，避免了在运行时出现ClassCastException。</p><br><br><h2 id="Java并发"><a href="#Java并发" class="headerlink" title="Java并发"></a>Java并发</h2><h3 id="为什么要使用多线程"><a href="#为什么要使用多线程" class="headerlink" title="为什么要使用多线程"></a>为什么要使用多线程</h3><p><strong>多线程并不一定能提升性能</strong>（甚至还会降低性能）；多线程也不只是为了提升性能。多线程主要有以下的应用场景：</p><ul><li><p><strong>避免阻塞（异步调用）</strong></p><p>  单个线程中的程序，是顺序执行的。如果前面的操作发生了阻塞，那么就会影响到后面的操作。这时候可以采用多线程，我感觉就等于是异步调用。这样的例子有很多：eg.ajax调用，就是浏览器会启一个新的线程，不阻塞当前页面的正常操作。</p></li><li><p><strong>避免CPU空转</strong></p><p>  以web请求为例，处理完一条请求，再处理下一条请求的话，CPU会存在大量的闲置时间。因为处理一条请求，经常涉及到RPC、数据库访问、磁盘IO等操作，这些操作的速度比CPU慢很多，而在等待这些响应的时候，CPU却不能去处理新的请求，因此都采用对每个请求创建新线程来响应的方式实现，这样在等待IO操作的等待时间里，就可以去继续处理其他请求，对并发的响应性就好了很多。</p></li><li><p><strong>提升性能</strong></p><p>  在满足条件的前提下，多线程确实能提升性能。<strong>多核CPU才行</strong></p></li></ul><br><h3 id="进程和线程"><a href="#进程和线程" class="headerlink" title="进程和线程"></a>进程和线程</h3><p>进程是执行着的应用程序，而线程是进程内部的一个执行序列。一个进程可以有多个线程。</p><ul><li>地址空间和其它资源：进程间相互独立，同一进程的各线程间共享。某进程内的线程在其它进程不可见。</li><li>进程是资源分配的最小单位，它使用独立的数据空间；线程是程序执行的最小单位，它共享进程的数据结构。</li></ul><h3 id="使用线程的三种方法"><a href="#使用线程的三种方法" class="headerlink" title="使用线程的三种方法"></a>使用线程的三种方法</h3><ul><li><p><strong>实现Runnable接口</strong></p><p>   1.创建：实现Runnable接口 + 重写run()</p><p>   2.启动：创建实现类对象 + Thread对象 + start</p>  <figure class="highlight java"><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="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">StartRun</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>&#123;</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="meta">@Override</span></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </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;<span class="number">10</span>;i++) &#123;</span><br><span class="line">      System.out.println(<span class="string">"一边听歌"</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="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">new</span> Thread(<span class="keyword">new</span> StartRun()).start();</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;<span class="number">10</span>;i++) &#123;</span><br><span class="line">      System.out.println(<span class="string">"一边敲代码"</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></li><li><p><strong>继承Thread类</strong></p><p>  1.创建：继承Thread + 重写run()</p><p>  2.启动：创建子类对象 + start</p>  <figure class="highlight java"><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="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">StartThread</span> <span class="keyword">extends</span> <span class="title">Thread</span> </span>&#123;</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="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </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;<span class="number">10</span>;i++) &#123;</span><br><span class="line">System.out.println(<span class="string">"一边听歌"</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="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line"><span class="comment">//启动线程</span></span><br><span class="line"><span class="comment">//1.创建子类对象</span></span><br><span class="line">StartThread st = <span class="keyword">new</span> StartThread();</span><br><span class="line"><span class="comment">//2.调用start</span></span><br><span class="line">st.start();   <span class="comment">//交给cpu，形成两条路径，但start方法不保证立即运行，由cpu去调用</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>;i&lt;<span class="number">10</span>;i++) &#123;</span><br><span class="line">System.out.println(<span class="string">"一边敲代码"</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></li><li><p><strong>实现Callable接口</strong></p><p>  与 Runnable 相比，Callable 可以有返回值，返回值通过 FutureTask 进行封装，并且抛出异常。</p>  <figure class="highlight java"><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"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyCallable</span> <span class="keyword">implements</span> <span class="title">Callable</span>&lt;<span class="title">Integer</span>&gt; </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> Integer <span class="title">call</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">123</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> ExecutionException, InterruptedException </span>&#123;</span><br><span class="line">      MyCallable mc = <span class="keyword">new</span> MyCallable();</span><br><span class="line">      FutureTask&lt;Integer&gt; ft = <span class="keyword">new</span> FutureTask&lt;&gt;(mc);</span><br><span class="line">      Thread thread = <span class="keyword">new</span> Thread(ft);</span><br><span class="line">      thread.start();</span><br><span class="line">      System.out.println(ft.get());</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>推荐实现接口：避免单继承的局限性，优先使用接口，方便共享资源。</p></li></ul>   <br><h3 id="基础线程机制"><a href="#基础线程机制" class="headerlink" title="基础线程机制"></a>基础线程机制</h3><ul><li><p><strong>线程池：</strong></p><p>  装有线程的池子，我们可以把要执行的多线程交给线程池来处理，和连接池的概念一样。使用实现了Executor接口的ThreadPoolExecutor来创建线程池。通过维护一定数量的线程池来达到多个线程的复用。<strong>（为了减少在创建和销毁线程上所花的时间以及系统资源的开销）</strong>。</p><p>  主要有三种 Executor：</p><ul><li>CachedThreadPool：一个任务创建一个线程；</li><li>FixedThreadPool：所有任务只能使用固定大小的线程；</li><li>SingleThreadExecutor：相当于大小为 1 的 FixedThreadPool。</li></ul></li><li><p><strong>守护线程(Daemon)：</strong></p><p>  当所有非守护线程结束时，程序也就终止，同时会杀死所有守护线程。</p><p>  main() 属于非守护线程。</p><p>  在线程启动之前使用 setDaemon() 方法可以将一个线程设置为守护线程。</p></li><li><p><strong>sleep():</strong></p><p>  Thread.sleep(millisec) 方法会休眠当前正在执行的线程，millisec 单位为毫秒。使线程停止运行一段时间，将处于<strong>阻塞状态</strong>。</p><p>  如果调用了sleep方法之后，没有其他等待执行的线程，这个时候当前线程<strong>不会马上恢复执行</strong>！</p><p>  sleep() 可能会抛出 InterruptedException，因为异常不能跨线程传播回 main() 中，因此必须在本地进行处理。线程中抛出的其它异常也同样需要在本地进行处理。</p>  <figure class="highlight java"><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="keyword">try</span> &#123;</span><br><span class="line">  Thread.sleep(<span class="number">100</span>);</span><br><span class="line">&#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">  e.printStackTrace();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p><strong>yield():</strong></p><p>  yield:礼让线程，暂停线程直接进入<strong>就绪状态</strong>，不是阻塞状态。</p><p>  如果调用了yield方法之后，没有其他等待执行的线程，这个时候当前线程就会<strong>马上恢复执行</strong>！</p></li></ul><br><h3 id="synchronized和ReentrantLock"><a href="#synchronized和ReentrantLock" class="headerlink" title="synchronized和ReentrantLock"></a>synchronized和ReentrantLock</h3><p>Java 提供了两种锁机制来控制多个线程对共享资源的互斥访问，第一个是 JVM 实现的 synchronized，而另一个是 JDK 实现的 ReentrantLock。</p><p><strong>synchronized：</strong></p><ul><li><strong>同步一个代码块</strong>：同一个对象</li><li><strong>同步一个方法</strong>：同一个对象</li><li><strong>同步一个类：</strong>两个线程调用该类的不同对象上的这种同步语句，也会进行同步</li><li><strong>同步一个静态方法：</strong>作用于整个类</li></ul><p><strong>ReentrantLock：</strong></p><ul><li>ReentrantLock 是 java.util.concurrent（J.U.C）包中的锁</li></ul><p><strong>比较：</strong></p><ul><li>锁的实现：synchronized 是 JVM 实现的，而 ReentrantLock 是 JDK 实现的。</li><li>性能：新版本 Java 对 synchronized 进行了很多优化，例如自旋锁等，synchronized 与 ReentrantLock 大致相同。</li><li>等待可中断：当持有锁的线程长期不释放锁的时候，正在等待的线程可以选择放弃等待，改为处理其他事情。ReentrantLock 可中断，而 synchronized 不行。</li><li>公平锁：公平锁是指多个线程在等待同一个锁时，必须按照申请锁的时间顺序来依次获得锁。synchronized 中的锁是非公平的，ReentrantLock 默认情况下也是非公平的，但是也可以是公平的。</li><li>锁绑定多个条件：一个 ReentrantLock 可以同时绑定多个 Condition 对象</li><li><strong>除非需要使用 ReentrantLock 的高级功能，否则优先使用 synchronized。</strong>这是因为 synchronized 是 JVM 实现的一种锁机制，JVM 原生地支持它，而 ReentrantLock 不是所有的 JDK 版本都支持。并且使用 synchronized 不用担心没有释放锁而导致死锁问题，因为 JVM 会确保锁的释放。</li></ul><br><h3 id="线程中的相互协作"><a href="#线程中的相互协作" class="headerlink" title="线程中的相互协作"></a>线程中的相互协作</h3><p><strong>join()：</strong></p><p>在线程中调用另一个线程的 join() 方法，会将当前线程挂起，直到目标线程结束。</p><p>虽然 b 线程先启动，但是如果在 b 线程中调用了 a 线程的 join() 方法，b 线程会等待 a 线程结束才继续执行，因此最后能够保证 a 线程的输出先于 b 线程的输出。</p><p><strong>wait()：</strong></p><p>调用 wait() 使得线程等待某个条件满足，线程在等待时会被挂起，当其他线程的运行使得这个条件满足时，其它线程会调用 notify() 或者 notifyAll() 来唤醒挂起的线程。</p><p><strong>注意：</strong></p><ul><li>使用 wait() 挂起期间，线程会释放锁，而sleep() 不会；</li><li>wait() 是 Object 的方法，而 sleep() 是 Thread 的静态方法；</li></ul><br><h3 id="线程状态"><a href="#线程状态" class="headerlink" title="线程状态"></a>线程状态</h3><p><img src="/2020/06/16/Java/Java-%E5%9F%BA%E7%A1%80/%E7%BA%BF%E7%A8%8B%E7%8A%B6%E6%80%81.png" alt="线程状态"></p><br><br><h2 id="Java-I-O"><a href="#Java-I-O" class="headerlink" title="Java I/O"></a>Java I/O</h2><h3 id="分类"><a href="#分类" class="headerlink" title="分类"></a>分类</h3><p>Java 的 I/O 大概可以分成以下几类：</p><ul><li>磁盘操作：File</li><li>字节操作：InputStream 和 OutputStream</li><li>字符操作：Reader 和 Writer</li><li>对象操作：Serializable</li><li>网络操作：Socket</li><li>新的输入/输出：NIO</li></ul><br><h3 id="磁盘操作"><a href="#磁盘操作" class="headerlink" title="磁盘操作"></a>磁盘操作</h3><p>File 类可以用于表示文件和目录的信息，但是它不表示文件的内容。</p><p>递归地列出一个目录下的所有 文件</p><figure class="highlight java"><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="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">show</span><span class="params">(File dir)</span></span>&#123;</span><br><span class="line">  <span class="keyword">if</span>(dir == <span class="keyword">null</span> &amp;&amp; !dir.exists)&#123;</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>(dir.isFile())&#123;</span><br><span class="line">    System.out.println(dir.getName());</span><br><span class="line">    <span class="keyword">return</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">for</span>(File f : dir.listFiles())&#123;</span><br><span class="line">    show(f);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><h3 id="字节操作"><a href="#字节操作" class="headerlink" title="字节操作"></a>字节操作</h3><ul><li><p>InputStream</p><p>  Java I/O 使用了装饰者模式来实现。以 InputStream 为例，</p><ul><li><p>InputStream 是抽象组件；</p></li><li><p>FileInputStream 是 InputStream 的子类，属于具体组件，提供了字节流的输入操作；</p></li><li><p>FilterInputStream 属于抽象装饰者，装饰者用于装饰组件，为组件提供额外的功能。例如 BufferedInputStream 为 FileInputStream 提供缓存的功能。</p><p>  <img src="/2020/06/16/Java/Java-%E5%9F%BA%E7%A1%80/IO%E8%A3%85%E9%A5%B0%E8%80%85%E6%A8%A1%E5%BC%8F.png" alt="IO装饰者模式"></p><p>  实例化一个具有缓存功能的字节流对象时，只需要在 FileInputStream 对象上再套一层 BufferedInputStream 对象即可</p></li></ul></li></ul><br><h3 id="字符操作"><a href="#字符操作" class="headerlink" title="字符操作"></a>字符操作</h3><ul><li><p>编码与解码：编码就是把字符转换为字节，而解码是把字节重新组合成字符。</p><ul><li>GBK 编码中，中文字符占 2 个字节，英文字符占 1 个字节；</li><li>UTF-8 编码中，中文字符占 3 个字节，英文字符占 1 个字节；</li><li>UTF-16be 编码中，中文字符和英文字符都占 2 个字节；<strong>(Java：Java 使用这种双字节编码是为了让一个中文或者一个英文都能使用一个 char 来存储。)</strong></li></ul></li><li><p>Reader和Writer</p><p>  <img src="/2020/06/16/Java/Java-%E5%9F%BA%E7%A1%80/Reader%E5%92%8CWriter.png" alt="Reader和Writer"></p><ul><li>InputStreamReader 实现从字节流解码成字符流；(转换流)</li></ul></li><li><p>OutputStreamWriter 实现字符流编码成为字节流。(转换流)</p><ul><li>从JDK文档中可以知道FileOutputStream是OutputStream的直接子类，FileInputStream也是InputStream的直接子类，但是在字符流文件的两个操作类却有一些特殊，FileWriter并不直接是Writer的子类，而是OutputStreamWriter的子类，而FileReader也不直接是Reader的子类，而是InputStreamReader的子类，那么从这两个类的继承关系就可以清楚的发现，<strong>不管是是使用字节流还是字符流实际上最终都是以字节形式操作输出流的。</strong></li></ul></li></ul><br><pre><code>### 对象操作</code></pre><p><strong>序列化：</strong></p><ul><li>序列化就是将一个对象转换成字节序列，方便存储和传输。<ul><li>序列化：ObjectOutputStream.writeObject()</li><li>反序列化：ObjectInputStream.readObject()</li></ul></li></ul><p>不会对静态变量进行序列化，因为<strong>序列化只是保存对象的状态，静态变量属于类的状态。</strong></p><p><strong>Serializable：</strong></p><ul><li>序列化的类需要实现 Serializable 接口，它只是一个标准，没有任何方法需要实现，但是如果不去实现它的话而进行序列化，会抛出异常。</li></ul><p><strong>transient：</strong></p><p>java 的transient关键字为我们提供了便利，你只需要实现Serilizable接口，将不需要序列化的属性前添加关键字transient，序列化对象的时候，这个属性就不会序列化到指定的目的地中。</p><p>ArrayList 中存储数据的数组 elementData 是用 transient 修饰的</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">transient</span> Object[] elementData;</span><br></pre></td></tr></table></figure><p><strong>通过一些重写的方法，只序列化数组中有内容的那部分数据</strong></p><br><h3 id="网络操作"><a href="#网络操作" class="headerlink" title="网络操作"></a>网络操作</h3><p><strong>Java 中的网络支持：</strong></p><ul><li>InetAddress：用于表示网络上的硬件资源，即 IP 地址；</li><li>URL：统一资源定位符；</li><li>Sockets：使用 TCP 协议实现网络通信；</li><li>Datagram：使用 UDP 协议实现网络通信。</li></ul><p><strong>从URL读取字节数据：</strong></p><figure class="highlight java"><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="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">  URL url = <span class="keyword">new</span> URL(<span class="string">"http://www.baidu.com"</span>);</span><br><span class="line"></span><br><span class="line">  <span class="comment">/* 字节流 */</span></span><br><span class="line">  InputStream is = url.openStream();</span><br><span class="line"></span><br><span class="line">  <span class="comment">/* 字符流 */</span></span><br><span class="line">  InputStreamReader isr = <span class="keyword">new</span> InputStreamReader(is, <span class="string">"utf-8"</span>);</span><br><span class="line"></span><br><span class="line">  <span class="comment">/* 提供缓存功能 */</span></span><br><span class="line">  BufferedReader br = <span class="keyword">new</span> BufferedReader(isr);</span><br><span class="line"></span><br><span class="line">  String line;</span><br><span class="line">  <span class="keyword">while</span> ((line = br.readLine()) != <span class="keyword">null</span>) &#123;</span><br><span class="line">    System.out.println(line);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  br.close();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>Sockets：</strong></p><ul><li>ServerSocket：服务器端类</li><li>Socket：客户端类</li><li>服务器和客户端通过 InputStream 和 OutputStream 进行输入输出。</li></ul><p><img src="/2020/06/16/Java/Java-%E5%9F%BA%E7%A1%80/Socket.png" alt="Socket"></p><br><h3 id="NIO"><a href="#NIO" class="headerlink" title="NIO"></a>NIO</h3><p>NIO即New IO，这个库是在<strong>JDK1.4</strong> 中才引入的。NIO和IO有相同的作用和目的，但实现方式不同，<strong>NIO主要用到的是块，所以NIO的效率要比IO高很多。</strong>在Java API中提供了两套NIO，一套是针对标准输入输出NIO，另一套就是网络编程NIO。</p><p><strong>流与块：</strong></p><ul><li><p>I/O 与 NIO 最重要的区别是数据打包和传输的方式，<strong>I/O 以流的方式处理数据</strong>，而 <strong>NIO 以块的方式处理数据。</strong></p><ul><li><p><strong>面向流的 I/O 一次处理一个字节数据</strong>：一个输入流产生一个字节数据，一个输出流消费一个字节数据。为流式数据创建过滤器非常容易，链接几个过滤器，以便每个过滤器只负责复杂处理机制的一部分。不利的一面是，面向流的 I/O 通常相当慢。</p></li><li><p><strong>面向块的 I/O 一次处理一个数据块，按块处理数据比按流处理数据要快得多。</strong>但是面向块的 I/O 缺少一些面向流的 I/O 所具有的优雅性和简单性。</p></li></ul></li></ul><p><strong>通道和缓冲区：</strong></p><ul><li><p><strong>通道 Channel</strong>： 是对原 I/O 包中的流的模拟，可以通过它读取和写入数据。</p><p>  通道与流的不同之处在于，流只能在一个方向上移动(一个流必须是 InputStream 或者 OutputStream 的子类)，而<strong>通道是双向的，可以用于读、写或者同时用于读写。</strong></p></li><li><p><strong>缓冲区：</strong>发送给一个通道的所有数据都必须首先放到缓冲区中，同样地，从通道中读取的任何数据都要先读到缓冲区中。也就是说，不会直接对通道进行读写数据，而是要先经过缓冲区。</p><ul><li><p>缓冲区实质上是一个数组，但它不仅仅是一个数组。缓冲区提供了对数据的结构化访问，而且还可以跟踪系统的读/写进程。</p></li><li><p>缓冲区状态变量：</p><p>  1.capacity：最大容量；</p><p>  2.position：当前已经读写的字节数；</p><p>  3.limit：还可以读写的字节数。</p></li></ul></li></ul><p><strong>选择器与非阻塞I/O：</strong></p><ul><li><p>NIO 常常被叫做非阻塞 IO，主要是因为 NIO 在网络通信中的非阻塞特性被广泛使用。</p></li><li><p>NIO 实现了 IO 多路复用中的 Reactor 模型，一个线程 Thread 使用一个选择器 Selector 通过轮询的方式去监听多个通道 Channel 上的事件，从而让一个线程就可以处理多个事件。</p><p>  <strong>通过配置监听的通道 Channel 为非阻塞，那么当 Channel 上的 IO 事件还未到达时，就不会进入阻塞状态一直等待，而是继续轮询其它 Channel，找到 IO 事件已经到达的 Channel 执行。</strong></p><p>  因为创建和切换线程的开销很大，因此使用一个线程来处理多个事件而不是一个线程处理一个事件，对于 IO 密集型的应用具有很好地性能。</p></li></ul><p><img src="/2020/06/16/Java/Java-%E5%9F%BA%E7%A1%80/NIO.png" alt="NIO"></p><p><strong>NIO 与 IO 主要区别：</strong></p><ul><li>NIO 面向块，IO 面向流</li><li>NIO 非阻塞，IO 阻塞</li></ul><br><br><h2 id="Java虚拟机"><a href="#Java虚拟机" class="headerlink" title="Java虚拟机"></a>Java虚拟机</h2><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><p>Cyc2018 ：<a href="https://cyc2018.github.io/CS-Notes/#/README" target="_blank" rel="noopener">https://cyc2018.github.io/CS-Notes/#/README</a></p>]]></content>
    
    <summary type="html">
    
      &lt;h2 id=&quot;Java面向对象&quot;&gt;&lt;a href=&quot;#Java面向对象&quot; class=&quot;headerlink&quot; title=&quot;Java面向对象&quot;&gt;&lt;/a&gt;Java面向对象&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;面向对象：&lt;/strong&gt;是一种程序设计的思想， 其基本思想是使用对象、类、封装、继承、多态等基本概念来进行程序设计。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;三大特性：&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;封装：&lt;/strong&gt;封装性就是尽可能的隐藏对象内部细节，只保留一些对外的接口使其与外部发生联系。用户无需关心对象内部的细节，但可以通过对象对外提供的接口来访问该对象。&lt;/p&gt;
&lt;p&gt;可以通过对类的成员设置一定的访问权限，实现类中成员的信息隐藏。&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;
    
    </summary>
    
    
      <category term="Java" scheme="https://chrisxb1996.github.io/categories/Java/"/>
    
    
      <category term="Java" scheme="https://chrisxb1996.github.io/tags/Java/"/>
    
  </entry>
  
  <entry>
    <title>剑指offer-中等篇</title>
    <link href="https://chrisxb1996.github.io/2020/06/10/%E5%89%91%E6%8C%87offer/%E5%89%91%E6%8C%87offer-%E4%B8%AD%E7%AD%89%E7%AF%87/"/>
    <id>https://chrisxb1996.github.io/2020/06/10/%E5%89%91%E6%8C%87offer/%E5%89%91%E6%8C%87offer-%E4%B8%AD%E7%AD%89%E7%AF%87/</id>
    <published>2020-06-10T13:03:53.000Z</published>
    <updated>2020-07-18T13:57:23.661Z</updated>
    
    <content type="html"><![CDATA[<h4 id="剪绳子"><a href="#剪绳子" class="headerlink" title="剪绳子"></a>剪绳子</h4><p><strong>题目描述：</strong>给你一根长度为n的绳子，请把绳子剪成整数长的m段（m、n都是整数，n&gt;1并且m&gt;1），每段绳子的长度记为k[0],k[1],…,k[m]。请问k[0] x k[1] x … x k[m]可能的最大乘积是多少？例如，当绳子的长度是8时，我们把它剪成长度分别为2、3、3的三段，此时得到的最大乘积是18。</p><p><u>思路</u>： </p><ul><li>5&lt;2x3，6&lt;3x3，比6更大的数字我们就更不用考虑了，肯定要继续分。</li><li>其次看2和3的数量，2的数量肯定小于3个，为什么呢？因为2x2x2 &lt; 3x3，那么题目就简单了。</li><li>直接用n除以3，根据得到的余数判断是一个2还是两个2还是没有2就行了。<a id="more"></a></li></ul><figure class="highlight java"><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="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">cutRope</span><span class="params">(<span class="keyword">int</span> target)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">if</span>(target == <span class="number">2</span>) <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">  <span class="keyword">if</span>(target == <span class="number">3</span>) <span class="keyword">return</span> <span class="number">2</span>;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">int</span> x = target % <span class="number">3</span>;</span><br><span class="line">  <span class="keyword">int</span> y = target / <span class="number">3</span>;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span>(x == <span class="number">0</span>)&#123;</span><br><span class="line">    <span class="keyword">return</span> (<span class="keyword">int</span>)Math.pow(<span class="number">3</span>,y);</span><br><span class="line">  &#125;<span class="keyword">else</span> <span class="keyword">if</span>(x == <span class="number">1</span>)&#123;<span class="comment">//7%3=2···1   2*2*3</span></span><br><span class="line">    <span class="keyword">return</span> <span class="number">2</span>*<span class="number">2</span>*(<span class="keyword">int</span>)Math.pow(<span class="number">3</span>,y-<span class="number">1</span>);</span><br><span class="line">  &#125;<span class="keyword">else</span>&#123;<span class="comment">//8%3=2···2    3*3*2</span></span><br><span class="line">    <span class="keyword">return</span> <span class="number">2</span>*(<span class="keyword">int</span>)Math.pow(<span class="number">3</span>,y);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="把二叉树打印成多行"><a href="#把二叉树打印成多行" class="headerlink" title="把二叉树打印成多行"></a>把二叉树打印成多行</h4><p><strong>题目描述：</strong>从上到下按层打印二叉树，同一层结点从左至右输出。每一层输出一行。</p><p><u>思路</u>：用队列实现二叉树的层次遍历(标准写法)</p><figure class="highlight java"><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">ArrayList&lt;ArrayList&lt;Integer&gt; &gt; Print(TreeNode pRoot) &#123;</span><br><span class="line">  <span class="keyword">if</span>(pRoot == <span class="keyword">null</span>) <span class="keyword">return</span> <span class="keyword">new</span> ArrayList();</span><br><span class="line">  ArrayList&lt;ArrayList&lt;Integer&gt; &gt; res = <span class="keyword">new</span> ArrayList&lt;ArrayList&lt;Integer&gt; &gt;();</span><br><span class="line">  Queue&lt;TreeNode&gt; queue = <span class="keyword">new</span> LinkedList&lt;&gt;();</span><br><span class="line">  queue.add(pRoot);</span><br><span class="line">  <span class="keyword">while</span>(!queue.isEmpty())&#123;</span><br><span class="line">    ArrayList&lt;Integer&gt; list = <span class="keyword">new</span> ArrayList&lt;Integer&gt;();</span><br><span class="line">    <span class="keyword">int</span> count = queue.size();</span><br><span class="line">    <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i&lt;count; i++)&#123;</span><br><span class="line">      TreeNode node = queue.poll();</span><br><span class="line">      list.add(node.val);</span><br><span class="line">      <span class="keyword">if</span>(node.left != <span class="keyword">null</span>) queue.add(node.left);</span><br><span class="line">      <span class="keyword">if</span>(node.right != <span class="keyword">null</span>) queue.add(node.right);</span><br><span class="line">    &#125;</span><br><span class="line">    res.add(list);</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></pre></td></tr></table></figure><br><br><h4 id="二叉树的下一个结点"><a href="#二叉树的下一个结点" class="headerlink" title="二叉树的下一个结点"></a>二叉树的下一个结点</h4><p><strong>题目描述：</strong>给定一个二叉树和其中的一个结点，请找出中序遍历顺序的下一个结点并且返回。注意，树中的结点不仅包含左右子结点，同时包含指向父结点的指针。</p><p><u>思路</u>：判断当前节点的右子节点是否为空</p><figure class="highlight java"><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="function"><span class="keyword">public</span> TreeLinkNode <span class="title">GetNext</span><span class="params">(TreeLinkNode pNode)</span></span>&#123;</span><br><span class="line">  <span class="keyword">if</span>(pNode.right != <span class="keyword">null</span>)&#123;<span class="comment">//当前节点右子节点不为空</span></span><br><span class="line">    TreeLinkNode node = pNode.right;</span><br><span class="line">    <span class="keyword">while</span>(node.left != <span class="keyword">null</span>)&#123;<span class="comment">//找到右子节点的最底层左子节点</span></span><br><span class="line">      node = node.left;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> node;</span><br><span class="line">  &#125;<span class="keyword">else</span>&#123;<span class="comment">//当前节点右子节点为空</span></span><br><span class="line">    <span class="keyword">while</span>(pNode.next != <span class="keyword">null</span>)&#123;</span><br><span class="line">      TreeLinkNode parent = pNode.next;<span class="comment">//指向当前节点的父节点</span></span><br><span class="line">      <span class="keyword">if</span>(parent.left == pNode)&#123;<span class="comment">//判断当前节点是否为父节点的左子节点</span></span><br><span class="line">        <span class="keyword">return</span> parent;</span><br><span class="line">      &#125;</span><br><span class="line">      pNode = pNode.next;</span><br><span class="line">    &#125; </span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="链表中环的入口结点"><a href="#链表中环的入口结点" class="headerlink" title="链表中环的入口结点"></a>链表中环的入口结点</h4><p><strong>题目描述：</strong>给一个链表，若其中包含环，请找出该链表的环的入口结点，否则，输出null。</p><p><u>思路</u>：<img src="/2020/06/10/%E5%89%91%E6%8C%87offer/%E5%89%91%E6%8C%87offer-%E4%B8%AD%E7%AD%89%E7%AF%87/%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8.png" alt="环形链表"></p><figure class="highlight java"><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="function"><span class="keyword">public</span> ListNode <span class="title">EntryNodeOfLoop</span><span class="params">(ListNode pHead)</span></span>&#123;</span><br><span class="line">  <span class="keyword">if</span>(pHead == <span class="keyword">null</span> || pHead.next == <span class="keyword">null</span>) <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">  ListNode fast = pHead;</span><br><span class="line">  ListNode slow = pHead;</span><br><span class="line">  <span class="keyword">do</span>&#123;</span><br><span class="line">    fast = fast.next.next;</span><br><span class="line">    slow = slow.next;</span><br><span class="line">  &#125;<span class="keyword">while</span>(slow != fast);</span><br><span class="line"></span><br><span class="line">  fast = pHead;</span><br><span class="line">  <span class="keyword">while</span>(fast != slow)&#123;</span><br><span class="line">    fast = fast.next;</span><br><span class="line">    slow = slow.next;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> fast;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="字符流中第一个不重复的字符"><a href="#字符流中第一个不重复的字符" class="headerlink" title="字符流中第一个不重复的字符"></a>字符流中第一个不重复的字符</h4><p><strong>题目描述：</strong>请实现一个函数用来找出字符流中第一个只出现一次的字符。例如，当从字符流中只读出前两个字符”go”时，第一个只出现一次的字符是”g”。当从该字符流中读出前六个字符“google”时，第一个只出现一次的字符是”l”。</p><p>如果当前字符流没有存在出现一次的字符，返回 # 字符。</p><p><u>思路</u>：用数组统计字符出现的次数，并将字符按顺序加入队列，如果队列中字符出现的次数大于1，则出队；如果最后队列不为空，则出队的字符就是第一个出现的字符。</p><figure class="highlight java"><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="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Solution</span> </span>&#123;</span><br><span class="line">  <span class="comment">//Insert one char from stringstream</span></span><br><span class="line">  <span class="keyword">int</span>[] counts = <span class="keyword">new</span> <span class="keyword">int</span>[<span class="number">256</span>];</span><br><span class="line">  <span class="keyword">private</span> Queue&lt;Character&gt; queue = <span class="keyword">new</span> LinkedList&lt;&gt;();</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">Insert</span><span class="params">(<span class="keyword">char</span> ch)</span></span>&#123;</span><br><span class="line">    counts[ch]++;</span><br><span class="line">    queue.add(ch);</span><br><span class="line">    <span class="keyword">while</span>(!queue.isEmpty() &amp;&amp; counts[queue.peek()] &gt; <span class="number">1</span>)&#123;</span><br><span class="line">      queue.poll();</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">//return the first appearence once char in current stringstream</span></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">char</span> <span class="title">FirstAppearingOnce</span><span class="params">()</span></span>&#123;</span><br><span class="line">    <span class="keyword">return</span> queue.isEmpty() ? <span class="string">'#'</span> : queue.peek();</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="表示数值的字符串"><a href="#表示数值的字符串" class="headerlink" title="表示数值的字符串"></a>表示数值的字符串</h4><p><strong>题目描述：</strong>请实现一个函数用来判断字符串是否表示数值（包括整数和小数）。例如，字符串”+100”,”5e2”,”-123”,”3.1416”和”-1E-16”都表示数值。 但是”12e”,”1a3.14”,”1.2.3”,”+-5”和”12e+4.3”都不是。</p><p><u>思路</u>：用法JDK方法：Double.parseDouble()</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isNumeric</span><span class="params">(<span class="keyword">char</span>[] str)</span> </span>&#123;</span><br><span class="line">  <span class="comment">//String string = String.valueOf(str);</span></span><br><span class="line">  <span class="comment">//return string.matches("[\\+-]?[0-9]*(\\.[0-9]*)?([eE][\\+-]?[0-9]+)?");</span></span><br><span class="line">  <span class="keyword">try</span>&#123;</span><br><span class="line">    <span class="keyword">double</span> res = Double.parseDouble(<span class="keyword">new</span> String(str));  </span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">catch</span>(NumberFormatException e)&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="数组中重复的数字"><a href="#数组中重复的数字" class="headerlink" title="数组中重复的数字"></a>数组中重复的数字</h4><p><strong>题目描述：</strong>在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的，但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如，如果输入长度为7的数组{2,3,1,0,2,5,3}，那么对应的输出是第一个重复的数字2。</p><p><u>思路</u>：<img src="/2020/06/10/%E5%89%91%E6%8C%87offer/%E5%89%91%E6%8C%87offer-%E4%B8%AD%E7%AD%89%E7%AF%87/%E6%95%B0%E7%BB%84%E4%B8%AD%E9%87%8D%E5%A4%8D%E7%9A%84%E6%95%B0%E5%AD%97.png" alt="数组中重复的数字"></p><figure class="highlight java"><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="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">duplicate</span><span class="params">(<span class="keyword">int</span> numbers[],<span class="keyword">int</span> length,<span class="keyword">int</span> [] duplication)</span></span>&#123;</span><br><span class="line">  <span class="keyword">if</span>(numbers == <span class="keyword">null</span> || numbers.length == <span class="number">1</span>) <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>;i&lt;numbers.length; i++)&#123;</span><br><span class="line">    <span class="keyword">while</span>(numbers[i] != i)&#123;</span><br><span class="line">      <span class="keyword">if</span>(numbers[i] == numbers[numbers[i]])&#123;</span><br><span class="line">        duplication[<span class="number">0</span>] = numbers[i];</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">      &#125;</span><br><span class="line">      swap(numbers, i, numbers[i]);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">swap</span><span class="params">(<span class="keyword">int</span> numbers[],<span class="keyword">int</span> i,<span class="keyword">int</span> j)</span></span>&#123;</span><br><span class="line">  <span class="keyword">int</span> temp = numbers[i];</span><br><span class="line">  numbers[i] = numbers[j];</span><br><span class="line">  numbers[j] = temp;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="求1-2-3-…-n"><a href="#求1-2-3-…-n" class="headerlink" title="求1+2+3+…+n"></a>求1+2+3+…+n</h4><p><strong>题目描述：</strong>求1+2+3+…+n，要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句（A?B:C）。</p><p><u>思路</u>：利用逻辑与得短路特性做为递归的终止条件。</p><figure class="highlight java"><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="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">Sum_Solution</span><span class="params">(<span class="keyword">int</span> n)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">int</span> sum = n;</span><br><span class="line">  <span class="keyword">boolean</span> flag = n &gt; <span class="number">0</span> &amp;&amp; (sum += Sum_Solution(n-<span class="number">1</span>)) &gt; <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">return</span> sum;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="孩子们的游戏-圆圈中最后剩下的数"><a href="#孩子们的游戏-圆圈中最后剩下的数" class="headerlink" title="孩子们的游戏(圆圈中最后剩下的数)"></a>孩子们的游戏(圆圈中最后剩下的数)</h4><p><strong>题目描述：</strong>让小朋友们围成一个大圈。然后，随机指定一个数 m，让编号为 0 的小朋友开始报数。每次喊到 m-1 的那个小朋友要出列唱首歌，然后可以在礼品箱中任意的挑选礼物，并且不再回到圈中，从他的下一个小朋友开始，继续 0…m-1 报数 …. 这样下去 …. 直到剩下最后一个小朋友，可以不用表演。</p><p><u>思路</u>：约瑟夫环，用链表来模拟游戏过程；</p><figure class="highlight java"><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="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">LastRemaining_Solution</span><span class="params">(<span class="keyword">int</span> n, <span class="keyword">int</span> m)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">if</span>(n == <span class="number">0</span>) <span class="keyword">return</span> -<span class="number">1</span>;</span><br><span class="line">LinkedList&lt;Integer&gt; list = <span class="keyword">new</span> LinkedList&lt;&gt;();</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">    list.add(i);</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">int</span> beginIndex = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">while</span>(list.size() &gt; <span class="number">1</span>)&#123;</span><br><span class="line">    beginIndex = (beginIndex + m-<span class="number">1</span>)%list.size();<span class="comment">//循环</span></span><br><span class="line">    list.remove(beginIndex);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> list.get(<span class="number">0</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="扑克牌顺子"><a href="#扑克牌顺子" class="headerlink" title="扑克牌顺子"></a>扑克牌顺子</h4><p><strong>题目描述：</strong>LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张^_^)…他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿！！“红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子…..LL不高兴了,他想了想,决定大\小 王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。LL决定去买体育彩票啦。 现在,要求你使用这幅牌模拟上面的过程,然后告诉我们LL的运气如何， 如果牌能组成顺子就输出true，否则就输出false。为了方便起见,你可以认为大小王是0。</p><p><u>思路</u>：先统计大小王的个数，当成赖子，通过对抽到的牌进行排序，判断是否能 组成顺子。</p><figure class="highlight java"><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="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isContinuous</span><span class="params">(<span class="keyword">int</span> [] numbers)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">if</span>(numbers.length == <span class="number">0</span>) <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">  <span class="keyword">int</span> count = <span class="number">0</span>;</span><br><span class="line">  Arrays.sort(numbers);</span><br><span class="line">  <span class="comment">//统计大小王个数</span></span><br><span class="line"><span class="keyword">while</span>(numbers[count] == <span class="number">0</span>)&#123;</span><br><span class="line">    count++;</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">for</span>(<span class="keyword">int</span> i = count; i&lt;numbers.length-<span class="number">1</span>; i++)&#123;</span><br><span class="line">    <span class="comment">//如果重复的牌，则一定不能组成顺子</span></span><br><span class="line">    <span class="keyword">if</span>(numbers[i+<span class="number">1</span>] == numbers[i])&#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    count = count - (numbers[i+<span class="number">1</span>]-numbers[i]-<span class="number">1</span>); </span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">return</span> count &gt;= <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="左旋转字符串"><a href="#左旋转字符串" class="headerlink" title="左旋转字符串"></a>左旋转字符串</h4><p><strong>题目描述：</strong>汇编语言中有一种移位指令叫做循环左移（ROL），现在有个简单的任务，就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列S，请你把其循环左移K位后的序列输出。例如，字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果，即“XYZdefabc”。是不是很简单？OK，搞定它！</p><p><u>思路</u>：1.先分别反转字符串；2.再整体反转；</p><figure class="highlight java"><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="function"><span class="keyword">public</span> String <span class="title">LeftRotateString</span><span class="params">(String str,<span class="keyword">int</span> n)</span> </span>&#123;</span><br><span class="line"><span class="keyword">if</span>(str == <span class="keyword">null</span> || str.length() &lt;= n) <span class="keyword">return</span> str;</span><br><span class="line">  <span class="keyword">char</span>[] chars = str.toCharArray();</span><br><span class="line">  swapString(chars, <span class="number">0</span>, n-<span class="number">1</span>);</span><br><span class="line">  swapString(chars, n, chars.length-<span class="number">1</span>);</span><br><span class="line">  swapString(chars, <span class="number">0</span>, chars.length-<span class="number">1</span>);</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">new</span> String(chars);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//反转从 i 到 j 的字符串</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">swapString</span><span class="params">(<span class="keyword">char</span>[] str,<span class="keyword">int</span> i,<span class="keyword">int</span> j)</span></span>&#123;</span><br><span class="line"><span class="keyword">while</span>(i &lt; j)&#123;</span><br><span class="line">    <span class="keyword">char</span> temp = str[i];</span><br><span class="line">    str[i] = str[j];</span><br><span class="line">    str[j] = temp;</span><br><span class="line">    i++;</span><br><span class="line">    j--;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="和为S的两个数字"><a href="#和为S的两个数字" class="headerlink" title="和为S的两个数字"></a>和为S的两个数字</h4><p><strong>题目描述：</strong>输入一个递增排序的数组和一个数字S，在数组中查找两个数，使得他们的和正好是S，如果有多对数字的和等于S，输出两个数的乘积最小的。对应每个测试案例，输出两个数，小的先输出。</p><p><u>思路</u>：利用双指针，从头和尾分别进行遍历判断（和相同时，两数差距越大，乘积越小）</p><figure class="highlight java"><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="function"><span class="keyword">public</span> ArrayList&lt;Integer&gt; <span class="title">FindNumbersWithSum</span><span class="params">(<span class="keyword">int</span> [] array,<span class="keyword">int</span> sum)</span> </span>&#123;</span><br><span class="line">  ArrayList&lt;Integer&gt; res = <span class="keyword">new</span> ArrayList&lt;Integer&gt;();</span><br><span class="line"><span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">int</span> j = array.length-<span class="number">1</span>;</span><br><span class="line">  <span class="keyword">while</span>(i &lt; j)&#123;</span><br><span class="line">    <span class="keyword">if</span>(array[i] + array[j] == sum)&#123;</span><br><span class="line">      res.add(array[i]);</span><br><span class="line">      res.add(array[j]);</span><br><span class="line">      <span class="keyword">return</span> res;</span><br><span class="line">    &#125;<span class="keyword">else</span> <span class="keyword">if</span>(array[i] + array[j] &lt; sum)&#123;</span><br><span class="line">      i++;</span><br><span class="line">    &#125;<span class="keyword">else</span>&#123;</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">return</span> res;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="和为S的连续正数序列"><a href="#和为S的连续正数序列" class="headerlink" title="和为S的连续正数序列"></a>和为S的连续正数序列</h4><p><strong>题目描述：</strong>小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!<br>输出所有和为S的连续正数序列。序列内按照从小至大的顺序，序列间按照开始数字从小到大的顺序</p><p><u>思路</u>：<img src="/2020/06/10/%E5%89%91%E6%8C%87offer/%E5%89%91%E6%8C%87offer-%E4%B8%AD%E7%AD%89%E7%AF%87/%E5%92%8C%E4%B8%BA%E6%9F%90%E4%B8%AA%E6%95%B0%E7%9A%84%E5%BA%8F%E5%88%97.png" alt="和为某个数的序列"></p><figure class="highlight java"><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="keyword">public</span> ArrayList&lt;ArrayList&lt;Integer&gt; &gt; FindContinuousSequence(<span class="keyword">int</span> sum) &#123;</span><br><span class="line">  ArrayList&lt;ArrayList&lt;Integer&gt; &gt; res = <span class="keyword">new</span> ArrayList&lt;ArrayList&lt;Integer&gt; &gt;();</span><br><span class="line"><span class="keyword">int</span> L = <span class="number">1</span>;</span><br><span class="line">  <span class="keyword">int</span> R = <span class="number">2</span>;</span><br><span class="line">  <span class="keyword">int</span> curSum = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">while</span>(L &lt; R)&#123;</span><br><span class="line">    curSum = (L + R)*(R - L + <span class="number">1</span>)/<span class="number">2</span>;</span><br><span class="line">    <span class="keyword">if</span>(curSum == sum)&#123;</span><br><span class="line">      ArrayList&lt;Integer&gt; list = <span class="keyword">new</span> ArrayList&lt;Integer&gt;();</span><br><span class="line">      <span class="keyword">for</span>(<span class="keyword">int</span> i = L; i&lt;=R; i++)&#123;</span><br><span class="line">        list.add(i);</span><br><span class="line">      &#125;</span><br><span class="line">      res.add(list);</span><br><span class="line">      L++;</span><br><span class="line">    &#125;<span class="keyword">else</span> <span class="keyword">if</span>(curSum &lt; sum)&#123;</span><br><span class="line">      R++;</span><br><span class="line">    &#125;<span class="keyword">else</span>&#123;</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></pre></td></tr></table></figure><br><br><h4 id="数组中只出现一次的数字"><a href="#数组中只出现一次的数字" class="headerlink" title="数组中只出现一次的数字"></a>数组中只出现一次的数字</h4><p><strong>题目描述：</strong>一个整型数组里除了两个数字之外，其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。</p><p><u>思路</u>：把所有的数异或，得到的结果即两个不同的数异或的结果，<strong>这个结果的二进制中的1，表现的是这两个不同的数的不同位。</strong>就按照这个结果中为1的位的位置划分，该位为1划分为一组，为0划分为一组。这样两个不同的数就被划分开了，再分别对这两组做异或操作，就找到了两个不同的数。</p><p><img src="/2020/06/10/%E5%89%91%E6%8C%87offer/%E5%89%91%E6%8C%87offer-%E4%B8%AD%E7%AD%89%E7%AF%87/%E6%89%BE%E5%88%B0%E6%95%B0%E7%BB%84%E4%B8%AD%E4%B8%A4%E4%B8%AA%E4%B8%8D%E5%90%8C%E7%9A%84%E6%95%B0.png" alt="找到数组中两个不同的数"></p><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">FindNumsAppearOnce</span><span class="params">(<span class="keyword">int</span> [] array,<span class="keyword">int</span> num1[] , <span class="keyword">int</span> num2[])</span> </span>&#123;</span><br><span class="line"><span class="keyword">int</span> binaryRes = <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;array.length; i++)&#123;</span><br><span class="line">    binaryRes = binaryRes ^ array[i];</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">int</span> index = getIndex1(binaryRes);</span><br><span class="line">  <span class="keyword">for</span>(<span class="keyword">int</span> num : array)&#123;</span><br><span class="line">    <span class="keyword">if</span>(is1Index(num, index))&#123;</span><br><span class="line">      num1[<span class="number">0</span>] = num1[<span class="number">0</span>] ^ num;</span><br><span class="line">    &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">      num2[<span class="number">0</span>] = num2[<span class="number">0</span>] ^ num;</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">* 返回 binaryRes 中第一位为1的位置</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">int</span> <span class="title">getIndex1</span><span class="params">(<span class="keyword">int</span> binaryRes)</span></span>&#123;</span><br><span class="line">  <span class="keyword">int</span> index = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">while</span>(((binaryRes &amp; <span class="number">1</span>) == <span class="number">0</span>) &amp;&amp; index &lt; <span class="number">32</span>)&#123;</span><br><span class="line">    binaryRes = binaryRes&gt;&gt; <span class="number">1</span>;</span><br><span class="line">    index++;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> index;</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">* 判断 num 的 index 位置是否为1</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">boolean</span> <span class="title">is1Index</span><span class="params">(<span class="keyword">int</span> num, <span class="keyword">int</span> index)</span></span>&#123;</span><br><span class="line">  <span class="comment">//index 位为1，则返回true</span></span><br><span class="line">  <span class="keyword">return</span> ((num &gt;&gt; index) &amp; <span class="number">1</span>) == <span class="number">1</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="平衡二叉树"><a href="#平衡二叉树" class="headerlink" title="平衡二叉树"></a>平衡二叉树</h4><p><strong>题目描述：</strong>输入一棵二叉树，判断该二叉树是否是平衡二叉树。 </p><p>在这里，我们只需要考虑其平衡性，不需要考虑其是不是排序二叉树</p><p><u>思路</u>:递归得到二叉树的高度，判断左子树与右子树的高度差，如果高度差超过1，则返回false</p><figure class="highlight java"><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="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Solution</span> </span>&#123;</span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">boolean</span> isBalanced = <span class="keyword">true</span>;</span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">IsBalanced_Solution</span><span class="params">(TreeNode root)</span> </span>&#123;</span><br><span class="line">    depth(root);</span><br><span class="line">    <span class="keyword">return</span> isBalanced;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">private</span> <span class="keyword">int</span> <span class="title">depth</span><span class="params">(TreeNode root)</span></span>&#123;</span><br><span class="line">    <span class="keyword">if</span>(root == <span class="keyword">null</span>) <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">int</span> leftDepth = depth(root.left);</span><br><span class="line">    <span class="keyword">int</span> rightDepth = depth(root.right);</span><br><span class="line">    <span class="keyword">if</span>(Math.abs(leftDepth - rightDepth) &gt; <span class="number">1</span>)&#123;</span><br><span class="line">      isBalanced = <span class="keyword">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line"><span class="keyword">return</span> Math.max(leftDepth,rightDepth)+<span class="number">1</span>;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="数字在排序数组中出现的次数"><a href="#数字在排序数组中出现的次数" class="headerlink" title="数字在排序数组中出现的次数"></a>数字在排序数组中出现的次数</h4><p><strong>题目描述：</strong>统计一个数字在排序数组中出现的次数。</p><p><u>思路</u>：有序数组，可以利用二分法</p><p><img src="/2020/06/10/%E5%89%91%E6%8C%87offer/%E5%89%91%E6%8C%87offer-%E4%B8%AD%E7%AD%89%E7%AF%87/%E4%BA%8C%E5%88%86%E6%89%BE%E6%9C%80%E5%B7%A6.png" alt="二分找最左"></p><figure class="highlight java"><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="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">GetNumberOfK</span><span class="params">(<span class="keyword">int</span> [] array , <span class="keyword">int</span> k)</span> </span>&#123;</span><br><span class="line">  <span class="comment">//int res = 0;</span></span><br><span class="line">  <span class="comment">//for(int num : array)&#123;</span></span><br><span class="line">  <span class="comment">//  if(num == k) res++;</span></span><br><span class="line">  <span class="comment">// &#125;</span></span><br><span class="line">  <span class="comment">// return res;</span></span><br><span class="line">  <span class="keyword">if</span>(array.length == <span class="number">0</span>) <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">int</span> left = binarySearch(array, k);</span><br><span class="line">  <span class="keyword">int</span> right = binarySearch(array,  k+<span class="number">1</span>);</span><br><span class="line">  <span class="keyword">if</span>(array[array.length-<span class="number">1</span>] == k)&#123;</span><br><span class="line">    <span class="keyword">return</span> right-left+<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> right-left;</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">//返回数组中target中最左边的位置索引</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">binarySearch</span><span class="params">(<span class="keyword">int</span>[] nums, <span class="keyword">int</span> target)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">int</span> j = nums.length - <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>(i &lt; j)&#123;</span><br><span class="line">    mid = i + (j-i)/<span class="number">2</span>;</span><br><span class="line">    <span class="keyword">if</span>(nums[mid] &lt; target)&#123;</span><br><span class="line">      i = mid + <span class="number">1</span>;</span><br><span class="line">    &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">      j = mid;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> i;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="两个链表的第一个公共结点"><a href="#两个链表的第一个公共结点" class="headerlink" title="两个链表的第一个公共结点"></a>两个链表的第一个公共结点</h4><p><strong>题目描述：</strong>输入两个链表，找出它们的第一个公共结点。（注意因为传入数据是链表，所以错误测试数据的提示是用其他方式显示的，保证传入数据是正确的）</p><p><u>思路</u>：路程相等思想：当访问链表 A 的指针访问到链表尾部时，令它从链表 B 的头部重新开始访问链表 B；同样地，当访问链表 B 的指针访问到链表尾部时，令它从链表 A 的头部重新开始访问链表 A。这样就能控制访问 A 和 B 两个链表的指针能同时访问到交点。</p><p><img src="/2020/06/10/%E5%89%91%E6%8C%87offer/%E5%89%91%E6%8C%87offer-%E4%B8%AD%E7%AD%89%E7%AF%87/%E9%93%BE%E8%A1%A8%E7%9A%84%E5%85%AC%E5%85%B1%E4%BA%A4%E7%82%B9.png" alt="链表的公共交点"></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> ListNode <span class="title">FindFirstCommonNode</span><span class="params">(ListNode pHead1, ListNode pHead2)</span> </span>&#123;</span><br><span class="line">  ListNode a = pHead1;</span><br><span class="line">  ListNode b = pHead2;</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">while</span>(a != b)&#123;</span><br><span class="line">    a = a == <span class="keyword">null</span> ? pHead2 : a.next;</span><br><span class="line">    b = b == <span class="keyword">null</span> ? pHead1 : b.next;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">return</span> a;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="整数中1出现的次数（从1到n整数中1出现的次数）"><a href="#整数中1出现的次数（从1到n整数中1出现的次数）" class="headerlink" title="整数中1出现的次数（从1到n整数中1出现的次数）"></a>整数中1出现的次数（从1到n整数中1出现的次数）</h4><p><strong>题目描述：</strong>求出1<del>13的整数中1出现的次数,并算出100</del>1300的整数中1出现的次数？为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数（从1 到 n 中1出现的次数）。</p><p><u>思路</u>：</p><p><strong>个位</strong></p><p>我们知道在个位数上，1会每隔10出现一次，例如1、11、21等等，我们发现以10为一个阶梯的话，每一个完整的阶梯里面都有一个1，例如数字22，按照10为间隔来分三个阶梯，在完整阶梯0-9，10-19之中都有一个1，但是19之后有一个不完整的阶梯，我们需要去判断这个阶梯中会不会出现1，易推断知，如果最后这个露出来的部分小于1，则不可能出现1（这个归纳换做其它数字也成立）。</p><p>我们可以归纳个位上1出现的个数为：</p><blockquote><p><strong>n/10 * 1+(n%10!=0 ? 1 : 0)</strong></p></blockquote><p><strong>十位</strong></p><p>现在说十位数，十位数上出现1的情况应该是10-19，依然沿用分析个位数时候的阶梯理论，我们知道10-19这组数，每隔100出现一次，这次我们的阶梯是100，例如数字317，分析有阶梯0-99，100-199，200-299三段完整阶梯，每一段阶梯里面都会出现10次1（从10-19），最后分析露出来的那段不完整的阶梯。我们考虑如果露出来的数大于19，那么直接算10个1就行了，因为10-19肯定会出现；如果小于10，那么肯定不会出现十位数的1；如果在10-19之间的，我们计算结果应该是k - 10 + 1。例如我们分析300-317，17个数字，1出现的个数应该是17-10+1=8个。</p><p>那么现在可以归纳：十位上1出现的个数为：</p><blockquote><ul><li>设k = n % 100，即为不完整阶梯段的数字</li><li>归纳式为：<strong>(n / 100) * 10 + (if(k &gt; 19) 10 else if(k &lt; 10) 0 else k - 10 + 1)</strong></li></ul></blockquote><p><strong>百位</strong></p><p>现在说百位1，我们知道在百位，100-199都会出现百位1，一共出现100次，阶梯间隔为1000，100-199这组数，每隔1000就会出现一次。这次假设我们的数为2139。跟上述思想一致，先算阶梯数 * 完整阶梯中1在百位出现的个数，即n/1000 * 100得到前两个阶梯中1的个数，那么再算漏出来的部分139，沿用上述思想，不完整阶梯数k199，得到100个百位1，100&lt;=k&lt;=199则得到k - 100 + 1个百位1。</p><p>那么继续归纳百位上出现1的个数：</p><blockquote><ul><li>设k = n % 1000</li><li>归纳式为：<strong>(n / 1000) * 100 + (if(k &gt;199) 100 else if(k &lt; 100) 0 else k - 100 + 1)</strong></li></ul></blockquote><p>后面的依次类推….</p><p>完美！归纳式看起来已经很规整了。 来一个更抽象的归纳，设i为计算1所在的位数，i=1表示计算个位数的1的个数，10表示计算十位数的1的个数等等。</p><blockquote><ul><li>k = n % (i * 10)</li><li><strong>count(i) = (n / (i * 10)) * i + (if(k &gt; i * 2 - 1) i else if(k &lt; i) 0 else k - i + 1)</strong></li></ul></blockquote><p>好了，这样从10到10的n次方的归纳就完成了。</p><figure class="highlight java"><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="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">NumberOf1Between1AndN_Solution</span><span class="params">(<span class="keyword">int</span> n)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">if</span>(n &lt;= <span class="number">0</span>) <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">int</span> count = <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;= n; i *= <span class="number">10</span>)&#123;</span><br><span class="line">    <span class="keyword">int</span> div = i * <span class="number">10</span>;</span><br><span class="line">    <span class="keyword">int</span> k = n % div;</span><br><span class="line">    <span class="keyword">if</span>(k &gt; <span class="number">2</span>*i-<span class="number">1</span>)&#123;</span><br><span class="line">      count = count + n/div*i + i;</span><br><span class="line">    &#125;<span class="keyword">else</span> <span class="keyword">if</span>(k &lt; i)&#123;</span><br><span class="line">      count = count + n/div*i + <span class="number">0</span>;</span><br><span class="line">    &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">      count = count + n/div*i + (k-i+<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> count;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="连续子数组的最大和"><a href="#连续子数组的最大和" class="headerlink" title="连续子数组的最大和"></a>连续子数组的最大和</h4><p><strong>题目描述：</strong>HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢？例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组，返回它的最大连续子序列的和，你会不会被他忽悠住？(子向量的长度至少是1)</p><p><u>思路</u>：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">FindGreatestSumOfSubArray</span><span class="params">(<span class="keyword">int</span>[] array)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">int</span> dp = array[<span class="number">0</span>];</span><br><span class="line">  <span class="keyword">int</span> res = array[<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;array.length; i++)&#123;</span><br><span class="line">    dp = Math.max(dp + array[i], array[i]);</span><br><span class="line">    res = Math.max(res, dp); </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></pre></td></tr></table></figure><br><br><h4 id="数组中出现次数超过一半的数字"><a href="#数组中出现次数超过一半的数字" class="headerlink" title="数组中出现次数超过一半的数字"></a>数组中出现次数超过一半的数字</h4><p><strong>题目描述：</strong>数组中有一个数字出现的次数超过数组长度的一半，请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次，超过数组长度的一半，因此输出2。如果不存在则输出0。</p><p><u>思路</u>：<br>法1：对数组进行排序，中间的数一定是出现次数超过数组长度一般的数，否则返回0；<br>法2：用HashMap统计每个数字出现的次数；</p><figure class="highlight java"><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="comment">//方法一，时间复杂度nlogn</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">MoreThanHalfNum_Solution</span><span class="params">(<span class="keyword">int</span> [] array)</span> </span>&#123;</span><br><span class="line">  Arrays.sort(array);</span><br><span class="line"></span><br><span class="line">  <span class="keyword">int</span> mid = array[array.length/<span class="number">2</span>];</span><br><span class="line"></span><br><span class="line">  <span class="keyword">int</span> count = <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;array.length;i++)&#123;</span><br><span class="line">    <span class="keyword">if</span>(array[i] == mid)&#123;</span><br><span class="line">      count++;</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> count&gt;(array.length/<span class="number">2</span>) ? mid : <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight java"><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="comment">//方法二，时间复杂度n</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">MoreThanHalfNum_Solution</span><span class="params">(<span class="keyword">int</span> [] array)</span> </span>&#123;</span><br><span class="line">  HashMap&lt;Integer, Integer&gt; map = <span class="keyword">new</span> HashMap&lt;Integer, Integer&gt;();</span><br><span class="line">  <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i&lt;array.length; i++)&#123;</span><br><span class="line">    <span class="keyword">if</span>(!map.containsKey(array[i]))&#123;</span><br><span class="line">      map.put(array[i],<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">int</span> count = map.get(array[i]);</span><br><span class="line">      map.put(array[i],++count);</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> key : map.keySet())&#123;</span><br><span class="line">    <span class="keyword">int</span> count = map.get(key);</span><br><span class="line">    <span class="keyword">if</span>(count &gt; array.length/<span class="number">2</span>)&#123;</span><br><span class="line">      <span class="keyword">return</span> key;</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">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="二叉搜索树与双向链表"><a href="#二叉搜索树与双向链表" class="headerlink" title="二叉搜索树与双向链表"></a>二叉搜索树与双向链表</h4><p><strong>题目描述：</strong>输入一棵二叉搜索树，将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点，只能调整树中结点指针的指向。</p><p><u>思路</u>：中序遍历结果就是排序结果；中序递归；</p><p><img src="/2020/06/10/%E5%89%91%E6%8C%87offer/%E5%89%91%E6%8C%87offer-%E4%B8%AD%E7%AD%89%E7%AF%87/%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91%E4%B8%8E%E5%8F%8C%E5%90%91%E9%93%BE%E8%A1%A8.png" alt="二叉搜索树与双向链表"></p><figure class="highlight java"><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="keyword">private</span> TreeNode pre = <span class="keyword">null</span>;</span><br><span class="line"><span class="keyword">private</span> TreeNode head = <span class="keyword">null</span>;</span><br><span class="line"><span class="function"><span class="keyword">public</span> TreeNode <span class="title">Convert</span><span class="params">(TreeNode root)</span> </span>&#123;</span><br><span class="line">  inOrder(root);</span><br><span class="line">  <span class="keyword">return</span> head;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">inOrder</span><span class="params">(TreeNode node)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (node == <span class="keyword">null</span>) <span class="keyword">return</span>;</span><br><span class="line">  inOrder(node.left);</span><br><span class="line"></span><br><span class="line">  node.left = pre;</span><br><span class="line">  <span class="keyword">if</span> (pre != <span class="keyword">null</span>) pre.right = node;</span><br><span class="line">  pre = node;</span><br><span class="line">  <span class="keyword">if</span> (head == <span class="keyword">null</span>) head = node;</span><br><span class="line"></span><br><span class="line">  inOrder(node.right);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="栈的压入、弹出序列"><a href="#栈的压入、弹出序列" class="headerlink" title="栈的压入、弹出序列"></a>栈的压入、弹出序列</h4><p><strong>题目描述：</strong>输入两个整数序列，第一个序列表示栈的压入顺序，请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序，序列4,5,3,2,1是该压栈序列对应的一个弹出序列，但4,3,5,1,2就不可能是该压栈序列的弹出序列。（注意：这两个序列的长度是相等的）</p><p><u>思路</u>：用栈来模拟题目描述的过程；</p><figure class="highlight java"><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="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">IsPopOrder</span><span class="params">(<span class="keyword">int</span> [] pushA,<span class="keyword">int</span> [] popA)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">if</span>(pushA.length == <span class="number">0</span> || popA.length == <span class="number">0</span>) <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">  Stack&lt;Integer&gt; stack = <span class="keyword">new</span> Stack&lt;&gt;();</span><br><span class="line">  </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">0</span>; i &lt; pushA.length; i++ )&#123;</span><br><span class="line">    stack.push(pushA[i]);</span><br><span class="line">    <span class="keyword">while</span>(!stack.isEmpty() &amp;&amp; stack.peek() == popA[index])&#123;</span><br><span class="line">      stack.pop();</span><br><span class="line">      index++;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> stack.isEmpty();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="合并两个排序的链表"><a href="#合并两个排序的链表" class="headerlink" title="合并两个排序的链表"></a>合并两个排序的链表</h4><p><strong>题目描述：</strong>输入两个单调递增的链表，输出两个链表合成后的链表，当然我们需要合成后的链表满足单调不减规则。</p><p><u>思路</u>：</p><p><img src="/2020/06/10/%E5%89%91%E6%8C%87offer/%E5%89%91%E6%8C%87offer-%E4%B8%AD%E7%AD%89%E7%AF%87/%E5%90%88%E5%B9%B6%E9%93%BE%E8%A1%A8.png" alt="合并链表"></p><figure class="highlight java"><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="function"><span class="keyword">public</span> ListNode <span class="title">Merge</span><span class="params">(ListNode list1,ListNode list2)</span> </span>&#123;</span><br><span class="line">  ListNode newHead = <span class="keyword">new</span> ListNode(-<span class="number">1</span>);</span><br><span class="line">  ListNode temp = newHead;</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">while</span>(list1 != <span class="keyword">null</span> &amp;&amp; list2 != <span class="keyword">null</span>)&#123;</span><br><span class="line">    <span class="keyword">if</span>(list1.val &lt; list2.val)&#123;</span><br><span class="line">      temp.next = list1;</span><br><span class="line">      temp = temp.next;</span><br><span class="line">      list1 = list1.next;</span><br><span class="line">    &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">      temp.next = list2;</span><br><span class="line">      temp = temp.next;</span><br><span class="line">      list2 = list2.next;</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="keyword">if</span>(list1 != <span class="keyword">null</span>) temp.next = list1;</span><br><span class="line">  <span class="keyword">if</span>(list2 != <span class="keyword">null</span>) temp.next = list2;</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">return</span> newHead.next;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="反转链表"><a href="#反转链表" class="headerlink" title="反转链表"></a>反转链表</h4><p><strong>题目描述：</strong>输入一个链表，反转链表后，输出新链表的表头。</p><p><u>思路</u>：头插法：</p><p><img src="/2020/06/10/%E5%89%91%E6%8C%87offer/%E5%89%91%E6%8C%87offer-%E4%B8%AD%E7%AD%89%E7%AF%87/%E5%A4%B4%E6%8F%92%E6%B3%95%E8%AF%A6%E8%A7%A3.png" alt="头插法详解"></p><figure class="highlight java"><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="function"><span class="keyword">public</span> ListNode <span class="title">ReverseList</span><span class="params">(ListNode head)</span> </span>&#123;</span><br><span class="line">  <span class="comment">//头插法</span></span><br><span class="line">  ListNode newHead = <span class="keyword">new</span> ListNode(-<span class="number">1</span>);</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">while</span>(head != <span class="keyword">null</span>)&#123;</span><br><span class="line">    ListNode next = head.next;</span><br><span class="line">    head.next = newHead.next;</span><br><span class="line">    newHead.next = head;</span><br><span class="line">    head = next;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> newHead.next;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="数值的整数次方"><a href="#数值的整数次方" class="headerlink" title="数值的整数次方"></a>数值的整数次方</h4><p><strong>题目描述：</strong>给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。 </p><p>保证base和exponent不同时为0。</p><p><u>思路</u>：<br>法1：暴力法；<br>法2：递归法，时间复杂度logN；</p><figure class="highlight java"><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="function"><span class="keyword">public</span> <span class="keyword">double</span> <span class="title">Power</span><span class="params">(<span class="keyword">double</span> base, <span class="keyword">int</span> exponent)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">double</span> res = <span class="number">1</span>;</span><br><span class="line">  <span class="keyword">if</span>(exponent&gt;<span class="number">0</span>)&#123;</span><br><span class="line">    <span class="keyword">for</span>(<span class="keyword">double</span> i = <span class="number">0</span>;i&lt;exponent;i++)&#123;</span><br><span class="line">      res = res*base;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">    <span class="keyword">for</span>(<span class="keyword">double</span> i = exponent;i&lt;<span class="number">0</span>;i++)&#123;</span><br><span class="line">      res = res*base;</span><br><span class="line">    &#125;</span><br><span class="line">    res = <span class="number">1</span>/res;</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></pre></td></tr></table></figure><figure class="highlight java"><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 class="function"><span class="keyword">public</span> <span class="keyword">double</span> <span class="title">Power</span><span class="params">(<span class="keyword">double</span> base, <span class="keyword">int</span> exponent)</span> </span>&#123;</span><br><span class="line">  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="二进制中1的个数"><a href="#二进制中1的个数" class="headerlink" title="二进制中1的个数"></a>二进制中1的个数</h4><p><strong>题目描述：</strong>输入一个整数，输出该数二进制表示中1的个数。其中负数用补码表示。</p><p><u>思路</u>：<strong>n&amp;(n-1)：相当于把n二进制最后的1变为0</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">n       : 10110100</span><br><span class="line">n-1     : 10110011</span><br><span class="line">n&amp;(n-1) : 10110000</span><br></pre></td></tr></table></figure><figure class="highlight java"><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">public</span> <span class="keyword">int</span> <span class="title">NumberOf1</span><span class="params">(<span class="keyword">int</span> n)</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">while</span>(n != <span class="number">0</span>)&#123;</span><br><span class="line">    res++;</span><br><span class="line">    n = n&amp;(n-<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></pre></td></tr></table></figure><br><br><h4 id="矩形覆盖"><a href="#矩形覆盖" class="headerlink" title="矩形覆盖"></a>矩形覆盖</h4><p><strong>题目描述：</strong>我们可以用2<em>1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2</em>1的小矩形无重叠地覆盖一个2*n的大矩形，总共有多少种方法？ </p><p>比如n=3时，2*3的矩形块有3种覆盖方法：</p><p><u>思路</u>：斐波那契数列</p><p><img src="/2020/06/10/%E5%89%91%E6%8C%87offer/%E5%89%91%E6%8C%87offer-%E4%B8%AD%E7%AD%89%E7%AF%87/%E7%9F%A9%E5%BD%A2%E8%A6%86%E7%9B%96.png" alt="矩形覆盖"></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">RectCover</span><span class="params">(<span class="keyword">int</span> target)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">int</span> pre = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">int</span> cur = <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">for</span>(<span class="keyword">int</span> i = <span class="number">1</span>; i&lt;=target; i++)&#123;</span><br><span class="line">    res = pre + cur;</span><br><span class="line">    pre = cur;</span><br><span class="line">    cur = res;</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></pre></td></tr></table></figure><br><br><h4 id="跳台阶"><a href="#跳台阶" class="headerlink" title="跳台阶"></a>跳台阶</h4><p><strong>题目描述：</strong>一只青蛙一次可以跳上1级台阶，也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法（先后次序不同算不同的结果）。</p><p><u>思路</u>：斐波那契数列：跳 n 阶台阶，可以先跳 1 阶台阶，再跳 n-1 阶台阶；或者先跳 2 阶台阶，再跳 n-2 阶台阶，故有递推公式<code>f(n) = f(n-1) + f(n-2)</code></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">JumpFloor</span><span class="params">(<span class="keyword">int</span> target)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">int</span> pre = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">int</span> cur = <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">for</span>(<span class="keyword">int</span> i = <span class="number">1</span>; i&lt;=target; i++)&#123;</span><br><span class="line">    res = pre + cur;</span><br><span class="line">    pre = cur;</span><br><span class="line">    cur = res;</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></pre></td></tr></table></figure><br><br><h4 id="斐波那契数列"><a href="#斐波那契数列" class="headerlink" title="斐波那契数列"></a>斐波那契数列</h4><p><strong>题目描述：</strong>大家都知道斐波那契数列，现在要求输入一个整数n，请你输出斐波那契数列的第n项（从0开始，第0项为0，第1项是1）。 </p><p><u>思路</u>：斐波那契数列：<code>f(n) = f(n-1) + f(n-2)</code></p><figure class="highlight java"><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="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">Fibonacci</span><span class="params">(<span class="keyword">int</span> n)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">if</span>(n &lt;= <span class="number">1</span>) <span class="keyword">return</span> n;</span><br><span class="line">  <span class="keyword">int</span> res = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">int</span> pre = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">int</span> cur = <span class="number">1</span>;</span><br><span class="line">  <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">2</span>;i&lt;=n;i++)&#123;</span><br><span class="line">    res = pre + cur;</span><br><span class="line">    pre = cur;</span><br><span class="line">    cur = res;</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></pre></td></tr></table></figure><br><br><h4 id="旋转数组的最小数字"><a href="#旋转数组的最小数字" class="headerlink" title="旋转数组的最小数字"></a>旋转数组的最小数字</h4><p><strong>题目描述：</strong>把一个数组最开始的若干个元素搬到数组的末尾，我们称之为数组的旋转。输入一个非递减排序的数组的一个旋转，输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转，该数组的最小值为1。<br>NOTE：给出的所有元素都大于0，若数组大小为0，请返回0。</p><p><u>思路</u>：采用二分法；若中间的元素大于 j 指针的元素，说明旋转点在 mid 和 j 之间；否则在 i 和 mid 之间；</p><p><strong>特例：</strong>如果数组元素允许重复，会出现一个特殊的情况：nums[l] == nums[m] == nums[h]，此时无法确定解在哪个区间，需要切换到顺序查找。例如对于数组 {1,1,1,0,1}，l、m 和 h 指向的数都为 1，此时无法知道最小数字 0 在哪个区间。</p><figure class="highlight java"><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">public</span> <span class="keyword">int</span> <span class="title">minNumberInRotateArray</span><span class="params">(<span class="keyword">int</span> [] array)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">if</span>(array.length == <span class="number">0</span>) <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>;</span><br><span class="line">  <span class="keyword">int</span> j = array.length - <span class="number">1</span>;</span><br><span class="line">  <span class="keyword">while</span>(i &lt; j)&#123;</span><br><span class="line">    <span class="keyword">int</span> mid = i + (j - i)/<span class="number">2</span>;</span><br><span class="line">    <span class="keyword">if</span>(array[mid] == array[i] &amp;&amp; array[mid] == array[j])&#123;</span><br><span class="line">      <span class="keyword">for</span>(<span class="keyword">int</span> k = <span class="number">0</span>; k&lt;array.length-<span class="number">1</span>; k++)&#123;</span><br><span class="line">        <span class="keyword">if</span>(array[k] &gt; array[k+<span class="number">1</span>] ) &#123;</span><br><span class="line">          <span class="keyword">return</span> array[k+<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> array[<span class="number">0</span>];</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">if</span>(array[mid] &gt; array[j])&#123;</span><br><span class="line">      i = mid + <span class="number">1</span>;</span><br><span class="line">    &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">      j = mid;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> array[i];</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="重建二叉树"><a href="#重建二叉树" class="headerlink" title="重建二叉树"></a>重建二叉树</h4><p><strong>题目描述：</strong>输入某二叉树的前序遍历和中序遍历的结果，请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6}，则重建二叉树并返回。</p><p><u>思路</u>：</p>]]></content>
    
    <summary type="html">
    
      &lt;h4 id=&quot;剪绳子&quot;&gt;&lt;a href=&quot;#剪绳子&quot; class=&quot;headerlink&quot; title=&quot;剪绳子&quot;&gt;&lt;/a&gt;剪绳子&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;题目描述：&lt;/strong&gt;给你一根长度为n的绳子，请把绳子剪成整数长的m段（m、n都是整数，n&amp;gt;1并且m&amp;gt;1），每段绳子的长度记为k[0],k[1],…,k[m]。请问k[0] x k[1] x … x k[m]可能的最大乘积是多少？例如，当绳子的长度是8时，我们把它剪成长度分别为2、3、3的三段，此时得到的最大乘积是18。&lt;/p&gt;
&lt;p&gt;&lt;u&gt;思路&lt;/u&gt;： &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;5&amp;lt;2x3，6&amp;lt;3x3，比6更大的数字我们就更不用考虑了，肯定要继续分。&lt;/li&gt;
&lt;li&gt;其次看2和3的数量，2的数量肯定小于3个，为什么呢？因为2x2x2 &amp;lt; 3x3，那么题目就简单了。&lt;/li&gt;
&lt;li&gt;直接用n除以3，根据得到的余数判断是一个2还是两个2还是没有2就行了。&lt;/li&gt;&lt;/ul&gt;
    
    </summary>
    
    
      <category term="剑指offer" scheme="https://chrisxb1996.github.io/categories/%E5%89%91%E6%8C%87offer/"/>
    
      <category term="数据结构和算法" scheme="https://chrisxb1996.github.io/categories/%E5%89%91%E6%8C%87offer/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/"/>
    
    
      <category term="数据结构和算法" scheme="https://chrisxb1996.github.io/tags/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/"/>
    
      <category term="剑指offer" scheme="https://chrisxb1996.github.io/tags/%E5%89%91%E6%8C%87offer/"/>
    
  </entry>
  
  <entry>
    <title>剑指offer-简单篇</title>
    <link href="https://chrisxb1996.github.io/2020/06/07/%E5%89%91%E6%8C%87offer/%E5%89%91%E6%8C%87offer-%E7%AE%80%E5%8D%95%E7%AF%87/"/>
    <id>https://chrisxb1996.github.io/2020/06/07/%E5%89%91%E6%8C%87offer/%E5%89%91%E6%8C%87offer-%E7%AE%80%E5%8D%95%E7%AF%87/</id>
    <published>2020-06-07T09:02:50.000Z</published>
    <updated>2020-06-25T14:15:11.909Z</updated>
    
    <content type="html"><![CDATA[<h4 id="构建乘积数组"><a href="#构建乘积数组" class="headerlink" title="构建乘积数组"></a>构建乘积数组</h4><p><strong>题目描述：</strong>给定一个数组A[0,1,…,n-1],请构建一个数组B[0,1,…,n-1],其中B中的元素B[i]=A[0]A[1]…A[i-1]A[i+1]…A[n-1]。不能使用除法。（注意：规定B[0] = A[1] * A[2] * … * A[n-1]，B[n-1] = A[0] * A[1] * … * A[n-2];）<a id="more"></a></p><p><u>思路</u>：1.//从左向右累乘A[0]A[1]…A[i-1]；2.//从右向左累乘A[i+1]…A[n-1]    </p><figure class="highlight java"><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="keyword">public</span> <span class="keyword">int</span>[] multiply(<span class="keyword">int</span>[] A) &#123;</span><br><span class="line"><span class="comment">//从左向右累乘A[0]A[1]...A[i-1]</span></span><br><span class="line">  <span class="keyword">int</span> n = A.length;</span><br><span class="line">  <span class="keyword">int</span>[] B = <span class="keyword">new</span> <span class="keyword">int</span>[n];</span><br><span class="line">  <span class="keyword">int</span> temp = <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;n;i++)&#123;</span><br><span class="line">    B[i] = temp;</span><br><span class="line">    temp = temp*A[i];</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line"><span class="comment">//从右向左累乘A[i+1]...A[n-1]</span></span><br><span class="line">  temp = <span class="number">1</span>;</span><br><span class="line">  <span class="keyword">for</span>(<span class="keyword">int</span> i = n-<span class="number">1</span>;i&gt;=<span class="number">0</span>;i--)&#123;</span><br><span class="line">    B[i] = B[i]*temp;</span><br><span class="line">    temp = temp*A[i];</span><br><span class="line">  &#125; </span><br><span class="line">  <span class="keyword">return</span> B;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="不用加减乘除做加法"><a href="#不用加减乘除做加法" class="headerlink" title="不用加减乘除做加法"></a>不用加减乘除做加法</h4><p><strong>题目描述：</strong>写一个函数，求两个整数之和，要求在函数体内不得使用+、-、*、/四则运算符号。</p><p><u>思路</u>：1.不考虑进位：异或操作：^ ；例如：101^111 = 010;<br>​            2.计算进位值：与操作：&amp;，再左移一位；例如：101&amp;111&lt;&lt;1 = 101&lt;&lt;1 = 1010；<br>​            3.重复上述两步，直到进位值全为0，返回结果；</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">Add</span><span class="params">(<span class="keyword">int</span> num1,<span class="keyword">int</span> num2)</span> </span>&#123;</span><br><span class="line">  <span class="keyword">while</span>(num2 !=  <span class="number">0</span>) &#123;</span><br><span class="line"><span class="keyword">int</span> temp = num1 ^ num2;</span><br><span class="line"><span class="keyword">int</span> carry =  (num1 &amp; num2) &lt;&lt; <span class="number">1</span>;</span><br><span class="line">num1 = temp;</span><br><span class="line">num2 = carry;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> num1;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="二叉树的深度"><a href="#二叉树的深度" class="headerlink" title="二叉树的深度"></a>二叉树的深度</h4><p><strong>题目描述：</strong>输入一棵二叉树，求该树的深度。从根结点到叶结点依次经过的结点（含根、叶结点）形成树的一条路径，最长路径的长度为树的深度。</p><p><u>思路</u>：递归：结束条件：根节点位空</p><figure class="highlight java"><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="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">TreeDepth</span><span class="params">(TreeNode root)</span> </span>&#123;</span><br><span class="line"><span class="keyword">if</span>(root == <span class="keyword">null</span>) <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">int</span> left = TreeDepth(root.left);</span><br><span class="line">  <span class="keyword">int</span> right = TreeDepth(root.right);</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">return</span> Math.max(left,right)+<span class="number">1</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="二叉树的镜像"><a href="#二叉树的镜像" class="headerlink" title="二叉树的镜像"></a>二叉树的镜像</h4><p><strong>题目描述：</strong>操作给定的二叉树，将其变换为源二叉树的镜像。</p><p><u>思路</u>：递归：结束条件：根节点位空</p><figure class="highlight java"><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">public</span> <span class="keyword">void</span> <span class="title">Mirror</span><span class="params">(TreeNode root)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">if</span>(root == <span class="keyword">null</span>) <span class="keyword">return</span>;</span><br><span class="line">    <span class="keyword">if</span>(root.left != <span class="keyword">null</span>) Mirror(root.left);</span><br><span class="line">  <span class="keyword">if</span>(root.right != <span class="keyword">null</span>) Mirror(root.right);</span><br><span class="line">    TreeNode temp = root.left;</span><br><span class="line">    root.left = root.right;</span><br><span class="line">    root.right = temp;      </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="变态跳台阶"><a href="#变态跳台阶" class="headerlink" title="变态跳台阶"></a>变态跳台阶</h4><p><strong>题目描述：</strong>一只青蛙一次可以跳上1级台阶，也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。</p><p><u>思路</u>：推导：</p><ul><li><p>跳上 n-1 级台阶，可以从 n-2 级跳 1 级上去，也可以从 n-3 级跳 2 级上去…，那么:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">f(n-1) &#x3D; f(n-2) + f(n-3) + ... + f(0)</span><br></pre></td></tr></table></figure></li><li><p>同样，跳上 n 级台阶，可以从 n-1 级跳 1 级上去，也可以从 n-2 级跳 2 级上去… ，那么:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">f(n) &#x3D; f(n-1) + f(n-2) + ... + f(0)</span><br></pre></td></tr></table></figure></li><li><p>两式相减得到：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">f(n) &#x3D; 2*f(n-1) &#x3D; 2*2*f(n-2) &#x3D;...&#x3D; 2^(n-1)*f(1) &#x3D; 2^(n-1)</span><br></pre></td></tr></table></figure></li></ul><figure class="highlight java"><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="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">JumpFloorII</span><span class="params">(<span class="keyword">int</span> target)</span> </span>&#123;</span><br><span class="line"><span class="keyword">if</span>(target == <span class="number">0</span>)&#123;</span><br><span class="line">    <span class="keyword">return</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> (<span class="keyword">int</span>)Math.pow(<span class="number">2</span>,target-<span class="number">1</span>);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><h4 id="用两个栈实现队列"><a href="#用两个栈实现队列" class="headerlink" title="用两个栈实现队列"></a>用两个栈实现队列</h4><p><strong>题目描述：</strong>用两个栈来实现一个队列，完成队列的Push和Pop操作。 队列中的元素为int类型。</p><p><u>思路</u>：<strong>注意：</strong>stack2中有元素时，不能入栈，直接pop出元素即可；<br>                        必须stack2为空时，才能入栈；</p><p><img src="/2020/06/07/%E5%89%91%E6%8C%87offer/%E5%89%91%E6%8C%87offer-%E7%AE%80%E5%8D%95%E7%AF%87/%E5%8F%8C%E6%A0%88.png" alt="双栈"></p><figure class="highlight java"><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="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Solution</span> </span>&#123;</span><br><span class="line">  Stack&lt;Integer&gt; stack1 = <span class="keyword">new</span> Stack&lt;Integer&gt;();</span><br><span class="line">  Stack&lt;Integer&gt; stack2 = <span class="keyword">new</span> Stack&lt;Integer&gt;();</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">push</span><span class="params">(<span class="keyword">int</span> node)</span> </span>&#123;</span><br><span class="line">    stack1.push(node);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">pop</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">if</span>(stack2.isEmpty())&#123;</span><br><span class="line">      <span class="keyword">while</span>(!stack1.isEmpty())&#123;</span><br><span class="line">        <span class="keyword">int</span> node = stack1.pop();</span><br><span class="line">      stack2.push(node);</span><br><span class="line">      &#125; </span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> stack2.pop();   </span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      &lt;h4 id=&quot;构建乘积数组&quot;&gt;&lt;a href=&quot;#构建乘积数组&quot; class=&quot;headerlink&quot; title=&quot;构建乘积数组&quot;&gt;&lt;/a&gt;构建乘积数组&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;题目描述：&lt;/strong&gt;给定一个数组A[0,1,…,n-1],请构建一个数组B[0,1,…,n-1],其中B中的元素B[i]=A[0]A[1]…A[i-1]A[i+1]…A[n-1]。不能使用除法。（注意：规定B[0] = A[1] * A[2] * … * A[n-1]，B[n-1] = A[0] * A[1] * … * A[n-2];）&lt;/p&gt;
    
    </summary>
    
    
      <category term="剑指offer" scheme="https://chrisxb1996.github.io/categories/%E5%89%91%E6%8C%87offer/"/>
    
      <category term="数据结构和算法" scheme="https://chrisxb1996.github.io/categories/%E5%89%91%E6%8C%87offer/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/"/>
    
    
      <category term="数据结构和算法" scheme="https://chrisxb1996.github.io/tags/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/"/>
    
      <category term="剑指offer" scheme="https://chrisxb1996.github.io/tags/%E5%89%91%E6%8C%87offer/"/>
    
  </entry>
  
  <entry>
    <title>SpringBoot</title>
    <link href="https://chrisxb1996.github.io/2020/06/02/SpringBoot/"/>
    <id>https://chrisxb1996.github.io/2020/06/02/SpringBoot/</id>
    <published>2020-06-02T07:43:35.000Z</published>
    <updated>2020-06-02T08:11:21.766Z</updated>
    
    <content type="html"><![CDATA[<h1 id="日志"><a href="#日志" class="headerlink" title="日志"></a>日志</h1><p>SLF4J + logback</p><p><strong>如何让系统中所有的日志都统一到slf4j；</strong></p><p>1、将系统中其他日志框架先排除出去；</p><p>2、用中间包来替换原有的日志框架；</p><p>3、我们导入slf4j其他的实现；</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;SLF4J + logback&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;如何让系统中所有的日志都统一到slf4j；&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;1
      
    
    </summary>
    
    
      <category term="Java" scheme="https://chrisxb1996.github.io/categories/Java/"/>
    
    
      <category term="Java" scheme="https://chrisxb1996.github.io/tags/Java/"/>
    
      <category term="Spring" scheme="https://chrisxb1996.github.io/tags/Spring/"/>
    
      <category term="SpringBoot" scheme="https://chrisxb1996.github.io/tags/SpringBoot/"/>
    
  </entry>
  
  <entry>
    <title>Leetcode 167.两数之和 II - 输入有序数组</title>
    <link href="https://chrisxb1996.github.io/2020/05/27/Leetcode/Leetcode-167-%E4%B8%A4%E6%95%B0%E4%B9%8B%E5%92%8C-II-%E8%BE%93%E5%85%A5%E6%9C%89%E5%BA%8F%E6%95%B0%E7%BB%84/"/>
    <id>https://chrisxb1996.github.io/2020/05/27/Leetcode/Leetcode-167-%E4%B8%A4%E6%95%B0%E4%B9%8B%E5%92%8C-II-%E8%BE%93%E5%85%A5%E6%9C%89%E5%BA%8F%E6%95%B0%E7%BB%84/</id>
    <published>2020-05-27T14:52:47.000Z</published>
    <updated>2020-05-27T15:01:31.720Z</updated>
    
    <content type="html"><![CDATA[<p><a href="https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted/" target="_blank" rel="noopener">167</a>：给定一个已按照升序排列 的有序数组，找到两个数使得它们相加之和等于目标数。</p><p>函数应该返回这两个下标值 index1 和 index2，其中 index1 必须小于 index2。</p><p><strong>说明:</strong></p><ul><li>返回的下标值（index1 和 index2）不是从零开始的。</li><li>你可以假设每个输入只对应唯一的答案，而且你不可以重复使用相同的元素。</li></ul><figure class="highlight java"><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> </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span>[] twoSum(<span class="keyword">int</span>[] numbers, <span class="keyword">int</span> target) &#123;</span><br><span class="line">        <span class="keyword">if</span>(numbers.length &lt; <span class="number">2</span>) <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">        <span class="keyword">int</span>[] res = <span class="keyword">new</span> <span class="keyword">int</span>[<span class="number">2</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">int</span> j = numbers.length-<span class="number">1</span>;</span><br><span class="line">        <span class="keyword">while</span>(i &lt; j)&#123;</span><br><span class="line">            <span class="keyword">if</span>(numbers[i] + numbers[j] == target)&#123;</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">                i++;</span><br><span class="line">                j--;</span><br><span class="line">            &#125;<span class="keyword">else</span> <span class="keyword">if</span>(numbers[i] + numbers[j] &lt; target)&#123;</span><br><span class="line">                i++;</span><br><span class="line">            &#125;<span class="keyword">else</span>&#123;</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">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;&lt;a href=&quot;https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;167&lt;/a&gt;：给定一个已按照升序排列 的有序数组，找到两
      
    
    </summary>
    
    
      <category term="Leetcode" scheme="https://chrisxb1996.github.io/categories/Leetcode/"/>
    
    
      <category term="Leetcode" scheme="https://chrisxb1996.github.io/tags/Leetcode/"/>
    
      <category term="双指针" scheme="https://chrisxb1996.github.io/tags/%E5%8F%8C%E6%8C%87%E9%92%88/"/>
    
  </entry>
  
  <entry>
    <title>设计模式-观察者模式</title>
    <link href="https://chrisxb1996.github.io/2020/05/21/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F-%E8%A7%82%E5%AF%9F%E8%80%85%E6%A8%A1%E5%BC%8F/"/>
    <id>https://chrisxb1996.github.io/2020/05/21/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F-%E8%A7%82%E5%AF%9F%E8%80%85%E6%A8%A1%E5%BC%8F/</id>
    <published>2020-05-21T07:37:11.000Z</published>
    <updated>2020-05-21T16:00:22.230Z</updated>
    
    <content type="html"><![CDATA[<p><strong>适用于广播场景机制 ：</strong><br>•  聊天室程序的创建。服务器创建好后，A,B,C三个客户端连上来公开聊天。A向服务器发送数据，服务器端聊天数据改变。我们希望将这些聊天数据分别发给其他在线的客户。也就是说，每个客户端需要更新服务器端得数据。<br>•  网站上，很多人订阅了”java主题”的新闻。当有这个主题新闻时，就会将这些新闻发给所有订阅的人。<br>•  玩CS游戏时，服务器需要将每个人的方位变化发给所有的客户。<a id="more"></a></p><p>我们可以把<strong>多个订阅者、客户称之为观察者</strong>； 需要同步给多个订阅者的数据封装到对象中，称之为<strong>目标</strong>。</p><p><strong>核心：</strong>观察者模式主要用于1：<em>N</em>的通知。当一个对象(目标对象Subject，消息发布)的状态变化时，他需要及时告知一系列对象(观察者对象Observer，消息订阅)，令他们做出响，通知观察者的方式主要是<strong>推</strong>和<strong>拉</strong>：<br><strong>•  推：</strong>每次都会把通知以广播方式发送给所有观察者，所有观察者只能被动接收。<br><strong>•  拉：</strong>观察者只要直到有情况即可。至于什么时候获取内容，获取什么内容，都可以自主决定。</p><p><strong>代码实现：</strong></p><figure class="highlight java"><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="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Observer</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">update</span><span class="params">(Subject subject)</span></span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ObserverA</span> <span class="keyword">implements</span> <span class="title">Observer</span></span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> myState;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">update</span><span class="params">(Subject subject)</span> </span>&#123;</span><br><span class="line">        myState = ((ConcreteSubject)subject).getState();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setMyState</span><span class="params">(<span class="keyword">int</span> myState)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.myState = myState;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getMyState</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> myState;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight java"><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="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Subject</span> </span>&#123;</span><br><span class="line">    <span class="keyword">protected</span> List&lt;Observer&gt; list = <span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">registerObserver</span><span class="params">(Observer observer)</span></span>&#123;</span><br><span class="line">        list.add(observer);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">deletObserver</span><span class="params">(Observer observer)</span></span>&#123;</span><br><span class="line">        list.remove(observer);</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="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">notifyAllObservers</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">for</span> (Observer o : list) &#123;</span><br><span class="line">            o.update(<span class="keyword">this</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">*具体目标类</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ConcreteSubject</span> <span class="keyword">extends</span> <span class="title">Subject</span></span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> state;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setState</span><span class="params">(<span class="keyword">int</span> state)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.state = state;</span><br><span class="line">        <span class="comment">//目标值发生变换，通知所有的观察者</span></span><br><span class="line">        <span class="keyword">this</span>.notifyAllObservers();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getState</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> state;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight java"><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="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">test</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        ConcreteSubject  concreteSubject = <span class="keyword">new</span> ConcreteSubject();</span><br><span class="line"></span><br><span class="line">        <span class="comment">//创建多个观察者</span></span><br><span class="line">        ObserverA o1 = <span class="keyword">new</span> ObserverA();</span><br><span class="line">        ObserverA o2 = <span class="keyword">new</span> ObserverA();</span><br><span class="line">        ObserverA o3 = <span class="keyword">new</span> ObserverA();</span><br><span class="line"></span><br><span class="line">        <span class="comment">//添加到subject的观察者队伍中</span></span><br><span class="line">        concreteSubject.registerObserver(o1);</span><br><span class="line">        concreteSubject.registerObserver(o2);</span><br><span class="line">        concreteSubject.registerObserver(o3);</span><br><span class="line"></span><br><span class="line">      <span class="comment">//一次更新，所有观察者都改变状态！！！</span></span><br><span class="line">        concreteSubject.setState(<span class="number">300</span>);</span><br><span class="line">        System.out.println(o1.getMyState());</span><br><span class="line">        System.out.println(o2.getMyState());</span><br><span class="line">        System.out.println(o3.getMyState());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><img src="/2020/05/21/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F-%E8%A7%82%E5%AF%9F%E8%80%85%E6%A8%A1%E5%BC%8F/观察者模式.png" width="35%" height="35%"><p><strong>•  开发中常见的场景：</strong></p><ul><li>聊天室程序的，服务器转发给所有客户端</li><li>网络游戏(多人联机对战)场景中，服务器将客户端的状态进行分发</li><li>邮件订阅</li><li>Servlet中，监听器的实现</li><li>Android中，广播机制</li><li>JDK的AWT中事件处理模型,基于观察者模式的委派事件模型(Delegation Event Model)</li><li>事件源—————-目标对象</li><li>事件监听器————观察者</li><li>京东商城中，群发某商品打折信息</li></ul>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;&lt;strong&gt;适用于广播场景机制 ：&lt;/strong&gt;&lt;br&gt;•  聊天室程序的创建。服务器创建好后，A,B,C三个客户端连上来公开聊天。A向服务器发送数据，服务器端聊天数据改变。我们希望将这些聊天数据分别发给其他在线的客户。也就是说，每个客户端需要更新服务器端得数据。&lt;br&gt;•  网站上，很多人订阅了”java主题”的新闻。当有这个主题新闻时，就会将这些新闻发给所有订阅的人。&lt;br&gt;•  玩CS游戏时，服务器需要将每个人的方位变化发给所有的客户。&lt;/p&gt;
    
    </summary>
    
    
      <category term="设计模式" scheme="https://chrisxb1996.github.io/categories/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"/>
    
    
      <category term="Java" scheme="https://chrisxb1996.github.io/tags/Java/"/>
    
      <category term="设计模式" scheme="https://chrisxb1996.github.io/tags/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"/>
    
      <category term="观察者模式" scheme="https://chrisxb1996.github.io/tags/%E8%A7%82%E5%AF%9F%E8%80%85%E6%A8%A1%E5%BC%8F/"/>
    
  </entry>
  
  <entry>
    <title>设计模式-模版方法模式</title>
    <link href="https://chrisxb1996.github.io/2020/05/20/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F-%E6%A8%A1%E7%89%88%E6%96%B9%E6%B3%95%E6%A8%A1%E5%BC%8F/"/>
    <id>https://chrisxb1996.github.io/2020/05/20/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F-%E6%A8%A1%E7%89%88%E6%96%B9%E6%B3%95%E6%A8%A1%E5%BC%8F/</id>
    <published>2020-05-20T14:22:50.000Z</published>
    <updated>2020-05-20T14:46:48.091Z</updated>
    
    <content type="html"><![CDATA[<p>模板方法模式也叫方法回调或钩子方法，是编程中经常用得到模式。它定义了一个操作中的算法骨架，将某些步骤延迟到子类中实现。这样，新的子类可以在不改变一个算法结构的前提下重新定义该算法的某些特定步骤。</p><p><strong>核心：</strong>处理步骤父类中定义好，具体实现延迟到子类中定义。<a id="more"></a></p><figure class="highlight java"><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="keyword">public</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">BankTemplateMethod</span> </span>&#123;</span><br><span class="line">    <span class="comment">//具体方法</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">takeNumber</span><span class="params">()</span></span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"取号排队"</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">void</span> <span class="title">transact</span><span class="params">()</span></span>; <span class="comment">//办理具体的业务//钩子方法</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">evaluate</span><span class="params">()</span></span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"反馈评分"</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title">process</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.takeNumber();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">this</span>.transact();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">this</span>.evaluate();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight java"><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="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">test</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="comment">//采用匿名内部类</span></span><br><span class="line">        BankTemplateMethod btm = <span class="keyword">new</span> BankTemplateMethod()&#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">transact</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                System.out.println(<span class="string">"取钱：2000！！！"</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;;</span><br><span class="line">        btm.process();</span><br><span class="line"></span><br><span class="line">        BankTemplateMethod btm2 = <span class="keyword">new</span> BankTemplateMethod()&#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">transact</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                System.out.println(<span class="string">"我要存钱：2000000！！！"</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;;</span><br><span class="line">        btm2.process();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>•  什么时候用到模板方法模式：</strong>实现一个算法时，整体步骤很固定。但是，某些部分易变。易变部分可以抽象成出来，供子类实现。</p><p><strong>•  开发中常见的场景：</strong>非常频繁。各个框架、类库中都有他的影子。比如常见的有：<br>1.数据库访问的封装；<br>2.Junit单元测试；<br>3.servlet中关于doGet/doPost方法调用；<br>4.Hibernate中模板程序；<br>5.spring中JDBCTemplate、HibernateTemplate等；</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;模板方法模式也叫方法回调或钩子方法，是编程中经常用得到模式。它定义了一个操作中的算法骨架，将某些步骤延迟到子类中实现。这样，新的子类可以在不改变一个算法结构的前提下重新定义该算法的某些特定步骤。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;核心：&lt;/strong&gt;处理步骤父类中定义好，具体实现延迟到子类中定义。&lt;/p&gt;
    
    </summary>
    
    
      <category term="设计模式" scheme="https://chrisxb1996.github.io/categories/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"/>
    
    
      <category term="Java" scheme="https://chrisxb1996.github.io/tags/Java/"/>
    
      <category term="设计模式" scheme="https://chrisxb1996.github.io/tags/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"/>
    
      <category term="模版方法模式" scheme="https://chrisxb1996.github.io/tags/%E6%A8%A1%E7%89%88%E6%96%B9%E6%B3%95%E6%A8%A1%E5%BC%8F/"/>
    
  </entry>
  
  <entry>
    <title>设计模式-策略模式</title>
    <link href="https://chrisxb1996.github.io/2020/05/20/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F-%E7%AD%96%E7%95%A5%E6%A8%A1%E5%BC%8F/"/>
    <id>https://chrisxb1996.github.io/2020/05/20/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F-%E7%AD%96%E7%95%A5%E6%A8%A1%E5%BC%8F/</id>
    <published>2020-05-20T06:56:40.000Z</published>
    <updated>2020-05-20T07:46:44.167Z</updated>
    
    <content type="html"><![CDATA[<p>某个市场人员接到单后的报价策略(CRM系统中常见问题)。报价策略很复杂，可以简单作如下分类：<br>•  普通客户小批量报价<br>•  普通客户大批量报价<br>•  老客户小批量报价<br>•  老客户大批量报价<br>具体选用哪个报价策略，这需要根据实际情况来确定。这时候，我们采用策略模式即可。<a id="more"></a></p><p>我们先可以采用条件语句处理：</p><figure class="highlight java"><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="function"><span class="keyword">public</span> <span class="keyword">double</span> <span class="title">getPrice</span><span class="params">(String type, <span class="keyword">double</span> price)</span></span>&#123;</span><br><span class="line"><span class="keyword">if</span>(type.equals(<span class="string">"普通客户小批量"</span>))&#123;</span><br><span class="line">System.out.println(<span class="string">"不打折,原价"</span>);</span><br><span class="line"><span class="keyword">return</span> price;</span><br><span class="line">&#125;<span class="keyword">else</span> <span class="keyword">if</span>(type.equals(<span class="string">"普通客户大批量"</span>))&#123;</span><br><span class="line">System.out.println(<span class="string">"打九折"</span>);</span><br><span class="line"><span class="keyword">return</span> price*<span class="number">0.9</span>;</span><br><span class="line">&#125;<span class="keyword">else</span> <span class="keyword">if</span>(type.equals(<span class="string">"老客户小批量"</span>))&#123;</span><br><span class="line">System.out.println(<span class="string">"打八五折"</span>);</span><br><span class="line"><span class="keyword">return</span> price*<span class="number">0.85</span>;</span><br><span class="line">&#125;<span class="keyword">else</span> <span class="keyword">if</span>(type.equals(<span class="string">"老客户大批量"</span>))&#123;</span><br><span class="line">System.out.println(<span class="string">"打八折"</span>);</span><br><span class="line"><span class="keyword">return</span> price*<span class="number">0.8</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> price;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>但类型特别多，算法比较复杂时，整个条件控制代码会变得很长，难于维护。</strong></p><p>策略模式对应于解决某一个问题的一个<u><strong>算法族</strong></u>，允许用户从该算法族中任选一个算法解决某一问题，同时可以<u><strong>方便的更换算法或者增加新的算法</strong></u>。并且<u><strong>由客户端决定调用哪个算法</strong></u>。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//策略接口</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Strategy</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">double</span> <span class="title">getPrice</span><span class="params">(<span class="keyword">double</span> standardPrice)</span></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">public</span> <span class="class"><span class="keyword">class</span> <span class="title">NewCustomerFew</span> <span class="keyword">implements</span> <span class="title">Strategy</span></span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">double</span> <span class="title">getPrice</span><span class="params">(<span class="keyword">double</span> standardPrice)</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"不打折原价"</span>);</span><br><span class="line">        <span class="keyword">return</span> standardPrice;</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">//新客户大批量</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">NewCustomerLarge</span> <span class="keyword">implements</span> <span class="title">Strategy</span></span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">double</span> <span class="title">getPrice</span><span class="params">(<span class="keyword">double</span> standardPrice)</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"打九折！"</span>);</span><br><span class="line">        <span class="keyword">return</span> standardPrice*<span class="number">0.9</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="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">OldCustomerFew</span> <span class="keyword">implements</span> <span class="title">Strategy</span></span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">double</span> <span class="title">getPrice</span><span class="params">(<span class="keyword">double</span> standardPrice)</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"打85折"</span>);</span><br><span class="line">        <span class="keyword">return</span> standardPrice*<span class="number">0.85</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="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">OldCustomLarge</span> <span class="keyword">implements</span> <span class="title">Strategy</span></span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">double</span> <span class="title">getPrice</span><span class="params">(<span class="keyword">double</span> standardPrice)</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"打8折"</span>);</span><br><span class="line">        <span class="keyword">return</span> standardPrice*<span class="number">0.8</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">//负责和具体的策略类交互，是的客户端和算法独立</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Context</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> Strategy strategy; <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="function"><span class="keyword">public</span> <span class="title">Context</span><span class="params">(Strategy strategy)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.strategy = strategy;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//通过set方法注入</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setStrategy</span><span class="params">(Strategy strategy)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.strategy = strategy;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">printPrice</span><span class="params">(<span class="keyword">double</span> s)</span></span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"价格："</span>+strategy.getPrice(s));</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="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">test</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        Strategy s1 = <span class="keyword">new</span> OldCustomerFew();</span><br><span class="line">        Strategy s2 = <span class="keyword">new</span> OldCustomLarge();</span><br><span class="line">        Context ctx = <span class="keyword">new</span> Context(s1);</span><br><span class="line">        Context  ctx2 = <span class="keyword">new</span> Context(s2);</span><br><span class="line">        <span class="keyword">int</span> standardPrice = <span class="number">1000</span>;</span><br><span class="line"></span><br><span class="line">        ctx.printPrice(standardPrice);</span><br><span class="line">        ctx2.printPrice(standardPrice);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><img src="/2020/05/20/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F-%E7%AD%96%E7%95%A5%E6%A8%A1%E5%BC%8F/策略模式.png" width="100%" height="100%"><p><strong>•  本质：</strong>分离算法，选择实现。<br><strong>•  开发中常见的场景：</strong>JAVASE中GUI编程中，布局管理；Spring框架中，Resource接口，资源访问策略；javax.servlet.http.HttpServlet#service()</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;某个市场人员接到单后的报价策略(CRM系统中常见问题)。报价策略很复杂，可以简单作如下分类：&lt;br&gt;•  普通客户小批量报价&lt;br&gt;•  普通客户大批量报价&lt;br&gt;•  老客户小批量报价&lt;br&gt;•  老客户大批量报价&lt;br&gt;具体选用哪个报价策略，这需要根据实际情况来确定。这时候，我们采用策略模式即可。&lt;/p&gt;
    
    </summary>
    
    
      <category term="设计模式" scheme="https://chrisxb1996.github.io/categories/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"/>
    
    
      <category term="Java" scheme="https://chrisxb1996.github.io/tags/Java/"/>
    
      <category term="设计模式" scheme="https://chrisxb1996.github.io/tags/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"/>
    
      <category term="策略模式" scheme="https://chrisxb1996.github.io/tags/%E7%AD%96%E7%95%A5%E6%A8%A1%E5%BC%8F/"/>
    
  </entry>
  
  <entry>
    <title>应用层</title>
    <link href="https://chrisxb1996.github.io/2020/05/18/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E5%BA%94%E7%94%A8%E5%B1%82/"/>
    <id>https://chrisxb1996.github.io/2020/05/18/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E5%BA%94%E7%94%A8%E5%B1%82/</id>
    <published>2020-05-18T09:33:32.000Z</published>
    <updated>2020-05-20T09:10:26.085Z</updated>
    
    <content type="html"><![CDATA[<h3 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h3><p>•  每个应用层协议都是为了解决某一类应用问题，而问题的解决又往往是通过位于不同主机中的多个应用进程之间的通信和协同工作来完成的。应用层的具体内容就是规定应用进程在通信时所遵循的协议。</p><p>•  应用层的许多协议都是基于客户服务器方式。客户(client)和服务器(server)都是指通信中所涉及的两个应用进程。客户服务器方式所描述的是进程之间服务和被服务的关系。客户是服务请求方，服务器是服务提供方。<a id="more"></a> </p><p>•  常用端口：</p><img src="/2020/05/18/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E5%BA%94%E7%94%A8%E5%B1%82/常用端口.png" width="100%" height="100%"><h3 id="域名系统-DNS"><a href="#域名系统-DNS" class="headerlink" title="域名系统 DNS"></a>域名系统 DNS</h3><p>DNS 是一个<strong>分布式数据库</strong>，提供了主机名和 IP 地址之间相互转换的服务。这里的分布式数据库是指，每个站点只保留它自己的那部分数据。</p><p>域名具有层次结构，从上到下依次为：根域名、顶级域名、二级域名…</p><img src="/2020/05/18/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E5%BA%94%E7%94%A8%E5%B1%82/DNS域名.png" width="100%" height="100%"><h3 id="动态主机配置协议DHCP"><a href="#动态主机配置协议DHCP" class="headerlink" title="动态主机配置协议DHCP"></a>动态主机配置协议DHCP</h3><p>DHCP (Dynamic Host Configuration Protocol) 提供了即插即用的连网方式，用户不再需要手动配置 IP 地址(DHCP 配置的内容不仅是 IP 地址，还包括子网掩码、网关 IP 地址)等信息。</p><p>DHCP 服务器分配给 DHCP 客户的 IP 地址的临时的，因此 DHCP 客户只能在一段有限的时间内使用这个分配到的 IP 地址。DHCP 协议称这段时间为租用期。 </p><p>•  DHCP 服务器被动打开 UDP 端口 67，等待客户端发来的报文。<br>•  DHCP 客户从 UDP 端口 68发送 <strong>DHCP发现报文(DHCPDISCOVER)</strong>。该报文被放入 UDP 中，广播到同一个子网的所有主机上。如果客户端和 DHCP 服务器不在同一个子网，就需要使用中继代理。<br>•  凡收到 DHCP 发现报文的 DHCP 服务器都发出 <strong>DHCP 提供报文(DHCPOFFER)</strong>，因此 DHCP 客户可能收到多个 DHCP 提供报文。<br>•  DHCP 客户从几个 DHCP 服务器中选择其中的一个，并向所选择的 DHCP 服务器发送 <strong>DHCP 请求报文(DHCPREQUEST)</strong>。<br>•  被选择的 DHCP 服务器发送<strong>确认报文DHCPACK</strong>，进入已绑定状态，并可开始使用得到的临时 IP 地址了。</p><img src="/2020/05/18/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E5%BA%94%E7%94%A8%E5%B1%82/DHCP.png" width="100%" height="100%"><h3 id="文件传送协议-FTP"><a href="#文件传送协议-FTP" class="headerlink" title="文件传送协议 FTP"></a>文件传送协议 FTP</h3><p>文件传送协议 FTP (File Transfer Protocol) 是因特网上使用得最广泛的文件传送协议， FTP使用两个TCP连接：TCP控制链接、TCP数据连接：</p><ul><li><strong>控制连接：</strong>标准端口为21，在整个会话期间一直保持打开，FTP 客户发出的传送请求通过控制连接发送给服务器端的控制进程，但控制连接不用来传送文件。</li><li><strong>数据连接：</strong>标准端口为20，实际用于传输文件。</li></ul><img src="/2020/05/18/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E5%BA%94%E7%94%A8%E5%B1%82/FTP.png" width="100%" height="100%"><p>根据数据连接是否是服务器端主动建立，FTP 有主动和被动两种模式：</p><ul><li><strong>主动模式：</strong>服务端从20端口主动向客户端发起连接。</li><li><strong>被动模式：</strong>服务端在指定范围内的某个端口被动等待客户端发起连接</li></ul><p><strong>注意：</strong>主动模式要求客户端开放端口号给服务器端，需要去配置客户端的防火墙(需要在防火墙上开放20和21端口)。被动模式只需要服务器端开放端口号即可，无需客户端配置防火墙。但是被动模式会导致服务器端的安全性减弱，因为开放了过多的端口号。</p><h3 id="按远程终端协议-TELNET"><a href="#按远程终端协议-TELNET" class="headerlink" title="按远程终端协议 TELNET"></a>按远程终端协议 TELNET</h3><p>TELNET 是一个简单的远程终端协议，也是因特网的正式标准。</p><p>•  TELNET 用于登录到远程主机上，并且远程主机上的输出也会返回。<br>•  TELNET 可以适应许多计算机和操作系统的差异，例如不同操作系统系统的换行符定义。</p><h3 id="电子邮件协议-SMTP-POP3-IMAP"><a href="#电子邮件协议-SMTP-POP3-IMAP" class="headerlink" title="电子邮件协议(SMTP, POP3, IMAP)"></a>电子邮件协议(SMTP, POP3, IMAP)</h3><ul><li><strong>发送邮件的协议：</strong>SMTP使用TCP 25端口。</li><li><strong>读取邮件的协议：</strong>POP3 使用110端口和 IMAP使用的端口是143。</li></ul><img src="/2020/05/18/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E5%BA%94%E7%94%A8%E5%B1%82/电子邮件.png" width="100%" height="100%"><p>•  <strong>SMTP：</strong>SMTP 只能发送 ASCII 码，而互联网邮件扩充 MIME 可以发送二进制文件。MIME 并没有改动或者取代 SMTP，而是增加邮件主体的结构，定义了非 ASCII 码的编码规则。</p><img src="/2020/05/18/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E5%BA%94%E7%94%A8%E5%B1%82/SMTP.png" width="100%" height="100%"><p>•  <strong>POP3：</strong>POP3 的特点是只要用户从服务器上读取了邮件，就把该邮件删除。但最新版本的 POP3 可以不删除邮件。</p><p>•  <strong>IMAP：</strong>IMAP 协议中客户端和服务器上的邮件保持同步，如果不手动删除邮件，那么服务器上的邮件也不会被删除。IMAP 这种做法可以让用户随时随地去访问服务器上的邮件。</p><h3 id="超文本传送协议-HTTP"><a href="#超文本传送协议-HTTP" class="headerlink" title="超文本传送协议 HTTP"></a>超文本传送协议 HTTP</h3><p>在万维网客户程序与万维网服务器程序之间进行交互所使用的协议，是超文本传送协议 HTTP (HyperText Transfer Protocol)。</p><p>HTTP 是一个应用层协议，它使用 TCP 连接进行可靠的传送。</p><h4 id="URL"><a href="#URL" class="headerlink" title="URL"></a>URL</h4><p>使用统一资源定位符 URL (Uniform Resource Locator)来标志万维网上的各种文档。URL有如下一般形式：</p><p><strong>&lt;协议&gt;://&lt;主机&gt;:&lt;端口&gt;/&lt;路径&gt;</strong> </p><p>•  &lt;协议&gt; ftp、http、News…<br>•  &lt;主机&gt; 是存放资源的主机在因特网中的域名;<br>•  &lt;端口&gt;/&lt;路径&gt; 有时可省略；</p><p><strong>请求web服务的过程：</strong></p><img src="/2020/05/18/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E5%BA%94%E7%94%A8%E5%B1%82/万维网工作过程.png" width="100%" height="100%"><h4 id="HTTP的报文结构："><a href="#HTTP的报文结构：" class="headerlink" title="HTTP的报文结构："></a>HTTP的报文结构：</h4><p>HTTP 有两类报文：</p><p><strong>•  请求报文</strong>——从客户向服务器发送请求报文。<br><strong>•  响应报文</strong>——从服务器到客户的回答。<br><strong>•</strong>  由于 HTTP 是面向正文的(text-oriented)，因此在报文中的每一个字段都是一些 ASCII 码串，因而每个字段的长度都是不确定的。</p><img src="/2020/05/18/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E5%BA%94%E7%94%A8%E5%B1%82/HTTP报文(请求报文).png" width="100%" height="100%"><p>报文由三个部分组成，即开始行、首部行和实体主体。在请求报文中，开始行就是<strong>请求行</strong>。包含了方法字段。</p><img src="/2020/05/18/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E5%BA%94%E7%94%A8%E5%B1%82/HTTP方法.png" width="100%" height="100%"><p>响应报文的开始行是<strong>状态行</strong>。状态行包括三项内容，即 HTTP 的版本，状态码，以及解释状态码的简单短语。 </p><img src="/2020/05/18/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E5%BA%94%E7%94%A8%E5%B1%82/HTTP报文(响应报文).png" width="100%" height="100%"><p><strong>•  1xx</strong> ：Informational（信息性状态码），表示通知信息的，如请求收到了或正在进行处理。</p><ul><li>100 Continue ：表明到目前为止都很正常，客户端可以继续发送请求或者忽略这个响应。</li></ul><p><strong>•  2xx</strong> ：Success（成功状态码），表示成功，如接受或知道了。</p><ul><li>200 OK</li><li>204 No Content ：请求已经成功处理，但是返回的响应报文不包含实体的主体部分。一般在只需要从客户端往服务器发送信息，而不需要返回数据时使用。</li><li>206 Partial Content ：表示客户端进行了范围请求，响应报文包含由 Content-Range 指定范围的实体内容。</li></ul><p><strong>•  3xx</strong> ：Redirection（重定向状态码），表示重定向，表示要完成请求还必须采取进一步的行动。</p><ul><li>301 Moved Permanently ：永久性重定向</li><li>302 Found ：临时性重定向</li><li>303 See Other ：和 302 有着相同的功能，但是 303 明确要求客户端应该采用 GET 方法获取资源。</li><li>注：虽然 HTTP 协议规定 301、302 状态下重定向时不允许把 POST 方法改成 GET 方法，但是大多数浏览器都会在 301、302 和 303 状态下的重定向把 POST 方法改成 GET 方法。</li><li>304 Not Modified ：如果请求报文首部包含一些条件，例如：If-Match，If-Modified-Since，If-None-Match，If-Range，If-Unmodified-Since，如果不满足条件，则服务器会返回 304 状态码。</li><li>307 Temporary Redirect ：临时重定向，与 302 的含义类似，但是 307 要求浏览器不会把重定向请求的 POST 方法改成 GET 方法。</li></ul><p><strong>•  4xx</strong> ：Client Error（客户端错误状态码），表示客户的差错，如请求中有错误的语法或不能完成。</p><ul><li>400 Bad Request ：请求报文中存在语法错误。</li><li>401 Unauthorized ：该状态码表示发送的请求需要有认证信息（BASIC 认证、DIGEST 认证）。如果之前已进行过一次请求，则表示用户认证失败。</li><li>403 Forbidden ：请求被拒绝。</li><li>404 Not Found</li></ul><p><strong>•  5xx</strong>  ：Server Error（服务器错误状态码），表示服务器的差错，如服务器失效无法完成请求。</p><ul><li>500 Internal Server Error ：服务器正在执行请求时发生错误。</li><li>503 Service Unavailable ：服务器暂时处于超负载或正在进行停机维护，现在无法处理请求。</li></ul><h4 id="Cookie"><a href="#Cookie" class="headerlink" title="Cookie"></a>Cookie</h4>]]></content>
    
    <summary type="html">
    
      &lt;h3 id=&quot;概述&quot;&gt;&lt;a href=&quot;#概述&quot; class=&quot;headerlink&quot; title=&quot;概述&quot;&gt;&lt;/a&gt;概述&lt;/h3&gt;&lt;p&gt;•  每个应用层协议都是为了解决某一类应用问题，而问题的解决又往往是通过位于不同主机中的多个应用进程之间的通信和协同工作来完成的。应用层的具体内容就是规定应用进程在通信时所遵循的协议。&lt;/p&gt;
&lt;p&gt;•  应用层的许多协议都是基于客户服务器方式。客户(client)和服务器(server)都是指通信中所涉及的两个应用进程。客户服务器方式所描述的是进程之间服务和被服务的关系。客户是服务请求方，服务器是服务提供方。&lt;/p&gt;
    
    </summary>
    
    
      <category term="计算机网络" scheme="https://chrisxb1996.github.io/categories/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/"/>
    
    
      <category term="计算机网络" scheme="https://chrisxb1996.github.io/tags/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/"/>
    
      <category term="应用层" scheme="https://chrisxb1996.github.io/tags/%E5%BA%94%E7%94%A8%E5%B1%82/"/>
    
  </entry>
  
  <entry>
    <title>传输层</title>
    <link href="https://chrisxb1996.github.io/2020/05/17/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E4%BC%A0%E8%BE%93%E5%B1%82/"/>
    <id>https://chrisxb1996.github.io/2020/05/17/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E4%BC%A0%E8%BE%93%E5%B1%82/</id>
    <published>2020-05-17T08:06:11.000Z</published>
    <updated>2020-05-18T09:30:30.678Z</updated>
    
    <content type="html"><![CDATA[<h3 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h3><h4 id="进程之间的通信"><a href="#进程之间的通信" class="headerlink" title="进程之间的通信:"></a>进程之间的通信:</h4><ul><li>网络层只把分组发送到目的主机，但是真正通信的并不是主机而是主机中的进程。传输层提供了进程间的逻辑通信，传输层向高层用户屏蔽了下面网络层的核心细节，使应用程序看起来像是在两个传输层实体之间有一条端到端的逻辑通信信道。</li><li><strong>传输层向它上面的应用层提供通信服务，它属于面向通信部分的最高层，同时也是用户功能中的最低层。</strong></li><li>当网络的边缘部分中的两个主机使用网络的核心部分的功能进行端到端的通信时，只有位于网络边缘部分的主机的协议栈才有运输层，而网络核心部分中的路由器在转发分组时都只用到下三层的功能。<a id="more"></a> </li></ul><img src="/2020/05/17/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E4%BC%A0%E8%BE%93%E5%B1%82/传输层协议概述.png" width="100%" height="100%"><h4 id="TCP和UDP"><a href="#TCP和UDP" class="headerlink" title="TCP和UDP:"></a>TCP和UDP:</h4><p>运输层需要有两种不同的运输协议，即面向连接的 TCP 和无连接的 UDP。</p><ul><li>用户数据报协议 UDP (User Datagram Protocol)：是无连接的，尽最大可能交付，没有拥塞控制，面向报文（对于应用程序传下来的报文不合并也不拆分，只是添加 UDP 首部），支持一对一、一对多、多对一和多对多的交互通信。</li><li>传输控制协议 TCP (Transmission Control Protocol)：是面向连接的，提供可靠交付，有流量控制，拥塞控制，提供全双工通信，面向字节流（把应用层传下来的报文看成字节流，把字节流组织成大小不等的数据块），每一条 TCP 连接只能是点对点的（一对一）。</li></ul><h4 id="传输层的端口"><a href="#传输层的端口" class="headerlink" title="传输层的端口:"></a>传输层的端口:</h4><p>运行在计算机中的进程是用<strong>进程标识符</strong>来标志的，为了使运行不同操作系统的计算机的应用进程能够互相通信，就必须用统一的方法对 TCP/IP 体系的应用进程进行标志。解决这个问题的方法就是在运输层使用协议端口号(protocol port number)，或通常简称为<strong>端口</strong>(port)。</p><ul><li>端口用一个 16 位端口号进行标志。</li><li>端口号只具有<strong>本地意义</strong>，即端口号只是为了标志本计算机应用层中的各进程。在因特网中不同计算机的相同端口号是没有联系的。</li><li>三类端口 ：<br>1.熟知端口，数值一般为 0-1023；<br>2.登记端口号，数值为1024-49151，为没有熟知端口号的应用程序使用的；<br>3.客户端口号，数值为49152-65535，留给客户进程选择暂时使用；</li><li>常用应用层协议与传输层端口：<br>http = TCP + 80；<br>https = TCP + 443；<br>ftp = TCP + 21；<br>SMTP = TCP + 25；<br>POP3 = TCP + 101；<br>RDP = TCP + 3389；<br>SQL = TCP + 1433；<br>DNS = UDP + 53  or  TCP + 53(极少情况)</li><li><strong>计算机服务(对外的服务)运行后在TCP或UDP的某个端口侦听客户端请求。</strong></li></ul><h3 id="UDP"><a href="#UDP" class="headerlink" title="UDP"></a>UDP</h3><p>UDP 只在 IP 的数据报服务之上增加了很少一点的功能，即端口的功能和差错检测的功能。</p><ul><li>UDP 是<u><strong>无连接的</strong></u>，即发送数据之前不需要建立连接<u>(主要针对短包，实时性要求不高的数据)</u>。</li><li>UDP 使用尽最大努力交付，即<u><strong>不保证可靠交付</strong></u>，同时也<u><strong>不使用拥塞控制</strong></u>。</li><li>UDP 是<u><strong>面向报文</strong>的</u>。UDP 没有拥塞控制，很适合多媒体通信的要求。</li><li>UDP 支持一对一、一对多、多对一和多对多的交互通信。 </li><li>UDP 的首部开销小，只有 8 个字节。</li></ul><p><strong>面向报文：</strong>送方 UDP 对应用程序交下来的报文，在添加首部后就向下交付 IP 层。UDP 对应用层交下来的报文，既不合并，也不拆分，而是保留这些报文的边界。应用层交给 UDP 多长的报文，UDP 就照样发送，即一次发送一个报文。接收方 UDP 对 IP 层交上来的 UDP 用户数据报，在去除首部后就原封不动地交付上层的应用进程，一次交付一个完整的报文。应用程序必须选择合适大小的报文。</p><img src="/2020/05/17/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E4%BC%A0%E8%BE%93%E5%B1%82/UDP面向报文.png" width="100%" height="100%"><p><strong>UDP首部格式：</strong>首部字段只有 8 个字节，包括源端口、目的端口、长度、检验和。12 字节的伪首部是为了计算检验和临时添加的。</p><img src="/2020/05/17/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E4%BC%A0%E8%BE%93%E5%B1%82/UDP首部.png" width="100%" height="100%"><h3 id="TCP"><a href="#TCP" class="headerlink" title="TCP"></a>TCP</h3><h4 id="TCP-概述："><a href="#TCP-概述：" class="headerlink" title="TCP 概述："></a>TCP 概述：</h4><p>主要特点:<br>1.TCP是<strong>面向连接</strong>的运输层协议；<br>2.每一条 TCP 连接只能有两个端点，每一条 TCP 连接只能是<strong>点对点</strong>的(一对一)；<br>3.TCP 提供<strong>可靠交付</strong>的服务；<br>4.TCP 提供<strong>全双工通信</strong>；<br>5.<strong>面向字节流</strong>；</p><p><strong>面向字节流的传输过程：</strong></p><img src="/2020/05/17/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E4%BC%A0%E8%BE%93%E5%B1%82/TCP面向字节流的传输过程.png" width="100%" height="100%"><p><strong>注意：</strong><br>1.TCP 连接是一条虚连接而不是一条真正的物理连接。<br>2.TCP 连接的端点不是主机，不是主机的IP 地址，不是应用进程，也不是运输层的协议端口。TCP 连接的端点叫做<strong><u>套接字(socket)</u></strong>，端口号拼接到 IP 地址即构成了套接字。<br>套接字 socket = (IP地址: 端口号)；<br>3.每一条 TCP 连接唯一地被通信两端的两个端点（即两个套接字）所确定。即：<br>TCP 连接 ::= {socket1, socket2} = {(IP1: port1), (IP2: port2)}；</p><h4 id="TCP-报文首部格式："><a href="#TCP-报文首部格式：" class="headerlink" title="TCP 报文首部格式："></a>TCP 报文首部格式：</h4><img src="/2020/05/17/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E4%BC%A0%E8%BE%93%E5%B1%82/TCP首部格式.png" width="100%" height="100%"><ul><li><strong>源端口和目的端口字段——各占 2 字节</strong>，端口传输层与应用层的服务接口。传输层的复用和分用功能都要通过端口才能实现。 </li><li><strong>序号字段——占 4 字节</strong>，TCP 连接中传送的字节流中的每一个数据段都编上一个序号。序号字段的值则指的是<strong>本报文段</strong>所发送的数据的<strong>第一个字节的序号</strong>。</li><li><strong>确认号字段——占 4 字节</strong>，是期望收到对方的<strong>下一个报文段</strong>的数据的第<strong>一个字节的序号</strong>。</li><li><strong>数据偏移(即首部长度)——占 4 位</strong>，它表示首部长度，最长60个字节，故可变长度最长40个字节。</li><li><strong>保留字段——占 6 位</strong>，保留为今后使用，但目前应置为 0。 </li><li><strong>紧急 URG</strong> —— 当 URG = 1 时，表明紧急指针字段有效。它告诉系统此报文段中有紧急数据，应尽快传送。</li><li><strong>确认 ACK</strong> —— 只有当 ACK = 1 时确认号字段才有效。当 ACK = 0 时，确认号无效。 </li><li><strong>推送 PSH</strong> —— 接收 TCP 收到 PSH = 1 的报文段，就尽快地交付接收应用进程，而不再等到整个缓存都填满了后再向上交付。 </li><li><strong>复位 RST</strong>  —— 当 RST = 1 时，表明 TCP 连接中出现严重差错(如由于主机崩溃或其他原因)，必须释放连接，然后再重新建立运输连接。</li><li><strong>同步 SYN</strong> —— 同步 SYN = 1 表示这是一个连接请求或连接接受报文。</li><li><strong>终止 FIN</strong> —— 用来释放一个连接。FIN = 1 表明此报文段的发送端的数据已发送完毕，并要求释放运输连接。</li><li><strong>窗口字段 —— 占 2 字节</strong>，用来让对方设置发送窗口的依据，单位为字节。 </li><li><strong>检验和 —— 占 2 字节</strong>，检验和字段检验的范围包括首部和数据这两部分。在计算检验和时，要在 TCP 报文段的前面加上 12 字节的伪首部。</li><li><strong>紧急指针字段 —— 占 16 位</strong>，指出在本报文段中紧急数据共有多少个字节（紧急数据放在本报文段数据的最前面）。 </li><li><strong>选项字段 —— 长度可变</strong>，TCP 最初只规定了一种选项，即最大报文段长度 MSS。MSS 告诉对方 TCP：“我的缓存所能接收的报文段的数据字段的最大长度是 MSS 个字节。”  </li></ul><h4 id="TCP-可靠传输："><a href="#TCP-可靠传输：" class="headerlink" title="TCP 可靠传输："></a>TCP 可靠传输：</h4><p><strong>停止等待协议：</strong></p><img src="/2020/05/17/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E4%BC%A0%E8%BE%93%E5%B1%82/TCP可靠传输.png" width="100%" height="100%"><p>使用上述的确认和重传机制，我们就可以在不可靠的传输网络上实现可靠的通信，这种可靠传输协议常称为<strong>自动重传请求ARQ(Automatic Repeat reQuest)</strong> 。</p><p><strong>TCP 滑动窗口：</strong></p><ul><li>停止等待协议的优点是简单，但缺点是信道利用率太低。</li></ul><img src="/2020/05/17/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E4%BC%A0%E8%BE%93%E5%B1%82/停止等待协议缺点.png" width="100%" height="100%"><ul><li>针对这一缺点，一般采用<strong>滑动窗口(流水线传输)</strong>和<strong>累积确认(接收窗口)</strong>的方法提高信道利用率。<br><strong>滑动窗口：</strong>发送方可连续发送多个分组，不必每发完一个分组就停顿下来等待对方的确认。<br>1.如下图所示，根据 B 给出的窗口值A构造出自己的发送窗口；<br>2.A 发送了 11 个字节的数据；<br>3.A 收到新的确认号后，发送窗口向前滑动；<br>4.若A 的发送窗口内的序号都已用完，但还没有再收到确认，必须停止发送；<br><strong>累积确认：</strong>接收方一般采用累积确认的方式。即不必对收到的分组逐个发送确认，而是对按序到达的最后一个分组发送确认，这样就表示：<strong>到这个分组为止的所有分组都已正确收到了</strong>。</li></ul><img src="/2020/05/17/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E4%BC%A0%E8%BE%93%E5%B1%82/流水线传输和滑动窗口.png" width="100%" height="100%"><h4 id="TCP-流量控制："><a href="#TCP-流量控制：" class="headerlink" title="TCP 流量控制："></a>TCP 流量控制：</h4><p>一般说来，我们总是希望数据传输得更快一些。但如果发送方把数据发送得过快，接收方就可能来不及接收，这就会造成数据的丢失。<strong>流量控制(flow control)</strong>就是让发送方的发送速率不要太快，既要让接收方来得及接收，也不要使网络发生拥塞。利用<strong>滑动窗口机制</strong>可以很方便地在 TCP 连接上实现流量控制。 </p><p><strong>接收方发送的确认报文中的窗口字段可以用来控制发送方窗口大小，从而影响发送方的发送速率。将窗口字段设置为 0，则发送方不能发送数据。</strong></p><h4 id="TCP-拥塞控制："><a href="#TCP-拥塞控制：" class="headerlink" title="TCP 拥塞控制："></a>TCP 拥塞控制：</h4><p><strong>拥塞控制：</strong>所要做的都有一个前提，就是网络能够承受现有的网络负荷。拥塞控制是一个全局性的过程，涉及到所有的主机、所有的路由器，以及与降低网络传输性能有关的所有因素。 </p><p><strong>流量控制：</strong>往往指在给定的发送端和接收端之间的点对点通信量的控制。主要是抑制发送端发送数据的速率，以便使接收端来得及接收。 </p><img src="/2020/05/17/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E4%BC%A0%E8%BE%93%E5%B1%82/TCP拥塞控制.png" width="100%" height="100%"><p><strong>几种拥塞控制方法：</strong>慢开始、拥塞避免、快重传、快恢复</p><p><strong>慢开始和拥塞避免算法：</strong></p><img src="/2020/05/17/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E4%BC%A0%E8%BE%93%E5%B1%82/慢开始和拥塞避免算法.png" width="100%" height="100%"><p>1.发送的最初执行慢开始，令 cwnd = 1，发送方只能发送 1 个报文段；当收到确认后，将 cwnd 加倍，因此之后发送方能够发送的报文段数量为：2、4、8 …</p><p>2.注意到慢开始每个轮次都将 cwnd 加倍，这样会让 cwnd 增长速度非常快，从而使得发送方发送的速度增长速度过快，网络拥塞的可能性也就更高。设置一个慢开始门限 ssthresh，当 cwnd &gt;= ssthresh 时，进入拥塞避免，每个轮次只将 cwnd 加 1。</p><p>3.如果出现了超时，则令 ssthresh = cwnd / 2，然后重新执行慢开始。</p><p><strong>注意：</strong>发送方需要维护一个叫做拥塞窗口（cwnd）的状态变量，注意拥塞窗口与发送方窗口的区别：拥塞窗口只是一个状态变量，实际决定发送方能发送多少数据的是发送方窗口。</p><p><strong>快重传和快恢复：</strong></p><p><strong>快重传：</strong>在接收方，要求每次接收到报文段都应该对最后一个已收到的有序报文段进行确认。例如已经接收到 M1 和 M2，此时收到 M4，应当发送对 M2 的确认。<br>在发送方，如果收到三个重复确认，那么可以知道下一个报文段丢失，此时执行快重传，立即重传下一个报文段。例如收到三个 M2，则 M3 丢失，立即重传 M3。</p><img src="/2020/05/17/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E4%BC%A0%E8%BE%93%E5%B1%82/快重传.png" width="100%" height="100%"><p><strong>快恢复：</strong>在这种情况下，只是丢失个别报文段，而不是网络拥塞。因此执行快恢复，令 ssthresh = cwnd / 2 ，cwnd = ssthresh，注意到此时直接进入拥塞避免。</p><img src="/2020/05/17/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E4%BC%A0%E8%BE%93%E5%B1%82/快恢复.png" width="100%" height="100%"><p><strong>注意：</strong>慢开始和快恢复的快慢指的是 cwnd 的设定值，而不是 cwnd 的增长速率。慢开始 cwnd 设定为 1，而快恢复 cwnd 设定为 ssthresh。</p><h4 id="TCP-链接管理："><a href="#TCP-链接管理：" class="headerlink" title="TCP 链接管理："></a>TCP 链接管理：</h4><p>运输连接就有三个阶段，即：<strong>连接建立</strong>、<strong>数据传送</strong>和<strong>连接释放</strong>。运输连接的管理就是使运输连接的建立和释放都能正常地进行。</p><p><strong>TCP建立连接的三次握手：</strong><br>TCP 连接的建立都是采用客户服务器方式：<br>• 主动发起连接建立的应用进程叫做客户(client)<br>• 被动等待连接建立的应用进程叫做服务器(server)</p><p>三次握手：</p><ol><li>A 的 TCP 向 B 发出连接请求报文段，其首部中的同步位 SYN = 1，并选择序号 seq = x，表明传送数据时的第一个数据字节的序号是 x。</li><li>B 的 TCP 收到连接请求报文段后，如同意，则发回确认. B 在确认报文段中应使 SYN = 1，使 ACK = 1，其确认号ack = x + 1，自己选择的序号 seq = y。</li><li>A 收到此报文段后向 B 给出确认，其 ACK = 1，确认号 ack = y + 1。</li><li>A 的 TCP 通知上层应用进程，连接已经建立。</li></ol><img src="/2020/05/17/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E4%BC%A0%E8%BE%93%E5%B1%82/三次握手.png" width="100%" height="100%"><p><strong>注意：</strong>三次握手的原因：<strong>第三次握手是为了防止失效的连接请求到达服务器，让服务器错误打开连接。</strong>如果不进行三次握手，那么服务器就会打开两个连接。导致连接失败，如果有第三次握手，客户端会忽略服务器之后发送的对滞留连接请求的连接确认。</p><p><strong>TCP连接释放的四次挥手：</strong></p><p>四次挥手：</p><ol><li>A 把连接释放报文段首部的 FIN = 1，其序号seq = u，等待 B 的确认。</li><li>B 发出确认，确认号 ack = u + 1，而这个报文段自己的序号 seq = v。TCP 服务器进程通知高层应用进程。从 A 到 B 这个方向的连接就释放了，TCP 连接处于半关闭状态。B 若发送数据，A 仍要接收。</li><li>若 B 已经没有要向 A 发送的数据，其应用进程就通知 TCP 释放连接。 </li><li>A 收到连接释放报文段后，必须发出确认。在确认报文段中 ACK = 1，确认号 ack = w + 1，自己的序号 seq = u + 1。 </li><li>TCP 连接必须经过时间 2MSL(最大报文存活时间)后才真正释放掉。</li></ol><img src="/2020/05/17/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E4%BC%A0%E8%BE%93%E5%B1%82/四次挥手.png" width="100%" height="100%"><p><strong>注意：</strong>客户端A的TIME-WAIT状态必须等待2MSL的原因：<br>第一，为了保证 A 发送的最后一个 ACK 报文段能够到达 B。<br>第二，防止 “已失效的连接请求报文段”出现在本连接中。A 在发送完最后一个 ACK 报文段后，再经过时间 2MSL，就可以使本连接持续的时间内所产生的所有报文段，都从网络中消失。这样就可以使下一个新的连接中不会出现这种旧的连接请求报文段。</p>]]></content>
    
    <summary type="html">
    
      &lt;h3 id=&quot;概述&quot;&gt;&lt;a href=&quot;#概述&quot; class=&quot;headerlink&quot; title=&quot;概述&quot;&gt;&lt;/a&gt;概述&lt;/h3&gt;&lt;h4 id=&quot;进程之间的通信&quot;&gt;&lt;a href=&quot;#进程之间的通信&quot; class=&quot;headerlink&quot; title=&quot;进程之间的通信:&quot;&gt;&lt;/a&gt;进程之间的通信:&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;网络层只把分组发送到目的主机，但是真正通信的并不是主机而是主机中的进程。传输层提供了进程间的逻辑通信，传输层向高层用户屏蔽了下面网络层的核心细节，使应用程序看起来像是在两个传输层实体之间有一条端到端的逻辑通信信道。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;传输层向它上面的应用层提供通信服务，它属于面向通信部分的最高层，同时也是用户功能中的最低层。&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;当网络的边缘部分中的两个主机使用网络的核心部分的功能进行端到端的通信时，只有位于网络边缘部分的主机的协议栈才有运输层，而网络核心部分中的路由器在转发分组时都只用到下三层的功能。&lt;/li&gt;&lt;/ul&gt;
    
    </summary>
    
    
      <category term="计算机网络" scheme="https://chrisxb1996.github.io/categories/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/"/>
    
    
      <category term="计算机网络" scheme="https://chrisxb1996.github.io/tags/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/"/>
    
      <category term="传输层" scheme="https://chrisxb1996.github.io/tags/%E4%BC%A0%E8%BE%93%E5%B1%82/"/>
    
  </entry>
  
  <entry>
    <title>网络层</title>
    <link href="https://chrisxb1996.github.io/2020/05/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E7%BD%91%E7%BB%9C%E5%B1%82/"/>
    <id>https://chrisxb1996.github.io/2020/05/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E7%BD%91%E7%BB%9C%E5%B1%82/</id>
    <published>2020-05-15T13:55:05.000Z</published>
    <updated>2020-05-18T04:47:39.741Z</updated>
    
    <content type="html"><![CDATA[<h3 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h3><ul><li>因为网络层是整个互联网的核心，因此应当让网络层尽可能简单。网络层向上只提供简单灵活的、无连接的、尽最大努力交互的数据报服务。使用 IP 协议，可以把异构的物理网络连接起来，使得在网络层看起来好像是一个统一的网络。</li></ul><p><img src="/2020/05/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E7%BD%91%E7%BB%9C%E5%B1%82/虚拟互联网络.png" width="100%" height="100%"><a id="more"></a> </p><h3 id="TCP-IP协议栈"><a href="#TCP-IP协议栈" class="headerlink" title="TCP/IP协议栈"></a>TCP/IP协议栈</h3><img src="/2020/05/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E7%BD%91%E7%BB%9C%E5%B1%82/协议栈.png" width="80%" height="80%"><h3 id="IP地址编址"><a href="#IP地址编址" class="headerlink" title="IP地址编址"></a>IP地址编址</h3><h4 id="点分十进制记法："><a href="#点分十进制记法：" class="headerlink" title="点分十进制记法："></a>点分十进制记法：</h4><img src="/2020/05/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E7%BD%91%E7%BB%9C%E5%B1%82/点分十进制记法.png" width="100%" height="100%"><h4 id="分类："><a href="#分类：" class="headerlink" title="分类："></a>分类：</h4><ul><li><p>由两部分组成，网络号和主机号，其中不同分类具有不同的网络号长度，并且是固定的。<br>IP 地址 ::= {&lt; 网络号 &gt;, &lt; 主机号 &gt;}</p></li><li><p>1-126：A类地址，127是本机地址；<br>128-191：B类地址；<br>192-223：C类地址；<br>224-240：D类地址；</p></li></ul><img src="/2020/05/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E7%BD%91%E7%BB%9C%E5%B1%82/IP地址分类.png" width="100%" height="100%"><ul><li><strong>特殊的几个地址：</strong><br>127.0.0.1   本地环回地址；<br>169.254.0.0   windows链接失败自动分配的地址；<br>10.0.0.0   保留的私网地址；<br>172.16.0.0   —   172.31.0.0   保留的私网地址；<br>192.168.0.0  —   192.168.255.0   保留的私网地址；</li></ul><h4 id="划分子网："><a href="#划分子网：" class="headerlink" title="划分子网："></a>划分子网：</h4><ul><li><p>通过在<strong>主机号字段中拿一部分作为子网号</strong>，把两级 IP 地址划分为三级 IP 地址。划分子网纯属一个单位内部的事情。单位对外仍然表现为没有划分子网的网络。</p></li><li><p>IP 地址 ::= {&lt; 网络号 &gt;, &lt; 子网号 &gt;, &lt; 主机号 &gt;}</p></li><li><p>要使用子网，必须配置子网掩码。例如：一个 C 类地址的默认子网掩码为 255.255.255.0，如果 B 类地址的子网占两个比特，那么子网掩码为11111111 11111111 11111111 11000000，也就是 255.255.255.192。</p></li></ul><p><strong>注意：</strong>外部网络看不到子网的存在。</p><img src="/2020/05/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E7%BD%91%E7%BB%9C%E5%B1%82/子网划分.png" width="100%" height="100%"><h4 id="构造超网-无分类CIDR-："><a href="#构造超网-无分类CIDR-：" class="headerlink" title="构造超网(无分类CIDR)："></a>构造超网(无分类CIDR)：</h4><ul><li>CIDR 消除了传统的 A 类、B 类和 C 类地址以及划分子网的概念，因而可以更加有效地分配 IPv4 的地址空间。</li><li>CIDR使用各种长度的“网络前缀”(network-prefix)来代替分类地址中的网络号和子网号。从三级编址（使用子网掩码）又回到了两级编址。</li><li>IP地址 ::= {&lt;网络前缀&gt;, &lt;主机号&gt;}      </li><li>一个 CIDR 地址块可以表示很多地址，这种地址的聚合常称为路由聚合，它使得路由表中的一个项目可以表示很多个（例如上千个）原来传统分类地址的路由。路由聚合也称为构成超网(supernetting)。</li><li>CIDR 虽然不使用子网了，但仍然使用“掩码”这一名词（但不叫子网掩码）。</li><li>在路由表中的项目由“网络前缀”和“下一跳地址”组成，在查找时可能会得到不止一个匹配结果，应当采用最长前缀匹配来确定应该匹配哪一个。</li></ul><h4 id="计算机A到B的通信过程："><a href="#计算机A到B的通信过程：" class="headerlink" title="计算机A到B的通信过程："></a>计算机A到B的通信过程：</h4><img src="/2020/05/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E7%BD%91%E7%BB%9C%E5%B1%82/数据通信过程.png" width="100%" height="100%"><h3 id="ARP协议"><a href="#ARP协议" class="headerlink" title="ARP协议"></a>ARP协议</h3><img src="/2020/05/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E7%BD%91%E7%BB%9C%E5%B1%82/ARP.png" width="100%" height="100%"><ul><li><p>不管网络层使用的是什么协议，在实际网络的链路上传送数据帧时，最终还是必须使用硬件地址。 </p></li><li><p>每一个主机都设有一个 ARP 高速缓存(ARP cache)，里面有所在的局域网上的各主机和路由器的 IP 地址到硬件地址的映射表。</p></li><li><p>当主机 A 欲向本局域网上的某个主机 B 发送 IP 数据报时，就先在其 ARP 高速缓存中查看有无主机 B 的 IP 地址。如有，就可查出其对应的硬件地址，再将此硬件地址写入 MAC 帧，然后通过局域网将该 MAC 帧发往此硬件地址。 </p></li></ul><img src="/2020/05/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E7%BD%91%E7%BB%9C%E5%B1%82/ARP请求过程.png" width="100%" height="100%"><p><strong>注意：</strong>ARP 是解决同一个局域网上的主机或路由器的 IP 地址和硬件地址的映射问题。如果所要找的主机和源主机不在同一个局域网上，那么就要通过 ARP 找到一个位于本局域网上的某个路由器的硬件地址，然后把分组发送给这个路由器，让这个路由器把分组转发给下一个网络。剩下的工作就由下一个网络来做。</p><h3 id="IP数据包"><a href="#IP数据包" class="headerlink" title="IP数据包"></a>IP数据包</h3><ul><li>一个 IP 数据包由首部和数据两部分组成。</li><li>首部的前一部分是固定长度，共 20 字节，是所有 IP 数据报必须具有的。</li><li>在首部的固定部分的后面是一些可选字段，其长度是可变的。</li></ul><img src="/2020/05/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E7%BD%91%E7%BB%9C%E5%B1%82/IP数据包.png" width="100%" height="100%"><ul><li><strong>版本——占 4 位：</strong>指 IP 协议的版本：4（IPv4）和 6（IPv6）</li><li><strong>首部长度——占 4 位：</strong>可表示的最大数值，是 15 个单位(一个单位为 4 字节)，因此 IP 的首部长度的最大值是 60 字节。</li><li><strong>区分服务——占 8 位：</strong>用来获得更好的服务，在一般的情况下都不使用这个字段 。</li><li><strong>总长度——占 16 位：</strong>指首部和数据之和的长度，单位为字节，因此数据报的最大长度为 65535 字节。总长度必须不超过最大传送单元 MTU。</li><li><strong>标识——占 16 位：</strong>它是一个计数器，用来产生数据报的标识。 </li><li><strong>标志——占 3 位：</strong>目前只有前两位有意义。</li><li><strong>生存时间——占 8 位：</strong>记为 TTL (Time To Live)，数据报在网络中可通过的路由器个数的最大值。</li><li><strong>协议——占 8 位：</strong>该字段指出此数据报携带的数据使用何种协议以便目的主机的 IP 层将数据部分上交给哪个处理过程。</li><li><strong>首部检验和——占 16 位：</strong>因为数据报每经过一个路由器，都要重新计算检验和，因此检验和不包含数据部分可以减少计算的工作量(简单计算)。</li><li><strong>源地址和目的地址——占 32 位：</strong>都各占 4 字节。</li><li><strong>片偏移——占 312位：</strong>较长的分组在分片后某片在原分组中的相对位置。片偏移以 <strong>8 个字节为偏移单位</strong>。</li></ul><img src="/2020/05/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E7%BD%91%E7%BB%9C%E5%B1%82/IP数据报分片.png" width="100%" height="100%"><p><strong>注意：</strong>IP 首部的可变部分就是一个选项字段，用来支持排错、测量以及安全等措施，内容很丰富。选项字段的长度可变，从 1 个字节到 40 个字节不等，取决于所选择的项目。增加首部的可变部分是为了增加 IP 数据报的功能，但这同时也使得 IP 数据报的首部长度成为可变的。这就增加了每一个路由器处理数据报的开销。实际上这些选项很少被使用。 </p><h3 id="IP转发分组"><a href="#IP转发分组" class="headerlink" title="IP转发分组"></a>IP转发分组</h3><ul><li>路由就是路由器从一个网段到另外一个网段转发数据包的过程，即数据包通过路由器转发，就是数据路由。</li><li>网络畅通条件，要求数据包必须能够到达目标地址，同时数据包必须能够返回发送地址。(有去有回)</li><li>这就要求沿途经过的路由器必须知道到目标网络如何转发数据包，即到达目的网络下一跳转发给哪个路由器，也就是必须有到达目标网络的路由，沿途的路由器还必须有数据包返回所需的路由。</li></ul><p><strong>注意：IP 数据报的首部中没有地方可以用来指明“下一跳路由器的 IP 地址”。当路由器收到待转发的数据报，不是将下一跳路由器的 IP 地址填入 IP 数据报，而是送交下层的网络接口软件。网络接口软件使用 ARP 负责将下一跳路由器的 IP 地址转换成硬件地址，并将此硬件地址放在链路层的 MAC 帧的首部，然后根据这个硬件地址找到下一跳路由器。</strong> </p><h3 id="网际控制报文协议-ICMP"><a href="#网际控制报文协议-ICMP" class="headerlink" title="网际控制报文协议 ICMP"></a>网际控制报文协议 ICMP</h3><ul><li>ICMP 是为了更有效地转发 IP 数据报和提高交付成功的机会。它封装在 IP 数据报中，ICMP 报文作为 IP 层数据报的数据，加上数据报的首部，组成 IP 数据报发送出去。ICMP 不是高层协议，而是 IP 层的协议。</li><li>ICMP 报文的种类有两种，即 ICMP <strong>差错报告报文</strong>和 ICMP <strong>询问报文</strong>。</li><li>ICMP 报文的前 4 个字节是统一的格式，共有三个字段：即<strong>类型</strong>、<strong>代码</strong>和<strong>检验和</strong>。接着的 4 个字节的内容与 ICMP 的类型有关。 </li></ul><img src="/2020/05/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E7%BD%91%E7%BB%9C%E5%B1%82/ICMP报文格式.png" width="100%" height="100%"><ul><li>几种常见的ICMP报文类型：</li></ul><img src="/2020/05/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E7%BD%91%E7%BB%9C%E5%B1%82/ICMP报文类型.png" width="100%" height="100%"><ul><li><strong>Ping：</strong>用来测试两个主机之间的连通性；是应用层直接使用网络层 ICMP 的例子，它没有通过运输层的 TCP 或UDP；</li><li><strong>Traceroute：</strong> 是 ICMP 的另一个应用，用来跟踪一个分组从源点到终点的路径，发送的 IP 数据报封装的是无法交付的 UDP 用户数据报，并由目的主机发送终点不可达差错报告报文；</li></ul><h3 id="路由选择协议"><a href="#路由选择协议" class="headerlink" title="路由选择协议"></a>路由选择协议</h3><h4 id="基本概念："><a href="#基本概念：" class="headerlink" title="基本概念："></a>基本概念：</h4><p>从路由算法的自适应性考虑可分为：静态路由选择策略和动态路由选择策略：</p><ul><li>静态路由选择策略——即非自适应路由选择，其特点是简单和开销较小，但不能及时适应网络状态的变化。 </li><li>动态路由选择策略——即自适应路由选择，其特点是能较好地适应网络状态的变化，但实现起来较为复杂，开销也比较大。 </li></ul><p><strong>路由选择协议都是自适应的</strong>，能随着网络通信量和拓扑结构的变化而自适应地进行调整。互联网可以划分为许多较小的自治系统 AS，一个 AS 可以使用一种和别的 AS 不同的路由选择协议。可以把路由选择协议划分为两大类：</p><ul><li><strong>自治系统内部的路由选择</strong>：RIP 和 OSPF；</li><li><strong>自治系统间的路由选择</strong>：BGP</li></ul><h4 id="内部网关协议-RIP："><a href="#内部网关协议-RIP：" class="headerlink" title="内部网关协议 RIP："></a>内部网关协议 RIP：</h4><ul><li><p>RIP是一种分布式的基于<strong>距离</strong>向量的路由选择协议，RIP 协议中的<strong>距离</strong>即为<strong>跳数</strong>，RIP允许一条路径最多只能包含 15 个路由器。跳数的最大值为16 时相当于不可达。可见RIP只适用于小型互联网。</p></li><li><p>RIP协议的三个要点：<br>1.仅和相邻路由器交换信息；<br>2.交换的信息是当前本路由器所知道的全部信息，即自己的路由表；<br>3.按固定的时间间隔(30秒)交换路由信息；</p></li><li><p>优缺点：<br><strong>优点：</strong>RIP 协议实现简单，开销小。<br><strong>缺点：</strong>但是 RIP 能使用的最大距离为 15，限制了网络的规模；并且当网络出现故障时，要经过比较长的时间才能将此消息传送到所有路由器；同时仅基于跳数选择最佳路由也不够合理；</p></li></ul><h4 id="内部网关协议-OSPF-Open-Shortest-Path-First"><a href="#内部网关协议-OSPF-Open-Shortest-Path-First" class="headerlink" title="内部网关协议 OSPF(Open Shortest Path First)"></a>内部网关协议 OSPF(Open Shortest Path First)</h4><ul><li><p>基本特点：<br>1.“开放”表明 OSPF 协议不是受某一家厂商控制，而是公开发表的;<br>2.“最短路径优先”是因为使用了 Dijkstra 提出的最短路径算法SPF;</p></li><li><p>三个要点 :<br>1.向本自治系统中所有路由器发送信息，使用的方法是洪泛法。<br>2.发送的信息就是与本路由器相邻的所有路由器的链路状态，但这只是路由器所知道的部分信息。<br>3.只有当链路状态发生变化时，路由器才用洪泛法向所有路由器发送此信息。</p></li><li><p>OSPF 能够用于规模很大的网，的更新过程收敛得快;</p></li></ul><h4 id="外部网关协议-BGP"><a href="#外部网关协议-BGP" class="headerlink" title="外部网关协议 BGP"></a>外部网关协议 BGP</h4><p> BGP 是不同自治系统的路由器之间交换路由信息的协议。 </p><ul><li>因特网的规模太大，使得自治系统之间路由选择非常困难；</li><li>边界网关协议 BGP 只能是力求寻找一条能够到达目的网络且比较好的路由（不能兜圈子），而并非要寻找一条最佳路由；</li></ul><p><strong>每个 AS 都必须配置 BGP 发言人，通过在两个相邻 BGP 发言人之间建立 TCP 连接来交换路由信息。</strong></p><img src="/2020/05/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E7%BD%91%E7%BB%9C%E5%B1%82/BGP协议.png" width="100%" height="100%"><h3 id="虚拟专用网VPN"><a href="#虚拟专用网VPN" class="headerlink" title="虚拟专用网VPN"></a>虚拟专用网VPN</h3><p>专用网段：<br>10.0.0.0 到 10.255.255.255<br>172.16.0.0 到 172.31.255.255<br>192.168.0.0 到 192.168.255.255</p><p>这些地址只能用于一个机构的内部通信，而不能用于和因特网上的主机通信。</p><p>下图中，场所 A 和 B 的通信经过互联网，如果场所 A 的主机 X 要和另一个场所 B 的主机 Y 通信，IP 数据报的源地址是 10.1.0.1，目的地址是 10.2.0.3。数据报先发送到与互联网相连的路由器 R1，R1 对内部数据进行加密，然后重新加上数据报的首部，源地址是路由器 R1 的全球地址 125.1.2.3，目的地址是路由器 R2 的全球地址 194.4.5.6。路由器 R2 收到数据报后将数据部分进行解密，恢复原来的数据报，此时目的地址为 10.2.0.3，就交付给 Y。</p><img src="/2020/05/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E7%BD%91%E7%BB%9C%E5%B1%82/VPN.png" width="100%" height="100%"><h3 id="网络地址转换NAT"><a href="#网络地址转换NAT" class="headerlink" title="网络地址转换NAT"></a>网络地址转换NAT</h3><p>需要在专用网连接到因特网的路由器上安装 NAT 软件。装有 NAT 软件的路由器叫做 NAT路由器，它至少有一个有效的外部全球地址 IP。</p><p>所有使用本地地址的主机在和外界通信时都要在 NAT 路由器上将其本地地址转换成 IP才能和因特网连。</p><p>在以前，NAT 将本地 IP 和全球 IP 一一对应，这种方式下拥有 n 个全球 IP 地址的专用网内最多只可以同时有 n 台主机接入互联网。为了更有效地利用全球 IP 地址，现在常用的 NAT 转换表把传输层的端口号也用上了，<strong>使得多个专用网内部的主机共用一个全球 IP 地址</strong>。使用端口号的 NAT 也叫做网络地址与端口转换 NAPT。</p><h3 id="Internet组播管理协议-IGMP"><a href="#Internet组播管理协议-IGMP" class="headerlink" title="Internet组播管理协议 IGMP"></a>Internet组播管理协议 IGMP</h3><ul><li>当某个主机加入新的多播组时，该主机应向多播组的多播地址发送IGMP 报文，声明自己要成为该组的成员。本地的多播路由器收到 IGMP 报文后，将组成员关系转发给因特网上的其他多播路由器。</li><li>因为组成员关系是动态的，因此本地多播路由器要周期性地探询本地局域网上的主机，以便知道这些主机是否还继续是组的成员。</li></ul>]]></content>
    
    <summary type="html">
    
      &lt;h3 id=&quot;概述&quot;&gt;&lt;a href=&quot;#概述&quot; class=&quot;headerlink&quot; title=&quot;概述&quot;&gt;&lt;/a&gt;概述&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;因为网络层是整个互联网的核心，因此应当让网络层尽可能简单。网络层向上只提供简单灵活的、无连接的、尽最大努力交互的数据报服务。使用 IP 协议，可以把异构的物理网络连接起来，使得在网络层看起来好像是一个统一的网络。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/2020/05/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E7%BD%91%E7%BB%9C%E5%B1%82/虚拟互联网络.png&quot; width=&quot;100%&quot; height=&quot;100%&quot;&gt;&lt;/p&gt;
    
    </summary>
    
    
      <category term="计算机网络" scheme="https://chrisxb1996.github.io/categories/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/"/>
    
    
      <category term="计算机网络" scheme="https://chrisxb1996.github.io/tags/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/"/>
    
      <category term="网络层" scheme="https://chrisxb1996.github.io/tags/%E7%BD%91%E7%BB%9C%E5%B1%82/"/>
    
  </entry>
  
  <entry>
    <title>数据链路层</title>
    <link href="https://chrisxb1996.github.io/2020/05/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E6%95%B0%E6%8D%AE%E9%93%BE%E8%B7%AF%E5%B1%82/"/>
    <id>https://chrisxb1996.github.io/2020/05/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E6%95%B0%E6%8D%AE%E9%93%BE%E8%B7%AF%E5%B1%82/</id>
    <published>2020-05-15T07:05:33.000Z</published>
    <updated>2020-05-18T04:47:50.792Z</updated>
    
    <content type="html"><![CDATA[<h3 id="基本问题"><a href="#基本问题" class="headerlink" title="基本问题"></a>基本问题</h3><h4 id="基本概念："><a href="#基本概念：" class="headerlink" title="基本概念："></a>基本概念：</h4><p>1.主机H1向H2发送数据：<br>层次上来看：<br><img src="/2020/05/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E6%95%B0%E6%8D%AE%E9%93%BE%E8%B7%AF%E5%B1%82/图片 1.png" width="100%" height="100%"><br>仅从数据链路层观察帧的流动：<br><img src="/2020/05/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E6%95%B0%E6%8D%AE%E9%93%BE%E8%B7%AF%E5%B1%82/图片 2.png" width="100%" height="100%"></p><p><strong>注意：</strong>可以看到路由器只到网络层(三层协议)，没有应用层，和传输层；<a id="more"></a> </p><p>2.数据链路层传输的是帧：<br><img src="/2020/05/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E6%95%B0%E6%8D%AE%E9%93%BE%E8%B7%AF%E5%B1%82/数据链路层传送帧.png" width="100%" height="100%"></p><h4 id="数据链路层的三个基本点："><a href="#数据链路层的三个基本点：" class="headerlink" title="数据链路层的三个基本点："></a>数据链路层的三个基本点：</h4><p>1.封装成帧<br>2.透明传输<br>3.差错控制</p><p><strong>封装成帧：</strong>封装成帧(framing)就是在一段数据的前后分别添加首部和尾部，然后就构成了一个帧。确定帧的界限。首部和尾部的一个重要作用就是进行帧定界。<br><img src="/2020/05/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E6%95%B0%E6%8D%AE%E9%93%BE%E8%B7%AF%E5%B1%82/封装成帧.png" width="100%" height="100%"></p><p><strong>透明传输：</strong>发送端的数据链路层在数据中出现控制字符“SOH”或“EOT”的前面插入一个转义字符“ESC”。如果转义字符也出现数据当中，那么应在转义字符前插入一个转义字符。在接收端进行处理之后可以还原出原始数据。这个过程透明传输的内容是转义字符，用户察觉不到转义字符的存在。<br><img src="/2020/05/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E6%95%B0%E6%8D%AE%E9%93%BE%E8%B7%AF%E5%B1%82/透明传输.png" width="100%" height="100%"></p><p><strong>差错控制：</strong>在数据链路层传送的帧中，广泛使用了循环冗余检验 (CRC) 的检错技术：<strong>CRC是一种无比特差错，而不是无传输差错的检测机制</strong>。将得到的FCS(帧检验序列 )添加在原序列后面，在接收端检验：若得出的余数 <em>R</em> = 0，则判定这个帧没有差错，就接受(accept)；若余数 <em>R</em> != 0，则判定这个帧有差错，就丢弃，在高层进行重传指令。<br><img src="/2020/05/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E6%95%B0%E6%8D%AE%E9%93%BE%E8%B7%AF%E5%B1%82/CRC.png" width="100%" height="100%"></p><h3 id="数据链路层的信道类型"><a href="#数据链路层的信道类型" class="headerlink" title="数据链路层的信道类型"></a>数据链路层的信道类型</h3><h4 id="点对点信道："><a href="#点对点信道：" class="headerlink" title="点对点信道："></a>点对点信道：</h4><p>使用一对一的点对点通信方式，不会发生碰撞，因此也比较简单，使用 PPP 协议进行控制。PPP 协议是用户计算机和 ISP 进行通信时所使用的数据链路层协议，支持身份验证，支持多个网络层协议。<br>PPP协议帧格式：<br>1.A、C：在点到点信道没有实际意义，固定为：FF、03；<br>2.协议字段(2字节)：用于标识信息部分是什么内容；<br>3.FCS(2字节)：表示CRC得到的帧检验序列；<br><img src="/2020/05/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E6%95%B0%E6%8D%AE%E9%93%BE%E8%B7%AF%E5%B1%82/PPP协议.png" width="100%" height="100%"></p><h4 id="广播信道："><a href="#广播信道：" class="headerlink" title="广播信道："></a>广播信道：</h4><p>这种信道使用一对多的广播通信方式，因此过程比较复杂。广播信道上连接的主机很多，因此必须使用专用的共享信道协议来协调这些主机的数据发送<strong>(随机接入)</strong>：CSMA/CD(载波监听多点接入/碰撞检测) 协议：<br><strong>多点接入：</strong>表示许多计算机以多点接入的方式连接在一根总线上。<br><strong>载波监听：</strong>是指每一个站在发送数据之前先要检测一下总线上是否有其他计算机在发送数据，如果有，则暂时不要发送数据，以免发生碰撞。<br><strong>碰撞检测</strong>：在发送中，如果监听到信道已有其它主机正在发送数据，就表示发生了碰撞。虽然每个主机在发送数据之前都已经监听到信道为空闲，但是由于传播时延的存在，还是有可能会发生碰撞。<br><img src="/2020/05/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E6%95%B0%E6%8D%AE%E9%93%BE%E8%B7%AF%E5%B1%82/随机接入碰撞.png" width="100%" height="100%"></p><p>记端到端的传播时延为 τ，最先发送的站点最多经过 2τ 就可以知道是否发生了碰撞，<strong>称 2τ 为 争用期</strong> 。只有经过争用期之后还没有检测到碰撞，才能肯定这次发送不会发生碰撞。以太网中经过计算，最短有效帧长为512bit，也就是64个字节，规定凡是长度小于64字节的帧都是无效帧。<br>当发生碰撞时，站点要停止发送，等待一段时间再发送。这个时间采用 <strong>截断二进制指数退避算法</strong> 来确定。从离散的整数集合 {0, 1, .., (2k-1)} 中随机取出一个数，记作 r，然后取 r 倍的争用期作为重传等待时间。<br><strong>注意：</strong>该协议只能(只能进行半双工通信)。</p><h3 id="以太局域网"><a href="#以太局域网" class="headerlink" title="以太局域网"></a>以太局域网</h3><h4 id="概述："><a href="#概述：" class="headerlink" title="概述："></a>概述：</h4><p><strong>以太网是一种星型拓扑结构局域网。</strong>早期使用集线器(hub)进行连接，<strong>集线器是一种物理层设备</strong>， 作用于比特而不是帧。目前以太网使用交换机替代了集线器，<strong>交换机是一种链路层设备</strong>，它不会发生碰撞，能根据 MAC 地址进行存储转发。<br>以太网提供的服务是不可靠的交付，即尽最大努力的交付。当接收站收到有差错的数据帧时就丢弃此帧，其他什么也不做。差错的纠正由高层来决定。如果高层发现丢失了一些数据而进行重传，但以太网并不知道这是一个重传的帧，而是当作一个新的数据帧来发送。</p><h4 id="信道利用率："><a href="#信道利用率：" class="headerlink" title="信道利用率："></a>信道利用率：</h4><p>一个帧从开始发送，经可能发生的碰撞后，将再重传数次，到发送成功且信道转为空闲时为止，是发送一帧所需的平均时间。 信道利用率可以表示为：T0/发送一帧所需的平均时间。<br><img src="/2020/05/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E6%95%B0%E6%8D%AE%E9%93%BE%E8%B7%AF%E5%B1%82/以太网信道利用率.png" width="100%" height="100%"> </p><h4 id="MAC层-数据链路层的子层-："><a href="#MAC层-数据链路层的子层-：" class="headerlink" title="MAC层(数据链路层的子层)："></a>MAC层(数据链路层的子层)：</h4><p>在局域网中，硬件地址又称为物理地址，或 MAC 地址。MAC 地址是链路层地址，长度为 6 字节（48 位），用于唯一标识网络适配器（网卡）。一台主机拥有多少个网络适配器就有多少个 MAC 地址。例如笔记本电脑普遍存在无线网络适配器和有线网络适配器，因此就有两个 MAC 地址。<br>以太网MAC帧格式：<br><img src="/2020/05/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E6%95%B0%E6%8D%AE%E9%93%BE%E8%B7%AF%E5%B1%82/以太网帧格式.png" width="100%" height="100%"> </p><h3 id="扩展以太网"><a href="#扩展以太网" class="headerlink" title="扩展以太网"></a>扩展以太网</h3><h4 id="网桥-淘汰-："><a href="#网桥-淘汰-：" class="headerlink" title="网桥(淘汰)："></a>网桥(淘汰)：</h4><p>在数据链路层扩展局域网是使用网桥。网桥工作在数据链路层，它根据 MAC 帧的目的地址对收到的帧进行转发。网桥具有过滤帧的功能。当网桥收到一个帧时，并不是向所有的接口转发此帧，而是先检查此帧的目的 MAC 地址，然后再确定将该帧转发到哪一个接口。<br><img src="/2020/05/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E6%95%B0%E6%8D%AE%E9%93%BE%E8%B7%AF%E5%B1%82/网桥扩展以太网.png" width="100%" height="100%"> </p><h4 id="交换机："><a href="#交换机：" class="headerlink" title="交换机："></a>交换机：</h4><p>交换机具有自学习能力，学习的是交换表的内容，交换表中存储着 MAC 地址到接口的映射。正是由于这种自学习能力，因此交换机是一种即插即用设备，不需要网络管理员手动配置交换表内容。<br>1.端口独享带宽；<br>2.比集线器安全，可以设置固定MAC地址；<br>3.接口到计算机全双工；<br>4.全双工模式不再使用CSMA/CD协议；<br>5.接口可以工作在不同的速率；<br>6.广播帧会转发到全部端口；<br><img src="/2020/05/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E6%95%B0%E6%8D%AE%E9%93%BE%E8%B7%AF%E5%B1%82/交换机.png" width="100%" height="100%"> </p><h4 id="虚拟局域网-VLAN"><a href="#虚拟局域网-VLAN" class="headerlink" title="虚拟局域网(VLAN):"></a>虚拟局域网(VLAN):</h4><p>虚拟局域网可以建立与物理位置无关的逻辑组，只有在同一个虚拟局域网中的成员才会收到链路层广播信息。例如：在研发部某台主机广播的消息只能住研发部收到，销售部和人力资源部则收不到消息。<br>使用 VLAN 干线连接来建立虚拟局域网，每台交换机上的一个特殊接口被设置为干线接口，以互连 VLAN 交换机。IEEE 定义了一种扩展的以太网帧格式 802.1Q，它在标准以太网帧上加进了 4 字节首部 VLAN 标签，用于表示该帧属于哪一个虚拟局域网。<br><img src="/2020/05/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E6%95%B0%E6%8D%AE%E9%93%BE%E8%B7%AF%E5%B1%82/VLAN.png" width="100%" height="100%"> </p>]]></content>
    
    <summary type="html">
    
      &lt;h3 id=&quot;基本问题&quot;&gt;&lt;a href=&quot;#基本问题&quot; class=&quot;headerlink&quot; title=&quot;基本问题&quot;&gt;&lt;/a&gt;基本问题&lt;/h3&gt;&lt;h4 id=&quot;基本概念：&quot;&gt;&lt;a href=&quot;#基本概念：&quot; class=&quot;headerlink&quot; title=&quot;基本概念：&quot;&gt;&lt;/a&gt;基本概念：&lt;/h4&gt;&lt;p&gt;1.主机H1向H2发送数据：&lt;br&gt;层次上来看：&lt;br&gt;&lt;img src=&quot;/2020/05/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E6%95%B0%E6%8D%AE%E9%93%BE%E8%B7%AF%E5%B1%82/图片 1.png&quot; width=&quot;100%&quot; height=&quot;100%&quot;&gt;&lt;br&gt;仅从数据链路层观察帧的流动：&lt;br&gt;&lt;img src=&quot;/2020/05/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E6%95%B0%E6%8D%AE%E9%93%BE%E8%B7%AF%E5%B1%82/图片 2.png&quot; width=&quot;100%&quot; height=&quot;100%&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;注意：&lt;/strong&gt;可以看到路由器只到网络层(三层协议)，没有应用层，和传输层；&lt;/p&gt;
    
    </summary>
    
    
      <category term="计算机网络" scheme="https://chrisxb1996.github.io/categories/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/"/>
    
    
      <category term="计算机网络" scheme="https://chrisxb1996.github.io/tags/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/"/>
    
      <category term="数据链路层" scheme="https://chrisxb1996.github.io/tags/%E6%95%B0%E6%8D%AE%E9%93%BE%E8%B7%AF%E5%B1%82/"/>
    
  </entry>
  
  <entry>
    <title>计算机网络概述</title>
    <link href="https://chrisxb1996.github.io/2020/05/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E6%A6%82%E8%BF%B0/"/>
    <id>https://chrisxb1996.github.io/2020/05/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E6%A6%82%E8%BF%B0/</id>
    <published>2020-05-15T06:26:57.000Z</published>
    <updated>2020-05-16T09:21:03.551Z</updated>
    
    <content type="html"><![CDATA[<p><strong>OSI七层参考模型:</strong><br>1.应用层：能够产生网络流量能够和用户交互的应用程序；<br>2.表示层：加密，压缩，开发人员；<br>3.会话层：服务和客户建立的会话：netstat -n；<br>4.传输层：可靠传输建立会话，不可靠传输，流量控制；<br>5.网络层：IP地址编址，选择最佳路径；<a id="more"></a><br>6.数据链路层：数据如何封装，添加物理层地址(MAC)；<br>7.物理层：电压，借口标准；</p><p><strong>网络排错：</strong>从底层到高层</p><p><strong>五层参考模型:</strong><br><strong>传输的过程：</strong><br><img src="/2020/05/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E6%A6%82%E8%BF%B0/001.png" width="100%" height="100%"></p><img src="/2020/05/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E6%A6%82%E8%BF%B0/002.png" width="100%" height="100%">]]></content>
    
    <summary type="html">
    
      &lt;p&gt;&lt;strong&gt;OSI七层参考模型:&lt;/strong&gt;&lt;br&gt;1.应用层：能够产生网络流量能够和用户交互的应用程序；&lt;br&gt;2.表示层：加密，压缩，开发人员；&lt;br&gt;3.会话层：服务和客户建立的会话：netstat -n；&lt;br&gt;4.传输层：可靠传输建立会话，不可靠传输，流量控制；&lt;br&gt;5.网络层：IP地址编址，选择最佳路径；&lt;/p&gt;
    
    </summary>
    
    
      <category term="计算机网络" scheme="https://chrisxb1996.github.io/categories/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/"/>
    
    
      <category term="计算机网络" scheme="https://chrisxb1996.github.io/tags/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/"/>
    
  </entry>
  
  <entry>
    <title>设计模式-工厂模式</title>
    <link href="https://chrisxb1996.github.io/2020/05/14/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F-%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F/"/>
    <id>https://chrisxb1996.github.io/2020/05/14/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F-%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F/</id>
    <published>2020-05-14T07:56:13.000Z</published>
    <updated>2020-05-15T06:47:57.322Z</updated>
    
    <content type="html"><![CDATA[<p><strong>核心：</strong>实现了创建者和调用者的分离，用工厂方法代替new操作。将选择实现类、创建对象统一管理和控制。从而将调用者跟我们的实现类解耦。<br><strong>三种类型的工厂模式：</strong><br><strong>1.简单工厂（使用较多）：</strong>又叫静态工厂模式，就是工厂类一般是使用静态方法，通过不同的方法(或是通过传递不同的参数)来返回不同的对象实例；<br><strong>2.工厂方法：</strong>为了避免简单工厂模式的缺点，不完全满足OCP（开闭原则）。工厂方法模式和简单工厂模式最大的不同：简单工厂模式只有一个（对于一个项目或者一个独立模块而言）工厂类，而工厂方法模式有一组实现了相同接口的工厂类。根据设计理论建议：工厂方法模式，<strong>但实际上，我们一般都用简单工厂模式</strong>；<a id="more"></a><br><strong>3.抽象工厂：</strong>用来生产不同产品族的全部产品：在有多个业务品种、业务分类时，通过抽象工厂模式产生需要的对象是一种非常好的解决方式；</p><p><strong>不使用工厂模式的情况：</strong></p><figure class="highlight java"><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="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Audi</span> <span class="keyword">implements</span> <span class="title">Car</span></span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"Audi跑！！！"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight java"><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="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Byd</span> <span class="keyword">implements</span> <span class="title">Car</span></span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"Byd跑！！！"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight java"><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="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">test01</span> </span>&#123; <span class="comment">//调用者</span></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">    Car c1 = <span class="keyword">new</span> Audi();</span><br><span class="line">    Car c2 = <span class="keyword">new</span> Byd();</span><br><span class="line">    c1.run();</span><br><span class="line">    c2.run();</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>简单工厂：</strong></p><figure class="highlight java"><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="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CarFactory</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Car <span class="title">createAudi</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> Audi();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Car <span class="title">createByd</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> Byd();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight java"><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="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">test01</span> </span>&#123;<span class="comment">//调用者</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        Car car1 = CarFactory.createAudi();</span><br><span class="line">        Car car2 = CarFactory.createByd();</span><br><span class="line">        car1.run();</span><br><span class="line">        car2.run();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><img src="/2020/05/14/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F-%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F/simplefactory.png" width="32%" height="32%"><p><strong>工厂方法：</strong><br>增加两个实现类：</p><figure class="highlight java"><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="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">CarFactory</span> </span>&#123;</span><br><span class="line">    <span class="function">Car <span class="title">createCar</span><span class="params">()</span></span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">AudiFactory</span> <span class="keyword">implements</span> <span class="title">CarFactory</span></span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Car <span class="title">createCar</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> Audi();</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">public</span> <span class="class"><span class="keyword">class</span> <span class="title">BydFactory</span> <span class="keyword">implements</span> <span class="title">CarFactory</span></span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Car <span class="title">createCar</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> Byd();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight java"><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="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">test01</span> </span>&#123;<span class="comment">//调用者</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        Car car1 = <span class="keyword">new</span> AudiFactory().createCar();</span><br><span class="line">        Car car2 = <span class="keyword">new</span> BydFactory().createCar();</span><br><span class="line">        car1.run();</span><br><span class="line">        car2.run();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><img src="/2020/05/14/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F-%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F/factorymethod.png" width="48%" height="48%"><p><strong>抽象工厂：</strong><br><img src="/2020/05/14/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F-%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F/abstractfactory.png" width="100%" height="100%"></p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;&lt;strong&gt;核心：&lt;/strong&gt;实现了创建者和调用者的分离，用工厂方法代替new操作。将选择实现类、创建对象统一管理和控制。从而将调用者跟我们的实现类解耦。&lt;br&gt;&lt;strong&gt;三种类型的工厂模式：&lt;/strong&gt;&lt;br&gt;&lt;strong&gt;1.简单工厂（使用较多）：&lt;/strong&gt;又叫静态工厂模式，就是工厂类一般是使用静态方法，通过不同的方法(或是通过传递不同的参数)来返回不同的对象实例；&lt;br&gt;&lt;strong&gt;2.工厂方法：&lt;/strong&gt;为了避免简单工厂模式的缺点，不完全满足OCP（开闭原则）。工厂方法模式和简单工厂模式最大的不同：简单工厂模式只有一个（对于一个项目或者一个独立模块而言）工厂类，而工厂方法模式有一组实现了相同接口的工厂类。根据设计理论建议：工厂方法模式，&lt;strong&gt;但实际上，我们一般都用简单工厂模式&lt;/strong&gt;；&lt;/p&gt;
    
    </summary>
    
    
      <category term="设计模式" scheme="https://chrisxb1996.github.io/categories/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"/>
    
    
      <category term="Java" scheme="https://chrisxb1996.github.io/tags/Java/"/>
    
      <category term="设计模式" scheme="https://chrisxb1996.github.io/tags/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"/>
    
      <category term="工厂模式" scheme="https://chrisxb1996.github.io/tags/%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F/"/>
    
  </entry>
  
  <entry>
    <title>设计模式-单例模式</title>
    <link href="https://chrisxb1996.github.io/2020/05/13/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F-%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F/"/>
    <id>https://chrisxb1996.github.io/2020/05/13/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F-%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F/</id>
    <published>2020-05-13T09:12:28.000Z</published>
    <updated>2020-05-14T13:07:29.495Z</updated>
    
    <content type="html"><![CDATA[<p><strong>核心作用：</strong>保证一个类只有一个实例，并且提供一个访问该实例的全局访问点,减少了系统性能开销。<br><strong>常见应用场景：</strong>Windows的任务管理器就是很典型的单例模式；数据库连接池的设计一般也是采用单例模式…<br><strong>常见的五种单例模式实现方式：</strong><br>  1.饿汉式：线程安全，调用效率高。 但是，不能延时加载；<br>  2.懒汉式：线程安全，调用效率不高，可以延时加载；<br>  3.静态内部类式：线程安全，调用效率高，可以延时加载；<a id="more"></a><br>  4.枚举式：线程安全，调用效率高，不能延时加载。并且可以天然的防止反射和反序列化创建对象的漏洞！<br>  5.<del>双重检测锁式</del>：JVM底层内部模型原因，偶尔会出问题。<strong>不建议使用；</strong></p><p>饿汉式：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//饿汉式：</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SingletonDemo01</span> </span>&#123;</span><br><span class="line">    <span class="comment">//类初始化时，上来先创建对象（没有延时加载的优势），加载类时，天然线程安全</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> SingletonDemo01 instance = <span class="keyword">new</span> SingletonDemo01();</span><br><span class="line">    <span class="comment">//构造器私有</span></span><br><span class="line">    <span class="function"><span class="keyword">private</span>  <span class="title">SingletonDemo01</span><span class="params">()</span></span>&#123;&#125;</span><br><span class="line">    <span class="comment">//优点：方法没有同步调用效率高</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> SingletonDemo01 <span class="title">getInstance</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span>  instance;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>懒汉式：</p><figure class="highlight java"><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"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SingletonDemo02</span> </span>&#123;</span><br><span class="line">    <span class="comment">//类初始化时，不创建对象（延时加载，真正用的时候再创建）</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> SingletonDemo02 instance;</span><br><span class="line">    <span class="comment">//构造器私有</span></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="title">SingletonDemo02</span><span class="params">()</span></span>&#123;&#125;</span><br><span class="line">    <span class="comment">//需要加同步，保证单例模式，效率较低</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">synchronized</span> SingletonDemo02 <span class="title">getInstance</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(instance == <span class="keyword">null</span>) instance = <span class="keyword">new</span> SingletonDemo02();</span><br><span class="line">        <span class="keyword">return</span>  instance;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>静态内部类式:</p><figure class="highlight java"><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"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SingletonDemo03</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">SingletonInnerClass</span></span>&#123;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> SingletonDemo03 instance = <span class="keyword">new</span> SingletonDemo03();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//构造器私有</span></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="title">SingletonDemo03</span><span class="params">()</span></span>&#123;&#125;</span><br><span class="line">    <span class="comment">//优点：方法没有同步调用效率高</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> SingletonDemo03 <span class="title">getInstance</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span>  SingletonInnerClass.instance;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>枚举式:</p><figure class="highlight java"><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="comment">//枚举类方式：线程安全，但没有延时加载；同时能够避免反射和反序列的漏洞</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">enum</span> SingletonDemo04 &#123;</span><br><span class="line">    INSTANCE;</span><br><span class="line">    <span class="comment">//可以自己添加一些操作方法</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">instanceOper</span><span class="params">()</span></span>&#123;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>如何选用合适的单例模式：</strong><br>单例对象占用资源少，不需要延时加载：枚举式 &gt; 饿汉式;<br>单例对象占用资源大，需要 延时加载：静态内部类式 &gt; 懒汉式;</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;&lt;strong&gt;核心作用：&lt;/strong&gt;保证一个类只有一个实例，并且提供一个访问该实例的全局访问点,减少了系统性能开销。&lt;br&gt;&lt;strong&gt;常见应用场景：&lt;/strong&gt;Windows的任务管理器就是很典型的单例模式；数据库连接池的设计一般也是采用单例模式…&lt;br&gt;&lt;strong&gt;常见的五种单例模式实现方式：&lt;/strong&gt;&lt;br&gt;  1.饿汉式：线程安全，调用效率高。 但是，不能延时加载；&lt;br&gt;  2.懒汉式：线程安全，调用效率不高，可以延时加载；&lt;br&gt;  3.静态内部类式：线程安全，调用效率高，可以延时加载；&lt;/p&gt;
    
    </summary>
    
    
      <category term="设计模式" scheme="https://chrisxb1996.github.io/categories/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"/>
    
    
      <category term="Java" scheme="https://chrisxb1996.github.io/tags/Java/"/>
    
      <category term="设计模式" scheme="https://chrisxb1996.github.io/tags/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"/>
    
      <category term="单例模式" scheme="https://chrisxb1996.github.io/tags/%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F/"/>
    
  </entry>
  
  <entry>
    <title>JVM核心机制-类加载过程</title>
    <link href="https://chrisxb1996.github.io/2020/05/13/Java/JVM%E6%A0%B8%E5%BF%83%E6%9C%BA%E5%88%B6-%E7%B1%BB%E5%8A%A0%E8%BD%BD%E8%BF%87%E7%A8%8B/"/>
    <id>https://chrisxb1996.github.io/2020/05/13/Java/JVM%E6%A0%B8%E5%BF%83%E6%9C%BA%E5%88%B6-%E7%B1%BB%E5%8A%A0%E8%BD%BD%E8%BF%87%E7%A8%8B/</id>
    <published>2020-05-13T06:38:30.000Z</published>
    <updated>2020-05-18T04:49:14.599Z</updated>
    
    <content type="html"><![CDATA[<p><strong>类加载的作用：</strong>将class文件字节码内容加载到内存中，并将这些静态数据转换成方法区中的运行时数据结构，在堆中生成一个代表这个类的java.lang.Class对象，作为方法区类数据的访问入口：</p><img src="/2020/05/13/Java/JVM%E6%A0%B8%E5%BF%83%E6%9C%BA%E5%88%B6-%E7%B1%BB%E5%8A%A0%E8%BD%BD%E8%BF%87%E7%A8%8B/JVM01.png" width="80%" height="80%"><p><strong>类加载器的层次结构(树状结构):</strong></p><ul><li>引导类加载器（bootstrap class loader）：它用来加载 Java 的核心库)，是用C来实现的，并不继承自 java.lang.ClassLoader；<a id="more"></a></li><li>扩展类加载器（extensions class loader）：用来加载 Java 的扩展库，Java 虚拟机的实现会提供一个<strong>扩展库</strong>目录。该类加载器在此目录里面查找并加载 Java类，由ExtClassLoader实现；</li><li>应用程序类加载器（application class loader）：它根据 Java 应用的类路径来加载 Java 类，一般来说，Java 应用的类都是由它来完成加载的，由AppClassLoader实现；</li><li>自定义类加载器： 开发人员可以通过继承 java.lang.ClassLoader类的方式，实现自己的类加载器，以满足一些特殊的需求。</li></ul><p>注意：<u>类加载器加载类的时候是线程安全的</u></p><img src="/2020/05/13/Java/JVM%E6%A0%B8%E5%BF%83%E6%9C%BA%E5%88%B6-%E7%B1%BB%E5%8A%A0%E8%BD%BD%E8%BF%87%E7%A8%8B/JVM02.png" width="80%" height="80%"><p><strong>双亲委托机制：</strong></p><ul><li>就是某个特定的类加载器在接到加载类的请求时，首先将加载任务委托给父类加载器，依次追溯，直到最高的爷爷辈的，如果父类加载器可以完成类加载任务，就成功返回；只有父类加载器无法完成此加载任务时，才自己去加载。</li><li>双亲委托机制是为了保证 Java 核心库的类型安全，这种机制就保证不会出现用户自己能定义java.lang.Object类的情况。</li><li>类加载器除了用于加载类，也是安全的最基本的屏障。</li><li>双亲委托机制是代理模式的一种，但并不是所有的类加载器都采用双亲委托机制：tomcat服务器类加载器也使用代理模式，所不同的是它是首先尝试去加载某个类，如果找不到再代理给父类加载器，这与一般类加载器的顺序是相反的。</li></ul>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;&lt;strong&gt;类加载的作用：&lt;/strong&gt;将class文件字节码内容加载到内存中，并将这些静态数据转换成方法区中的运行时数据结构，在堆中生成一个代表这个类的java.lang.Class对象，作为方法区类数据的访问入口：&lt;/p&gt;
&lt;img src=&quot;/2020/05/13/Java/JVM%E6%A0%B8%E5%BF%83%E6%9C%BA%E5%88%B6-%E7%B1%BB%E5%8A%A0%E8%BD%BD%E8%BF%87%E7%A8%8B/JVM01.png&quot; width=&quot;80%&quot; height=&quot;80%&quot;&gt;

&lt;p&gt;&lt;strong&gt;类加载器的层次结构(树状结构):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;引导类加载器（bootstrap class loader）：它用来加载 Java 的核心库)，是用C来实现的，并不继承自 java.lang.ClassLoader；&lt;/li&gt;&lt;/ul&gt;
    
    </summary>
    
    
      <category term="Java" scheme="https://chrisxb1996.github.io/categories/Java/"/>
    
    
      <category term="Java" scheme="https://chrisxb1996.github.io/tags/Java/"/>
    
      <category term="JVM" scheme="https://chrisxb1996.github.io/tags/JVM/"/>
    
  </entry>
  
</feed>
