数据结构——树 c++详解

树的定义
  树是由一个集合以及在该集合上定义的一种关系构成的,集合中的元素称为树的结点,所定义的关系称为父子关系。父子关系在树的结点之间建立了一个层次结构,在这种层次结构中有一个结点具有特殊的地位,这个结点称为该树的根结点。

  数据结构中有很多树的结构,其中包括二叉树、二叉搜索树、2-3树、红黑树等等,本文着重介绍二叉树。

树的基本术语
  节点的度:一个节点含有的子树的个数称为该节点的度;
  叶节点或终端节点:度为0的节点称为叶节点;
  非终端节点或分支节点:度不为0的节点;
  双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点;
  孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点;
  兄弟节点:具有相同父节点的节点互称为兄弟节点;
  树的度:一棵树中,最大的节点的度称为树的度;
  节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推;
  树的高度或深度:树中节点的最大层次;
  堂兄弟节点:双亲在同一层的节点互为堂兄弟;
  节点的祖先:从根到该节点所经分支上的所有节点;
  子孙:以某节点为根的子树中任一节点都称为该节点的子孙。
  森林:由m(m>=0)棵互不相交的树的集合称为森林;
树的存储结构
双亲表示法


孩子表示法


二叉树
  二叉树是数据结构中一种重要的数据结构,也是树表家族最为基础的结构。

  二叉树的定义:二叉树的每个结点至多只有二棵子树(不存在度大于2的结点),二叉树的子树有左右之分,次序不能颠倒。

满二叉树
  一棵深度为k且有2 k − 1 2^k-12 k−1 个结点的二叉树称为满二叉树。

完全二叉树
  深度为k的,有n个结点的二叉树,当且仅当其每一个结点都与深度为k的满二叉树中编号从1至n的结点一一对应时,称之为完全二叉树。

  **注:**完全二叉树是效率很高的数据结构,堆是一种完全二叉树或者近似完全二叉树,所以效率极高,像十分常用的排序算法、Dijkstra算法、Prim算法等都要用堆才能优化,二叉排序树的效率也要借助平衡性来提高,而平衡性基于完全二叉树。

二叉排序树
  二叉查找树定义:又称为是二叉排序树(Binary Sort Tree)或二叉搜索树。

二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:

若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
若它的右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值;
它的左、右子树也分别为二叉排序树。
平衡二叉树
  平衡二叉树(Balanced Binary Tree)又被称为AVL树。它或者是一棵空树,或者是具有下列性质的二叉树:它的左子树和右子树都是平衡二叉树,且左子树和右子树的深度之差的绝对值不超过1。(注:平衡二叉树应该是一棵二叉排序树)
例题1:

问题 A: 【一本通数据结构 树 二叉树】【例3-1】找树根和孩子

[题目描述]

给定一棵树,输出树的根root,孩子最多的结点max以及他的孩子。

输入

第一行:n(结点个数≤100),m(边数≤200)。

以下m行:每行两个结点x和y,表示y是x的孩子(x,y≤1000)。

输出

第一行:树根:root;

第二行:孩子最多的结点max;

第三行:max的孩子(按编号由小到输出)。

样例输入

8 7
4 1
4 2
1 3
1 5
2 6
2 7
2 8

样例输出

4
2 
6 7 8
#include 
using namespace std;
struct NODE
{
    int cnt_son;
    int son[201];
    int father;
}parent[1001];
int main()
{
    int x, y, n, m;
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= m; i++)
    {
        scanf("%d%d", &x, &y);
        parent[y].father = x;
        parent[x].cnt_son++;
        parent[x].son[parent[x].cnt_son] = y;
    }
     
    int root = 0;
    for(int i = 1; i <= n; i++)
    {
        if(parent[i].father == 0)
        {
            root = i;
            break;
        }
    }
     
    int maxi = 0;
    for(int i = 1; i <= n; i++)
    {
        if(parent[maxi].cnt_son < parent[i].cnt_son)
            maxi = i;
    }
     
    printf("%d\n%d\n", root, maxi);
    for(int i = 1; i <= parent[maxi].cnt_son; i++)
    {
        printf("%d ", parent[maxi].son[i]);
    }
    return 0;
}

例题2: 

问题 C: 【一本通数据结构 树 二叉树】【例3-3】医院设置

[题目描述]

