数据结构研究之六 树

时间:2022-10-03 10:31:37
1.树:
a.简介:树是由结点及连结结点的边组成。有根树的节点之间有父子关系。
2.二叉树:
a.简介:如果一颗树有1个根结点及所有结点的子结点数都不超过2,那么此树被称为有根二叉树。
b.二叉树可以递归地进行定义。

c.代码:二叉树的表达

//
// Created by 叶子 on 2018/2/2.
// 有根树的表达
//
#include "iostream"
using namespace std;

struct Node { int p ,l,r;};
const int NIL= -1;

Node T[100005],D[100005];
int n;

void print (int u){
    int i,c;
    cout << "node" << u << ":";
    cout << "parent = " << T[u].p << ",";
    cout << "depth = "<<D[u].p<<",";

    if ( T[u].p == NIL) cout << "root,";
    else if ( T[u].l == NIL) cout << "leaf,";
    else cout << "internal ndoe,";

    cout << "[";

    for ( i = 0 , c = T[u].l ; c != NIL; i++,c = T[c].r){
        if (i) cout << "," ;
        cout <<c;
    }
    cout << "]" <<endl;
}

int rec(int u,int p){
    D[u].p = p;
    if ( T[u].r != NIL ) rec(T[u].r,p); //? 这一句不是很理解
    if ( T[u].l != NIL ) rec(T[u].l,p+1);
}

int  main(){
    int i,j,d,v,c,l,r;
    cin >> n;
    for ( i = 0 ; i < n ; i ++) T[i].p = T[i].l = T[i].r = NIL;

    for ( i = 0 ; i < n ; i ++){
        cin >> v>> d;
        for ( j = 0 ; j < d ; j ++){
            cin >> c;
            if ( j == 0 ) T[v].l = c;
            else T[l].r = c;
            l = c;
            T[c].p = v;
        }
    }

    for ( i = 0 ; i < n ; i ++){
        if (T[i].p == NIL ) r = i ;
    }

    rec(r,0);

    for ( i = 0 ; i < n ; i ++) print(i);
    return 0 ;
}


2.普通二叉树:
a.表达:
//
// Created by 叶子 on 2018/2/2.
// 二叉树的表达
//

#include "cstdio"
const int MAX = 10000;
const int NIL = -1;

struct Node{ int parent,left,right;};

Node T[MAX];
int n,D[MAX],H[MAX];

void setDepth(int u,int d){
    if ( u == NIL) return;
    D[u] = d;
    setDepth(T[u].left,d+1);
    setDepth(T[u].right,d+1);
}

int setHeight(int u){
    int h1 = 0 ,h2 = 0;
    if (T[u].left != NIL){
        h1 = setHeight(T[u].left ) + 1;
    }
    if ( T[u].right != NIL){
        h2 = setHeight(T[u].right) + 1;
    }
    return H[u] = ( h1 > h2 ? h1 : h2);
}

int getSibling(int u){
    if (T[u].parent == NIL) return NIL;
    if ( T[T[u].parent].left != u && T[T[u].parent].left != NIL)
        return T[T[u].parent].left;
    if ( T[T[u].parent].right != u && T[T[u].parent].right != NIL)
        return T[T[u].parent].right;
    return NIL;
}

void print(int u){
    printf("node %d:",u);
    printf("parent = %d,",T[u].parent);
    printf("sibling = %d,",getSibling(u));
    int deg = 0;
    if (T[u].left != NIL) deg ++;
    if (T[u].right != NIL) deg ++;
    printf ("degree = %d,",deg);
    printf ("depth = %d,",D[u]);
    printf ("height = %d,",H[u]);

    if ( T[u].parent == NIL){
        printf("root\n");
    }else if ( T[u].left == NIL && T[u].right == NIL ){
        printf("left\n");
    }else{
        printf("internal node\n");
    }
}

int main(){
    int v,l,r,root = 0 ;
    scanf("%d",&n);

    for ( int i = 0 ; i < n ; i ++ ) T[i].parent = NIL;

    for ( int i = 0 ; i < n ; i ++){
        scanf("%d %d %d",&v,&l,&r);
        T[v].left = l;
        T[v].right = r;
        if ( l != NIL) T[l].parent = v;
        if ( r != NIL) T[r].right = v;
    }

    for ( int i = 0 ; i < n ; i ++) if ( T[i].parent == NIL) root = i;

    setDepth(root,0);
    setHeight(root);

    for ( int i = 0 ; i < n ; i ++) print(i);
    return 0;
}

3.树的遍历:
a.三种遍历方式
前序遍历:根 左 右
中序遍历:左 根 右
后序遍历:左 右 根
是以根的位置定的顺序
b.注意的点:当用递归实现遍历算法时,如果树的结点数量大并且分布不均,很可能导致递归深度过深
c.代码:
//
// Created by 叶子 on 2018/2/4.
// 二叉树的遍历
//

#include "stdio.h"
const int MAX = 10000;
const int NIL = -1;

struct Node { int p,l,r;};
struct Node T[MAX];
int n;

//前序遍历
void preParse(int u){
    if ( u == NIL) return;
    printf(" %d",u);
    preParse(T[u].l);
    preParse(T[u].r);
}

//中序遍历
void inParse(int u){
    if ( u== NIL) return;
    inParse(T[u].l);
    printf(" %d",u);
    inParse(T[u].r);
}

//后序遍历
void postParse(int u){
    if ( u == NIL) return;
    postParse(T[u].l);
    postParse(T[u].r);
    printf(" %d",u);
}

int main(){
    int i,v,l,r,root;

    scanf("%d",&n);
    for ( i = 0 ; i < n ; i ++){
        T[i].p == NIL;
    }

    for ( i = 0 ; i < n ; i ++){
        scanf("%d %d %d",&v,&l,&r);
        T[v].l = l;
        T[v].r = r;
        if ( l != NIL) T[l].p = v;
        if ( r != NIL) T[r].p = v;
    }

    for ( i = 0 ; i < n ; i ++) if ( T[i].p == NIL) root = i;

    printf("Precorder\n");
    preParse(root);
    printf("\n");
    printf("Inorder\n");
    inParse(root);
    printf("\n");
    printf("Postorder\n");
    postParse(root);
    printf("\n");

    return 0;
}
4.树的重建:
a.题目:根据树的先序遍历和中序遍历的结果,生成此树按后序遍历得到的结果
b.分析:可以在遍历先序遍历结果的同时,依次根据中序遍历得到树的左右子树
c.代码:
//
// Created by 叶子 on 2018/2/4.
// 根据树的先序遍历和中序遍历的结果得到后序遍历的结果
//

#include "iostream"
#include "vector"
using namespace std;

int n,pos;
vector<int> pre,in,post;

void rec(int l ,int r){
    if ( l >= r) return;
    int root = pre[pos++];
    int m = distance(in.begin(),find(in.begin(),in.end(),root));
    rec(l,m);
    rec(m+1,r);
    post.push_back(root);
}

void solve(){
    pos = 0;
    rec(0,pre.size());
    for ( int i = 0 ; i < n ; i ++){
        if ( i )  cout << " ";
        cout << post[i];
    }
    cout << endl;
}

int main(){
    int k;
    cin >> n;
    for ( int i = 0 ; i < n ; i ++){
        cin >> k ;
        pre.push_back(k);
    }

    for ( int i = 0 ; i < n ; i++){
        cin >> k;
        in.push_back(k);
    }
    solve();
    return 0;
}