@@ -125,15 +125,15 @@ tags: ["数据结构", "算法", "树"]
125125- 判断i是否有右孩子: 2i + 1 <= n
126126- 判断i是否是叶子/分支节点: i > n / 2
127127
128- ![ ] ( https://jihulab.com/xnzone/earth-bear/-/raw/master/tree-array.jpg )
128+ ![ ] ( https://s2.loli.net/2025/09/28/OUeyS9H7o1wLAXC.png )
129129
130130
131131### 链式存储
132132
133133- 可以简单找到p节点的左右节孩子,但只能通过从根开始遍历找到p的父节点
134134- 可以多定义一个父节点指针来方便查找父节点
135135
136- ![ ] ( https://jihulab.com/xnzone/earth-bear/-/raw/master/tree-list.jpg )
136+ ![ ] ( https://s2.loli.net/2025/09/28/X1gVH8myQBNcetL.png )
137137
138138
139139## 二叉树遍历
@@ -145,16 +145,16 @@ tags: ["数据结构", "算法", "树"]
145145
146146### 前序遍历
147147
148- ![ ] ( https://jihulab.com/xnzone/earth-bear/-/raw/master/tree-pre-order.jpg )
148+ ![ ] ( https://s2.loli.net/2025/09/28/fn51EOekLZW4tDx.png )
149149
150150
151151### 中序遍历
152152
153- ![ ] ( https://jihulab.com/xnzone/earth-bear/-/raw/master/tree-in-order.jpg )
153+ ![ ] ( https://s2.loli.net/2025/09/28/O6Q4gidBP7tlaDH.png )
154154
155155### 后序遍历
156156
157- ![ ] ( https://jihulab.com/xnzone/earth-bear/-/raw/master/tree-post-order.jpg )
157+ ![ ] ( https://s2.loli.net/2025/09/28/8gms6ONM1WXGFrc.png )
158158
159159### 层序遍历
160160
@@ -163,7 +163,7 @@ tags: ["数据结构", "算法", "树"]
163163- 若队列非空,则队头节点处队,访问该节点,并将左右孩子插入队尾
164164- 重复第三步,直到队列为空
165165
166- ![ ] ( https://jihulab.com/xnzone/earth-bear/-/raw/master/tree-level-order.jpg )
166+ ![ ] ( https://s2.loli.net/2025/09/28/IOb1ulScfxPGrWJ.png )
167167
168168
169169## 构造二叉树
@@ -189,22 +189,91 @@ tags: ["数据结构", "算法", "树"]
189189
190190非递归
191191
192- ![ ] ( https://jihulab.com/xnzone/earth-bear/-/raw/master/bst-search.jpg )
192+ ``` c++
193+ // 在二叉排序树中查找值为key的结点
194+ BSTNode *BST_Search (BSTree T, int key) {
195+ // 若树空或等于根结点值,则结束循环
196+ while (T != NULL && key != T->key) {
197+ // 小于,则在左子树上查找
198+ if (key < T->key) T = T->lchild;
199+ // 大于,则在右子树上查找
200+ else T = T->rchild;
201+ }
202+ return T;
203+ }
204+ ```
205+
206+
193207
194208递归方式
195209
196- ![ ] ( https://jihulab.com/xnzone/earth-bear/-/raw/master/bst-search-track.jpg )
210+ ```c++
211+ // 在二叉排序树中查找值为key的结点(递归实现)
212+ BSTNode *BSTSearch(BSTree T, int key) {
213+ if (T == NULL)
214+ // 查找失败
215+ return NULL;
216+ if (key == T->key)
217+ // 查找成功
218+ return T;
219+ else if (key < T->key)
220+ // 在左子树中找
221+ return BSTSearch(T->lchild, key);
222+ else
223+ // 在右子树中找
224+ return BSTSearch(T->rchild, key);
225+ }
226+ ```
227+
228+
197229
198230### 插入
199231
200232- 二叉树为空,直接插入节点
201233- 若关键字k小于根节点,插入左子树,否则插入右子树
202234
203- ![ ] ( https://jihulab.com/xnzone/earth-bear/-/raw/master/bst-insert.jpg )
235+ ``` c++
236+ // 在二叉排序树插入关键字为k的新结点(递归实现)
237+ int BST_Insert (BSTree &T, int k) {
238+ // 原树为空,新插入的结点为根结点
239+ if (T == NULL) {
240+ T = (BSTree)malloc(sizeof(BSTNode));
241+ T->key = k;
242+ T->lchild = T->rchild = NULL;
243+ // 返回1,插入成功
244+ return 1;
245+ }
246+ // 树中存在相同关键字的结点,插入失败
247+ else if (k == T->key)
248+ return 0;
249+ // 插入到T的左子树
250+ else if (k < T->key)
251+ return BST_Insert(T->lchild, k);
252+ // 插入到T的右子树
253+ else
254+ return BST_Insert(T->rchild, k);
255+ }
256+ ```
257+
258+
204259
205260### 构造
206261
207- ![ ] ( https://jihulab.com/xnzone/earth-bear/-/raw/master/bst-create.jpg )
262+ ```c++
263+ // 按照 str[] 中的关键字序列建立二叉排序树
264+ void Creat_BST(BSTree &T, int str[], int n) {
265+ // 初始时T为空树
266+ T = NULL;
267+ int i = 0;
268+ // 依次将每个关键字插入到二叉排序树中
269+ while (i < n) {
270+ BST_Insert(T, str[i]);
271+ i++;
272+ }
273+ }
274+ ```
275+
276+
208277
209278### 删除
210279
@@ -254,7 +323,7 @@ LL平衡旋转
254323- 将A节点向右下旋转称为B的右子树的根节点
255324- B的原右子树则作为A节点的左子树
256325
257- ![ ] ( https://jihulab.com/xnzone/earth-bear/-/raw/master/avl-ll.jpg )
326+ ![ ] ( https://s2.loli.net/2025/09/28/HzRmucb6hTVilxQ.png )
258327
259328RR平衡旋转
260329
@@ -263,23 +332,23 @@ RR平衡旋转
263332- 将A节点向左下旋转称为B的左子树的根节点
264333- B的原左子树作为A节点的右子树
265334
266- ![ ] ( https://jihulab.com/xnzone/earth-bear/-/raw/master/avl-rr.jpg )
335+ ![ ] ( https://s2.loli.net/2025/09/28/6PlLmFAX4kWHZTi.png )
267336
268337LR平衡旋转
269338
270339- 由于在A的左孩子的右子树插入了新节点,A的平衡因子由1增至2,导致以A为根的子树失去平衡,需要进行两次旋转操作,先左旋转后右旋转
271340- 将A节点的左孩子的右子树的根节C点向左上旋转提升至节B节点的位置
272341- 再把该C节点向右上旋转提升到A节点的位置
273342
274- ![ ] ( https://jihulab.com/xnzone/earth-bear/-/raw/master/avl-lr.jpg )
343+ ![ ] ( https://s2.loli.net/2025/09/28/xUcgfSCA721ph8R.png )
275344
276345RL平衡旋转
277346
278347- 由于在A的右孩子(R)的左子树(L)上插入新结点,A的平衡因子由-1减至-2,导致以A为根的子树失去平衡,需要进行两次旋转操作,先右旋转后左旋转
279348- 将A结点的右孩子B的左子树的根结点C向右上旋转提升到B结点的位置
280349- 然后再把该C结点向左上旋转提升到A结点的位置
281350
282- ![ ] ( https://jihulab.com/xnzone/earth-bear/-/raw/master/avl-rl.jpg )
351+ ![ ] ( https://s2.loli.net/2025/09/28/mH8CG2aw6WtPpFD.png )
283352
284353
285354## 哈夫曼树
@@ -288,7 +357,7 @@ RL平衡旋转
288357
289358- 在含有n个带权叶节点的二叉树中,其中带权路径长度(WPL)最小的二叉树称为哈夫曼树,也称最优二叉树
290359
291- ![ ] ( https://jihulab.com/xnzone/earth-bear/-/raw/master/hafman-tree.jpg )
360+ ![ ] ( https://s2.loli.net/2025/09/28/M8OcCDtS1u3zsnW.png )
292361
293362### 构造
294363
@@ -305,7 +374,7 @@ RL平衡旋转
305374- 哈夫曼树中不存在度为1的节点
306375- 哈夫曼树并不惟一,但WPL必然相同并最优
307376
308- ![ ] ( https://jihulab.com/xnzone/earth-bear/-/raw/master/hafman-create.jpg )
377+ ![ ] ( https://s2.loli.net/2025/09/28/2rDpTL1sJlkj3R7.png )
309378
310379
311380### 哈夫曼编码
@@ -325,11 +394,11 @@ RL平衡旋转
325394
326395实际上就是树的双亲表示法,里面的值就是自己对应的根节点下标
327396
328- ![ ] ( https://jihulab.com/xnzone/earth-bear/-/raw/master/find-union-create.jpg )
397+ ![ ] ( https://s2.loli.net/2025/09/28/6zwFP9fmEIdlt2y.png )
329398
330399### 并、查
331400
332- ![ ] ( https://jihulab.com/xnzone/earth-bear/-/raw/master/find-union.jpg )
401+ ![ ] ( https://s2.loli.net/2025/09/28/u9mRcO4TWMiQGIa.png )
333402
334403### 并的优化
335404
@@ -338,15 +407,34 @@ RL平衡旋转
338407- union操作让小树合并到大树
339408- 查的最坏时间复杂度变为O($\log_2n$)
340409
341- ![ ] ( https://jihulab.com/xnzone/earth-bear/-/raw/master/union-best.jpg )
410+ ![ ] ( https://s2.loli.net/2025/09/28/WpxoidVKEG8SfUl.png )
342411
343412
344413### 压缩路径
345414
346415- 核心思想就是让树越来越矮
347416- Find操作先找到根节点,再将查找路径上所有节点都挂到根节点下
348417
349- ![ ] ( https://jihulab.com/xnzone/earth-bear/-/raw/master/find-union-path.jpg )
418+ ``` c++
419+ // Find "查"操作优化,先找到根节点,再进行"压缩路径"
420+ int Find (int S[ ] , int x) {
421+ int root = x;
422+ // 循环找到根
423+ while (S[ root] >= 0) root = S[ root] ;
424+ // 压缩路径
425+ while (x != root) {
426+ // t指向x的父节点
427+ int t = S[ x] ;
428+ // x直接挂到根节点下
429+ S[ x] = root;
430+ x = t;
431+ }
432+ // 返回根节点编号
433+ return root;
434+ }
435+ ```
436+
437+
350438
351439- 这样可以让树的高度不超过O($\alpha(n)$)
352440- O($\alpha(n)$)是一个增长很慢的函数,对于常见的n值,O($\alpha(n)$)通常<=4
0 commit comments