【C-数据结构】二叉树的插入(建树)

二叉树是什么


概念

在计算机科学中,二叉树是每个节点最多有两个子树的树结构。


组成

有两个子树,左子树(left subtree)和右子树(right subtree)。


用途

二叉树常被用于实现二叉查找树和二叉堆。


特点

  • 度:
    • 每个节点至多只有二棵子树(不存在度大于2的节点)
    • 第N层最多的度:2 ^ (N - 1)
    • 前N-1层的度:2 ^ (N - 1) - 1
  • 次序:二叉树的子树有左右之分, 次序不能颠倒。

类型

  • 满二叉树:一棵深度为k,且有2^k-1个节点称之为满二叉树;节点的度要么是0,要么是2
  • 完全二叉树:深度为k,有n个节点的二叉树,前k-1层是满二叉树;度为1的节点,最多有1个

存储

  • 可以顺序存储
  • 可以链式存储





二叉树的建树


头文件 BinaryTree.h

#ifndef __BINARYTREE_H__
#define __BINARYTREE_H__

#define TYPENAME char

//二叉树节点
typedef struct TreeNode {
    //数据域
    TYPENAME _data;
    //指针域
    struct TreeNode *_pLeft;
    struct TreeNode *_pRight;
}TreeNode_t, *pTreeNode_t;

//静态建树,已知树节点个数
void build_binaryTree(pTreeNode_t *ppRoot, TYPENAME *begin, TYPENAME *end);

//队列节点
typedef struct QueueNode {
    pTreeNode_t _data;  //树节点地址
    struct QueueNode *_pNext;
}QueueNode_t, *pQueueNode_t;

//队列
typedef struct Queue {
    pQueueNode_t _pHead;    //队头
    pQueueNode_t _pTail;    //队尾
}Queue_t, *pQueue_t;

//动态建树,不清楚节点个数,通过辅助队列
//辅助队列中,是所有没放完指针域的树节点
void insertTree_queue(pTreeNode_t *ppRoot, pQueue_t pQue, TYPENAME val);

//遍历
void preOrder(pTreeNode_t pRoot);   //先序遍历
void midOrder(pTreeNode_t pRoot);   //中序遍历
void postOrder(pTreeNode_t pRoot);  //后序遍历


#endif





实现文件 BinaryTree.c

#include "BinaryTree.h"
#include <stdio.h>
#include <stdlib.h>


void build_binaryTree(pTreeNode_t *ppRoot, TYPENAME *begin, TYPENAME *end)
{
    //求出二叉树的节点个数
    TYPENAME *start = begin;
    int len = 0;
    while (start != end) {
        ++start;
        ++len;
    }

    //申请所有树节点所需空间
    pTreeNode_t pArr = (pTreeNode_t)calloc(len, sizeof(TreeNode_t));

    //根据传入的数据,给所有树节点赋值
    start = begin;
    for (int i = 0; i < len; ++i, ++start) {
        pArr[i]._data = *start;
    }

    //建树
    //i 用来遍历树节点
    //j 表示要修改指针域的树节点
    *ppRoot = pArr;
    for (int i = 1, j = 0; i < len; ++i) {
        if (NULL == pArr[j]._pLeft) {
            pArr[j]._pLeft = &pArr[i];  //放左孩子
        }
        else {
            pArr[j]._pRight = &pArr[i]; //放右孩子
            ++j;    //当前节点指针域已全部放完,换下一个节点
        }
    }

    return;
}

void insertTree_queue(pTreeNode_t *ppRoot, pQueue_t pQue, TYPENAME val)
{
    //新建树节点,新建队列节点然后将其加入辅助队列
    pTreeNode_t pT = (pTreeNode_t)calloc(1, sizeof(TreeNode_t));
    pT->_data = val;
    pQueueNode_t pQ = (pQueueNode_t)calloc(1, sizeof(QueueNode_t));
    pQ->_data = pT;

    //如果树为空,给根节点赋值, 队列节点入队
    if (NULL == *ppRoot) {
        *ppRoot = pT;
        pQue->_pHead = pQ;
        pQue->_pTail = pQ;
        return;
    }

    //树不为空
    //队列节点入队
    pQue->_pTail->_pNext = pQ;
    pQue->_pTail = pQ;

    //将新树节点地址,赋给队首指向的树节点的指针域
    pQueueNode_t pCur = pQue->_pHead;
    if (NULL == pCur->_data->_pLeft) {
        //放左孩子
        pCur->_data->_pLeft = pT;
    }
    else {
        //放右孩子
        pCur->_data->_pRight = pT;
        //队首指向的树节点的指针域全部放完,出队
        pQue->_pHead = pQue->_pHead->_pNext;
        //释放队首
        free(pCur);
        pCur = NULL;
    }
}

void preOrder(pTreeNode_t pRoot)
{
    if (pRoot) {
        printf("%c ", pRoot->_data);
        preOrder(pRoot->_pLeft);
        preOrder(pRoot->_pRight);
    }
}
void midOrder(pTreeNode_t pRoot)
{
    if (pRoot) {
        midOrder(pRoot->_pLeft);
        printf("%c ", pRoot->_data);
        midOrder(pRoot->_pRight);
    }
}
void postOrder(pTreeNode_t pRoot)
{
    if (pRoot) {
        postOrder(pRoot->_pLeft);
        postOrder(pRoot->_pRight);
        printf("%c ", pRoot->_data);
    }
}





测试文件 test_tree.c

#include "BinaryTree.h"

#include <stdio.h>
#include <string.h>

void test0()
{
    pTreeNode_t pRoot = NULL;

    char arr[] = "abcdefghi";
    TYPENAME *begin = arr; //第一个元素的地址
    TYPENAME *end = arr + strlen(arr) - 1;  //最后一个元素的地址

    build_binaryTree(&pRoot, begin, end);
    
    printf("--------------test print_tree--------------\n");
    preOrder(pRoot);
    printf("\n");

    midOrder(pRoot);
    printf("\n");

    postOrder(pRoot);
    printf("\n");
}

void test1()
{
    pTreeNode_t pRoot = NULL;
    Queue_t que;


    char val;
    while (scanf("%c", &val)) {
        if ('\n' == val) {
            break;
        }
        insertTree_queue(&pRoot, &que, val);
    }

    
    printf("--------------test print_tree--------------\n");
    preOrder(pRoot);
    printf("\n");

    midOrder(pRoot);
    printf("\n");

    postOrder(pRoot);
    printf("\n");

}

int main()
{
    /* test0(); */
    test1();

    return 0;
}

  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值