diff --git a/codes/cpp/chapter_searching/hashing_search.cpp b/codes/cpp/chapter_searching/hashing_search.cpp index ee37a18..674376f 100644 --- a/codes/cpp/chapter_searching/hashing_search.cpp +++ b/codes/cpp/chapter_searching/hashing_search.cpp @@ -40,7 +40,7 @@ int main() { cout << "目标元素 3 的索引 = " << index << endl; /* 哈希查找(链表) */ - ListNode* head = vectorToLinkedList(nums); + ListNode* head = vecToLinkedList(nums); // 初始化哈希表 unordered_map map1; while (head != nullptr) { diff --git a/codes/cpp/chapter_searching/linear_search.cpp b/codes/cpp/chapter_searching/linear_search.cpp index c2de816..e1f2a56 100644 --- a/codes/cpp/chapter_searching/linear_search.cpp +++ b/codes/cpp/chapter_searching/linear_search.cpp @@ -42,7 +42,7 @@ int main() { cout << "目标元素 3 的索引 = " << index << endl; /* 在链表中执行线性查找 */ - ListNode* head = vectorToLinkedList(nums); + ListNode* head = vecToLinkedList(nums); ListNode* node = linearSearch(head, target); cout << "目标结点值 3 的对应结点对象为 " << node << endl; diff --git a/codes/cpp/chapter_stack_and_queue/queue.cpp b/codes/cpp/chapter_stack_and_queue/queue.cpp index c529a7c..ccaefb1 100644 --- a/codes/cpp/chapter_stack_and_queue/queue.cpp +++ b/codes/cpp/chapter_stack_and_queue/queue.cpp @@ -6,6 +6,8 @@ #include "../include/include.hpp" + +/* Driver Code */ int main(){ /* 初始化队列 */ queue queue; diff --git a/codes/cpp/chapter_stack_and_queue/stack.cpp b/codes/cpp/chapter_stack_and_queue/stack.cpp index 52d0b77..91cff94 100644 --- a/codes/cpp/chapter_stack_and_queue/stack.cpp +++ b/codes/cpp/chapter_stack_and_queue/stack.cpp @@ -6,7 +6,9 @@ #include "../include/include.hpp" -int main(){ + +/* Driver Code */ +int main() { /* 初始化栈 */ stack stack; @@ -25,15 +27,15 @@ int main(){ /* 元素出栈 */ stack.pop(); - cout<< "出栈元素 pop = " << top << ",出栈后 stack = "; + cout << "出栈元素 pop = " << top << ",出栈后 stack = "; PrintUtil::printStack(stack); /* 获取栈的长度 */ int size = stack.size(); - cout<< "栈的长度 size = " << size << endl; + cout << "栈的长度 size = " << size << endl; /* 判断是否为空 */ bool empty = stack.empty(); - + return 0; } diff --git a/codes/cpp/chapter_tree/binary_search_tree.cpp b/codes/cpp/chapter_tree/binary_search_tree.cpp index 601f89a..246bdba 100644 --- a/codes/cpp/chapter_tree/binary_search_tree.cpp +++ b/codes/cpp/chapter_tree/binary_search_tree.cpp @@ -6,3 +6,149 @@ #include "../include/include.hpp" +/* 二叉搜索树 */ +class BinarySearchTree { +private: + TreeNode* root; + +public: + BinarySearchTree(vector nums) { + sort(nums.begin(), nums.end()); // 排序数组 + root = buildTree(nums, 0, nums.size() - 1); // 构建二叉搜索树 + } + + /* 获取二叉树根结点 */ + TreeNode* getRoot() { + return root; + } + + /* 构建二叉搜索树 */ + TreeNode* buildTree(vector nums, int i, int j) { + if (i > j) return nullptr; + // 将数组中间结点作为根结点 + int mid = (i + j) / 2; + TreeNode* root = new TreeNode(nums[mid]); + // 递归建立左子树和右子树 + root->left = buildTree(nums, i, mid - 1); + root->right = buildTree(nums, mid + 1, j); + return root; + } + + /* 查找结点 */ + TreeNode* search(int num) { + TreeNode* cur = root; + // 循环查找,越过叶结点后跳出 + while (cur != nullptr) { + // 目标结点在 root 的右子树中 + if (cur->val < num) cur = cur->right; + // 目标结点在 root 的左子树中 + else if (cur->val > num) cur = cur->left; + // 找到目标结点,跳出循环 + else break; + } + // 返回目标结点 + return cur; + } + + /* 插入结点 */ + TreeNode* insert(int num) { + // 若树为空,直接提前返回 + if (root == nullptr) return nullptr; + TreeNode *cur = root, *pre = nullptr; + // 循环查找,越过叶结点后跳出 + while (cur != nullptr) { + // 找到重复结点,直接返回 + if (cur->val == num) return nullptr; + pre = cur; + // 插入位置在 root 的右子树中 + if (cur->val < num) cur = cur->right; + // 插入位置在 root 的左子树中 + else cur = cur->left; + } + // 插入结点 val + TreeNode* node = new TreeNode(num); + if (pre->val < num) pre->right = node; + else pre->left = node; + return node; + } + + /* 删除结点 */ + TreeNode* remove(int num) { + // 若树为空,直接提前返回 + if (root == nullptr) return nullptr; + TreeNode *cur = root, *pre = nullptr; + // 循环查找,越过叶结点后跳出 + while (cur != nullptr) { + // 找到待删除结点,跳出循环 + if (cur->val == num) break; + pre = cur; + // 待删除结点在 root 的右子树中 + if (cur->val < num) cur = cur->right; + // 待删除结点在 root 的左子树中 + else cur = cur->left; + } + // 若无待删除结点,则直接返回 + if (cur == nullptr) return nullptr; + // 子结点数量 = 0 or 1 + if (cur->left == nullptr || cur->right == nullptr) { + // 当子结点数量 = 0 / 1 时, child = nullptr / 该子结点 + TreeNode* child = cur->left != nullptr ? cur->left : cur->right; + // 删除结点 cur + if (pre->left == cur) pre->left = child; + else pre->right = child; + } + // 子结点数量 = 2 + else { + // 获取中序遍历中 cur 的下一个结点 + TreeNode* nex = min(cur->right); + int tmp = nex->val; + // 递归删除结点 nex + remove(nex->val); + // 将 nex 的值复制给 cur + cur->val = tmp; + } + return cur; + } + + /* 获取最小结点 */ + TreeNode* min(TreeNode* root) { + if (root == nullptr) return root; + // 循环访问左子结点,直到叶结点时为最小结点,跳出 + while (root->left != nullptr) { + root = root->left; + } + return root; + } +}; + + +/* Driver Code */ +int main() { + /* 初始化二叉搜索树 */ + vector nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; + BinarySearchTree* bst = new BinarySearchTree(nums); + cout << endl << "初始化的二叉树为\n" << endl; + PrintUtil::printTree(bst->getRoot()); + + /* 查找结点 */ + TreeNode* node = bst->search(5); + cout << endl << "查找到的结点对象为 " << node << ",结点值 = " << node->val << endl; + + /* 插入结点 */ + node = bst->insert(16); + cout << endl << "插入结点 16 后,二叉树为\n" << endl; + PrintUtil::printTree(bst->getRoot()); + + /* 删除结点 */ + bst->remove(1); + cout << endl << "删除结点 1 后,二叉树为\n" << endl; + PrintUtil::printTree(bst->getRoot()); + bst->remove(2); + cout << endl << "删除结点 2 后,二叉树为\n" << endl; + PrintUtil::printTree(bst->getRoot()); + bst->remove(4); + cout << endl << "删除结点 4 后,二叉树为\n" << endl; + PrintUtil::printTree(bst->getRoot()); + + return 0; +} diff --git a/codes/cpp/chapter_tree/binary_tree.cpp b/codes/cpp/chapter_tree/binary_tree.cpp index 8235cf9..3258d9c 100644 --- a/codes/cpp/chapter_tree/binary_tree.cpp +++ b/codes/cpp/chapter_tree/binary_tree.cpp @@ -6,3 +6,35 @@ #include "../include/include.hpp" + +/* Driver Code */ +int main() { + /* 初始化二叉树 */ + // 初始化结点 + TreeNode* n1 = new TreeNode(1); + TreeNode* n2 = new TreeNode(2); + TreeNode* n3 = new TreeNode(3); + TreeNode* n4 = new TreeNode(4); + TreeNode* n5 = new TreeNode(5); + // 构建引用指向(即指针) + n1->left = n2; + n1->right = n3; + n2->left = n4; + n2->right = n5; + cout << endl << "初始化二叉树\n" << endl; + PrintUtil::printTree(n1); + + /* 插入与删除结点 */ + TreeNode* P = new TreeNode(0); + // 在 n1 -> n2 中间插入结点 P + n1->left = P; + P->left = n2; + cout << endl << "插入结点 P 后\n" << endl; + PrintUtil::printTree(n1); + // 删除结点 P + n1->left = n2; + cout << endl << "删除结点 P 后\n" << endl; + PrintUtil::printTree(n1); + + return 0; +} diff --git a/codes/cpp/chapter_tree/binary_tree_bfs.cpp b/codes/cpp/chapter_tree/binary_tree_bfs.cpp index 9fd2faf..ce0072b 100644 --- a/codes/cpp/chapter_tree/binary_tree_bfs.cpp +++ b/codes/cpp/chapter_tree/binary_tree_bfs.cpp @@ -6,3 +6,39 @@ #include "../include/include.hpp" +/* 层序遍历 */ +vector hierOrder(TreeNode* root) { + // 初始化队列,加入根结点 + queue queue; + queue.push(root); + // 初始化一个列表,用于保存遍历序列 + vector vec; + while (!queue.empty()) { + TreeNode* node = queue.front(); + queue.pop(); // 队列出队 + vec.push_back(node->val); // 保存结点 + if (node->left != NULL) + queue.push(node->left); // 左子结点入队 + if (node->right != NULL) + queue.push(node->right); // 右子结点入队 + } + return vec; +} + + +/* Driver Code */ +int main() { + /* 初始化二叉树 */ + // 这里借助了一个从数组直接生成二叉树的函数 + TreeNode* root = vecToTree(vector + { 1, 2, 3, 4, 5, 6, 7, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX }); + cout << endl << "初始化二叉树\n" << endl; + PrintUtil::printTree(root); + + /* 层序遍历 */ + vector vec = hierOrder(root); + cout << endl << "层序遍历的结点打印序列 = "; + PrintUtil::printVector(vec); + + return 0; +} diff --git a/codes/cpp/chapter_tree/binary_tree_dfs.cpp b/codes/cpp/chapter_tree/binary_tree_dfs.cpp index e38c4ad..08a0a33 100644 --- a/codes/cpp/chapter_tree/binary_tree_dfs.cpp +++ b/codes/cpp/chapter_tree/binary_tree_dfs.cpp @@ -6,3 +6,63 @@ #include "../include/include.hpp" +// 初始化列表,用于存储遍历序列 +vector vec; + +/* 前序遍历 */ +void preOrder(TreeNode* root) { + if (root == nullptr) return; + // 访问优先级:根结点 -> 左子树 -> 右子树 + vec.push_back(root->val); + preOrder(root->left); + preOrder(root->right); +} + +/* 中序遍历 */ +void inOrder(TreeNode* root) { + if (root == nullptr) return; + // 访问优先级:左子树 -> 根结点 -> 右子树 + inOrder(root->left); + vec.push_back(root->val); + inOrder(root->right); +} + +/* 后序遍历 */ +void postOrder(TreeNode* root) { + if (root == nullptr) return; + // 访问优先级:左子树 -> 右子树 -> 根结点 + postOrder(root->left); + postOrder(root->right); + vec.push_back(root->val); +} + + +/* Driver Code */ +int main() { + /* 初始化二叉树 */ + // 这里借助了一个从数组直接生成二叉树的函数 + TreeNode* root = vecToTree(vector + { 1, 2, 3, 4, 5, 6, 7, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX}); + cout << endl << "初始化二叉树\n" << endl; + PrintUtil::printTree(root); + + /* 前序遍历 */ + vec.clear(); + preOrder(root); + cout << endl << "前序遍历的结点打印序列 = "; + PrintUtil::printVector(vec); + + /* 中序遍历 */ + vec.clear(); + inOrder(root); + cout << endl << "中序遍历的结点打印序列 = "; + PrintUtil::printVector(vec); + + /* 后序遍历 */ + vec.clear(); + postOrder(root); + cout << endl << "后序遍历的结点打印序列 = "; + PrintUtil::printVector(vec); + + return 0; +} diff --git a/codes/cpp/include/ListNode.hpp b/codes/cpp/include/ListNode.hpp index 47beb36..bd91f25 100644 --- a/codes/cpp/include/ListNode.hpp +++ b/codes/cpp/include/ListNode.hpp @@ -25,7 +25,7 @@ struct ListNode { * @param list * @return ListNode* */ -ListNode* vectorToLinkedList(vector& list) { +ListNode* vecToLinkedList(vector list) { ListNode *dum = new ListNode(0); ListNode *head = dum; for (int val : list) { diff --git a/codes/cpp/include/PrintUtil.hpp b/codes/cpp/include/PrintUtil.hpp index f326f78..06f2f63 100644 --- a/codes/cpp/include/PrintUtil.hpp +++ b/codes/cpp/include/PrintUtil.hpp @@ -238,4 +238,27 @@ class PrintUtil { } cout << "[" + s.str() + "]" << '\n'; } + + /** + * @brief + * + * @tparam T + * @param queue + */ + template + static void printQueue(queue &queue) + { + // Generate the string to print + ostringstream s; + bool flag = true; + while(!queue.empty()) { + if (flag) { + s << queue.front(); + flag = false; + } + else s << ", " << queue.front(); + queue.pop(); + } + cout << "[" + s.str() + "]" << '\n'; + } }; diff --git a/codes/cpp/include/TreeNode.hpp b/codes/cpp/include/TreeNode.hpp index 7c8f170..614d799 100644 --- a/codes/cpp/include/TreeNode.hpp +++ b/codes/cpp/include/TreeNode.hpp @@ -23,7 +23,7 @@ struct TreeNode { * @param list * @return TreeNode* */ -TreeNode* vectorToTree(vector& list) { +TreeNode* vecToTree(vector list) { TreeNode *root = new TreeNode(list[0]); queue que; que.emplace(root); diff --git a/codes/java/chapter_tree/binary_search_tree.java b/codes/java/chapter_tree/binary_search_tree.java index f39f3d1..0770c56 100644 --- a/codes/java/chapter_tree/binary_search_tree.java +++ b/codes/java/chapter_tree/binary_search_tree.java @@ -9,6 +9,7 @@ package chapter_tree; import java.util.*; import include.*; +/* 二叉搜索树 */ class BinarySearchTree { private TreeNode root; diff --git a/docs/chapter_tree/binary_search_tree.md b/docs/chapter_tree/binary_search_tree.md index 07e547f..8b0f9ba 100644 --- a/docs/chapter_tree/binary_search_tree.md +++ b/docs/chapter_tree/binary_search_tree.md @@ -59,12 +59,43 @@ comments: true } ``` +=== "C++" + + ```cpp title="binary_search_tree.cpp" + /* 查找结点 */ + TreeNode* search(int num) { + TreeNode* cur = root; + // 循环查找,越过叶结点后跳出 + while (cur != nullptr) { + // 目标结点在 root 的右子树中 + if (cur->val < num) cur = cur->right; + // 目标结点在 root 的左子树中 + else if (cur->val > num) cur = cur->left; + // 找到目标结点,跳出循环 + else break; + } + // 返回目标结点 + return cur; + } + ``` + +=== "Python" + + ```python title="binary_search_tree.py" + + ``` + +=== "Go" + + ```go title="binary_search_tree.go" + + ``` + ### 插入结点 给定一个待插入元素 `num` ,为了保持二叉搜索树 “左子树 < 根结点 < 右子树” 的性质,插入操作分为两步: 1. **查找插入位置:** 与查找操作类似,我们从根结点出发,根据当前结点值和 `num` 的大小关系循环向下搜索,直到越过叶结点(遍历到 $\text{null}$ )时跳出循环; - 2. **在该位置插入结点:** 初始化结点 `num` ,将该结点放到 $\text{null}$ 的位置 ; 二叉搜索树不允许存在重复结点,否则将会违背其定义。因此若待插入结点在树中已经存在,则不执行插入,直接返回即可。 @@ -97,6 +128,44 @@ comments: true } ``` +=== "C++" + + ```cpp title="binary_search_tree.cpp" + /* 插入结点 */ + TreeNode* insert(int num) { + // 若树为空,直接提前返回 + if (root == nullptr) return nullptr; + TreeNode *cur = root, *pre = nullptr; + // 循环查找,越过叶结点后跳出 + while (cur != nullptr) { + // 找到重复结点,直接返回 + if (cur->val == num) return nullptr; + pre = cur; + // 插入位置在 root 的右子树中 + if (cur->val < num) cur = cur->right; + // 插入位置在 root 的左子树中 + else cur = cur->left; + } + // 插入结点 val + TreeNode* node = new TreeNode(num); + if (pre->val < num) pre->right = node; + else pre->left = node; + return node; + } + ``` + +=== "Python" + + ```python title="binary_search_tree.py" + + ``` + +=== "Go" + + ```go title="binary_search_tree.go" + + ``` + 为了插入结点,需要借助 **辅助结点 `prev`** 保存上一轮循环的结点,这样在遍历到 $\text{null}$ 时,我们也可以获取到其父结点,从而完成结点插入操作。 与查找结点相同,插入结点使用 $O(\log n)$ 时间。 @@ -188,6 +257,69 @@ comments: true } ``` +=== "C++" + + ```cpp title="binary_search_tree.cpp" + /* 删除结点 */ + TreeNode* remove(int num) { + // 若树为空,直接提前返回 + if (root == nullptr) return nullptr; + TreeNode *cur = root, *pre = nullptr; + // 循环查找,越过叶结点后跳出 + while (cur != nullptr) { + // 找到待删除结点,跳出循环 + if (cur->val == num) break; + pre = cur; + // 待删除结点在 root 的右子树中 + if (cur->val < num) cur = cur->right; + // 待删除结点在 root 的左子树中 + else cur = cur->left; + } + // 若无待删除结点,则直接返回 + if (cur == nullptr) return nullptr; + // 子结点数量 = 0 or 1 + if (cur->left == nullptr || cur->right == nullptr) { + // 当子结点数量 = 0 / 1 时, child = nullptr / 该子结点 + TreeNode* child = cur->left != nullptr ? cur->left : cur->right; + // 删除结点 cur + if (pre->left == cur) pre->left = child; + else pre->right = child; + } + // 子结点数量 = 2 + else { + // 获取中序遍历中 cur 的下一个结点 + TreeNode* nex = min(cur->right); + int tmp = nex->val; + // 递归删除结点 nex + remove(nex->val); + // 将 nex 的值复制给 cur + cur->val = tmp; + } + return cur; + } + /* 获取最小结点 */ + TreeNode* min(TreeNode* root) { + if (root == nullptr) return root; + // 循环访问左子结点,直到叶结点时为最小结点,跳出 + while (root->left != nullptr) { + root = root->left; + } + return root; + } + ``` + +=== "Python" + + ```python title="binary_search_tree.py" + + ``` + +=== "Go" + + ```go title="binary_search_tree.go" + + ``` + ## 二叉搜索树的优势 假设给定 $n$ 个数字,最常用的存储方式是「数组」,那么对于这串乱序的数字,常见操作的效率为: diff --git a/docs/chapter_tree/binary_tree.md b/docs/chapter_tree/binary_tree.md index e96e3b8..422b259 100644 --- a/docs/chapter_tree/binary_tree.md +++ b/docs/chapter_tree/binary_tree.md @@ -18,6 +18,35 @@ comments: true } ``` +=== "C++" + + ```cpp + /* 链表结点结构体 */ + struct TreeNode { + int val; // 结点值 + TreeNode *left; // 左子结点指针 + TreeNode *right; // 右子结点指针 + TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + }; + ``` + +=== "Python" + + ```python + """ 链表结点类 """ + class TreeNode: + def __init__(self, val=0, left=None, right=None): + self.val = val # 结点值 + self.left = left # 左子结点指针 + self.right = right # 右子结点指针 + ``` + +=== "Go" + + ```go + + ``` + 结点的两个指针分别指向「左子结点 Left Child Node」和「右子结点 Right Child Node」,并且称该结点为两个子结点的「父结点 Parent Node」。给定二叉树某结点,将左子结点以下的树称为该结点的「左子树 Left Subtree」,右子树同理。 ![binary_tree_definition](binary_tree.assets/binary_tree_definition.png) @@ -84,20 +113,75 @@ comments: true n2.right = n5; ``` +=== "C++" + + ```cpp title="binary_tree.cpp" + /* 初始化二叉树 */ + // 初始化结点 + TreeNode* n1 = new TreeNode(1); + TreeNode* n2 = new TreeNode(2); + TreeNode* n3 = new TreeNode(3); + TreeNode* n4 = new TreeNode(4); + TreeNode* n5 = new TreeNode(5); + // 构建引用指向(即指针) + n1->left = n2; + n1->right = n3; + n2->left = n4; + n2->right = n5; + ``` + +=== "Python" + + ```python title="binary_tree.py" + + ``` + +=== "Go" + + ```go title="binary_tree.go" + + ``` + **插入与删除结点。** 与链表类似,插入与删除结点都可以通过修改指针实现。 ![binary_tree_add_remove](binary_tree.assets/binary_tree_add_remove.png)

Fig. 在二叉树中插入与删除结点

-```java title="binary_tree.java" -TreeNode P = new TreeNode(0); -// 在 n1 -> n2 中间插入结点 P -n1.left = P; -P.left = n2; -// 删除结点 P -n1.left = n2; -``` +=== "Java" + + ```java title="binary_tree.java" + TreeNode P = new TreeNode(0); + // 在 n1 -> n2 中间插入结点 P + n1.left = P; + P.left = n2; + // 删除结点 P + n1.left = n2; + ``` + +=== "C++" + + ```cpp title="binary_tree.cpp" + /* 插入与删除结点 */ + TreeNode* P = new TreeNode(0); + // 在 n1 -> n2 中间插入结点 P + n1->left = P; + P->left = n2; + // 删除结点 P + n1->left = n2; + ``` + +=== "Python" + + ```python title="binary_tree.py" + + ``` + +=== "Go" + + ```go title="binary_tree.go" + + ``` !!! note @@ -140,6 +224,41 @@ n1.left = n2; } ``` +=== "C++" + + ```cpp title="binary_tree_bfs.cpp" + /* 层序遍历 */ + vector hierOrder(TreeNode* root) { + // 初始化队列,加入根结点 + queue queue; + queue.push(root); + // 初始化一个列表,用于保存遍历序列 + vector vec; + while (!queue.empty()) { + TreeNode* node = queue.front(); + queue.pop(); // 队列出队 + vec.push_back(node->val); // 保存结点 + if (node->left != NULL) + queue.push(node->left); // 左子结点入队 + if (node->right != NULL) + queue.push(node->right); // 右子结点入队 + } + return vec; + } + ``` + +=== "Python" + + ```python title="binary_tree_bfs.py" + + ``` + +=== "Go" + + ```go title="binary_tree_bfs.go" + + ``` + ### 前序、中序、后序遍历 相对地,前、中、后序遍历皆属于「深度优先遍历 Depth-First Traversal」,其体现着一种 “先走到尽头,再回头继续” 的回溯遍历方式。 @@ -191,6 +310,49 @@ n1.left = n2; } ``` +=== "C++" + + ```cpp title="binary_tree_dfs.cpp" + /* 前序遍历 */ + void preOrder(TreeNode* root) { + if (root == nullptr) return; + // 访问优先级:根结点 -> 左子树 -> 右子树 + vec.push_back(root->val); + preOrder(root->left); + preOrder(root->right); + } + + /* 中序遍历 */ + void inOrder(TreeNode* root) { + if (root == nullptr) return; + // 访问优先级:左子树 -> 根结点 -> 右子树 + inOrder(root->left); + vec.push_back(root->val); + inOrder(root->right); + } + + /* 后序遍历 */ + void postOrder(TreeNode* root) { + if (root == nullptr) return; + // 访问优先级:左子树 -> 右子树 -> 根结点 + postOrder(root->left); + postOrder(root->right); + vec.push_back(root->val); + } + ``` + +=== "Python" + + ```python title="binary_tree_dfs.py" + + ``` + +=== "Go" + + ```go title="binary_tree_dfs.go" + + ``` + !!! note 使用循环一样可以实现前、中、后序遍历,但代码相对繁琐,有兴趣的同学可以自行实现。