树和二叉树

github地址:https://github.com/Tory123/Algorithm-test/blob/master/tree.h

树的特点

1、相对于列表和向量的区别:
向量的优势在于静态操作,比如查找
列表的优势在于动态操作,比如插入,删除
树结构的由于在于可以兼顾静态和动态操作,可视作半线性结构,是无环连通图

2、树结构的特点:
1、
有根树:数据结构中的树都要定义根结点
有序树:兄弟之间按照度数定义长幼次序,度数为结点拥有孩子的个数
2、任何树结构所含的边数,等于所有结点的度数之和,也等于顶点总数-1,
树的边数与顶点个数同阶,因此在衡量时间复杂度时,用顶点个数n作为参照
3、
深度:根结点到任一结点存在唯一一条路径,路径的长度称为这个结点在树中的深度。
高度:针对单个结点而言,从以该结点为根,到最深叶子结点的路径长度,空树的高度为1.
4、如果将树的祖先视作前驱,后代视作后继,则在任一层次上,树结点的前驱是唯一的,而后继则不是,这也是将树结构视作半线性结构的原因,而图结构则这两点都不能满足。
5、任何一个结点的高度与深度之和 <= 树的高度

树的表示

长子-兄弟表示法:每个结点记录两个引用,一个是长子,另一个是下一个兄弟。
在这里插入图片描述

二叉树

定义:结点度数不超过2的树
1、特点:
(1)因为结点不超过2,因此深度为k的结点,最多不超过2^k个
(2)含n个结点,高度为h的二叉树中,h<n<2^(h+1)
(3)n = 2^h -1的二叉树称作满二叉树
(4)二叉树的宽度是高度的指数,因此随着结点的增长,二叉树的高度增长会越来越慢——引入二叉搜索树
(5)真二叉树:每个结点的出度都是偶数的二叉树,或0或2。相较于一般性的二叉树,在很多操作上会简便很多。转化:
在这里插入图片描述
通过二叉树描述多叉树:
当二叉树有根且有序时,可以描述多叉树。
因为使用长子-兄弟表示法,每个结点记录两个引用,因此可看成是一种二叉树的表示。

2、遍历:
(1)先序遍历:
1、递归实现:

void travPre(BinNodePosi p){
    if(!p)return ;
    cout << p->data;
    travPre(p->lchild);
    travPre(p->rchild);
}

2、迭代实现:
在这里插入图片描述

//二叉树迭代先序遍历—版本1
void travPre_I1(BinNodePosi p){
    Stack<BinNodePosi> S;
    if(p)S.push(p);
    while(S.size!=0){
        BinNodePosi T = S.pop();
        cout << T->data;
        if(T->rchild)S.push(T->rchild);
        if(T->lchild)S.push(T->lchild);
    }
}
//二叉树迭代先序遍历—版本2
static void visitAlongLeftBranch(BinNodePosi x,Stack<BinNodePosi>& s){
    if(!x)return;
    while (x) {
        cout << x->data;
        s.push(x->rchild);
        x= x->lchild;
    }
}
void travPre_I2(BinNodePosi x){
    Stack<BinNodePosi> s;
    while(true){
        visitAlongLeftBranch(x,s);
        if(s.size==0)break;
        x = s.pop();
    }
}

(2)中序遍历:

//二叉树中序遍历递归
void travMid(BinNodePosi x){
    if(!x) return;
    travMid(x->lchild);
    cout << x->data<<endl;
    travMid(x->rchild);
}
//二叉树中序迭代遍历
static void goAlongLeftBranch(BinNodePosi x,Stack<BinNodePosi>& s){
    if(!x)return;
    while (x) {
        s.push(x);
        x = x->lchild;
    }
}
void travMid_I(BinNodePosi x){
     Stack<BinNodePosi> s;
    while (true) {
        goAlongLeftBranch(x,s);
        if(s.size==0)break;
        x = s.pop();
        cout << x->data;
        x=x->rchild;
    }
}

(3)层次遍历

/*
 层序遍历
 采用什么数据结构——队列
 为什么——>所有的结点都严格按照深度次序接受访问
 */
void travLevel(BinNodePosi p){
   Queue<BinNodePosi> Q;
      if(!p)return ;
      Q.enqueue(p);
      while(Q.size !=0){
          BinNodePosi t = Q.dequeue();
          cout << t->data;
          if(t->lchild) Q.enqueue(t->lchild);
          if(t->rchild) Q.enqueue(t->rchild);
      }
}

3、重构:能否根据某棵树的遍历序列还原拓扑结构?
结论:只需要中序遍历序列 + 先序/后序之一 即可还原
在某些特定情况下,通过先序+后序可以还原树的结构——>真二叉树

4、测试代码:

int main(int argc, const char * argv[]) {
    BinNode *root = new BinNode(5,NULL);
    BinNode *l = new BinNode(4,NULL);
    root->lchild = l;
    root->insertAsLR(3);
    l->insertAsLC(6);
    BinTree * tree = new BinTree();
    tree->updateHeight(root);
    //travMid_I(root);
    travLevel(root);
    // cout << root->height <<endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值