二叉樹的基本操作

  • 首先我們來了解一下什麼是二叉樹
    二叉樹是每個節點最多有兩個子樹的樹結構。通常子樹被稱作“左子樹”(left subtree)和“右子樹”(right subtree)。

  • 二叉樹的特點:
    1.每個節點最多有兩棵子樹,即二叉樹不存在度大於2的節點
    2.二叉樹的子樹有左右之分,其子樹的順序不能顛倒
    3.滿二叉樹: 在一棵二叉樹中,如果所有分支節點都存在左子樹和右子樹,並且所有葉子節點都在同一層上
    4.完全二叉樹:如果一棵具有N個節點的二叉樹的結構與滿二叉樹的前N個節點的結構相同,稱爲完全二叉樹
    5.滿二叉樹與完全二叉樹之間的關係:滿二叉樹是一個特殊的完全二叉樹
    這裏寫圖片描述

  • 二叉樹的性質:
    1.若規定根節點的層數爲1,則一棵非空二叉樹的第i層上最多有2^(i-1)(i > 0)個節點;
    3.對任何一棵二叉樹,如果其葉子節點個數爲n0,度爲2的非葉子節點個數爲n2,則有n0 = n2 +1;
    4.具有n個節點的完全二叉樹的深度爲k爲log2(n+1)上取整;
    5.對於具有n個節點的完全二叉樹,如果按照從上至下從左至右的順序對所有節點從0開始編號,則對於序號爲i的節點有:
    (1)若 i>0,雙親序號:(i-1)/2 i=0,
    i爲根節點編號,無雙親節點
    (2)若 n>2i+1,左孩子序號爲2i+1,否則無左孩子
    (3)若 n>2i+1,右孩子序號爲2i+1,否則無右孩子
    這裏寫圖片描述

  • 二叉樹的存儲結構:
    二叉樹主要有順序存儲結構和鏈式存儲結構
    順序存儲結構:對於一棵完全二叉樹所有節點按照層序自頂向下,同一層自左向右順序編號,就得到一個節點的順序序列
    優點:存儲完全二叉樹,簡單省空間
    缺點:存儲一般二叉樹尤其單支樹,存儲空間利用不高
    鏈式存儲結構:
    這裏寫圖片描述

這裏寫圖片描述

  • 二叉樹的遍歷:
    1.先序遍歷:
    (1)訪問根節點
    (2)遍歷左子樹
    (3)遍歷右子樹
    2.中序遍歷:
    (1)遍歷左子樹
    (2)訪問根節點
    (3)遍歷右子樹
    3.後續遍歷:
    (1)遍歷左子樹
    (2)遍歷右子樹
    (3)訪問根節點
    4.層序遍歷:
    按照二叉樹的層序次序,同一層中按先左子樹再右子樹的次序遍歷二叉樹

  • 下面就是對二叉樹的四種遍歷代碼的實現:
    這裏寫圖片描述

  • 首先是 .h 文件

#pragma once
#include<stdio.h>
typedef char TreeNodeType;

//使用孩子表示法來表示一個樹
typedef struct TreeNode
{
    TreeNodeType data;
    struct TreeNode* lchild;
    struct TreeNode* rchild;
}TreeNode;

//對於鏈表來說,使用鏈表的頭節點的指針表示一個鏈表
//對於一個樹來書,使用根節點的指針來表示一個樹
void TreeInit(TreeNode** pRoot);

void TreePreOrder(TreeNode* root);//先序
void TreeInOrder(TreeNode* root);//中序
void TreePostOrder(TreeNode* root);//後序
void TreeLevelOrder(TreeNode* root);//層序
#include <stdio.h>
#include"bin_tree.h"
#include"seqqueue.h"//因爲層序用到了隊列,所以將前面的隊列代碼引用進來
#include<stdlib.h>
#include<stddef.h>

TreeNode* CreateTreeNode(TreeNodeType value)//創建一個新的節點
{
    TreeNode* new_node = (TreeNode*)malloc(sizeof(TreeNode));
    new_node->data = value;
    new_node->lchild = NULL;
    new_node->rchild = NULL;
    return new_node;
}
void DestroyTreeNode(TreeNode* node)
{
    free(node);
}
void TreeInit(TreeNode** pRoot)//初始化
{
    if(pRoot == NULL)
    {
        //非法輸入
        return;
    }
    if(*pRoot == NULL)
    {
        //空樹
        return;
    }
    *pRoot = NULL;
    return;
}
  • 先序遍歷的實現:
    這裏寫圖片描述
