LeetCode刷題之樹

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;
        }
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章