用树的遍历求解层次问题

来源:互联网 发布:经纬度定位软件ios 编辑:程序博客网 时间:2024/05/08 05:32

树的性质:
(1)有且仅有一个节点没有前件(父节点),该节点称为树的根。
(2)除根外,每个节点都有且仅有一个前件。
(3)除根外,每个节点都有唯一的路径连到根上。

层次型问题一般具备的结构特征:
有且仅有一个初始状态,所有相关因素按照不同属性自上而下分解成若干层次。
树的遍历:
按照一定规律不重复的访问访问树中的每一个节点。
遍历过程实质上是将树这种非线性结构转化成线性结构。

1.先序遍历树:由上而下,由左而右。
规则:若树为空则退出;否则先序访问树的根节点。然后先序遍历每棵子树。

//伪代码void preorder(int v){    for(i属于v相邻的节点集){//先序遍历每个与v相邻的未访问节点        if(节点i未被访问){            preorder(i);        }    }}

由于先序遍历中对任一节点的处理是在对他所有的子节点被处理之前进行的。常用于计算树中节点的层次,节点至根的路径等运算。

2.后续遍历:由下而上,由左而右
规则:若树为空则退出。否则先一次后序遍历每棵子树,最后访问根节点。

//伪代码void postorder(int v){    for(i属于v相邻的节点集){        if(节点i未被访问){            postorder(i);        }    }    访问处理节点v;}

由于在后序遍历中,任一节点处的工作是在他所有的子节点被处理之后进行的。适宜于统计相连的下层节点的状态。如计算节点高度。子树的节点总数。节点权和等等。

三种常用的树的存储:

(1)广义表表示
树中的节点可以分为三种,叶节点,根节点,除根节点以外的其他非叶节点(也称分支节点)。在广义表中有三种节点与之对应。即原子节点,表头节点,子表节点。
广义表链表:
假设一棵树的括号表示法为A(B(E,F),C(G(K,L)),D(H,I,J(M)))。
树根节点A有三个非叶节点的子女,则在他的广义表链表中,表头节点为A,他有三个子表节点,各有一个广义表子链表:第一个广义表子链表的表头节点B,他有两个原子节点EF,以此类推。
(2)双亲表示
对树进行后序遍历时,一般采用双亲表示的存储方式。以一组连续的存储单元来存放树的节点,每个节点有两个域。一个是数据域data,用来存放数据元素。一个是父指针域,用来存放指示其双亲节点位置的指针。
(3)多重链表
对树进行先序遍历的时候,一般采用多重链表的存储方式。即存储每个节点的数据与子指针。一棵树中每个节点的子数个数可能不相同。采用变长节点方式将给存储管理带来很多麻烦。我们可以根据树的度d为每个节点存储d个指针域。坏处是管理空间很大很浪费。假设树中有n个节点,就有n*d个指针域。实际上只有n-1个指针域被用到。也可以用STL中的vector进行存储。

现在回想起来这道题。有没有想到就是一个树的先序遍历+回溯。用vector存储每个点的子节点。当时怎么就。。。反应不过来呢。。数据结构学太渣。。。
http://blog.csdn.net/quanzw0120/article/details/72582135

Poj 1330 编写一个程序计算树中两个不同节点的最近公共祖先。
输入:
输入由T个测试数据组成。
第一行给出测试用例数T。
每个测试数据第一行给出n(树的节点数)。节点用(1~n)标示。
后面的n-1行,每行给出两个整数;表示一条边。第一个整数是第二个整数的父母节点。

https://vjudge.net/problem/POJ-1330

