日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

mysql递归查询所有上下节点_非递归打印二叉树的所有路径,保存父节点和孩子节点到底有啥差别...

發布時間:2023/12/2 数据库 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mysql递归查询所有上下节点_非递归打印二叉树的所有路径,保存父节点和孩子节点到底有啥差别... 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目解讀

題目要求輸出二叉樹的所有路徑(字符串形式),乍一看很簡單,不就是二叉樹的遍歷嘛!其實不然,首先,我們用非遞歸的方式(C++)解決這道題(遞歸在產品代碼中是不允許使用的,其次定位 bug 的時候非常困難)。這道題并非簡單的 dfs(深度優先搜索),需要點技巧。

題目描述

標準 dfs 遍歷輸出 - 每次輸出孩子節點

/**

* Definition for a binary tree node.

* struct TreeNode {

* int val;

* TreeNode *left;

* TreeNode *right;

* TreeNode(int x) : val(x), left(NULL), right(NULL) {}

* };

*/

class Solution {

public:

vector binaryTreePaths(TreeNode* root) {

if (root == nullptr) {

return {};

}

vector ans;

vector> allPath;

stack s;

vector path;

s.push(root);

path.push_back(root->val);

cout << path.back() << endl;

while (!s.empty()) {

TreeNode* curr = s.top();

s.pop();

if (curr->right != nullptr) {

path.push_back(curr->right->val);

s.push(curr->right);

cout << path.back() << endl;

}

if (curr->left != nullptr) {

path.push_back(curr->left->val);

s.push(curr->left);

cout << path.back() << endl;

}

}

return ans;

}

};

借助棧,上述代碼實現了最簡單的 dfs 遍歷,結果如下:

標準 dfs 輸出 - 每次輸出孩子節點

棧中之所以先添加右葉子節點,是為了保證最終路徑輸出順序從左往右。

標準 dfs 遍歷輸出 - 每次輸出父親節點

上述代碼實現了標準 dfs 遍歷,但顯然不能滿足題目要求,那該怎么處理呢?我們繼續往下看。

class Solution {

public:

vector binaryTreePaths(TreeNode* root) {

if (root == nullptr) {

return {};

}

vector ans;

vector> allPath;

stack s;

vector path;

s.push(root);

path.push_back(root->val);

// cout << path.back() << endl;

while (!s.empty()) {

TreeNode* curr = s.top();

cout << curr->val << endl;

s.pop();

if (curr->right != nullptr) {

path.push_back(curr->right->val);

s.push(curr->right);

// cout << path.back() << endl;

}

if (curr->left != nullptr) {

path.push_back(curr->left->val);

s.push(curr->left);

// cout << path.back() << endl;

}

}

return ans;

}

};

上述代碼中,我們打印棧頂每次彈出的元素,可以得到如下結果:

標準 dfs 輸出 - 每次輸出父節點

也就是說,每次只要某個節點的孩子節點都入棧了,該節點就可以不用考慮了。這個例子中,棧中初始節點是 1,然后加入其孩子節點 3、2,1 出棧;再加入節點 2 的孩子節點 5,2 出棧;以此類推。可是,這還無法得到題目要求的結果呀!不著急,我們離答案已經越來越近了。

二叉樹的所有路徑

通過觀察發現:每次從棧頂彈出的節點,如果它沒有孩子節點,那么這個節點就是葉子節點,而且遇到的第一個葉子節點也是最左邊的葉子節點。我們把每次從棧頂彈出的節點記錄下來,保存在 vector 中,那么遇到第一個葉子節點時,我們就得到最左邊的一條路徑(1->2->5).但是,接下來棧頂彈出的元素可是 3,想要得到一條完整的路徑,必須將 3 和 1->2 拼接。或者說,要知道 3 之前彈出了哪些元素,我們把 3 之前棧頂彈出的元素 和 3 拼接,再與 3 之后的路徑拼接起來,即可得到第二條路徑。如何實現這點是這道題的關鍵所在。很容易想到的一點是,在輸出的前一條路徑(vector)基礎上,不斷將尾部元素丟棄,那什么時候停止丟棄呢?顯然,丟棄直到第一條路徑的尾部元素的右孩子節點是 3 即可。所以,path 這個 vector 中就不能記錄節點的值了,而要記錄節點的地址,因為值不是唯一的,而地址是唯一的。

/**

* Definition for a binary tree node.

* struct TreeNode {

* int val;

* TreeNode *left;

* TreeNode *right;

* TreeNode(int x) : val(x), left(NULL), right(NULL) {}

* };

*/

class Solution {

public:

vector binaryTreePaths(TreeNode* root) {

if (root == nullptr) {

return {};

}

vector ans;

stack s;

vector path;

s.push(root);

string tmp;

while (!s.empty()) {

TreeNode* curr = s.top();

s.pop();

path.push_back(curr);

if (curr->right != nullptr) {

s.push(curr->right);

}

if (curr->left != nullptr) {

s.push(curr->left);

}

if (curr->left == nullptr && curr->right == nullptr) {

for (auto node : path) {

tmp += to_string(node->val);

if (node != path.back()) {

tmp += "->";

}

}

ans.push_back(tmp);

tmp.clear();

while (path.empty() == false && s.empty() == false && path.back()->right != s.top()) {

path.pop_back();

}

}

}

return ans;

}

};

這一次,終于得到了我們想要的結果了。上述代碼中記錄 string 的過程可以有更有效的方法,這里為了使代碼的呈現更加容易理解,就不處理了,讀者可以自己去研究下。

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的mysql递归查询所有上下节点_非递归打印二叉树的所有路径,保存父节点和孩子节点到底有啥差别...的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。