1. 程式人生 > >資料結構---二叉樹的基本操作

資料結構---二叉樹的基本操作

何為二叉樹

概念:一棵二叉樹是結點的一個有限集合,該集合或者為空,或者是由一個根節點加上兩棵分別稱為左子樹和右子樹的二叉樹組成

特點:

  • 每個結點最多有兩棵子樹
  • 二叉樹的子樹有左右之分,其子樹的次序不能顛倒

基本操作介紹

  • 二叉樹的遍歷(遞迴和非遞迴),可以說是所有操作中最重要的
  • 求樹的結點個數
  • 求樹的葉子結點的個數
  • 求第K層結點的個數
  • 求樹的高度
  • 在樹中查詢指定元素
  • 給定一個結點,查詢它的父結點
  • 複製一棵二叉樹
  • 求一個二叉樹的映象(遞迴和非遞迴)
  • 構建一個二叉樹(給出前序遍歷結果,帶有空結點)
  • 還原一個二叉樹(給出前序和中序遍歷結果,不帶空節點)

話不多說,直接附上程式碼來解釋這些操作

結構體宣告:

typedef char TreeNodeType;

typedef struct TreeNode{
    struct TreeNode* lchild;//左孩子結點
    struct TreeNode* rchild;//右孩子結點
    TreeNodeType data;
}TreeNode;

函式體宣告:

//初始化二叉樹
void TreeNodeInit(TreeNode** root);
//先序遍歷二叉樹
void PreOrder(TreeNode* root);
//中序遍歷
void InOrder(TreeNode* root);
//後序遍歷
void PostOrder(TreeNode* root)
; //層序遍歷 void LevelOrder(TreeNode* root); //求樹的節點個數 size_t TreeSize(TreeNode* root); //求樹的葉節點的個數 size_t LeafTreeSize(TreeNode* root); //求第K層節點的個數 size_t TreeLevelSize(TreeNode* root,size_t k); //求樹的高度 size_t TreeHeight(TreeNode* root); //在樹中查詢指定元素 TreeNode* TreeFind(TreeNode* root, TreeNodeType to_find); //給一個節點,找它的父節點
TreeNode* Parents(TreeNode* root,TreeNode* node); //非遞迴遍歷二叉樹 void PreOrderByLoop(TreeNode* root);//前 void InOrderByLoop(TreeNode* root);//中 void PostOrderByLoop(TreeNode* root);//後 //求一個二叉樹的映象 //遞迴版 void TreeMirror(TreeNode* root); //非遞迴版 void TreeMirrorByLoop(TreeNode* root); //銷燬一棵樹 TreeNode* TreeDestroy(TreeNode* root);

嘿嘿,下面開始瘋狂的貼上程式碼了
這裡寫圖片描述

簡單明瞭初始化和銷燬,不解釋

//初始化
void TreeNodeInit(TreeNode** root)
{
    if(root == NULL)
    {
        //非法輸入
        return;
    }
    *root = NULL;
}
//銷燬單個結點
void Destroy(TreeNode* root)
{
    free(root);
}

下面進行遞迴和非遞迴的遍歷,這個才是最重要的,其他的都可以不管,這個必須要仔細看
這裡寫圖片描述