思路:
一开始看确实很慌。就是感觉理论知识掌握得很好。看别人的也看得很懂然后自己写写就感觉不会。
先想想一下。题目已经说了是一棵树。那我们要选择什么样的方式建树?我们要记录什么东西?因为要找共同的祖先。那一定要往回找。那我们需要记录的是不是就是它的父节点?于是开了father数组记录父节点。想要计算出层数就需要先序遍历。于是找到了合适的存储方式多重链表?于是开了一个vector记录他的子节点。
建树大概就是这样。那如何去找它们共同祖先呢?假设我当前给出的这个节点在第6层,另一个节点在第9层。那是不是我要把在第九层的往回找。一直找到第6层,。这时候同层有可能就找到共同的祖先了,也有可能找不到,假设没有找到就轮着往上找呗。

每次用STL库的时候都要翻书。。有空总结一下STL库。
至少vector不要再忘了。

#include <iostream>#include <cstdio>#include <cstring>#include <vector>using namespace std;const int maxn=10005;vector<int>vec[maxn];int father[maxn];int anstemp[maxn];void dfs(int rec,int step){    anstemp[rec]=step;    vector<int>::iterator iter;    for(iter=vec[rec].begin();iter!=vec[rec].end();iter++){        dfs(*iter,step+1);    }}int main(){    //freopen("1.txt","r",stdin);    int T,n,tempa,tempb,root,step,quesa,quesb,a,b;    scanf("%d",&T);    while(T--){        scanf("%d",&n);        for(int i=0;i<n;i++){            vec[i].clear();        }//vector的初始化啊。别忘了。        memset(father,-1,sizeof(father));        memset(anstemp,0,sizeof(anstemp));        for(int i=0;i<n-1;i++){//记录父节点+子节点            scanf("%d%d",&tempa,&tempb);            tempa--;//这些++--其实都可以不要的,只是因为喜欢从0开始,所以把所有的下标都--了。            tempb--;            vec[tempa].push_back(tempb);            father[tempb]=tempa;        }        for(int i=0;i<n;i++){            if(father[i]==-1){                root=i;            }        }        dfs(root,0);        scanf("%d%d",&quesa,&quesb);        quesa--;        quesb--;        while(quesa!=quesb){//其实我觉得这一段很妙的。就是不停反复的往上找,也没什么好妙的。不这么写,,,那还能怎么写。            if(anstemp[quesa]>anstemp[quesb]){                quesa=father[quesa];            }            else{                quesb=father[quesb];            }        }        printf("%d\n",quesa+1);    }    return 0;}

https://vjudge.net/problem/POJ-2003
就是一个关于公司关系层次的问题。链表用的不好。照着书敲的。回头线性结构表要补补。还有一个bug就是c++过不了编译。。交G++就过了。。。

#include <iostream>#include <cstdio>#include <cstring>#include <map>#include <list>using namespace std;struct Tman{    string name;    Tman *f;    list<Tman *>s;    Tman(){        f=NULL;    }};map<string,Tman*>has;Tman* root;void print(long dep,Tman *now){    if(now==NULL) return;    for(int i=0;i<dep;i++) cout<<"+";    cout<<now->name<<endl;    for(list<Tman*>::iterator j=now->s.begin();j!=now->s.end();j++){        print(dep+1,*j);    }}void hires(string s1,string s2){    Tman *f=has[s1];    Tman *s=new Tman();    s->name=s2;    s->f=f;    f->s.push_back(s);    has[s2]=s;}void fire(string n1){    Tman *s=has[n1];    Tman *f=s->f;    has.erase(n1);    while(s->s.size()!=0){        s->name=s->s.front()->name;        has[s->name]=s;        s=s->s.front();    }    s->f->s.remove(s);    delete s;}void solve(){    string s1,s2;    long i;    cin>>s1;    root=new Tman();    has[s1]=root;    root->name=s1;    while(cin>>s1){        if(s1=="print"){            print(0,root);            for(int i=0;i<60;i++){                cout<<"-";            }            cout<<endl;        }        else if(s1=="fire"){            cin>>s2;            fire(s2);        }        else{            cin>>s2;            cin>>s2;            hires(s1,s2);        }    }}int main(){    //freopen("1.txt","r",stdin);    solve();    return 0;}

链表学的真是菜啊。。

原创粉丝点击