哪吒、敖丙和申公豹的二叉树扁平化大作战:递归与迭代的终极对决
大家好,我是哪吒!今天不闹海,也不打妖怪,咱们来聊聊二叉树的扁平化。你没听错,就是那个让你头大的二叉树!最近我在《哪吒2》里和敖丙、申公豹一起研究了这个难题,今天就来给大家分享一下我们的“战斗”过程。
什么是二叉树扁平化?
简单来说,就是把一棵二叉树变成一个链表,而且这个链表还是按照前序遍历的顺序排列的。听起来是不是有点像把一棵树“拍扁”成一条线?没错,就是这么回事!就像我哪吒的风火轮,把复杂的树结构碾成一条直线!
第一回合:递归 vs 迭代
递归:哪吒的“分身术”
递归就像我的分身术,自己调用自己,直到完成任务。敖丙看了直呼:“这也太神奇了吧!”我们先用Java和C++来实现一下。
Java代码:
public void flatten(TreeNode root) {
List<TreeNode> list = new ArrayList<>();
preIterator(list, root);
if (list.size() != 0 && list.size() >= 1) {
for (int i = 1; i < list.size(); i++) {
TreeNode pre = list.get(i - 1);
TreeNode next = list.get(i);
pre.left = null;
pre.right = next;
}
}
}
public void preIterator(List<TreeNode> list, TreeNode root) {
if (root == null) {
return;
}
list.add(root);
preIterator(list, root.left); // 分身术:左子树
preIterator(list, root.right); // 分身术:右子树
}
C++代码:
void flatten(TreeNode* root) {
vector<TreeNode*> vector;
preIterator(vector, root);
if (vector.size() <= 1) {
return;
}
for (int i = 1; i < vector.size(); i++) {
TreeNode* pre = vector.at(i - 1);
TreeNode* next = vector.at(i);
pre->left = nullptr;
pre->right = next;
}
}
void preIterator(vector<TreeNode*>& vector, TreeNode* root) {
if (root == nullptr) {
return;
}
vector.push_back(root);
preIterator(vector, root->left); // 分身术:左子树
preIterator(vector, root->right); // 分身术:右子树
}
敖丙看完代码后,感叹道:“这递归真是妙啊!就像你的分身术,一层一层地解决问题。”我得意地笑了笑:“那当然,这可是我的看家本领!”
迭代:申公豹的“风火轮计划”
申公豹听了不服气,跳出来说:“哼,递归算什么!我的迭代才是真正的‘风火轮计划’,一步一个脚印,稳扎稳打!”于是,他掏出了迭代的代码。
Java代码:
public void flatten(TreeNode root) {
if (root == null) {
return;
}
Stack<TreeNode> stack = new Stack<>();
List<TreeNode> list = new ArrayList<>();
TreeNode node = root;
while (node != null || !stack.isEmpty()) {
while (node != null) {
list.add(node);
stack.push(node);
node = node.left; // 先往左冲
}
node = stack.pop();
node = node.right; // 再往右冲
}
if (list.size() <= 1) {
return;
}
for (int i = 1; i < list.size(); i++) {
TreeNode pre = list.get(i - 1);
TreeNode next = list.get(i);
pre.left = null;
pre.right = next;
}
}
C++代码:
void flatten(TreeNode* root) {
if (root == nullptr) {
return;
}
stack<TreeNode*> stack;
vector<TreeNode*> list;
TreeNode* node = root;
while (node != nullptr || !stack.empty()) {
while (node != nullptr) {
list.push_back(node);
stack.push(node);
node = node->left; // 先往左冲
}
node = stack.top();
stack.pop();
node = node->right; // 再往右冲
}
if (list.size() <= 1) {
return;
}
for (int i = 1; i < list.size(); i++) {
TreeNode* pre = list.at(i - 1);
TreeNode* next = list.at(i);
pre->left = nullptr;
pre->right = next;
}
}
申公豹得意地说:“看到没?我的迭代就像风火轮,一步一步往前滚,稳得不行!”敖丙点点头:“确实,迭代虽然代码长点,但不容易栈溢出,适合大规模战斗。”
第二回合:递归 vs 迭代,谁更胜一筹?
哪吒(我):“递归代码简洁,但可能会遇到栈溢出的问题,就像我的分身术,分身太多也会累趴下。”
敖丙:“迭代代码稍显复杂,但更节省内存,就像申公豹的风火轮,虽然慢点,但稳扎稳打。”
申公豹:“哼,你们俩别争了!递归和迭代各有千秋,关键看场景。就像我们三个,各有各的本事,合作才能无敌!”
坚持的意义
无论是递归还是迭代,解决问题的关键在于坚持。就像我在《哪吒2》里一样,面对困难不退缩,最终总能找到解决的办法。敖丙和申公豹也深有感触:“编程如修行,坚持才能突破自我!”
总结
今天,我们通过哪吒、敖丙和申公豹的视角,学习了二叉树的扁平化。递归像哪吒的分身术,简洁但可能栈溢出;迭代像申公豹的风火轮,稳扎稳打但代码稍长。无论选择哪种方法,坚持才是最重要的!
哪吒的口号:我命由我不由天,代码由我不由Bug!
敖丙的口号:稳扎稳打,步步为营!
申公豹的口号:风火轮计划,一步一个脚印!
好了,今天的分享就到这里。如果你觉得这篇文章对你有帮助,别忘了点赞、分享哦!我们下次再见!
作者:哪吒、敖丙、申公豹
合作宣言:编程如修行,合作才能无敌!