前序遍历是一种二叉树的遍历方式,其遍历顺序是先访问根节点,然后递归地遍历左子树,最后递归地遍历右子树。具体来说,前序遍历的顺序是根节点->左子树->右子树。
前序遍历到底部为何会返回到顶部是因为在进行递归遍历时,每次都会先处理当前节点,然后递归地处理它的左子节点和右子节点。当递归到叶子节点时,即左右子节点为空时,递归调用会返回到上一层,继续处理上一层节点的右子节点。这样不断地递归调用直到整个树都被遍历完毕。
这种递归的方式实际上利用了函数调用栈的特性。每次递归调用都会将当前函数的状态保存在栈中,包括局部变量、函数参数等信息。当递归调用返回时,栈顶的状态会被弹出,恢复到上一次调用的状态,从而实现了递归的回溯和返回。
总之,前序遍历利用递归实现了从树的根节点开始的深度优先遍历,遍历到底部并返回到顶部是通过递归调用和函数调用栈来实现的。
函数调用栈(Function Call Stack)是计算机内存中用于管理函数调用和返回的一种数据结构。它是一种后进先出(LIFO)的栈结构,用于存储函数调用的上下文信息。每当程序调用一个函数时,该函数的调用信息(包括参数、局部变量、返回地址等)都会被压入栈顶,形成一个新的栈帧(Stack Frame)。当函数执行完毕返回时,相应的栈帧就会被弹出,控制权返回给调用函数。
函数调用栈的主要作用有以下几点:
- 存储函数调用的上下文信息:每个栈帧都包含了函数调用所需的所有信息,包括参数、局部变量、返回地址等。
- 实现函数的嵌套调用:当一个函数内部调用另一个函数时,调用信息会被压入栈顶,保证了函数调用的嵌套顺序。
- 支持函数的递归调用:当一个函数递归地调用自身时,每次调用都会创建一个新的栈帧,保证了递归调用的正确执行。
-----------
在函数调用 preorderTraversalLeftSubtree(root->left)
中,假设 root->left
指向的节点不为空,这个函数调用会如何压栈呢?
首先,当程序执行到这行代码时,会将函数调用信息压入函数调用栈。这个函数调用信息包括函数的参数、局部变量和返回地址等。
假设 root->left
指向的节点不为空,那么会执行 preorderTraversalLeftSubtree(root->left)
函数。这个函数会继续递归调用 preorderTraversalLeftSubtree
函数,传入 root->left
指向的节点作为参数。
这个过程会一直递归下去,直到遇到叶子节点,即节点的左右子节点均为空。在叶子节点的情况下,递归调用会停止,函数调用栈不再继续压栈,而是开始弹栈。
在弹栈的过程中,每个函数调用完成后会将相应的函数调用信息从栈顶弹出,控制权返回到调用它的函数。这样依次弹栈,直到栈为空,整个递归调用过程结束。
因此,在这个过程中,函数调用栈的压栈和弹栈是通过递归调用的方式来实现的。每次递归调用都会将函数调用信息压入栈顶,每次函数调用完成后又会从栈顶弹出相应的函数调用信息。
#include <iostream>
#include <conio.h> // 用于 _getch() 函数using namespace std;// 定义二叉树节点结构
struct TreeNode {int value;TreeNode *left;TreeNode *right;TreeNode(int x) : value(x), left(nullptr), right(nullptr) {}
};// 函数用于前序遍历根节点及其左子树的所有节点
void preorderTraversalLeftSubtree(TreeNode* node) {if (node != nullptr) {// 访问当前节点cout << node->value << " ";// 递归遍历左子节点preorderTraversalLeftSubtree(node->left);// 递归遍历右子节点,但仅在左子树中preorderTraversalLeftSubtree(node->right);}
}
// 主函数
int main() {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);root->right->left = new TreeNode(6);root->right->right = new TreeNode(7);root->left->left->left = new TreeNode(8);// root->left->left->right = new TreeNode(9);root->left->right->left = new TreeNode(10);// root->left->right->right = new TreeNode(11);// 调用前序遍历函数cout << "前序遍历结果:";cout << root->value << " "; // 手动输出根节点preorderTraversalLeftSubtree(root->left); // 仅前序遍历左子树cout << endl << "请按任意键继续. . ." << endl;_getch(); // 等待用户按键return 0;
}