数据结构-二叉树(7)树与森林

一般树有4种常用表示方法:

1.广义表表示法

2.父指针表示法

寻找父指针的操作时间复杂度为O(1),但寻找子女的操作时间复杂度达到O(n)

3.子女链表表示法

适合需要频繁寻找子女的应用

寻找子女的操作在子女链表中进行,时间复杂度为O(d),d为树的度。但寻找父结点的操作时间复杂度达到O(n)

4.子女-兄弟链表示法

用二叉树表示一般树,每个结点的度都为2,由三个域组成:data、firstChild、nextSibling。

若要访问x结点的第k个子女,只要从x->firstChild开始沿着nextSibling继续走k-1步。当nextsibling指针为空时为最后一个子女。

适合需要频繁寻找子女的应用

寻找子女的操作在子女链表中进行,时间复杂度为O(d),d为树的度。但寻找父结点的操作时间复杂度达到O(n)

template <class T>
struct TreeNode{
    T data;
    TreeNode<T> *firstChild,*nextSibling;
    TreeNode(T value=0,TreeNode<T> *fc=NULL,TreeNode<T> *ns=NULL):data(value),firstChild(fc),nextSibling(ns){};
};

template <class T>
class Tree{
private:
    TreeNode<T> *root,*current;  //如果不设*current指针,每次插入新结点都必须从头开始逐个结点比较
    bool Find(TreeNode<T> *p,T value);
    void RemovesubTree(TreeNode<T> *p);
    bool FindParent(TreeNode<T> *t,TreeNode<T> *p);
public:
    Tree(){root=current=NULL;};
    bool Root();
    bool Isempty(){return root==NULL;}
    bool FirstChild();
    bool NextSibling();
    bool Parent();
    bool Find(T target);
};

template <class T>
bool Tree<T>::Root(){
    //寻找根使之成为当前结点
    if(root==NULL){
        current=NULL;
        return false;
    }
    else{
        current=root;
        return true;
    }
}

template <class T>
bool Tree<T>::Parent() {
    //在树中寻找当前结点current的父结点,使之成为当前结点
    TreeNode<T> *p=current;
    if(current==NULL||current==root){
        current=NULL;
        return false;
    }
    return FindParent(root,p);
}

template <class T>
bool Tree<T>::FindParent(TreeNode<T> *t, TreeNode<T> *p) {
    //在根为*t的树中寻找*p的父结点,并使之成为当前结点current
    TreeNode<T> *q=t->firstChild;
    bool succ;
    while(q!=NULL && q!=p){   //没找到时,递归搜索子树
        if((succ=FindParent(q,p))==true) return succ; //子树中找到
        q=q->nextSibling;   //子树中没找到,搜寻下一个兄弟
    }
    if(q!=NULL && q==p){
        current=t;
        return true;
    }
    else{
        current=NULL;
        return false;
    }
}

template <class T>
bool Tree<T>::FirstChild() {
    //在树中找当前结点的长子,并使之成为当前结点
    if(current==NULL||current->firstChild==NULL){
        current=NULL;
        return false;
    }
    current=current->firstChild;
    return true;
}

template  <class T>
bool Tree<T>::NextSibling() {
    //在树中找当前结点的下一个,并使之成为当前结点
    if(current!=NULL&&current->nextSibling!=NULL){
        current=current->nextSibling;
        return true;
    }
    current==NULL;
    return false;
}

template <class T>
bool Tree<T>::Find(T target) {
    if(Isempty()) return false;
    return Find(root,target);
}

template <class T>
bool Tree<T>::Find(TreeNode<T> *p, T value) {
    //在根为*p的树中找值为value的结点,找到后该结点成为当前结点,否则当前结点不变
    bool result=false;
    if(p->data==value){
        result=true;
        current=p;
    }
    else{
        TreeNode<T> *q=p->firstChild;
        while(q!=NULL && !(result=Find(q,value)))
            q=q->nextSibling;
    }
    return result;
}

树的深度优先遍历通常包括先根次序遍历和后根次序遍历,不适合定义中序遍历,访问根结点操作的位置较难确定(子女个数不确定),因为子树没有顺序,只能人为定义

#include <iostream.h>
#include "tree.h"
#include "queue.h"

template <class T>
void PreOrder(ostream& out,TreeNode<T> *p){
    //先根次序遍历并输出以*p为根的树:先访问树的根结点,再依次先根次序遍历树的每一棵子树
    if(p!=NULL){
        out<<p->data;
        for(p=p->firstChild;p!=NULL;p=p->nextSibling) PreOrder(out,p);
    }
}

template <class T>
void PostOrder(ostream& out,TreeNode<T> *p){
    //后根次序遍历并输出以*p为根的树
    if(p!=NULL){
        TreeNode<T> *q;
        for(q=p->firstChild;q!=NULL;q=q->nextSibling)
            PostOrder(out,q);
        out<<p->data;
    }
}

template <class T>
void LevelOrder(ostream& out,TreeNode<T> *p){
    //按广度优先次序(层次次序)分层遍历树,树的根结点是*p,算法中用到一个队列
    Queue<TreeNode<T> *> Q;
    if(p!=NULL){
        Q.EnQueue(p);
        while(!Q.IsEmpty()){
            Q.DeQueue(p);
            out<<p->data;
            for(p=p->firstChild;p!=NULL;p=p->nextSibling)
                Q=EnQueue(p);
        }
    }
}

可以用这种表示法下的二叉树表示森林,此时第一棵树的根的子树森林转化成左子树,剩余其它树组成的森林转换成右子树:

1)先根次序依次遍历森林里每一棵树:前序遍历二叉树即可

template <class T>
void preorder(TreeNode<T> *t,void (*visit)(TreeNode<T> *p)){
    if(t==NULL) return;
    visit(t);
    preorder(t->firstChild,visit);
    preorder(t->nextSibling,visit);
}

2)后根次序依次遍历森林里每一棵树:中序遍历二叉树即可

template <class T>
void postorder(TreeNode<T> *t,void (*visit)(TreeNode<T> *p)){
    if(t==NULL) return;
    postorder(t->firstChild,visit);
    visit(t);
    postorder(t->nextSibling,visit);
}

3)层次序遍历整个森林:先把所有树的根结点加入队列

template <class T>
void Levelorder(TreeNode<T> *t,void (*visit)(TreeNode<T> *p)){
    if(t==NULL) return;
    Queue<TreeNode<T>*> Q;
    for(;t!=NULL;t=t->nextSibling) Q.EnQueue(t);
    while(!Q.IsEmpty()){
        Q.DeQueue(t);
        visit(t);
        for(t=t->firstChild;t!=NULL;t=t->nextSibling) Q=EnQueue(t);
    }
}

 

转载于:https://www.cnblogs.com/yangyuliufeng/p/9448748.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值