非线性结构之树

非线性结构之树

1. 树的定义和表示

树是n ( n0 ) 个结点的有限集合,当 n=0 时,成为空树;当 n0 时,该集合满足如下条件:

  • 有且仅有一个根节点,该结点没有前驱,有 0 个后继
  • 除根节点之外的 n1 个结点可划分为m( m0 )个互不相交的有限集 T1,T2,T3,Tm ,每个 Ti 又是一棵树,称为根的子树,每颗子树的根结点有且仅有一个直接前驱,其前驱就是树的根节点,同时可以拥有零个或多个后继结点

2. 二叉树的定义

满足以下条件:

  • 每个结点的度不大于2
  • 结点每棵子树的位置是明确区分左右的,不能随意更改

相关的性质:

  • 在二叉树的第 i 层上至多有2i1个结点( i1
  • 深度为k的二叉树至多有 2k1 个结点
  • 对任意一棵二叉树,若终端结点数为 n0 ,度为2的结点的个数为 n2 ,则满足 n0=n2+1
    • 满二叉树:深度为 k 且含有2k1个结点的二叉树
    • 完全二叉树:深度为 k ,结点数为n (n2k1) 的二叉树,当且仅当其 n 个结点与满二叉树中连续编号为1 n 的位置的结点一一对应,称为完全二叉树
  • 具有n个结点的完全二叉树的深度为 logn2+1
  • 对于具有 n 个结点的完全二叉树,结点从0开始编号
    • 如果i=1,则结点 i 为根,其无双亲结点;如果i>1,则结点 i 的双亲结点序号为i/2
    • 如果 2in ,则结点 i 的左孩子结点序号为2i,否则,结点 i 无左孩子
    • 如果2i+1n,则结点 i 的右孩子的结点的序号为2i+1,否则,结点 i <script type="math/tex" id="MathJax-Element-78">i</script>无右孩子

3. 二叉树的创建

二叉树的链式存储结构:

typedef char elemType;
typedef struct BiNode {
    elemType data;
    struct BiNode *left, *right;
}BiNode, *BiTree; 

二叉树的创建:

void createTree(BiTree *root) {
    elemType data; 
    scanf("%c", &data);

    if(data == '#') {
        (*root) = NULL; 
    } else {
        (*root) = (BiTree)malloc(sizeof(BiNode));
        (*root)->data = data;
        createTree(&((*root)->left));
        createTree(&((*root)->right));          
    }   
}

在写上面的代码时候,就出现了问题,原因就是一个自己的习惯吧,在开始的时候,我判断了一下(*root)的值是不是NULL,这个当main函数调用createTree函数的时候,这个判断是成立的,可以当递归调用的时候,就会出现问题。

4.二叉树的遍历

先序遍历二叉树:根结点,左子树,右子树

中序遍历二叉树:左子树,根节点,右子树

后序遍历二叉树:左子树,右子树,根节点

先序遍历二叉树的代码:

void preTravel(BiTree root) {
    if(root != NULL) {
        printf("%c ", root->data);
        preTravel(root->left);
        preTravel(root->right);
    }       
}

5. 统计结点的个数

void orderNodes(BiTree root) {
    if(root) {
        count++;
        orderNodes(root->left);
        orderNodes(root->right);
    }
}

这里用到了一个全局变量count

6. 求二叉树的高度

void TreeDepth(BiTree root, int h) {
    if(root) {
        if(h > depth) {
            depth = h;
        }
        TreeDepth(root->left, h+1);
        TreeDepth(root->right, h+1);
    }
}

7. 二叉树的层次遍历

ab#d##C#e##
void LevelOrder(BiTree root) {
    SeQueue *Q = NULL;
    BiTree p;
    initQueue(&Q);
    inQueue(Q, root);

    while(!isEmpty(Q->rear, Q->front)) {
        outQueue(Q, &p);
        printf("%c ", p->data);
        if(p->left != NULL) {
            inQueue(Q, p->left);
        }
        if(p->right != NULL) {
            inQueue(Q, p->right);
        }   
    }   
}

主要的思想就是:初始化一个队列,将根节点加入到队列中,然后根节点出队,然后访问根节点的左孩子,若不为空则将左孩子入队列,然后同理访问右孩子,只要这个队列不为空,就说明还没有遍历完这棵二叉树,则要接着进行出队和入队操作。

8. 由遍历序列确定二叉树

  • 由先序和中序序列确定二叉树

    先序遍历中的第一个结点就是根结点D

    由根节点D分割中序序列,根结点之前是左子树L的中序序列,根节点之后是右子树R的中序序列

    根据左子树的L的结点个数,分割先序序列,第一个是根节点,之后是左子树L的先序序列,最后是右子树R的先序序列

  • 由中序和后序序列确定二叉树

    由后序序列的最后一个结点确定根结点D

    由根节点D分割中序序列,D之前是左子树L的中序序列,D之后是右子树R的中序序列,同时获得L和R的结点个数

    根据左子树L的结点个数,分割后序列:首先是左子树L的后序序列,随后是右子树R的后续序列,最后是根

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值