//先序遍歷(根節點,左子樹,右子樹)
void PreOrder(TreeNode* root)
{
    if(root == NULL)                                                                                                                    
    {
        //遇到空節點就返回,遞迴出口
        return;
    }
    //訪問該節點
    printf("%c ",root->data); //先訪問根節點
    PreOrder(root->lchild);//再訪問左子樹
    PreOrder(root->rchild);//再訪問右子樹
}
//中序遍歷(左子樹,根節點,右子樹)
void InOrder(TreeNode* root)
{
    if(root == NULL)
    {
        return;
    }
    InOrder(root->lchild);//遍歷到最後一個左子樹葉子結點
    printf("%c ",root->data);//和前序遍歷不同就是訪問語句調了個位置
    InOrder(root->rchild);
}
//後序遍歷(左子樹,右子樹,根節點)
void PostOrder(TreeNode* root)
{
    if(root == NULL)
    {
        return;
    }   
    PostOrder(root->lchild);
    PostOrder(root->rchild);
    printf("%c ",root->data);//看到這裡應該懂了前中後遍歷了吧
}   
//層序遍歷(比較複雜,各位得好好捋一捋)
void LevelOrder(TreeNode* root)
{
    if(root == NULL)
    {
        return;
    }
    //1.先把根節點插入佇列
    SeqQueue seq;
    SeqQueueInit(&seq);
    SeqQueuePush(&seq,root);
    //2.迴圈的取隊首元素
    while(1){
    SeqQueueType node;
    int ret = SeqQueueGetTop(&seq,&node);
    if(ret == 0)
    {
        return;
    }
    //3.訪問隊首元素並出佇列
    SeqQueuePop(&seq);
    if(node != NULL)
    {
    printf("%c ",node->data);
    //4.將隊首元素的左子樹節點和右子樹節點都依次入佇列
    SeqQueuePush(&seq,node->lchild);
    //5.進入下一次迴圈,直到佇列為空,說明遍歷完了
    SeqQueuePush(&seq,node->rchild);
    }                                                                                                                                   
    }
}
//非遞迴遍歷二叉樹(前序)
void PreOrderByLoop(TreeNode* root)
{
    if(root == NULL)
    {   
        return;
    }   
    SeqStack stack;
    SeqStackInit(&stack);
    SeqStackPush(&stack,root);
    while(1)
    {   
        //取棧頂元素
        SeqStackType cur;
        int ret = SeqStackFindTop(&stack,&cur);
        //如果棧空的話說明已經遍歷完了
        if(ret == 0)
        {   
            break;
        }   
        //訪問棧頂元素並且出棧
        SeqStackPop(&stack);
        printf("%c ",cur->data);
        //先把每個節點的右孩子節點入棧,
        //再把左孩子節點入棧,
        //保證每次訪問完自身後,再訪問左子樹
        if(cur->rchild != NULL)
        {   
            SeqStackPush(&stack,cur->rchild);
        }   
        if(cur->lchild != NULL)
        {   
            SeqStackPush(&stack,cur->lchild);                                                                                           
        }   
    }   
    printf("\n");
}
//非遞迴遍歷二叉樹(中序)
void InOrderByLoop(TreeNode* root)
{
    if(root == NULL)
    {
        return;
    }
    SeqStack stack;
    SeqStackInit(&stack);
    SeqStackType cur = root;
    while(1)
    {
        while(cur != NULL)
        {
            SeqStackPush(&stack,cur);
            cur = cur -> lchild;
        }
        SeqStackType top;
        int ret = SeqStackFindTop(&stack,&top);
        if(ret == 0)
        {
            break;
        }
        printf("%c ",top->data);
        SeqStackPop(&stack);
        cur = top->rchild;
    }
}       
//非遞迴遍歷二叉樹(後序)
void PostOrderByLoop(TreeNode* root)
{
    if(root == NULL)
    {
        return;
    }
    SeqStack stack;
    SeqStackInit(&stack);
    TreeNode* cur = root;
    //儲存上一個訪問的元素
    TreeNode* pre = NULL;
    while(1)
    {
        //迴圈的將左子樹入棧
        while(cur!=NULL)
        {
            SeqStackPush(&stack,cur);
            cur = cur -> lchild;
        }
        //取出棧頂元素
        SeqStackType top;
        int ret = SeqStackFindTop(&stack,&top);
        if(ret == 0)
        {
            return;
        }
        //在訪問前要判斷
        //   1.它的右子樹是否為空
        //   2.或者判斷它的右子樹是否剛被訪問過
        //滿足任意一個條件就可以訪問當前元素並將其出棧
        if(top->rchild == NULL || top->rchild == pre)
        {                                                                                                                               
            printf("%c ",top->data);
            SeqStackPop(&stack);
            pre = top;
                    }
        //否則cur = cur->rchild ,跳到迴圈開始繼續
        else{
            cur = top->rchild;
        }
    }
}

其餘小操作

