<?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/categories/%E5%90%8E%E7%AB%AF/</link>
    <description>Recent content in 后端 on Archai&#39;s home</description>
    <generator>Hugo -- gohugo.io</generator>
    <lastBuildDate>Thu, 22 Jul 2021 00:00:00 +0000</lastBuildDate><atom:link href="https://blog.archai.space/categories/%E5%90%8E%E7%AB%AF/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>寻址方式与存储模式</title>
      <link>https://blog.archai.space/p/%E5%AF%BB%E5%9D%80%E6%96%B9%E5%BC%8F%E4%B8%8E%E5%AD%98%E5%82%A8%E6%A8%A1%E5%BC%8F/</link>
      <pubDate>Thu, 22 Jul 2021 00:00:00 +0000</pubDate>
      
      <guid>https://blog.archai.space/p/%E5%AF%BB%E5%9D%80%E6%96%B9%E5%BC%8F%E4%B8%8E%E5%AD%98%E5%82%A8%E6%A8%A1%E5%BC%8F/</guid>
      <description>寻址方式    基本寻址方式 特 征 优 点 缺 点 备 注     隐含寻址 操作数的存放地由操作码决定      立即寻址 操作数直接在指令中 加快执行速度 增加指令长度，不方便修改操作数 适用提供常数，设定初始值   寄存器寻址 操作数在指令指定的寄存器中 方便修改，访问寄存器加快指令执行，缩短指令长度，编程更灵活     直接寻址 操作数地址在指令中，操作数在主存单元中  指令字较长，不方便地址修改    间接寻址 操作数地址的地址在指令中，操作数在主存中 方便修改指针，编程更灵活 访问两次主存获取操作数，降低执行速度 形式地址，有效地址EA(=操作数地址)   寄存器间接寻址 操作数地址在指令指定的寄存器中，操作数在主存单元中 压缩指令长度，修改寄存器内容就可以修改主存地址指针  方便编写循环程序   相对寻址 操作数地址由PC和指令提供的地址偏移量决定,操作数在主存单元中   EA=PC+D，适用与地址无关的程序设计   基址寻址 操作数地址由基址寄存器(RB)和指令提供的地址偏移量决定，操作数在主存单元中 缩短指令长度，扩大寻址空间  大型计算机，用户的逻辑地址→主存的物理地址，EA=(RB)+D   变址寻址 操作数地址由变址寄存器(RI)和指令提供的地址偏移量决定，操作数在主存单元中   寻址到操作数RI内容(地址)自动修改，EA=(RI)+D   堆栈寻址 寻址方式由指令操作码决定   适用涉及堆栈操作的指令，EA=(SP)</description>
    </item>
    
    <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>PHP语法小结</title>
      <link>https://blog.archai.space/p/php%E8%AF%AD%E6%B3%95%E5%B0%8F%E7%BB%93/</link>
      <pubDate>Wed, 14 Oct 2020 00:00:00 +0000</pubDate>
      
      <guid>https://blog.archai.space/p/php%E8%AF%AD%E6%B3%95%E5%B0%8F%E7%BB%93/</guid>
      <description>基本语法 输出语句    语句 功能     echo 输出字符串类型   print_r 输出引用类型(对象,数组等)   var_dunp 检测变量类型    ::: tip echo语句可用于给前端返回响应体。比如前端通过ajax请求，可以在xhr.response中直接得到echo的内容 :::
变量&amp;amp;常量 👉🏼 变量
   语句 功能 返回值     isset() 检测变量是否存在 boolean   unset() 删除某个变量 none    👉🏼 常量
常量用const 或 define 定义，常量名一般全部大写，不受作用域的限制
::: tip
一般是define在类外定义常量，const在类内定义常量，并且const必须通过类名::变量名来进行访问。但是php5.3以上支持类外通过const定义常量。
:::
:::danger
const不能在条件语句中使用，必出错
:::
 参考文章 《PHP中define() 与 const定义常量的区别详解》</description>
    </item>
    
    <item>
      <title>JavaScript生成图片文件路径json</title>
      <link>https://blog.archai.space/p/javascript%E7%94%9F%E6%88%90%E5%9B%BE%E7%89%87%E6%96%87%E4%BB%B6%E8%B7%AF%E5%BE%84json/</link>
      <pubDate>Sun, 05 Jul 2020 00:00:00 +0000</pubDate>
      
      <guid>https://blog.archai.space/p/javascript%E7%94%9F%E6%88%90%E5%9B%BE%E7%89%87%E6%96%87%E4%BB%B6%E8%B7%AF%E5%BE%84json/</guid>
      <description>在写小demo的过程中，经常需要把某个文件夹的图片文件的路径给引入，除非全部重命名成有序的数字，不然不好处理，这就用到了node中的fs和path模块，还没学&amp;hellip;
