数据结构-树

数据结构-树(上)

定义

Tree = (D, H), D是具有相同特性的数据元素的集合, H是D上二元关系的集合, T满足如下定义

ADT Tree{

数据对象: D

数据关系: H

​ 若 D= D = ∅ , H也为 , 称为空树

​ (1) 若D中只有唯一的元素(树根),H为空

​ (2) 若 D=Droot D ′ = D − r o o t 不为空, 则存在 D D ′ 的一个划分

D1,D2,...Dm(m>0),jk(1j,km)DjDk= D 1 , D 2 , . . . D m ( m > 0 ) , ∀ j ≠ k ( 1 ≤ j , k ≤ m ) 有 D j ⋂ D k = ∅

​ 对于

i[1,m],xiDi,使<root,xi>H ∀ i ∈ [ 1 , m ] , 都 存 在 唯 一 的 想 x i ∈ D i , 使 得 < r o o t , x i >∈ H

​ (3) 对于(2)的划分, H<root,x1>,<root,x2>,....<root,xm>H1,H2,...Hm H − < r o o t , x 1 > , < r o o t , x 2 > , . . . . < r o o t , x m > 有 唯 一 的 一 个 划 分 H 1 , H 2 , . . . H m

jk1j,km,Hj Hk= ∀ j ≠ k ⋀ 1 ≤ j , k ≤ m , H j ⋂   H k = ∅

​ 且

i(1im),HiDi,(Di,Hi),root, ∀ i ( 1 ≤ i ≤ m ) , H i 是 D i 上 的 关 系 , ( D i , H i ) 是 一 棵 符 合 本 定 义 的 树 , 称 为 r o o t 的 子 树 , 各 子 树 构 成 森 林

操作集: 略

H中的关系在树上就是指两结点之间边

​ 对于 <f,s>H,fs,sf < f , s >∈ H , f 是 s 的 双 亲 结 点 , s 是 f 的 孩 子 结 点 <script type="math/tex" id="MathJax-Element-12"> \in H, f是s的双亲结点, s是f的孩子结点</script>

}

特点

递归定义, 树根和子树的根节点满足二元关系

基本术语

  • 结点: 包含一个数据元素及若干指向其子树的分支
  • 结点的度:结点拥有的子树数
  • 树的度:树内各节点的度的最大值
  • 非终端结点:度大于0的结点
  • 叶子结点:度为0的结点
  • 内部结点:除树根以外的终端结点
  • 树的层次:树根层次为1, 其他结点层次是其双亲结点的层次+1
  • 兄弟, 堂兄弟, 祖先, 子孙(类比祖谱)
  • 树高(深度):树内结点的最大层次

二叉树(Binary Tree)

各结点度不超过2的树, 上述定义中每层划分数最大为2

二叉树的性质

  • 二叉树第i层的最大结点数: 2i1() 2 i − 1 ( 归 纳 法 可 证 )

  • 深度为k的二叉树结点数量最多为 2k1 2 k − 1

  • 设二叉树中度为2的结点个数为 n2 n 2 ,度为0的结点(叶子结点)个数为 n0 n 0 ,度为1的结点的个数为 n1 n 1

    n0=n2+1 n 0 = n 2 + 1

  • 满二叉树: 深度为k且结点数量为 2k1 2 k − 1 的二叉树, 即每层结点数量都是最大值

  • 完全二叉树: 与其深度相同的满二叉树在相应位置的结点编号相同

  • 结点数为n的完全二叉树深度: log2n+1log2n+1 ⌊ log 2 ⁡ n ⌋ + 1 或 ⌈ log 2 ⁡ n + 1 ⌉

  • 编号为i(从1开始编号)的结点的双亲节点的编号为 i2 ⌊ i 2 ⌋ ,0表示不存在双亲节点, 左右孩子结点若存在,其编号分别为 i2,i2+1 i ∗ 2 , i ∗ 2 + 1

  • 结点数为n的二叉树有多少种(形状):

    Catalan:Cn2nn+1 C a t a l a n 数 : C 2 n n n + 1

    证明: 固定一个结点rt为根, 则rt的坐子树结点数l满足 l[0,n1] l ∈ [ 0 , n − 1 ] , 右子树结点数为n-1-l

    f(n)n,f(n)=n1i=0f(i)f(n1i) f ( n ) 表 示 n 个 结 点 二 叉 树 种 类 数 , 则 f ( n ) = ∑ i = 0 n − 1 f ( i ) ∗ f ( n − 1 − i )

    f(0)=f(1)=1 f ( 0 ) = f ( 1 ) = 1 ,即为 Catalan C a t a l a n

