树系列---基础概念


一、基础概念

1.定义

在这里插入图片描述说人话就是:
在这里插入图片描述
长这样的图。


2、术语(说人话版本):

(先规定一般树都是上面小、下面大)
父(母)节点:上面那一个节点
子节点:自己下面那几个节点
节点的度:从自己开始,自己生出来的节点
叶节点或终端节点:没有子节点了的
子孙:子节点都是子孙
节点的祖先:从自己往上走,经过的都可以是祖先
层次:根节点算第一层,儿子算第二层、儿子的儿子算第三层…
兄弟节点:同一个父节点
堂兄弟:父节点在同一层
森林:多个树的集合

3、性质

  • 每个节点都只有有限个子节点或无子节点;
  • 没有父节点的节点称为根节点;
  • 每一个非根节点有且只有一个父节点;
  • 除了根节点外,每个子节点可以分为多个不相交的子树;
  • 树里面没有环路(cycle)

可以简单理解为:一旦分道扬镳,再也没有交集
举几个反例就知道了:
在这里插入图片描述这个有了交集(D和 E),就不能叫树。

二、表示法

1.双亲表示法

双亲表示法采用顺序表(也就是数组)存储普通树,其实现的核心思想是:顺序存储各个节点的同时,给各节点附加一个记录其父节点位置的变量。

简单地来说,就是运用类似于链表的方法,只不过是用的是数组的朴素方法,记录一下上一个(就是父节点)的数组下标。
在这里插入图片描述

#include<stdio.h>
#include<stdlib.h>
#define MAX_SIZE 20
typedef char ElemType;//宏定义树结构中数据类型
typedef struct Snode  //结点结构
{
    ElemType data;
    int parent;
}PNode;

typedef struct  //树结构
{
    PNode tnode[MAX_SIZE];
    int n;                 //结点个数
}PTree;

PTree InitPNode(PTree tree)
{
    int i, j;
    char ch;
    printf("请输出节点个数:\n");
    scanf("%d", &(tree.n));

    printf("请输入结点的值其双亲位于数组中的位置下标:\n");
    for (i = 0; i < tree.n; i++)
    {
        getchar();
        scanf("%c %d", &ch, &j);
        tree.tnode[i].data = ch;
        tree.tnode[i].parent = j;
    }
    return tree;
}

void FindParent(PTree tree)
{
    char a;
    int isfind = 0;
    printf("请输入要查询的结点值:\n");
    getchar();
    scanf("%c", &a);
    for (int i = 0; i < tree.n; i++) {
        if (tree.tnode[i].data == a) {
            isfind = 1;
            int ad = tree.tnode[i].parent;
            printf("%c的父节点为 %c,存储位置下标为 %d", a, tree.tnode[ad].data, ad);
            break;
        }
    }
    if (isfind == 0) {
        printf("树中无此节点");
    }
}

int main()
{
    PTree tree;
    for (int i = 0; i < MAX_SIZE; i++) {
        tree.tnode[i].data = " ";
        tree.tnode[i].parent = 0;
    }
   
    tree = InitPNode(tree);
    FindParent(tree);
    return 0;
}


2.孩子表示法

这个就是先把所有节点先放入数组,顺序存储,但是每个后面又用链表衔接
各自的子节点。
每个节点的数据域依然是 数组下标
因为之前说了,所有节点都在数组里,所以有下标就有节点。

在这里插入图片描述拿R根节点看,它后边跟着1、2、3,就是说,他的儿子们事在数组里面下标为1、2、3的A、B、C

#include<stdio.h>
#include<stdlib.h>
#define MAX_SIZE 20
#define TElemType char
//孩子表示法
typedef struct CTNode {
    int child;//链表中每个结点存储的不是数据本身,而是数据在数组中存储的位置下标
    struct CTNode * next;
}ChildPtr;
typedef struct {
    TElemType data;//结点的数据类型
    ChildPtr* firstchild;//孩子链表的头指针
}CTBox;
typedef struct {
    CTBox nodes[MAX_SIZE];//存储结点的数组
    int n, r;//结点数量和树根的位置
}CTree;
//孩子表示法存储普通树
CTree initTree(CTree tree) {
    printf("输入节点数量:\n");
    scanf("%d", &(tree.n));
    for (int i = 0; i < tree.n; i++) {
        printf("输入第 %d 个节点的值:\n", i + 1);
        getchar();
        scanf("%c", &(tree.nodes[i].data));
        tree.nodes[i].firstchild = (ChildPtr*)malloc(sizeof(ChildPtr));
        tree.nodes[i].firstchild->next = NULL;

        printf("输入节点 %c 的孩子节点数量:\n", tree.nodes[i].data);
        int Num;
        scanf("%d", &Num);
        if (Num != 0) {
            ChildPtr * p = tree.nodes[i].firstchild;
            for (int j = 0; j < Num; j++) {
                ChildPtr * newEle = (ChildPtr*)malloc(sizeof(ChildPtr));
                newEle->next = NULL;
                printf("输入第 %d 个孩子节点在顺序表中的位置", j + 1);
                scanf("%d", &(newEle->child));
                p->next = newEle;
                p = p->next;
            }
        }
    }
    return tree;
}

void findKids(CTree tree, char a) {
    int hasKids = 0;
    for (int i = 0; i < tree.n; i++) {
        if (tree.nodes[i].data == a) {
            ChildPtr * p = tree.nodes[i].firstchild->next;
            while (p) {
                hasKids = 1;
                printf("%c ", tree.nodes[p->child].data);
                p = p->next;
            }
            break;
        }
    }
    if (hasKids == 0) {
        printf("此节点为叶子节点");
    }
}

int main()
{
    CTree tree;
    for (int i = 0; i < MAX_SIZE; i++) {
        tree.nodes[i].firstchild = NULL;
    }
    tree = initTree(tree);
    //默认数根节点位于数组notes[0]处
    tree.r = 0;
    printf("找出节点 F 的所有孩子节点:");
    findKids(tree, 'F');
    return 0;
}


3.孩子兄弟表示法

第三种是一种思路最特殊的—从兄弟的角度构建的
首先看引入语
在这里插入图片描述
这句话刚开始看了很久也没看懂。
应该理解为:规定:一个节点的首个儿子为唯一和其直接联系的,二儿子、三儿子都和大儿子联系;
同理,这个节点自己也可能是别人的大儿子,那就负责联系二弟、三弟(兄弟节点);可能是二儿子、三儿子,那就只能找大哥。
画图一目了然

在这里插入图片描述


总结

这里是树的基本概念,接下来将要引出的是二叉树,那才是重点

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值