设有一棵二叉树(如图3-8,其中圈中的数字表示结点中居民的人口,圈边上数字表示结点编号。现在要求在某个结点上建立一个医院,使所有居民所走的路程之和为最小,同时约定,相邻结点之间的距离为1。就本图而言,若医院建在1处,则距离和=4+12+2*20+2*40=136;若医院建在3处,则距离和=4*2+13+20+40=81……

输入

第一行一个整数n,表示树的结点数(n≤100)。接下来的n行每行描述了一个结点的状况,包含三个整数,整数之间用空格(一个或多个)分隔,其中:第一个数为居民人口数;第二个数为左链接,为0表示无链接;第三个数为右链接,为0表示无链接。

输出

一个整数,表示最小距离和。

样例输入

5
13 2 3
4 0 0
12 4 5
20 0 0
40 0 0

样例输出

81
#include "bits/stdc++.h"
using namespace std;
 
//1、设计一种数据类型,存储本题“图中节点的连接关系”。参看本题题目中的提示
//采用的数据结构:采用二维数组,若i节点->j节点有直接连接,则在相应位置ljjz[i][j]赋值(距离),
//i == j的位置:写0,表示距离为0;其他无直接连接位置:ljjz[i][j] = 无穷大(暂时); 
int ljjz[101][101]; //存储各个节点之间的(最短)距离(邻接矩阵) 
int people[101];        //各节点对应的人口数 
int cnt;                //输入节点个数、后续数据的行数 
 
int main()
{
//2、数据输入。数据插入到distance[][]中
//题目明确给定:所有直接相连的节点距离为distance[][]=1 
//2.1输入节点总数、后续数据的行数(题目给定:cnt <=100,所有节点均为连接在一体) 
    cin >> cnt;   
     
    //2.1 初始化data[][]数据为cnt * 1,100为本题目中的无穷大,即大于最不利原则距离 
    for(int i = 0; i <= cnt; i++){
        for(int j = 0; j <= cnt; j++){
            if(i == j)
                ljjz[i][j] = 0; //distance
            else
                ljjz[i][j] = 100; //cnt * 1;    
        }
    }
         
    //2.2 数据插入到ljjz[][]中,数据输入完成。 
    int p, i = 1, j1, j2;//p人口数     
    for(int n = 1; n <= cnt; n++, i++){
        cin >> p; //该行第1个数据,人口数 
        cin >> j1;    //该行第2个数据,left节点地址
        cin >> j2;    //该行第3个数据,right节点地址 
         
        people[i] = p;  //记录该节点的人口数 
         
        if(j1 != 0){
            ljjz[i][j1] = 1;    //存放--直接相连的两点距离,1 
            ljjz[j1][i] = 1;
        }
        if(j2 != 0){
            ljjz[i][j2] = 1;    //存放--直接相连的两点距离,1 
            ljjz[j2][i] = 1;
        }
    }
 
//3、foled最短路径 
//迭代条件:如果 i->j 的间接距离([i][j])大于间接路径距离(i->k->j,[i][k]+[k][j]),
//将更小的间接路径距离赋给[i][j] 
    for(int i = 1; i <= cnt; i++){       
        for(int j = 1; j <= cnt; j++){
            if((i != j) ||(ljjz[i][j] != 1)){   //本身或则直接连接就不用再迭代了 
                for(int k = 1; k <= cnt; k++){
                    if(ljjz[i][j] > (ljjz[i][k] + ljjz[k][j]))
                        ljjz[i][j] = ljjz[i][k] + ljjz[k][j];                           
                }
            }           
        }
    }
     
//4、依次以每个节点为医院位置,求出所对应的所有居民所走的路程之和, 存于ljjz[0][j] 
//若以节点1为医院,则所有居民所走的路程之和存放于ljjz[0][1]
//ljjz[0][1] += people[i]*ljjz[i][1] (i from 1 to cnt)
    for(int j = 1; j <= cnt; j++){
        ljjz[0][j] = 0;
        for(int i = 1; i <= cnt; i++){
            ljjz[0][j] += people[i]*ljjz[i][j];
        }
    }
/*----------------------测试用-------------------------------// 
    //2.3 输出ljjz[][],检查数据输入环节是否正确。 
    cout << endl << endl << "邻接矩阵输出" << endl << endl;
    for(int i = 0; i <= cnt; i++)
    {   
        cout << setw(6) << people[i] << "  "; 
        for(int j = 1; j <= cnt; j++)
            cout << setw(6) << ljjz[i][j] << "  ";        
        cout << endl;
    }
    cout << endl << endl << "最短路径输出" << endl << endl;
//----------------------测试用-------------------------------*/
//5、求出 ljjz[0][j]的最小值,输出(j from 1 to cnt)
    int minx = ljjz[0][1]; 
    for(int j = 2; j <= cnt; j++){
        if(minx > ljjz[0][j])
            minx = ljjz[0][j];
    }       
    cout << minx << endl;
/*------------------foled最短路径5行代码-----------------------//
//迭代条件:如果 i->j 的间接距离([i][j])大于间接路径距离(i->k->j,[i][k]+[k][j]),
//将更小的间接路径距离赋给[i][j] 
    for(int i = 1; i <= cnt; i++){       
        for(int j = 1; j <= cnt; j++){
            for(int k = 1; k <= cnt; k++){               
                if(ljjz[i][j] > (ljjz[i][k] + ljjz[k][j]))
                    ljjz[i][j] = ljjz[i][k] + ljjz[k][j];                           
            }           
        }
    }
//----------------------------------------*/
/*----------------------测试用-------------------------------// 
    //2.3 输出ljjz[][],检查数据输入环节是否正确。 
    cout << endl << endl << "邻接矩阵输出" << endl << endl;
    for(int i = 0; i <= cnt; i++)
    {   
        cout << people[i] << "  ";  
        for(int j = 1; j <= cnt; j++)
            cout << ljjz[i][j] << "  ";     
        cout << endl;
    }
//----------------------测试用-------------------------------*/
    return 0;
}

你可能感兴趣的:(数据结构,算法)