94. 二叉樹的中序遍歷
思路:想到了常規遞歸算法,但是官方解使用提供了三種解法。第一中是最容易理解的,遞歸;第二中,棧和迭代完成遍歷並返回數據;第三中,用了一種特殊的樹來完成,這個方法我覺得就沒必要學了。
遞歸解法:
C代碼
typedef struct TreeNode {
int val;
struct TreeNode* left;
struct TreeNode* right;
}TreeNode;
//get樹的節點數
int getSize(struct TreeNode* root)
{
if (!root)
return 0;
return getSize(root->left) + getSize(root->right) + 1;
}
//中序遍歷樹,並將數據讀入堆上分配的內存中
void inorderTree(struct TreeNode* root, int* res)
{
//靜態變量具有記憶功能
static int index = 0;
if (!root)
return;
inorderTree(root->left, res);
res[index++] = root->val;
inorderTree(root->right, res);
}
//主體函數,上面2個函數是輔助函數
int* inorderTraversal(struct TreeNode* root, int* returnSize) {
*returnSize = getSize(root);
int* res = (int*)malloc(sizeof(int) * *returnSize);
if (*returnSize == 0)
{
return res;
}
inorderTree(root, res);
return res;
}
c++代碼
class Solution {
public:
vector<int> res;
vector<int> inorderTraversal(TreeNode* root) {
if (!root)
return res;
inorderTraversal(root->left);
res.push_back(root->val);
inorderTraversal(root->right);
return res;
}
};
144. 二叉樹的前序遍歷
思路:
1.遞歸算法,簡潔明瞭,簡單易懂,不做解釋。
2.迭代算法,基於對遞歸算法的觀察得出,代碼中有詳細註釋爲總結。
遞歸算法:
C代碼
typedef struct TreeNode {
int val;
struct TreeNode* left;
struct TreeNode* right;
}TreeNode;
int getSize(struct TreeNode* root)
{
if (!root) return 0;
return getSize(root->left) + getSize(root->right) + 1;
}
void preorder(struct TreeNode* root, int* res)
{
static int index = 0;
if (!res || !root) return;
res[index++] = root->val;
preorder(root->left, res);
preorder(root->right, res);
}
int* preorderTraversal(struct TreeNode* root, int* returnSize) {
*returnSize = getSize(root);
int* res = (int*)malloc(sizeof(int) * (*returnSize));
if (*returnSize == 0) return res;
//遞歸的先序遍歷tree,並依次訪問節點。
preorder(root, res);
return res;
}
c++代碼
class Solution {
public:
vector<int> res;
vector<int> preorderTraversal(TreeNode* root) {
if(!root)
return res;
res.push_back(root->val);
//以下爲遞歸調用,任何一次遞歸調用執行具有實質效果的代碼都是上面的代碼,這就如同迭代
//任何一次迭代都將執行相同形式的代碼,尾遞歸形式是最好轉爲迭代的。
preorderTraversal(root->left);
preorderTraversal(root->right);
return res;
}
};
迭代算法1:
遺憾的是,該迭代形式儘管十分容易理解但卻並不通用與中序,後序。
C代碼(什麼接口都要自己寫。。。好不方便,不用C寫了。)
C++代碼
class Solution {
public:
vector<int> res;
vector<int> preorderTraversal(TreeNode* root) {
stack<const TreeNode*> S; //維護一個臨時的輔助棧,元素爲指向節點的指針,由於我們不修改節點數據設定底層const
if (root) S.push(root); //根節點存在,入棧
while (!S.empty()) //棧非空,往返循環
{
//以代碼作用爲,訪問局部root節點,在依次訪問左孩子,右孩子節點,此爲先序遍歷
//若孩子節點不存在,即爲空,沒有任何實質操作,我們用if限制這種特殊情況
auto t = S.top();
vist(t, res);
S.pop();
if (t->right) S.push(t->right);
if (t->left) S.push(t->left);
}
return res;
}
//對節點進行訪問,依據題目不同要求可做修改,該題目要求爲讀取數據
inline void vist(const TreeNode* node, vector<int>& res)
{
res.push_back(node->val);
}
};
迭代算法2:
該迭代算法的思想可推廣至中序和後序,是通用的迭代算法。但該算法比較複雜難懂,註釋就不寫了,因爲寫了也沒用。
class Solution {
public:
vector<int> res;
vector<int> preorderTraversal(TreeNode* root) {
stack<TreeNode*> s;
while (true)
{
vistAlongLeft(s, root);
if (s.empty()) return res;
root = s.top();
s.pop();
}
}
void vistAlongLeft(stack<TreeNode*>& s, TreeNode* t)
{
while (t)
{
res.push_back(t->val);
s.push(t->right);
t = t->left;
}
}
};