1. 程式人生 > 其它 >【資料結構篇】樹(c語言)

【資料結構篇】樹(c語言)

樹的遍歷

前序遍歷

  • 首先訪問根節點,然後遍歷左子樹,最後遍歷右子樹

    遞迴寫法

    void preTravel(struct TreeNode*root)
    {
        if(root!=NULL)
        {
            printf("%d",root->val);
            travel(root->left);
            travel(root->right);
        }
    }
    

    迭代寫法 (迭代就是把遞迴過程中呼叫的棧顯式表達出來)

    void preTravel(struct TreeNode*root)
    {
        struct TreeNode *stk[100];
        int stk_top = -1;
        while (stk_top > -1 || root != NULL) 
        {
            while (root != NULL) 
            {
                printf("%d",root->val);
                stk[++stk_top] = root;
                root = root->left;
            }
            root = stk[stk_top--];
            root = root->right;
        }
    }
    

中序遍歷

  • 先左後根最後右(二叉搜尋樹中可以得到遞增的有序序列

    遞迴寫法

    void inorderTravel(struct TreeNode*root)
    {
         if(root==NULL)
            return;
        inorderTravel(root->left);
        printf("%d",root->val);
        inorderTravel(root->right);
    }
    

    迭代寫法 (迭代就是把遞迴過程中呼叫的棧顯式表達出來)

    void inorderTravel(struct TreeNode*root)
    {
        struct TreeNode *stk[100];
        int stk_top = -1;
        while (stk_top > -1 || root != NULL) 
        {
            while (root != NULL) 
            {
                stk[++stk_top] = root;
                root = root->left;
            }
            root = stk[stk_top--];
            printf("%d",root->val);
            root = root->right;
        }
    }
    

後序遍歷

  • 先左後右最後根

    遞迴寫法

     void postTravel(struct TreeNode*root)
    {
         if(root==NULL)
            return;
        postTravel(root->left,a,returnSize);
        printf("%d",root->val);
        postTravel(root->right,a,returnSize);
    }
    

    迭代寫法

    void preTravel(struct TreeNode*root)
    {
        struct TreeNode *stk[100];
        struct TreeNode *prev = NULL;
        int stk_top = -1;
        if(root==NULL)
            return;
        while (stk_top > -1 || root != NULL) 
        {
            while (root != NULL) 
            {
                stk[++stk_top] = root;
                root = root->left;
            }
            root=stk[stk_top--];
            if (root->right == NULL || root->right == prev) {
                printf("%d",root->val);
                prev = root;
                root = NULL;
            } 
            else 
            {
                stk[top++] = root;
                root = root->right;
            }
        }
    }
    

層序遍歷

  • 用佇列實現廣度優先搜尋,逐層遍歷
#define MAX 2000
int **levelOrder(struct TreeNode*root,int *returnSize,int **returnColumnSize)
{//返回逐層遍歷的二維陣列,returnColumnSize記錄每一層的大小
    *returnSize=0;//層數
    if(root==NULL)
        return;
    int**res=(int**)malloc(sizeof(int*)*MAX);//申請一個二維陣列空間
    struct TreeNode*Q[MAX];//隊,存放所有結點
    *returnColumnSize=(int*)malloc(sizeof(int)*MAX);
    int flag,size,front=0,rear=0;
    struct TreeNode*tmp=NULL;
    Q[rear++]=root;
    while(front!=rear)
    {//佇列不空時
        flag=rear;//當前層尾指標
        size=0;//當前層陣列大小
        res[*returnSize]=(int*)malloc(sizeof(int*)*(flag-front));
        while(front<flag)
        {//處理當前層
            tmp=Q[front++];
            res[*returnSize][size++]=tmp->val;
            //每個結點的左右孩子入隊
            if(p->left)
                Q[rear++]=p->left;
            if(p->right)
                Q[rear++]=p->right;
        }
        (*returnColumnSize)[*returnSize]=size;
        returnSize++;
    }
    return res;
}

遞迴解決問題

  • 最大深度
int maxDepth(struct TreeNode* root){
     return root == NULL ? 0 :fmax(maxDepth(root->left), maxDepth(root->right))+ 1;
}
  • 對稱二叉樹
bool isMirror(struct TreeNode*p,struct TreeNode*q)
{//遞迴思想:如果對稱,那每個樹的右子樹映象對稱另一個樹的左子樹
    if(!p&&!q)
        return true;
    if(!p||!q)
        return false;
    return (p->val==q->val)&&(isMirror(p->left,q->right))&&(isMirror(p->right,q->left));
}
bool isSymmetric(struct TreeNode* root){
    return isMirror(root,root);
}
  • 路徑總和
//判斷二叉樹中是否有一條路徑節點之和等於目標值
bool hasPathSum(struct TreeNode* root, int targetSum){
    if(!root)
        return false;
    if(!root->left&&!root->right)
        return root->val==targetSum;
    return hasPathSum(root->left,targetSum-root->val)||hasPathSum(root->right,targetSum-root->val);
}
  • 最近公共祖先
struct TreeNode* lowestCommonAncestor(struct TreeNode* root, struct TreeNode* p, struct TreeNode* q) {
    struct TreeNode* ancestor=root;
    while(1)
    {
        if(p->val<ancestor->val&&q->val<ancestor->val)
            ancestor=ancestor->left;
        else if(p->val>ancestor->val&&q->val>ancestor->val)
            ancestor=ancestor->right;
        else
            break;
    }
    return ancestor;
}
  • 最長路徑
#include <stdio.h>
#include <string.h>

using namespace std;

const int N = 100010;

int e[N] , ne[N] , h[N] , idx;
int f[N];//f[u]表示u到最遠葉節點的距離。顯然如果u是節點,則f[u]=0。
int n , m , ans;

void add(int a , int b)
{
    e[idx] = b , ne[idx] = h[a] , h[a] = idx++;
}

void dfs(int u)//求以u為根節點到葉節點的最大距離
{
    int a = 0 , b = 0;//a記錄u到最遠葉節點的距離,b記錄u到次遠葉節點的距離
    for(int i = h[u] ; ~i ; i = ne[i])
    {
        int j = e[i];
        //求子節點j到最遠葉節點的距離
        dfs(j);

        int t = f[j] + 1;//u通過j能到的最遠葉節點的距離

        //更新a、b
        if(t >= a)
            b = a , a = t;
        else if(t > b)
            b = t;
    }

    f[u] = a;
    //最後的答案就是u所能到的最遠葉節點距離和次遠葉節點距離之和
    ans = max(ans , a + b);
}

int main()
{
    cin >> n >> m;

    memset(h , -1 , sizeof h);
    //電腦其實和交換機等價,所以電腦的標號從n繼續往後標記即可
    for(int i = 2 ; i <= n + m ; i++)
    {
        int j;
        cin >> j;
        add(j , i);//因為是自根向下DP,所以建一條邊即可。
    }

    dfs(1);

    cout << ans << endl;
}