void TreePreOrder(TreeNode* root)
{
    if(root == NULL)
    {
        printf("#");
        return;
    }
    //先訪問根結點,再左子樹,再右子樹
    printf("%c",root->data);
    TreePreOrder(root->lchild);
    TreePreOrder(root->rchild);
    return;
}
void TestPreOrder()
{
    TEST_HEADER;
    TreeNode* a = CreateTreeNode('a');
    TreeNode* b = CreateTreeNode('b');
    TreeNode* c = CreateTreeNode('c');
    TreeNode* d = CreateTreeNode('d');
    TreeNode* e = CreateTreeNode('e');
    TreeNode* f = CreateTreeNode('f');
    TreeNode* g = CreateTreeNode('g');
    a->lchild = b;
    a->rchild = c;
    b->lchild = d;
    b->rchild = e;
    e->lchild = g;
    c->lchild = f;
    TreePreOrder(a);
    return;
}

這裏寫圖片描述

  • 中序遍歷的實現:
    這裏寫圖片描述
void TreeInOrder(TreeNode* root)
{
    if(root == NULL)
    {
        return;
    }
    //先遍歷左子樹,再遍歷根節點,最後遍歷右子樹
    TreeInOrder(root->lchild);
    printf("%c",root->data);
    TreeInOrder(root->rchild);
    return;
}
void TestInOrder()
{
    TEST_HEADER;
    TreeNode* a = CreateTreeNode('a');
    TreeNode* b = CreateTreeNode('b');
    TreeNode* c = CreateTreeNode('c');
    TreeNode* d = CreateTreeNode('d');
    TreeNode* e = CreateTreeNode('e');
    TreeNode* f = CreateTreeNode('f');
    TreeNode* g = CreateTreeNode('g');
    a->lchild = b;
    a->rchild = c;
    b->lchild = d;
    b->rchild = e;
    e->lchild = g;
    c->lchild = f;
    TreeInOrder(a);
    return;
}

這裏寫圖片描述

  • 後序遍歷的實現:
    這裏寫圖片描述
void TreePostOrder(TreeNode* root)
{
    if(root == NULL)
    {
        return;
    }
    //先遍歷左子樹,再遍歷右子樹,最後訪問根結點
    TreePostOrder(root->lchild);
    TreePostOrder(root->rchild);
    printf("%c",root->data);
    return;
}
void TestPostOrder()
{
    TEST_HEADER;
    TreeNode* a = CreateTreeNode('a');
    TreeNode* b = CreateTreeNode('b');
    TreeNode* c = CreateTreeNode('c');
    TreeNode* d = CreateTreeNode('d');
    TreeNode* e = CreateTreeNode('e');
    TreeNode* f = CreateTreeNode('f');
    TreeNode* g = CreateTreeNode('g');
    a->lchild = b;
    a->rchild = c;
    b->lchild = d;
    b->rchild = e;
    e->lchild = g;
    c->lchild = f;
    TreePostOrder(a);
    printf("\n");
    return;
}

這裏寫圖片描述

  • 層序遍歷的實現:
    這裏寫圖片描述
void TestLevelOrder()
{
    TEST_HEADER;
    TreeNode* a = CreateTreeNode('a');
    TreeNode* b = CreateTreeNode('b');
    TreeNode* c = CreateTreeNode('c');
    TreeNode* d = CreateTreeNode('d');
    TreeNode* e = CreateTreeNode('e');
    TreeNode* f = CreateTreeNode('f');
    TreeNode* g = CreateTreeNode('g');
    a->lchild = b;
    a->rchild = c;
    b->lchild = d;
    b->rchild = e;
    e->lchild = g;
    c->lchild = f;
    TreeLevelOrder(a);
    printf("\n");
    return;
}
void TreeLevelOrder(TreeNode* root)
{
    if(root == NULL)
    {
        return;
    }
    SeqQueue queue;
    SeqQueueInit(&queue);
    SeqQueuePush(&queue,root);
    while(1)
    {
        SeqQueueType front;
        int ret = SeqQueueFront(&queue,&front);
        if(ret == 0)
        {
            //如果取隊列首元素失敗,說明隊列爲空
            //如果隊列爲空,說明遍歷已經結束
            break;
        }
        printf("%c",front->data);
        SeqQueuePop(&queue);
        if(front->lchild != NULL)
        {
            SeqQueuePush(&queue,front->lchild);
        }
        if(front->rchild != NULL)
        {
            SeqQueuePush(&queue,front->rchild);
        }
    }
    printf("\n");
    return;
}

這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章