实验二 二叉树的基本操作
一、实验目的
本实验通过实现二叉树的链式存储实现及二叉树的基本操作,掌握递归算法的
设计、递归算法与非递归算法之间的转换和遍历技术,为后续章节学习图的内容奠
定基础。
二、实验内容
(1)、以链表为存储结构创建二叉树;
(2)、分别用递归和非递归方式实现二叉树的中序遍历;
三、实验原理、方法和手段
链表存储二叉树通常具有两个指针域的链表作为二叉树的存储结构,其中每个
结点由数据域、左指针域和右指针域组成。两个指针域分别指向该结点的左、右孩
子。若某结点没有左孩子或右孩子,则对应的指针域为空。最后,还需要一个链表
的头指针指向根结点。
二叉树是非线性结构,遍历时先访问根结点还是先访问子树、先访问左子树还
是先访问右子树必须有所规定,这就是遍历规则。采用不同的遍历规则会产生不同
的遍历结果,因此对二叉树进行遍历时,必须设定遍历规则。根据遍历规则采用递
归或者非递归的方式实现二叉树的遍历。采用非递归算法实现中序遍历时要用到栈
结构。根据中序遍历二叉树的递归定义,转换成非递归函数时用栈来保存返回的结
点,先扫描根结点的所有左结点并入栈,出栈一个结点,访问之,然后扫描该结点
的右结点并入栈再扫描该右结点的所有左结点并入栈,如此下去……,直到到栈空
为止。
代码如下
#include <iostream>
#include <stack>
using namespace std;
class TreeNode {
public:
int value;
TreeNode* left, * right;
TreeNode(int value) {
this->value = value;
left = right = nullptr;
}
};
TreeNode* createBinaryTree() {
// 创建一个简单的二叉树(硬编码)
TreeNode* root = new TreeNode(1);
root->left = new TreeNode(2);
root->right = new TreeNode(3);
root->left->left = new TreeNode(4);
root->left->right = new TreeNode(5);
return root;
}
// 注释处为递归遍历算法
/*void inorderTraversalRecursive(TreeNode* node) {
if (node == nullptr) return;
inorderTraversalRecursive(node->left);
cout << node->value << " ";
inorderTraversalRecursive(node->right);
}*/
void inorderTraversalIterative(TreeNode* root) {
stack<TreeNode*> stk;
TreeNode* current = root;
while (current != nullptr || !stk.empty()) {
while (current != nullptr) {
stk.push(current);
current = current->left;
}
current = stk.top();
stk.pop();
cout << current->value << " ";
current = current->right;
}
}
int main() {
TreeNode* root = createBinaryTree();
// 注释处为递归遍历算法
/* cout << "Inorder Traversal (Recursive): ";
inorderTraversalRecursive(root);
cout << endl;*/
cout << "Inorder Traversal (Iterative): ";
inorderTraversalIterative(root);
cout << endl;
return 0;
}
结果:
实验结果分析
在实验中,我们实现了二叉树的中序遍历的两种方法:递归和非递归(利用栈)。这两种方法虽然在实现细节上有所不同,但它们都按照左子树-根节点-右子树的顺序访问树中的每个节点。
1. 递归方法:
优点:代码简洁易懂,直观地反映了中序遍历的定义。
缺点:对于深度很大的树,可能会导致调用栈溢出。
2. 非递归方法(使用栈):
优点:避免了递归可能导致的栈溢出问题,适用于深度较大的树。
缺点:代码相对复杂,需要额外的数据结构(栈)来存储访问路径。
对于给定的二叉树,两种方法都能正确地输出中序遍历的结果(4 2 5 1 3),这验证了方法的正确性。
思考题
如何实现层次遍历?
#include <queue>
void levelOrderTraversal(TreeNode* root) {
if (root == nullptr) return;
queue<TreeNode*> q;
q.push(root);
while (!q.empty()) {
TreeNode* current = q.front();
q.pop();
cout << current->value << " ";
if (current->left != nullptr) {
q.push(current->left);
}
if (current->right != nullptr) {
q.push(current->right);
}
}
}
-
levelOrderTraversal()
函数接受一个指向树根节点的指针作为参数,用于层序遍历二叉树。 -
首先,检查树是否为空,如果为空则直接返回。
-
创建一个队列
q
,并将根节点入队。 -
进入循环,直到队列为空。在每一轮循环中:
- 出队队首元素,将当前节点的值输出。
- 如果当前节点的左子节点不为空,将左子节点入队。
- 如果当前节点的右子节点不为空,将右子节点入队。
-
循环直到队列为空,此时完成了层序遍历。