<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>数据结构 on Archai&#39;s home</title>
    <link>https://blog.archai.space/tags/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/</link>
    <description>Recent content in 数据结构 on Archai&#39;s home</description>
    <generator>Hugo -- gohugo.io</generator>
    <lastBuildDate>Thu, 10 Jun 2021 00:00:00 +0000</lastBuildDate><atom:link href="https://blog.archai.space/tags/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>外部排序相关</title>
      <link>https://blog.archai.space/p/%E5%A4%96%E9%83%A8%E6%8E%92%E5%BA%8F%E7%9B%B8%E5%85%B3/</link>
      <pubDate>Thu, 10 Jun 2021 00:00:00 +0000</pubDate>
      
      <guid>https://blog.archai.space/p/%E5%A4%96%E9%83%A8%E6%8E%92%E5%BA%8F%E7%9B%B8%E5%85%B3/</guid>
      <description>由于数据元素太多，无法一次全部读入内存进行内部排序，这是就要通过外部排序来解决...</description>
    </item>
    
    <item>
      <title>排序算法相关</title>
      <link>https://blog.archai.space/p/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95%E7%9B%B8%E5%85%B3/</link>
      <pubDate>Thu, 10 Jun 2021 00:00:00 +0000</pubDate>
      
      <guid>https://blog.archai.space/p/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95%E7%9B%B8%E5%85%B3/</guid>
      <description>排序算法 平均时间复杂度 空间复杂度 稳定性 适用情况     插入排序 $O(n^2)$ O(1) 稳定 n较小，初始序列基本有序   希尔排序 $O(n^{1.3})$ O(1) 不稳定    冒泡排序 $O(n^2)$ O(1) 稳定 n较小，初始序列基本有序   快速排序 $O(n\log_2n)$ $O(nlog_2n)$ 不稳定 初始序列无序   简单选择排序 $O(n^2)$ O(1) 不稳定 n较小   堆排序 $O(n\log_2n)$ O(1) 不稳定 n较大或只排前几位   2-路归并排序 $O(n\log_2n)$ O(n) 稳定 n很大   链式基数排序 $O(d(n+rd))$ $O(rd)$ 稳定 n大，关键字值小    相关概念 1.</description>
    </item>
    
    <item>
      <title>查找算法相关</title>
      <link>https://blog.archai.space/p/%E6%9F%A5%E6%89%BE%E7%AE%97%E6%B3%95%E7%9B%B8%E5%85%B3/</link>
      <pubDate>Sun, 06 Jun 2021 00:00:00 +0000</pubDate>
      
      <guid>https://blog.archai.space/p/%E6%9F%A5%E6%89%BE%E7%AE%97%E6%B3%95%E7%9B%B8%E5%85%B3/</guid>
      <description>顺序查找 typedef struct{//查找表的数据结构（顺序表）  int *elem;//动态数组基址  int TableLen;//查找表长度 }SSTable; int Seq_Search(SSTable ST,int key){ ST.elem[0]=key; int i; for (i = ST.TableLen;ST.elem[i]!=key ; i--) {}//从后往前查找，最终返回下标i  return i;//返回0说明没找到 } 效率分析 对于长度为n的顺序表，如果查找成功 $$ ASL={\frac{1+2+&amp;hellip;+n}{n}}=\frac{n+1}{2} $$ 若果查找失败，则 $ASL=n+1$
总体上，该算法时间复杂度为 $O(n)$
优化思路 1.如果使得表中的元素有序存放……，可以构造出一棵查找判定树
此时，查找失败时$ASL=\frac{1+2+&amp;hellip;+n+n}{n+1}=\frac{n}{2}+\frac{n}{n+1}$
优点： 容易查找失败时ASL更小
2.如果各元素被查找的概率不同……，可以把概率大的靠前
优点： 容易查找成功时ASL更小
折半查找  折半查找，又称“二分查找”，仅适用于有序的顺序表。
 针对升序排列的顺序表，代码实现如下
typedef struct{//查找表的数据结构（顺序表）  int *elem;//动态数组基址  int TableLen;//查找表长度 }SSTable; int BinarySearch(SSTable L,int key){ int low=0,high=L.TableLen-1,mid; while (low&amp;lt;=high) { mid=(low+high)/2; if (L.</description>
    </item>
    
    <item>
      <title>图的应用</title>
      <link>https://blog.archai.space/p/%E5%9B%BE%E7%9A%84%E5%BA%94%E7%94%A8/</link>
      <pubDate>Fri, 04 Jun 2021 00:00:00 +0000</pubDate>
      
      <guid>https://blog.archai.space/p/%E5%9B%BE%E7%9A%84%E5%BA%94%E7%94%A8/</guid>
      <description>一、最小生成树 📌什么是生成树？ 连通图的生成树是包含图中所有顶点的一个极小连通子图，通俗地讲，就是“边尽可能少，但需保持连通”。
规律： 对于一个顶点数|V|=n的树，其生成树的边数|E|=n-1。如果将|E|+1，必然会形成回路；如果将|E|-1，则会成为非连通图。

📌什么是最小生成树？  最小生成树，也称最小代价树(Minimum Spanning Tree，MST)
 是带权连通无向图的生成树中边的权值之和最小的一棵树，联系实际问题不难理解其中“最小代价”的意味。
Prim（普利姆算法），Kruskal（克鲁斯卡尔算法）就是寻找最小生成树的常用算法。
1.Prim（普利姆算法）  从某一顶点开始，每次将代价最小的新顶点纳入生成树，直至所有顶点都纳入为止。
 图示 
易知，此方法得到的最小生成子树是不唯一的。
代码实现 void MiniSpanTree_PRIMI(Graph G,int u){ //从顶点u出发找G的最小生成树  for (int i = 0; i &amp;lt;G.vexnum; ++i) {//辅助数组初始化  if(i!=u){ closedge[i]={u,G.arcs[u][i]}; } } closedge[u].lowcost=0; for (int j = 0; j &amp;lt; G.vexnum; j++) { k=minimum(closedge);//求生成树的下一个节点  cout&amp;lt;&amp;lt;cloedge[k].adjvex&amp;lt;&amp;lt;G.vex[k]; closedge[k].lowcost=0; for (int i = 0; i &amp;lt; G.vexnum; i++) { if (G.arc[k][j].adj&amp;lt;closedge[j].lowcost) { closedge[j]={G.</description>
    </item>
    
    <item>
      <title>图的遍历</title>
      <link>https://blog.archai.space/p/%E5%9B%BE%E7%9A%84%E9%81%8D%E5%8E%86/</link>
      <pubDate>Thu, 03 Jun 2021 00:00:00 +0000</pubDate>
      
      <guid>https://blog.archai.space/p/%E5%9B%BE%E7%9A%84%E9%81%8D%E5%8E%86/</guid>
      <description>广度优先遍历（BFS）  BFS(Breadth-First-Search)，参考对树的层序遍历
 
对上面的图从①出发进行BFS得到序列：
①②⑤ ⑥ ③⑦ ④⑧
若采用不同的储存结构，可能会得到不同的遍历结果（这个差异主要来自寻找邻接点的过程），对于邻接矩阵存储的图，由于邻接矩阵是唯一的，所以BFS序列也是唯一的；同理，邻接表存储的图BFS序列不唯一。
BFS算法  与树的层序遍历不同的是，由于图中存在回路，遍历过程中会出现重复访问的问题，故可构造visited数组，用来标记已访问过的数组。
此外，还应针对非连通图做额外的判断，遍历完一个连通分量（极大连通子图）后，遍历查找visited数组中是否还存在未遍历的，如果有即为另一连通分量，继续调用BFS即可。
 void BFS(Graph G,int v); bool visited[MAX_VERTEX_NUM]; SqQueue Q;//辅助队列 void BFSTraverse(Graph G){ //初始化visited数组  for (int i = 0; i &amp;lt; G.vexnum; ++i) {//使下标从1开始  visited[i]=false; } //对非连通图的处理  for (int v = 0; v &amp;lt; G.vexnum; ++v) { if (!visited[v]) BFS(G,v); } } //从顶点v出发广度优先遍历图G void BFS(Graph G,int v){ visit(v); visited[v]=true; EnQueue(Q,v);//顶点v入队列Q  while(!isEmpty(Q)){ DeQueue(Q,v);//顶点v出队列Q  for (w=FirstNeighbor(G,v);w&amp;gt;=0;w=NextNeighbor(G,v,w))//处理v的所有邻接点  if (!</description>
    </item>
    
    <item>
      <title>图的存储</title>
      <link>https://blog.archai.space/p/%E5%9B%BE%E7%9A%84%E5%AD%98%E5%82%A8/</link>
      <pubDate>Wed, 02 Jun 2021 00:00:00 +0000</pubDate>
      
      <guid>https://blog.archai.space/p/%E5%9B%BE%E7%9A%84%E5%AD%98%E5%82%A8/</guid>
      <description>邻接矩阵  Vextex/Vertices 顶点; Martix 矩阵; Arc 弧.
 
代码实现 #define MaxVextexNum 100//容许存储的最大顶点数  typedef struct{ char Vex[MaxVextexNum]; //可以将定点之间的关系用int 类型01表示，也可定义为boolean/枚举类型，占空间更小  bool Edge[MaxVextexNum][MaxVextexNum]; int vexnum,arcnum;//顶点数和弧|边数 }MGraph; 即
找度 根据邻接矩阵计算结点的度TD
    无向图 有向图     $TD(V_i)$ 第i行（或i列）中非零元素的个数 $ID(V_i)$ : i行非零元素个数
$OD(V_i)$: i列非零元素个数
TD=ID+OD    对于带权图（网） 
#define MaxVextexNum 100//容许存储的最大顶点数 #define INIFINITY //宏定义，表示无穷  typedef char VextexType;//顶点 typedef int EdgeType;//权值  typedef struct{ VextexType Vex[MaxVextexNum]; EdgeType Edge[MaxVextexNum][MaxVextexNum]; int vexnum,arcnum; }MGraph; 复杂度 空间复杂度来自数组Vex[]跟Edge[]，故空间复杂度为$|V|+|V|^2=O(|V|^2)$，即为顶点数量的二次方，故此方法更适合存储稠密图，不然有较多浪费。</description>
    </item>
    
    <item>
      <title>AVL树</title>
      <link>https://blog.archai.space/p/avl%E6%A0%91/</link>
      <pubDate>Sun, 23 May 2021 00:00:00 +0000</pubDate>
      
      <guid>https://blog.archai.space/p/avl%E6%A0%91/</guid>
      <description>平衡二叉树是Adelson-Velsky和 Landis发明，故命名为AVL树。也称平衡二叉查找树。
 ✨特点： ①左子树&amp;lt;根&amp;lt;右子树； ②任一节点，左右子树高度之差不超过1.
平衡因子 $平衡因子=左子树高-右子树高$
AVL树的插入操作 AVL树插入新结点导致不平衡之后，只需将最小不平衡子树平衡，其他祖先结点会随之恢复平衡。
调整最小不平衡子树 注意：调整过后必须保证其BST的特性，即“左子树1.LL  即在以A为根节点的树的左孩子B的左子树上插入新结点，导致A成为最小不平衡子树。
 
调整过程如下：

2.RR  即在以A为根节点的树的右孩子B的右子树上插入新结点，导致A成为最小不平衡子树。
 
调整过程如下：

3.LR  即在以A为根节点的树的左孩子B的右子树上插入新结点，导致A成为最小不平衡子树。
 
观察得知，所进行的调整就是保证$|平衡因子|&amp;lt;=1$，因此若插入操作使得
左 - 右 &amp;gt; 1 =&amp;gt; 右旋
右 - 左 &amp;gt; 1 =&amp;gt;左旋
而当进行了LR插入操作之后，导致以A为根节点的树 左-右&amp;gt;1，理应右旋但是，由上述结果可知，经过右旋之后：

可以看到，为了保证其左子树&amp;lt;根&amp;lt;右子树的特性，经过调整后，依然存在右-左&amp;gt;1的问题；
因此，对于LR型不能简单进行右旋调整，应该先将其转化为LL型 (左旋)，再进行右旋；
为此，我们需要将BR结点展开，之后旋转成为LL型插入

可以看到，展开后又出现两种插入情况CL&amp;amp;CR，但其实两者处理大同小异：
CR插入调整过程如下：

4.RL  即在以A为根节点的树的右孩子B的左子树上插入新结点，导致A成为最小不平衡子树。
 
参考LR型，其调整过程如下：

查找操作效率分析 Assuming that, $n_h$表示深度为h的平衡树中含有的最少结点，则
$n_0=0$,$n_1=1$,$n_2=2$&amp;hellip;存在递归关系 $n_h=n_{h-1}+n_{h-2}+1$,即左右子树结点之和+根节点。
可以证明(AVL证明)，n个结点的平衡二叉树最大深度数量级为$\log_2n$，则其查找操作的复杂度为$O(\log_2n)$</description>
    </item>
    
    <item>
      <title>哈夫曼树</title>
      <link>https://blog.archai.space/p/%E5%93%88%E5%A4%AB%E6%9B%BC%E6%A0%91/</link>
      <pubDate>Sun, 23 May 2021 00:00:00 +0000</pubDate>
      
      <guid>https://blog.archai.space/p/%E5%93%88%E5%A4%AB%E6%9B%BC%E6%A0%91/</guid>
      <description>基本概念 1.结点的权
每个结点带有的具有某种现实意义的数值(比如代表重要性等)
2.结点的带权路径长度
从树的根到该结点的路径长度（经过的边数）与该结点上权值的乘积
3.树的带权路径长度
树中所有叶结点的带权路径长度之和（WPL, Weighted Path Length）
$WPL=\sum_{i=1}^{n}w_il_i$
✨4.哈夫曼树
在含有n个带权叶结点的二叉树中，其中带权路径长度（WPL）最小的二叉树称为哈夫曼树，也称最优二叉树
构造哈夫曼树 给定n个权值分别为 $w_1,w_2,&amp;hellip;,w_n$ 的结点，其构造过程描述如下：
① 将这n个结点分别作为n棵仅含一个结点的二叉树，构成森林F
② 构造一个新结点，从F中选取两棵根结点权值最小的树作为新结点的左右子树，并且将新结点的权值置为左、右子树上根结点的权值之和。
③ 从F中删除刚才选出的两棵树，同时将新得到的树加入F中。
④ 重复步骤②和③，直至F中只剩下一棵树为止。
假设给定结点在经过步骤①之后如下

则其②③④步骤为：

$WPL_{min}=1*7+2*3+3*2+4*1+4*2=31$
或者

$WPL_{min}=1*7+3*(1+2+2+3)=31$
👇👇👇👇👇👇
哈夫曼树特点： ① 每个初始结点最终都成为叶结点，且权值越小的结点到根结点的路径长度越大。 ② 哈夫曼树的结点总数为2n-1。 ③ 哈夫曼树中不存在度为1的结点。 ④ 哈夫曼树并不唯一，但WPL必然相同且为最优。
哈夫曼编码 固定长度编码 如ASCII码
可变长度编码 前缀编码 没有一个编码是另一个编码的前缀

哈夫曼编码 由哈夫曼树得到哈夫曼编码——字符集中的每个字符作为一个叶子结点，各个字符出现的频度作为结点的权值，根据之前介绍的方法构造哈夫曼树。
✨ 应用
可用于数据压缩
如图，为英文字母使用频率表，若不进行压缩，第 i 个字母频率用$l_i表示$，路径长至少为5($2^4&amp;lt;26&amp;lt;2^5$)，则
$WPL=5×\sum_{i=1}^{n}l_i$=500

若通过构造哈夫曼树进行哈夫曼编码
则$WPL_{min}=$
$v=\frac{WPL_{min}}{WPL}$</description>
    </item>
    
    <item>
      <title>树</title>
      <link>https://blog.archai.space/p/%E6%A0%91/</link>
      <pubDate>Sat, 22 May 2021 00:00:00 +0000</pubDate>
      
      <guid>https://blog.archai.space/p/%E6%A0%91/</guid>
      <description>普通树 对于一棵普通类型的树形结构，可将其转化为二叉树之后再参考二叉树的方法进行相关操作。
孩子兄弟表示法（链式结构） 通过此方法可将普通树转化为二叉树
//孩子兄弟即Child, Sibling typedef struct CSNode{ Elemtype data; struct CSNode *firstchild,*nextsibling;//第一个孩子和右兄弟指针,等价于*lchild,*rchild }CSNode,*CSTree 图示如下

树的遍历 1.深度优先遍历（先根遍历&amp;amp;后根遍历）
 先根遍历   若树非空，先访问根结点，再依次对每棵子树进行先根遍历(递归)。
 对如上图所示的树进行先根遍历：
A B C D
A	(BE )	(CF)	(DG)
A	(BEH) (CF)	(DG)
即先根遍历序列为A B E H C F D G
发现与通过“孩子兄弟法”将树转为二叉树后的先序遍历序列相同
 后根遍历   若树非空，先依次对每棵子树进行后根遍历，最后再访问根结点。
 对如上图所示的树进行后根遍历：
B	C	D	A
(E	B) (F	C) (G	D) A
(H	E	B) (F	C) (GD) A</description>
    </item>
    
    <item>
      <title>线索二叉树</title>
      <link>https://blog.archai.space/p/%E7%BA%BF%E7%B4%A2%E4%BA%8C%E5%8F%89%E6%A0%91/</link>
      <pubDate>Sat, 15 May 2021 00:00:00 +0000</pubDate>
      
      <guid>https://blog.archai.space/p/%E7%BA%BF%E7%B4%A2%E4%BA%8C%E5%8F%89%E6%A0%91/</guid>
      <description>线索二叉树 WHY  方便从任一个结点出发，找到其前驱、后继；方便遍历
 普通二叉树中，对任意一个结点，若想找到其前驱/后继结点，只能再进行一次相应的前/中/后序遍历才行，复杂度太高。
为此，我们引入前驱线索，后继线索的概念。其中，前驱线索由左孩子指针充当，后继线索由右孩子指针充当。
typedef struct BiTNode{ ElemType data; struct BiTNode *lchild,*rchild; }BiTNode,*BiTree; 构建出如下图所示的结构：

但是，
*lchild(*rchild)有可能指向存在的结点，为此我们引入线索标志。当线索标志为1时，表示孩子指针指向前驱后继，线索标志为0时，表示孩子指针指向左右孩子。此时
typedef struct ThreadNode{ ElemType data; struct ThreadNode *lchild,*rchild; int ltag,rtag;//左右线索标志 }ThreadNode,*ThreadTree; 这样，每一个线索链表中的结点就可以图示为:

HOW  如何分别用代码实现前中后序遍历下的线索链表
 1.中序线索化  其实中序线索化的过程就是再进行一遍中序遍历，为每个节点添加额外的信息(lchild, rcild, ltag, rtag).
 🍔初始定义结构体
typedef struct ThreadNode{ ElemType data; struct ThreadNode *lchild,*rchild; int ltag,rtag; }ThreadNode,*ThreadTree; 🍔定义前驱指针
ThreadNode *pre=NULL;  前驱指针还可以定义在局部，这里为了方便起见，将pre定义为全局。
 🍔开始定义处理函数
void CreatInThread(ThreadTree T){ pre=NULL; if(T!=NULL){ InThread(T); if(pre-&amp;gt;rchild==NULL){ pre-&amp;gt;rtag=1; } } }  注意：最后一个节点单独处理</description>
    </item>
    
    <item>
      <title>由遍历序列构造出二叉树</title>
      <link>https://blog.archai.space/p/%E7%94%B1%E9%81%8D%E5%8E%86%E5%BA%8F%E5%88%97%E6%9E%84%E9%80%A0%E5%87%BA%E4%BA%8C%E5%8F%89%E6%A0%91/</link>
      <pubDate>Sun, 09 May 2021 00:00:00 +0000</pubDate>
      
      <guid>https://blog.archai.space/p/%E7%94%B1%E9%81%8D%E5%8E%86%E5%BA%8F%E5%88%97%E6%9E%84%E9%80%A0%E5%87%BA%E4%BA%8C%E5%8F%89%E6%A0%91/</guid>
      <description>由遍历序列构造出二叉树 仅知道一种遍历序列是无法确定唯一的二叉树的，以中序遍历为例，对于一个中序遍历序列“BDCAE”，其对应的树形结构可能有下面三种：

因此，至少需要两种遍历序列才可以推知树形结构。
1.前序+中序遍历序列 🎈基本步骤 由前序遍历的特性得知，前序遍历中第一个节点必然为根节点，因此根据中序遍历特性，根节点左边为左子树下的所有节点，右边为右子树下的所有节点，然后分别在左子树序列右子树序列中重复进行即可。
🎈示例
 前序遍历序列：A D B C E 中序遍历序列：B D C A E  首先能确定根节点为A，根据中序遍历序列可以得到：

对于左子树BDC，根据前序遍历，此子树根节点为D，根据中序遍历序列：

至此，二叉树的还原工作就完成了！至于更复杂的序列，逐步推断即可😋
2.后序+中序遍历序列 🔑与1不用的是，后序遍历中根节点为后序遍历序列尾部的那个节点，其余参照1即可！
3.层序遍历+中序遍历 🔑 根据层序遍历特性，层序遍历中根节点始终在子树前面，“根左右”
🎈示例
 层序遍历序列：A D E B C 中序遍历序列：B D C A E  根节点为A，根据中序遍历序列可以得到：

对于左子树BDC，根据前序遍历，此子树根节点为D，根据中序遍历序列：

思考  如果前序，后续，层序两两组合能否确定唯一的树结构？
 
假设给定序列如下：
 前序：A B 后序：B A 层序：A B  其两两组合都满足两种结构：

因此前序，后续，层序两两组合不能确定唯一的树结构。</description>
    </item>
    
    <item>
      <title>向量空间管理策略</title>
      <link>https://blog.archai.space/p/%E5%90%91%E9%87%8F%E7%A9%BA%E9%97%B4%E7%AE%A1%E7%90%86%E7%AD%96%E7%95%A5/</link>
      <pubDate>Mon, 16 Nov 2020 00:00:00 +0000</pubDate>
      
      <guid>https://blog.archai.space/p/%E5%90%91%E9%87%8F%E7%A9%BA%E9%97%B4%E7%AE%A1%E7%90%86%E7%AD%96%E7%95%A5/</guid>
      <description>向量的空间管理，有静态和动态两种策略
 静态空间管理策略 开辟内部数组_elem[]并使用一段地址连续的物理空间，_capacity表示总容量 ，_size表示当前的实际规模n，示意图如下：

若采用静态空间管理策略，容量_capacity固定，则有明显的不足&amp;hellip;
上溢/overflow： _elem[]不足以存放所有元素，尽管此时系统往往仍有足够的空间
下溢/underflow：  _elem[]中的元素寥寥无几，装填因子 λ = _size / _capacity &amp;laquo; 50%
动态空间管理策略 在即将上溢时，适当扩大内部数组的容量
递增策略 当需要扩容时，为_capacity追加固定大小的空间，即
T* oldElem = _elem; _elem = new T[ _capacity += INCREMENT ]; 考虑最坏情况，在初始容量为0的空向量中连续插入n = m*I个元素
那么，在第1，I+1，2I+1，3I+1&amp;hellip;次插入元素时都需要扩容，表示为

倍增策略 当需要扩容时，增加_capacity 为原来的两倍，即
T* oldElem = _elem; _elem = new T[ _capacity &amp;lt;&amp;lt;= 1 ]; 考虑最坏情况，在初始容量为1的空向量中连续插入n = 2^m个元素
那么，在第1，2，4，8&amp;hellip;次插入元素时都需要扩容，表示为

两种策略的复杂度分析 考虑最坏的情况，两种策略的复杂度分别为
 递增策略： 为算术级数，0+I+2I+&amp;hellip;=O(n ²) 倍增策略： 为几何级数，1+2¹+2²+2³+&amp;hellip;=O(2^m)=O(n)      递增策略 倍增策略     累计时间 O(n ²) O(n)   分摊时间 O(n) O(1)   装填因子 λ ≈100% &amp;gt;50%    可以看出，倍增策略在牺牲空间的基础上，换取时间上的巨大提升，可采取√</description>
    </item>
    
    <item>
      <title>减而治之与分而治之</title>
      <link>https://blog.archai.space/p/%E5%87%8F%E8%80%8C%E6%B2%BB%E4%B9%8B%E4%B8%8E%E5%88%86%E8%80%8C%E6%B2%BB%E4%B9%8B/</link>
      <pubDate>Sun, 15 Nov 2020 00:00:00 +0000</pubDate>
      
      <guid>https://blog.archai.space/p/%E5%87%8F%E8%80%8C%E6%B2%BB%E4%B9%8B%E4%B8%8E%E5%88%86%E8%80%8C%E6%B2%BB%E4%B9%8B/</guid>
      <description>减而治之(Decrease and conquer)  什么是“减而治之”？
为求解一个大规模的问题，可以将其划分为两个问题，其一平凡，另一规模缩减 ，分别求解子问题，由子问题的解得原问题的解
 
比如说，对于一个数组A的求和问题，可以设计如下的算法
sum( int A[], int n ) { return n &amp;lt; 1? 0 : sum(A, n - 1) + A[n - 1]; } 当规模缩减到一定程度后，抵达递归基，返回0
复杂度分析 1. 递归跟踪
 绘出计算过程中出现过的所有递归实例（及其调用关系） ，那么它们各自所需时间之总和，即为整体运行时间
 上例中，共计n+1个递归实例(分析)，各自只需O(1)时间 故总体运行时间为：
T(n) =O(1) × (n+1) =O(n)
2.递推方程
 对于大规模的问题、复杂的递归算法，递归跟踪不再适用 此时可采用另一抽象的方法&amp;hellip;
 在本例中，有T(n)=T(n-1) + O(1),T(0)=O(1)
则，T(n) = T(n-2)+O(2) = T(n-3)+O(3) = T(n-n)+O(n)=O(n)
 可以看到，两种分析方法的出来复杂度都为O(n)
 分而治之(Divide and conquer)  什么是“分而治之”？</description>
    </item>
    
    <item>
      <title>DS导论</title>
      <link>https://blog.archai.space/p/ds%E5%AF%BC%E8%AE%BA/</link>
      <pubDate>Tue, 10 Nov 2020 00:00:00 +0000</pubDate>
      
      <guid>https://blog.archai.space/p/ds%E5%AF%BC%E8%AE%BA/</guid>
      <description>导论  所谓算法，即特定计算模型下，旨在解决特定问题的指令序列。输入：待处理的信息（问题）输出：经处理的信息（答案）
 正确性 的确可以解决指定的问题
确定性 任一算法都可以描述为一个由基本操作组成的序列
可行性 每一基本操作都可实现，且在常数时间内完成
有穷性 对于任何输入，经有穷次基本操作，都可以得到输出
::: tip Algorithms + Data Structures = Programs
(Algorithms + Data Structures) x Efficiency = Computation
:::
如何评判算法的其优劣(计算模型)  实验统计是最直接的方法，但足以准确反映算法的真正效率？不足够！ - 不同的算法，可能更适应于不同规模的输入 - 不同的算法，可能更适应于不同类型的输入 - 同一算法，可能由不同程序员、用不同程序语言、经不同编译器生成 - 同一算法，可能实现并运行于不同的体系结构、操作系统&amp;hellip; 为给出客观的评判，需要抽象出一个理想的平台或模型 - 不再依赖于上述种种具体的因素 - 从而直接而准确地描述、测量并评价算法
 1.图灵机模型(TM) 
   组成 说明     Tape 依次均匀地划分为单元格 各存有某一字符，初始均为&#39;#&#39;   Head 总是对准某一单元格，并可 读取或改写其中的字符。每经过一个节拍，可 转向左侧或右侧的邻格   Alphabet 字符的种类有限   State TM总是处于有限种状态中的某一种 。每经过一个节拍 可按照规则转向另一种状态 。统一约定，&amp;lsquo;h&amp;rsquo; = halt(停止)    2.</description>
    </item>
    
  </channel>
</rss>
