树的存储结构及详细完整代码

树的存储结构

 树的存储方式有多种,既可以采用顺序存储结构,又可以采用链式存储结构,但无论何种存储方式,都要求能够唯一的反映树中各结点之间的逻辑关系。

常用的存储结构主要有:
 <1> 双亲表示法
 <2> 孩子表示法
 <3> 孩子兄弟表示法


<1>双亲表示法

 采用一组连续空间来存储每个结点,同时在每个结点中增设一个伪指针,指示其双亲结点在数组中的位置

 如下图所示,根结点的下标为0,其伪指针域为-1。
在这里插入图片描述

 这种双亲表示法的存储结构描述如下:

#define MaxSize 100  //树中最多结点数
typedef struct{  //树的结点定义
    char data;  //数据元素
    int parent;  //双亲位置域
}PTNode;

typedef struct{  //树的类型定义
    PTNode nodes[MaxSize];  //双亲表示
    int n;  //结点数
}PTree;

对于上图的完整代码实现如下:

#include<bits/stdc++.h>
using namespace std;

#define MaxSize 100  //树中最多的结点数

typedef struct{  //结点定义
    char data; //数据
    int parent; //双亲位置域
}PTNode;

typedef struct{
    PTNode nodes[MaxSize]; //双亲表示,存放树中所有结点
    int n; //结点数
}PTree;

//树的结点初始化
PTree InitPNode(PTree tree){
    cout<<"请输入结点个数: ";
    cin>>tree.n;
    
    cout<<"请输入结点的值及其双亲位于数组中的位置下标:"<<endl;
    char ch;
    int j;
    for(int i=0; i<tree.n; i++){
        fflush(stdin);  //清空输入缓冲区
        cin>>ch>>j;
        tree.nodes[i].data = ch;  //结点数据
        tree.nodes[i].parent = j;  //双亲结点在数组中的位置
    }
    return tree;
}

//查找树中指定结点
void FindParent(PTree tree){
    cout<<"请输入要查询的结点值:";
    fflush(stdin);  //清空输入缓冲区
    char a; 
    cin>>a; //输入要查询的结点值
    int flag = 0;
    for(int i=0; i<tree.n; i++){
        if(tree.nodes[i].data == a){
            flag = 1;
            if(i == 0){ //此时为根结点
                cout<<"此结点为根结点!"<<endl;
                break;
            }
            int ad = tree.nodes[i].parent;
            cout<<a<<"的父结点为: "<<tree.nodes[ad].data<<endl;
            cout<<"存储位置为: "<<ad<<endl;
            break;
        }
    }
    if(flag == 0){
        cout<<"树中无此结点。"<<endl;
    }
}


int main(){
    PTree tree;
    tree = InitPNode(tree);
    FindParent(tree);
    return 0;
}

 运行结果为:
在这里插入图片描述

<2>孩子表示法

 将每个结点的孩子结点都用单链表链接起来形成一个线性结构,此时n个结点就有n个孩子链表(叶子结点的孩子链表为空表),如下图所示。

在这里插入图片描述

特点:孩子表示法这种存储方式寻找子女的操作非常直接,而寻找双亲的操作需要遍历n个结点中孩子链表指针域所指向的n个孩子链表


 树的孩子表示法采用的是**“顺序表+链表”**的组合结构,其存储过程为,从树的根结点开始,使用顺序表依次存储树中各个结点,并给每一个结点分配一个链表,用于存储各个结点的孩子结点位于顺序表中的位置。如果该结点没有孩子结点(即是叶子结点),则该结点的链表为空链表。

对于上图的完整实现代码如下:

#include<bits/stdc++.h>
using namespace std;

#define MaxSize 100

typedef struct ChildNode{ //链表中每个结点的定义
    //链表中每个结点存储的不是数据本身,而是数据在数组中存储的位置下标
    int child;
    struct ChildNode *next;
}ChildNode;

typedef struct{  //树中每个结点的定义
    char data;  //结点的数据类型
    ChildNode *firstchild;  //孩子链表头指针
}CHNode;

typedef struct{
    CHNode nodes[MaxSize];  //存储结点的数组
    int n;
}CTree;

//树中结点初始化
CTree InitTree(CTree tree){
    cout<<"请输入结点总数:";
    cin>>tree.n;
    for(int i=0; i<tree.n; i++){
        cout<<"请输入第"<<i+1<<"个结点的值:";
        fflush(stdin);
        cin>>tree.nodes[i].data;
        //链表结点
        tree.nodes[i].firstchild = (ChildNode *)malloc(sizeof(ChildNode));
        tree.nodes[i].firstchild->next = NULL;
        
        cout<<"请输入结点"<<tree.nodes[i].data<<"的孩子结点数量:";
        int num;
        cin>>num;
        if(num != 0){
            ChildNode *p = tree.nodes[i].firstchild; //p为操作指针
            for(int j=0; j<num; j++){
                ChildNode *q = (ChildNode *)malloc(sizeof(ChildNode)); //新建结点
                q->next = NULL;
                cout<<"请输入第"<<j+1<<"个孩子结点在顺序表中的存储位置: ";
                cin>>q->child;
                p->next = q;
                p = p->next;
            }
        }
    }
    return tree;
}


