[数据结构] 3. 树与二叉树

1. 定义

  1. 如何理解节点、边?
    节点是集合,边是关系(根节点是全集)

  2. 链表看作“一叉树”,结构定义中表示关系的指针扩展为指针数组,就变成了树的结构定义

  3. 二进制可以表示所有进制,二叉树可以表示所有树形结构(左孩子右兄弟,又称十字链表法)

  4. 二叉树性质:
    节点数量等于边数+1 --> 度为0的节点比度为2的节点多1个

  5. 二叉树中,若除掉最大阶层后为满二叉树,且最大阶层节点均向左靠齐,则称为完全二叉树

  6. 二叉树性质
    性质1:二叉树的第 i 层最多有 2i-1 个节点
    性质2:深度为 k 的二叉树最多有 2k-1 个节点
    性质3:二叉树终端节点个数为 n0,度为2的节点个数为 n2,则 n0=n2+1
    性质4:具有 n 个节点的完全二叉树的深度为 [log2n]+1

  7. 完全二叉树可以通过顺序结构(数组)实现,关系通过计算得到,不同于指针的记录方式

  8. 广义表是用字符串存储表示二叉树(节点和关系),实现二叉树的共享

【理解】函数的判断一般是对传入参数的合法性的判断

2. 代码

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

typedef struct Node {
    int data;
    struct Node *lchild, *rchild;
} Node;
typedef struct Tree {
    Node *root;//指向二叉树根结点的指针变量
    int n;//二叉树的结点个数
} Tree;

//结构操作:结点的初始化和树的初始化
Node *getNewNode(int val) {//val封装成二叉树的结点
    //指向结点的指针变量p,记录malloc申请空间的首地址
    Node *p = (Node *)malloc(sizeof(Node));
    //初始化p的字段
    p->data = val;
    p->lchild = p->rchild = NULL;
    return p;
}
Tree *getNewTree() {
    //指向该二叉树的指针变量tree,记录malloc开辟的树的首地址
    Tree *tree = (Tree *)malloc(sizeof(Tree));
    //初始化tree的字段
    tree->root = NULL;
    tree->n = 0;
    return tree;
}
//清空结点和二叉树
void clearNode(Node *node) {
    if (node == NULL) return ;
    //递归回收孩子结点
    clearNode(node->lchild);
    clearNode(node->rchild);
    free(node);
    return ;
}
void clear(Tree *tree) {
    if (tree == NULL) return ;
    //调用clearNode沿着根结点去递归回收
    clearNode(tree->root);
    free(tree);
    return ;
}
//insert_node返回当前二叉树的根结点
Node *insert_node(Node *root, int val, int *flag) {
//定义flag指针变量
    if (root == NULL) {
        *flag = 1;//通过不断地递归调用,root为空时val成功插入
        return getNewNode(val);//root为空,调用getNewNode把val封装成一个结点,就是当前树的根结点
    }
    
    //根结点的值等于待插入的val,什么也不做,返回root
    if (root->data == val) return root;
    //val<root->data时,向当前根结点的左子树递归插入
    //【递归】:先判断插入位置,递归调用insert_node,插入位置为空时才能插入
    if (val < root->data) root->lchild = insert_node(root->lchild, val, flag);
    else root->rchild = insert_node(root->rchild, val, flag);
    return root;
}
//二叉排序树(二叉查找树)的性质:对于任何一个三元组,左孩子值<根结点值<右孩子值
//向当前tree插入一个值为val的结点
void insert(Tree *tree, int val){
    int flag = 0;//在tree中判断val成功插入与否
    //注意&,flag是传出参数,执行完insert_node后传回来
    tree->root = insert_node(tree->root, val, &flag);
    tree->n += flag;//插入成功+1,失败+0
    return ;
}
//前序遍历
void pre_order_node(Node *node) {
    //传进来结点的地址
    if (node == NULL) return ;
    printf("%d ", node->data);
    pre_order_node(node->lchild);
    pre_order_node(node->rchild);
    return ;
}
void pre_order(Tree *tree) {//传进来一棵树
    if (tree == NULL) return ;
    printf("pre_order : ");
    pre_order_node(tree->root);//沿着根结点进行前序遍历
    printf("\n");
    return ;
}

//中序遍历,对于二叉排序树而言打印出来是从小到大排序
void in_order_node(Node *node) {
    //传进来结点的地址
    if (node == NULL) return ;
    in_order_node(node->lchild);
    //打印根结点的值放在中间
    printf("%d ", node->data);
    in_order_node(node->rchild);
    return ;
}
void in_order(Tree *tree) {//传进来一棵树
    if (tree == NULL) return ;
    printf("in_order : ");
    in_order_node(tree->root);//沿着根结点进行前序遍历
    printf("\n");
    return ;
}
//后序遍历
void post_order_node(Node *node) {
    //传进来结点的地址
    if (node == NULL) return ;
    post_order_node(node->lchild);
    post_order_node(node->rchild);
    //后序遍历打印根结点的值放在最后
    printf("%d ", node->data);
    return ;
}
void post_order(Tree *tree) {//传进来一棵树
    if (tree == NULL) return ;
    printf("post_order : ");
    post_order_node(tree->root);//沿着根结点进行前序遍历
    printf("\n");
    return ;
}
void output_node(Node *root) {
    if (root == NULL) return ;
    //先打印根结点的值
    printf("%d", root->data);
    if (root->lchild == NULL && root->rchild == NULL) return ;
    //先考虑输出数据,后面补充括号和逗号的输出
    printf("(");
    output_node(root->lchild);
    printf(",");
    output_node(root->rchild);
    printf(")");
    return ;
}

//输出二叉树的广义表表示方法
void output(Tree *tree) {
    if (tree == NULL) return ;
    printf("tree(%d) : ", tree->n);
    output_node(tree->root);
    printf("\n");
    return ;
}
int main() {
    srand(time(0));
    //初始化一棵二叉树
    Tree *tree = getNewTree();
    #define max_op 10
    for (int i = 0; i < max_op; i++) {
        int val = rand() % 100;
        insert(tree, val);
        output(tree);
    }
    pre_order(tree);
    in_order(tree);
    post_order(tree);
    #undef max_op
    clear(tree);
    return 0;
}

3. 广义表转二叉树代码

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值