How to Implement a Website with MVC Architecture using PHP

The MVC Architecture, benefiting the developers maintaining and improving the web considerably, has becoming the trends and mature technique with numerous frameworks. The following slides is the simply intro and analysis about MVC using PHP (Laravel),  Hoping helps!

LeetCode - 94. Binary Tree Inorder Traversal

Category: Algorithm
Difficulty: Medium
Tags: Tree, Hash Table, Stack
Discription: https://leetcode.com/problems/binary-tree-inorder-traversal/#/description
正如題目Binary Tree Inorder Traversal,本題便是實作中序走訪。
在這裡,共有四種實作方式:
1.          Recursion 遞迴:時間複雜度O(n) ,空間複雜度O(n)
(1)       最直覺而簡單易懂的實作方式,依左子樹、根、右子樹之順序遞迴呼叫自己。
(2)       但缺點是遞迴受限於二元樹之階層數,有記憶體空間利用上的缺陷。
/**
 * 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<int> inorderTraversal(TreeNode* root) {
        vector<int> result;
        in_tra(root, &result);
        return result;
    }
    void in_tra(TreeNode* node, vector<int>* result){
        if(!node) return;
        in_tra(node->left, result);
        (*result).push_back(node->val);
        in_tra(node->right, result);
    }
};

2.          Stack & Map 堆疊與映射:時間複雜度O(n) ,空間複雜度O(n)
(1)       建立一TreeNode指標(TreeNode*)型態之StackMap(TreeNode*bool)
(2)       Stack是為了實作出遞迴,而Map是為了記憶走訪過之節點。
(3)       流程解說:
l   確認「Stack不為空」後進入while迴圈:(在開始之前已將根節點root推入Stack)
n   先將Stack頂層元素指定給currNode,再進行分支判斷。
n   分支判斷一(if):「currNode之左元素不為空」且「Map中對映currNode之布林值為false
u  currNodee之左元素推入Stack
u  Map中對映currNode之布林值改為true
n   分支判斷二(else)
u  currNode值推入回傳結果陣列(result)
u  移除Stack頂端元素(就是現在的currNode,未來不再走訪)
u  分支判斷:「currNode之右元素不為NULL
²  currNode之右元素推入Stack
l   繼續重複while迴圈,直到退出並回傳結果陣列(result)
/**
 * 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<int> inorderTraversal(TreeNode* root) {
        vector<int> result;
        if(!root) return result;
        
        unordered_map<TreeNode*, bool> map;
        vector<TreeNode*> stack;
        stack.push_back(root);
        TreeNode *currNode;
        
        while(!stack.empty()){
            currNode = stack.back();
            if(currNode->left && !map[currNode]){
                stack.push_back(currNode->left);
                map[currNode] = true;
            }
            else{
                result.push_back(currNode->val);
                stack.pop_back();
                if(currNode->right){
                    stack.push_back(currNode->right);
                }
            }
        }
        return result;
    }
};

3.          Pure Stack 純堆疊:時間複雜度O(n),空間複雜度O(n)
(1)       這個方式是由上一個演算法修改而來,並在保留Stack的基礎上,新增了兩個變數:currNodepreNode(皆為TreeNode*型態)
(2)       currNode意指「正在走訪的節點」,而preNode意指「currNode的上一個節點」。
(3)       流程解說:
l   確認「Stack不為空」或「currNode不為空」後進入while迴圈:(在開始之前將currNode設為根節點root)
n   分支判斷一(if):「currNode不為空」
u  currNode推入Stack
u  currNode指向currNode之左元素。
n   分支判斷二(else)
u  Stack頂層元素指定給preNode
u  preNode值推入回傳結果陣列(result)
u  移除Stack頂端元素(就是現在的preNode,未來不會再走訪)
u  currNode指向preNode之右元素。
l   繼續重複迴圈,直到退出並回傳結果陣列(result)
/**
 * 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<int> inorderTraversal(TreeNode* root) {
        vector<int> result;
        vector<TreeNode*> stack;
        TreeNode *currNode = root;
        TreeNode *preNode;
        
        while(!stack.empty() || currNode){
            if(currNode){
                stack.push_back(currNode);
                currNode = currNode->left;
            }
            else{
                preNode = stack.back();
                result.push_back(preNode->val);
                stack.pop_back();
                currNode = preNode->right;
            }
        }
        return result;
    }
};

4.          Morris Traversal 莫里斯走訪:時間複雜度O(n),空間複雜度O(1)
(1)       這個演算法實作出的中序走訪不需要Stack,也因此空間複雜度為O(1)
(2)       這個演算法不會破壞原二元樹形狀。(中間過程有變形)
(3)       使用「引線二元樹」的概念(threaded binary tree),令元素的左右指標指向上一個或下一個節點,以此在缺少Stack的情況下實作出從子節點走訪回父節點的方式。
(4)       currNode意指「正在走訪的節點」,而preNode意指「currNode的上一個節點」。
(5)       流程解說:
l   確認「currNode不為空」後進入while迴圈:(在開始之前將currNode設為根節點root)
n   分支判斷一(if):「currNode之左元素不為空」(在現在的左子樹底下找到preNode)
u  preNode指向currNode之左元素。
u  while迴圈:「preNode之右元素不為空」且「preNode之右元素不為currNodee
²  preNode指向preNode之右元素。(此為preNode)
u  分支判斷一(if):「preNode之右元素為空」(改變樹的形狀)
²  preNode之右元素指向currNode
²  currNode指向currNode之左元素。(繼續走訪下一個元素)
u  分支判斷一(else):「preNode之右元素不為空」(回復樹的形狀)
²  preNode之右元素指向NULL
²  currNode值推入回傳結果陣列(result)
²  currNode指向currNode之右元素。(繼續走訪下一個元素)
n   分支判斷二(else)
u  currNode值推入回傳結果陣列(result)
u  currNode指向currNode之右元素。(繼續走訪下一個元素)
l   繼續重複迴圈,直到退出並回傳結果陣列(result)
/**
 * 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<int> inorderTraversal(TreeNode* root) {
        vector<int> result;
        TreeNode* currNode = root;
        TreeNode* preNode;
        
        while(currNode){
            if(currNode->left){
                preNode = currNode->left;
                while(preNode->right && (preNode->right)!=currNode)
                    preNode = preNode->right;
                if(!(preNode->right)){
                    preNode->right = currNode;
                    curNode = currNode->left;
                }
                else{
                    preNode->right = NULL;
                    result.push_back(curNode->val);
                    curNode = curNode->right;
                }
            }
            else{
                result.push_back(curNode->val);
                curNode = curNode->right;
            }
        }
        return result;
    }
};

留言