数据结构——树与二叉树

一、树的定义和性质

(1)树的定义:树是n(n>=0)个结点的有限集。

  1. 当n=0时该树称为空树。
  2. 当n>0时,仅有一个称为根的结点。同时其余节点可分为m(m>0)个互不相交的有限集T1,T2,…,Tm,其中每个集合本身又是一棵树,并且称为根的子树。

结点的度:一个结点拥有的子树个数称为该结点的度。

叶节点(终端结点):度为0的结点称为叶节点。

分支结点:度不为0的结点。

父结点:当一个结点有子结点,则称这个结点为这个子结点的父结点。

子结点:若一个结点含有的子树的根结点,则称该结点的子结点。

兄弟结点:拥有相同的父结点称为兄弟结点。

树的度:在一棵树中,最大的结点的度被称为树的度。

结点的层次:定义上来说根结点层次为1,根节点的子结点层次为2,如此类推。

树的高度:树中结点的最大层次。

堂兄弟的节点:父节点在同一层的节点称为堂兄弟结点。

节点的祖先:从根结点到该结点所经过分支的所有结点,被称为该结点的祖先(包括根结点)。

子孙:以某结点为根的子树中任意一结点都称为该结点的子孙。

森林:由n(n>0)棵不相交的树组成的集合称为森林。

(2)树的性质

  1. 树中结点数 = 所有结点的度+1。
  2. 度为m的树中第i层最多有m^(i-1)个结点。
  3. 高度为h的m叉树最多有(m^h - 1)/ (m - 1)个结点。
  4. 有n个结点的m叉树最小高度为logm  (n(m-1)+1)

(3)树与非树

  1. 子树不相交。
  2. 除了根结点外每个结点都有且仅有一个父结点。
  3. 一棵n个结点的树,有n-1条度。

二、二叉树

二叉树是一种特殊的树,度最大为2。

二叉树有左右子树之分,次序不能颠倒,所以二叉树的有序树。

满二叉树

当一个二叉树每一层的结点都达到饱和,我们称这个二叉树为满二叉树。(如图)

所以,一个满h层的二叉树有2^h - 1个结点。 

完全二叉树

完全二叉树除了最后一层外,其余层必须饱和。最后一层可以不饱和(也可以饱和),但必须遵循从左到右连续。

注:满二叉树是特殊的完全二叉树。

 完全二叉树

 非完全二叉树

 没有遵循从左到右连续的原则。

所以当完全二叉树的高为h,那么他有[2^(h-1),2^h - 1]个结点。

二叉树的遍历

  • 二叉树的前序遍历:根->左->右
  • 二叉树的中序遍历:左->根->右
  • 二叉树的后序遍历:左->右->根
  • 二叉树的层序遍历:第一层->第二层->...->第h层

三、二叉树的代码实现

二叉树的定义

typedef int BTDataType;    //便于修改要存储的数据

typedef struct BinaryTreeNode
{
	BTDataType data;            //存储数据
	struct BinaryTreeNode* left;//左孩子(左子树根结点)
	struct BinaryTreeNode* right;//右孩子(右子树根结点)
}BTNode;

二叉树的构建 

以数组"ABD##E#H##CF##G##"为例,构建二叉树。

// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
// pi记录数组a使用到哪一个元素
BTNode* BinaryTreeCreate(BTDataType* a, int* pi)
{
    assert(a && pi);
    if (a[*pi] == '#')
    {
        (*pi)++;
        return NULL;
    }

    BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));
    if (newnode == NULL)
    {
        perror("malloc failure");
        exit(-1);
    }
    newnode->data = a[(*pi)++];

    newnode->left = BinaryTreeCreate(a, pi);
    newnode->right = BinaryTreeCreate(a, pi);

    return newnode;
}

二叉树销毁

void BinaryTreeDestory(BTNode** root)
{
    assert(root);
    if (*root == NULL)
        return;

    BinaryTreeDestory(&((*root)->left));
    BinaryTreeDestory(&((*root)->right));
    free(*root);
    *root = NULL;
}

二叉树节点个数

int BinaryTreeSize(BTNode* root)
{
    if (root == NULL)
        return 0;

    return BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
}

二叉树叶子节点个数

int BinaryTreeLeafSize(BTNode* root)
{
    if (root == NULL)
        return 0;

    if (root->left == NULL && root->right == NULL)
        return 1;
    
    return BinaryTreeLeafSize(root->right)+BinaryTreeLeafSize(root->left);
}

二叉树第k层节点个数

int BinaryTreeLevelKSize(BTNode* root, int k)
{
    assert(k > 0);
    if (root == NULL)
        return 0;

    if (k == 1)
        return 1;

    return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1);
}

二叉树查找值为x的节点

BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
    if (root == NULL)
        return NULL;

    if (root->data == x)
        return root;

    BTNode* ret = NULL;
    if (ret = BinaryTreeFind(root->left, x))
        return ret;
    
    if (ret = BinaryTreeFind(root->right, x))
        return ret;

    return NULL;
}

二叉树遍历

层序遍历是利用队列先进先出的特点来实现的,先将根结点入队,然后只要队列不为空就先访问访问队列中第一个元素,再依次去访问左右结点(根结点是第一层,他的左右结点是第二层,然后如此类推就是第三层)

//前序遍历
void BinaryTreePrevOrder(BTNode* root)
{
    if (root == NULL)
    {
        printf("N ");
        return;
    }

    printf("%c ", root->data);
    BinaryTreePrevOrder(root->left);
    BinaryTreePrevOrder(root->right);
}



//中序遍历
void BinaryTreeInOrder(BTNode* root)
{
    if (root == NULL)
    {
        printf("N ");
        return;
    }

    BinaryTreeInOrder(root->left);
    printf("%c ", root->data);
    BinaryTreeInOrder(root->right);
}

//后序遍历
void BinaryTreePostOrder(BTNode* root)
{
    if (root == NULL)
    {
        printf("N ");
        return;
    }

    BinaryTreePostOrder(root->left);
    BinaryTreePostOrder(root->right);
    printf("%c ", root->data);
}


//层序遍历
void BinaryTreeLevelOrder(BTNode* root)
{
    Queue q;
    QueueInit(&q);

    if (root != NULL)
    {
        QueuePush(&q, root);
    }

    while (QueueEmpty(&q) == 0)
    {
        printf("%c ", QueueFront(&q)->data);

        if (QueueFront(&q)->left != NULL)
        {
            QueuePush(&q, QueueFront(&q)->left);
        }

        if (QueueFront(&q)->right != NULL)
        {
            QueuePush(&q, QueueFront(&q)->right);
        }

        QueuePop(&q);
    }
}

判断二叉树是否是完全二叉树

bool BinaryTreeComplete(BTNode* root)
{
    Queue q;
    QueueInit(&q);
    if (root)
        QueuePush(&q, root);

    int levelSize = 1;
    while (!QueueEmpty(&q))
    {
        BTNode* front = QueueFront(&q);
        QueuePop(&q);

        if (front == NULL)
            break;

        QueuePush(&q, front->left);
        QueuePush(&q, front->right);
    }

    // 前面遇到空以后,后面还有非空就不是完全二叉树
    while (!QueueEmpty(&q))
    {
        BTNode* front = QueueFront(&q);
        QueuePop(&q);

        if (front)
        {
            QueueDestroy(&q);
            return false;
        }
    }

    QueueDestroy(&q);
    return true;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值