const path=require(&amp;#34;path&amp;#34;); const fs = require(&amp;#39;fs&amp;#39;); fs.stat(&amp;#39;../images&amp;#39;,(err)=&amp;gt;{//图片文件所在目录  if (err)return; var result=&amp;#39;{&amp;#39; fs.readdir(&amp;#34;../images&amp;#34;,(err,data)=&amp;gt;{//图片文件所在目录  for(var i=0;i&amp;lt;Object.keys(data).length;i++){ let ImgPath=&amp;#34;\&amp;#34;images/&amp;#34;+data[i]+&amp;#34;\&amp;#34;&amp;#34;; result+=&amp;#34;\&amp;#34;&amp;#34;+i+&amp;#34;\&amp;#34;:&amp;#34;+ImgPath+&amp;#34;,&amp;#34;; } result=result.substring(0,result.length-1); let length=&amp;#34;\&amp;#34;&amp;#34;+&amp;#34;length&amp;#34;+&amp;#34;\&amp;#34;&amp;#34;+&amp;#34;:&amp;#34;+&amp;#34;\&amp;#34;&amp;#34;+Object.keys(data).length+&amp;#34;\&amp;#34;&amp;#34;//文件数量  result+=&amp;#34;,&amp;#34;+length+&amp;#39;}&amp;#39; fs.writeFile(&amp;#34;../data/imgPath.json&amp;#34;,result,(err)=&amp;gt;{ if(err)return; console.log(&amp;#34;写入文件成功，一共&amp;#34;+Object.keys(data).length+&amp;#34;个文件&amp;#34;); }); }); }); 生成的文件大概就是这样的一个json数据
{&amp;#34;0&amp;#34;:&amp;#34;images/1.jpg&amp;#34;,&amp;#34;1&amp;#34;:&amp;#34;images/10.jpg&amp;#34;,&amp;#34;2&amp;#34;:&amp;#34;images/100.jpg&amp;#34;,&amp;#34;3&amp;#34;:&amp;#34;images/101.jpg&amp;#34;,&amp;#34;4&amp;#34;:&amp;#34;images/102.jpg&amp;#34;,&amp;#34;5&amp;#34;:&amp;#34;images/103.jpg&amp;#34;,&amp;#34;6&amp;#34;:&amp;#34;images/104.jpg&amp;#34;,&amp;#34;7&amp;#34;:&amp;#34;images/105.jpg&amp;#34;,&amp;#34;8&amp;#34;:&amp;#34;images/106.jpg&amp;#34;,&amp;#34;9&amp;#34;:&amp;#34;images/107.jpg&amp;#34;,&amp;#34;10&amp;#34;:&amp;#34;images/108.jpg&amp;#34;,&amp;#34;length&amp;#34;:&amp;#34;109&amp;#34;} </description>
    </item>
    
    <item>
      <title>python中关于文件的种种问题</title>
      <link>https://blog.archai.space/p/python%E4%B8%AD%E5%85%B3%E4%BA%8E%E6%96%87%E4%BB%B6%E7%9A%84%E7%A7%8D%E7%A7%8D%E9%97%AE%E9%A2%98/</link>
      <pubDate>Fri, 26 Jun 2020 00:00:00 +0000</pubDate>
      
      <guid>https://blog.archai.space/p/python%E4%B8%AD%E5%85%B3%E4%BA%8E%E6%96%87%E4%BB%B6%E7%9A%84%E7%A7%8D%E7%A7%8D%E9%97%AE%E9%A2%98/</guid>
      <description> 在python中，我们可以将那些在运行时可能会出现状况的代码放在try代码块中，在try代码块的后面可以跟上一个或多个except来捕获可能出现的异常状况。
  FileNotFoundError，文件找不到 LookupError指定了未知的编码 UnicodeDecodeError读取文件时无法按指定方式解码  def main(): f = None try: f = open(&#39;致橡树.txt&#39;, &#39;r&#39;, encoding=&#39;utf-8&#39;) print(f.read()) except FileNotFoundError: print(&#39;无法打开指定的文件!&#39;) except LookupError: print(&#39;指定了未知的编码!&#39;) except UnicodeDecodeError: print(&#39;读取文件时解码错误!&#39;) finally: if f: f.close() if __name__ == &#39;__main__&#39;: main()  finally块的代码不论程序正常还是异常都会执行到（甚至是调用了sys模块的exit函数退出Python环境，finally块都会被执行，因为exit函数实质上是引发了SystemExit异常），因此我们通常把finally块称为“总是执行代码块”，它最适合用来做释放外部资源的操作。
 或者， with关键字指定文件对象的上下文环境并在离开上下文环境时自动释放文件资源
def main(): try: with open(&#39;致橡树.txt&#39;, &#39;r&#39;, encoding=&#39;utf-8&#39;) as f: print(f.read()) except FileNotFoundError: print(&#39;无法打开指定的文件!&#39;) except LookupError: print(&#39;指定了未知的编码!&#39;) except UnicodeDecodeError: print(&#39;读取文件时解码错误!&#39;) if __name__ == &#39;__main__&#39;: main() </description>
    </item>
    
  </channel>
</rss>