//在樹中查詢指定元素
TreeNode* TreeFind(TreeNode* root, TreeNodeType to_find)
{
    if(root == NULL)
    {
        return NULL;
    }
    if(root->data == to_find)
    {
        return root;
    }
    TreeNode* Lresult = TreeFind(root->lchild,to_find);
    TreeNode* Rresult = TreeFind(root->rchild,to_find);
    //時間複雜度為O(n),最壞的情況是所有元素都遍歷了也沒找到
    //空間複雜度也是O(n)
    return Lresult == NULL?Rresult:Lresult;
}    
//求樹的高度
size_t TreeHeight(TreeNode* root)
{
    if(root == NULL)
    {
        return 0;
    }
    //比較左右兩子樹的深度,返回深度大的那個
    size_t lheight = TreeHeight(root->lchild);
    size_t rheight = TreeHeight(root->rchild);
    //相當於是呼叫次數的比較
    return lheight >= rheight? lheight+1:rheight+1;
    //下面的程式碼也可以實現相同功能,
    //但是函式會被遞迴呼叫三次,上一種方式只會被遞迴呼叫兩次
    //所以效率比較低
    //return TreeHeight(root->lchild) >= TreeHeight(root->rchild)?TreeHeight(root->lchild):TreeHeight(root->rchild);
}
    //求樹的葉節點個數                                                                                                                      
size_t LeafTreeSize(TreeNode* root)
{
    if(root == NULL)
    {
        return 0;
    }
    if(root->lchild == NULL && root->rchild == NULL)
    {
        return 1;
    }
    return LeafTreeSize(root->lchild) + LeafTreeSize(root->rchild);

}

//求第K層節點的個數
size_t TreeLevelSize(TreeNode* root,size_t k)
{
    //我們規定樹從第一層開始
    if(root == NULL || k < 1)
    {
        return 0;
    }
    if(k == 1)
    {
        return 1;
    }
    return TreeLevelSize(root->lchild,k-1) + TreeLevelSize(root->rchild,k-1);
}
//複製一棵樹
TreeNode* TreeClone(TreeNode* root)
{
    if(root == NULL)
    {
        return NULL;
    }
    TreeNode* newnode = CreateTreeNode(root->data);
    newnode->lchild = TreeClone(root->lchild);
    newnode->rchild = TreeClone(root->rchild);
    return newnode;
}

//求樹的節點個數
size_t TreeSize(TreeNode* root)
{
    if(root == NULL)
    {
        return 0;
    }
    return 1 + TreeSize(root->lchild) + TreeSize(root->rchild);
}
//給一個節點,找它的父節點
TreeNode* Parents(TreeNode* root,TreeNode* node)
{
    if(root == NULL)
    {
        return NULL;
    }
    if(root->lchild == node || root->rchild == node)
    {
        return root;
    }
    TreeNode* Lresult = Parents(root->lchild,node);
    TreeNode* Rresult = Parents(root->rchild,node);
    return Lresult != NULL? Lresult:Rresult;
}

//求一個二叉樹的映象(遞迴版)
void TreeMirror(TreeNode* root)
{
    if(root == NULL)                                                                                                                    
    {
        return;
    }
    TreeNode* tmp = root->lchild;
    root->lchild = root->rchild;
    root->rchild = tmp;
    TreeMirror(root->lchild);
    TreeMirror(root->rchild);
}
//非遞迴版
void TreeMirrorByLoop(TreeNode* root)
{
    if(root == NULL)
    {
        return;
    }
    SeqStack stack;
    SeqStackInit(&stack);
    SeqStackPush(&stack,root);
    while(1)
    {
        SeqStackType top;
        int ret = SeqStackFindTop(&stack,&top);
        if(ret == 0)
        {
            return;
        }
        TreeNode* tmp = top->lchild;
        top->lchild = top->rchild;
        top->rchild = tmp;
        SeqStackPop(&stack);
        if(top -> lchild != NULL)
        {
            SeqStackPush(&stack,top->lchild);
        }
        if(top -> rchild != NULL)
        {
            SeqStackPush(&stack,top->rchild);
        }
    }
}