void FindKids(CTree tree, char a){
    int flag = 0;
    for(int i=0; i<tree.n; i++){
        if(tree.nodes[i].data == a){
            cout<<a<<"的所有孩子结点为: ";
			ChildNode *p = tree.nodes[i].firstchild->next;
            while(p){
                flag = 1;
                //输出所有的孩子结点
                cout<<tree.nodes[p->child].data<<" ";
                p = p->next;
            }
            break;
        }
    }
    if(flag == 0){
        cout<<"此结点为叶子节点"<<endl;
    }
}

int main(){
    CTree tree;
    tree = InitTree(tree);
    char a;
    cout<<"请输入要查找其孩子结点的结点:";
    cin>>a;
    FindKids(tree, a);
    return 0;
}

 运行结果为:
在这里插入图片描述

<3>孩子兄弟表示法

 孩子兄弟表示法又称二叉树表示法,即以二叉链表作为树的存储结构。

 孩子兄弟表示法使每个结点包括三部分内容:结点值、指向结点第一个孩子结点的指针、指向结点下一个兄弟结点的指针(沿此域可以找到结点的所有兄弟结点)。

 结点结构示意图:
在这里插入图片描述

 孩子兄弟表示法的具体实例:
在这里插入图片描述

 孩子兄弟表示法的存储结构描述如下:

typedef struct CSNode{
    char data;  //数据域
    struct CSNode *firstchild, *nextsibling;  //第一个孩子和右兄弟指针    
}CSNode, *CSTree;

特点:孩子兄弟存储表示法比较灵活,其最大的优点是可以方便的实现树转换为二叉树的操作,易于查找结点的孩子等;缺点是从当前结点查找其双亲结点比较麻烦。
 若为每一个结点增设一个parent域指向其父结点,则查找结点的父结点也很方便。

 通过孩子兄弟表示法,任意一棵普通树都可以相应转化为一棵二叉树,也就是说,任意一棵普通树都有唯一一颗二叉树与之对应。

 这种方式的代码实现与二叉树的操作大致相同,故不再给出。

  • 20
    点赞
  • 97
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
下面是一个使用邻接表(Adjacency List)存储结构实现的示例代码: ```c #include <stdio.h> #include <stdlib.h> // 定义的节点结构 struct TreeNode { int value; struct TreeNode* firstChild; struct TreeNode* nextSibling; }; // 创建新节点 struct TreeNode* createNode(int value) { struct TreeNode* newNode = (struct TreeNode*)malloc(sizeof(struct TreeNode)); newNode->value = value; newNode->firstChild = NULL; newNode->nextSibling = NULL; return newNode; } // 添加子节点 void addChild(struct TreeNode* parent, struct TreeNode* child) { if (parent->firstChild == NULL) { parent->firstChild = child; } else { struct TreeNode* sibling = parent->firstChild; while (sibling->nextSibling != NULL) { sibling = sibling->nextSibling; } sibling->nextSibling = child; } } // 打印的结构 void printTree(struct TreeNode* node, int depth) { if (node == NULL) { return; } for (int i = 0; i < depth; i++) { printf(" "); } printf("%d\n", node->value); printTree(node->firstChild, depth + 1); printTree(node->nextSibling, depth); } int main() { // 创建根节点 struct TreeNode* root = createNode(1); // 创建子节点 struct TreeNode* child1 = createNode(2); struct TreeNode* child2 = createNode(3); struct TreeNode* child3 = createNode(4); // 添加子节点到根节点 addChild(root, child1); addChild(root, child2); addChild(root, child3); // 创建子节点的子节点 struct TreeNode* grandchild1 = createNode(5); struct TreeNode* grandchild2 = createNode(6); // 添加子节点的子节点 addChild(child1, grandchild1); addChild(child2, grandchild2); // 打印的结构 printTree(root, 0); return 0; } ``` 在这个示例,我们定义了一个`TreeNode`结构体,包含了节点的值、指向第一个子节点的指针`firstChild`和指向下一个兄弟节点的指针`nextSibling`。通过`createNode`函数创建新节点,并使用`addChild`函数将子节点添加到父节点。最后,使用`printTree`函数打印的结构。 这个示例创建了一个简单的,并打印了它的结构: ``` 1 2 5 3 6 4 ``` 你可以根据需要修改和扩展这个示例,以适应不同的结构。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值