操作集

  • 基础

    
    #include <stdio.h>
    
    
    #include <stdlib.h>
    
    
    #define Status int
    
    
    #define OK 1
    
    
    #define ERROR 1
    
    typedef int ElemType;
    
    typedef struct BiTree{            //结构定义
      ElemType data;
      BiTree * lch;
      BiTree * rch;
    }BiTree, * pTree;
    
    pTree newNode(ElemType data){ //newNode
      pTree res = (pTree)malloc(sizeof(BiTree));
      res->data = data;
      res->lch = NULL;
      res->rch = NULL;
      return res;    
    }
    
    void initTree(pTree &rt){     //init
      rt = NULL;
    }
    
    void destroyBiTree(pTree &rt){    //destory
      if(rt != NULL) {
          destroyBiTree(rt->lch);
          destroyBiTree(rt->rch);
          free(rt);
          rt = NULL;
      }
    }
    
    Status BiTreeEmpty(pTree rt){ //isEmpty
      return rt == NULL;
    }
    
    inline int max(int a, int b){ 
      return a >= b ? a : b;
    }
    
    int BiTreeDepth(pTree rt){        //树的高度
      if(rt == NULL) return 0;
      return 1 + max(BiTreeDepth(rt->lch), BiTreeDepth(rt->rch));
    }
    
    pTree getTree(pTree rt, int index){ //根据2进制获取某一结点
      while(index > 1){
          if(index & 1) rt = rt->rch;
          else rt = rt->lch;
          index >>= 1;
          if(rt == NULL) return rt;
      }
      return rt;
    }
    
    Status getValue(pTree rt, pTree e, ElemType &x){ //get
      int depth = BiTreeDepth(rt);
      for(int i = 1; i < 1 << depth; ++i){
          pTree elem = getTree(rt, i);
          if(elem == e) {
              x = elem->data;
              return OK;
          }
      }
      return ERROR;
    }
    
    Status assignValue(pTree rt, pTree e, ElemType x){//set
      int depth = BiTreeDepth(rt);
      for(int i = 1; i < 1 << depth; ++i){
          pTree elem = getTree(rt, i);
          if(elem == e) {
              elem->data = x;
              return OK;
          }
      }
      return ERROR;
    }
    
    pTree getParent(pTree rt, pTree e){           //获取双亲结点
      int depth = BiTreeDepth(rt);
      for(int i = 1; i < 1 << depth; ++i){
          pTree elem = getTree(rt, i);
          if(elem && (elem->lch == e || elem->rch == e)) return elem;
      }
      return NULL;
    }
    
    //test
    int main(){
      ElemType elem;
      pTree rt = newNode(1);
      pTree tree2 = newNode(3);
      pTree tree3 = newNode(6);
      pTree tree4 = newNode(5);
      rt->lch = tree2;
      rt->rch = tree3;
      tree2->rch = tree4;
      printf("Depth: %d\n", BiTreeDepth(rt));
      if(getValue(rt, tree3, elem)) printf("OldValue: %d\n", elem);
      else printf("Not in!\n");
      assignValue(rt, tree3, 7);
      if(getValue(rt, tree3, elem)) printf("NewValue: %d\n", elem);
      else printf("Not in!\n");
      pTree p = getParent(rt, tree3);
      if(p) printf("%d\n", p->data);
      destroyBiTree(rt);
      if(rt == NULL) printf("Destoryed!\n");
      return 0;
    }

  • 树的遍历(递归)

    //先序遍历
    void preOrder(pTree rt){
    if(rt == NULL) return;
        printf("%-3d", rt->data);
        preOrder(rt->lch);
        preOrder(rt->rch);
    }
    //中序遍历
    void inOrder(pTree rt){
        if(rt == NULL) return;
        inOrder(rt->lch);
        printf("%-3d", rt->data);
        inOrder(rt->rch);
    }
    //后序遍历
    void postOrder(pTree rt){
      if(rt == NULL) return;
        postOrder(rt->lch);
        postOrder(rt->rch);
        printf("%-3d", rt->data);
    }
  • 树的遍历(非递归)

    //stack, queue借助STL
    void inOrder1(pTree rt){
        stack<pTree> s;
        s.push(rt);
        while(!s.empty()){
            while(s.top()) s.push(s.top()->lch);
            s.pop();
            if(!s.empty()){
            pTree tmp = s.top();
                printf("%-3d", tmp->data);
                s.pop();
                s.push(tmp->rch);
          }
        }
    }
    
    void inOrder2(pTree rt){
    stack<pTree> s;
        while(rt || !s.empty()){
            if(rt) {
                s.push(rt);
                rt = rt->lch;
          }else{
                rt = s.top();
                printf("%-3d", rt->data);
                s.pop();
                rt = rt->rch;
          }
        }
    }
    
    void preOrder1(pTree rt){
        stack<pTree> s;
        while(rt || !s.empty()){
            if(rt){
                printf("%-3d", rt->data);
                s.push(rt);
                rt = rt->lch;
            }else{
                rt = s.top();
                s.pop();
                rt = rt->rch;
            }
        }
    }
    
    void postOrder1(pTree rt){
        pTree pre = NULL;
        stack<pTree> s;
        s.push(rt);
        while(!s.empty()){
            rt = s.top();
            if((rt->lch == NULL && rt->rch == NULL) ||){
                printf("%-3d", rt->data);
                s.pop();
                pre = rt;
            }else{
                if(rt->rch != NULL) s.push(rt->rch);
                if(rt->lch != NULL) s.push(rt->lch);
            }
        }
    }
    
    void display(pTree rt){
        if(rt != NULL){
            printf("%-3d", rt->data);
            if(rt->lch || rt->rch){
                printf("(");
                if(rt->lch) display(rt->lch);
                else printf("^");
                printf(",");
                if(rt->rch) display(rt->rch);
                else printf("^");
                printf(")");
          }
        }
    }
    
    void levelOrder(pTree rt){
        queue<pTree> que, tmp;
        que.push(rt);
        while(!que.empty()){
            while(!que.empty()){
                rt = que.front();
                que.pop();
                printf("%-3d", rt->data);
                if(rt->lch) tmp.push(rt->lch);
                if(rt->rch) tmp.push(rt->rch);
          }
            puts("");
            que = tmp;
            tmp.clear();
        }
    }
  • 中序线索化及遍历:

    
    #include <bits/stdc++.h>
    
    using namespace std;
    typedef int ElemType;
    typedef struct BiThrTree{
      ElemType data;
      BiThrTree * lch;
      BiThrTree * rch;
      bool lTag;
      bool rTag;
    }BiThrTree, * pTree;
    
    pTree newNode(ElemType data){ //newNode
      pTree res = (pTree)malloc(sizeof(BiThrTree));
      res->data = data;
      res->lch = NULL;
      res->rch = NULL;
      res->lTag = true;
      res->rTag = true;
      return res;
    }
    
    
    void inThreading(pTree rt, pTree &pre){
      if(rt){
          inThreading(rt->lch, pre);
          if(!pre->rch){
              pre->rTag = false;
              pre->rch = rt;
          }
          if(!rt->lch){
              rt->lTag = false;
              rt->lch = pre;
          }
          pre = rt;
          inThreading(rt->rch, pre);
      }
    }
    
    pTree inOrderThreading(pTree rt){//线索化
      pTree res = newNode(-1);
      res->lTag = true;
      res->rTag = false;
      res->rch = res;
      if(!rt){
          res->lch = res;
      }else{
          res->lch = rt;
          pTree pre = res;
          inThreading(rt, pre);
          //printf("%d %d\n", pre->data, res->data);
          pre->rTag = false;
          pre->rch = res;
          res->rch = pre;
      }
      return res;
    }
    
    void inOrder(pTree rt){
      pTree p = rt->lch;
      while(p != rt){
          //printf("%d\n", p->data);
          while(p->lTag == true) p = p->lch;
          printf("%-3d", p->data);
          while(p->rTag == false && p->rch != rt){
              p = p->rch;
              printf("%-3d", p->data);
          }
          p = p->rch;
      }
      puts("");
    }
    
    void inOrderReverse(pTree rt){
      pTree p = rt->rch;
      while(p != rt){
          while(p->rTag == true) p = p->rch;
          printf("%-3d", p->data);
          while(p->lTag == false && p->lch != rt){
              p = p->lch;
              printf("%-3d", p->data);
          }
          p = p->lch;
      }
      puts("");
    }
    
    int main(){
      pTree rt = newNode(1);
      pTree tree2 = newNode(3);
      pTree tree3 = newNode(6);
      pTree tree4 = newNode(5);
      rt->lch = tree2;
      rt->rch = tree3;
      tree2->rch = tree4;
      pTree head = inOrderThreading(rt);
      inOrder(head);
      inOrderReverse(head);
      return 0;
    }
  • 根据前序中序遍历确定后序遍历(确定二叉树的形状)

    只能是前序遍历或者后序遍历和中序遍历才能确定一棵二叉树, 前序遍历和后序遍历无法确定

    递归思想:

    codeUp1096

    
    #include <stdlib.h>
    
    
    #include <stack>
    
    
    #include <string>
    
    
    #include <iostream>
    
    using namespace std;
    
    typedef char ElemType;
    typedef struct BiTree{
      ElemType data;
      BiTree * lch;
      BiTree * rch;
    }BiTree, * pTree;
    
    pTree newNode(ElemType data){
      pTree res = (pTree)malloc(sizeof(BiTree));
      res->data = data;
      res->lch = NULL;
      res->rch = NULL;
      return res;
    }
    
    pTree getTree(string pre, string in){
      ElemType fi = pre[0];
      int pos = in.find(fi);
      pTree res = newNode(fi);
      if(pos > 0)
          res->lch = getTree(pre.substr(1, pos), in.substr(0, pos));
      if(pos + 1 < pre.length())
          res->rch = getTree(pre.substr(pos + 1), in.substr(pos + 1));
      return res;
    }
    
    void postOrder(pTree rt){
      stack<pTree> s;
      s.push(rt);
      pTree pre = NULL;
      while(!s.empty()){
          rt = s.top();
          if((!rt->lch && !rt->rch) || (pre && (pre == rt->lch || pre == rt->rch))){
              cout << rt->data;
              s.pop();
              pre = rt;
          }else{
              if(rt->rch) s.push(rt->rch);
              if(rt->lch) s.push(rt->lch);
          }
      }
      cout << endl;
    }
    
    int main(){
      string pre, in;
      while(cin >> pre >> in) {
          pTree rt = getTree(pre, in);
          postOrder(rt);
      }
      return 0;
    }

…. 待续

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值