【数据结构】-树形结构概述和操作

一、树形结构概述

        树形结构是数据结构中的一种逻辑关系结构,在此逻辑结构中数据元素之间满足一对多的分层结构关系,也称分层结构。

        1.所有的数据节点中的起始节点,有且仅有一个,也称为根节点。

                没有直接前驱,可以有多个直接后继节点。

        2.末尾节点,可以有一个或者多个,也称为叶节点,或者树叶。

                每一个节点没有直接后继节点,有且仅有一个直接前驱节点。

        3.中间的节点,也称为内部节点。

                每一个节点有且仅有一个直接前驱节点;可以有多个直接后继节点。

二、树的定义

        树是n个节点的有序集合,它满足两个条件:

                1.有且仅有一个特定的根节点;

                2.其余节点可以分为m个互不相交的有序集合T1,T2,......Tm,其中每个集合又是一棵树,称为其根的子树。

三、二叉树的定义

        二叉树是n个节点的有限集合,它或者是空集,或者是由一个根节点以及两棵互不相交、分别称为左右子树的二叉树组成。二叉树与普通有序树不同,二叉树严格区分左右孩子,即使只有一个子节点也会区分。

四、实例:

        创建如下图的二叉树,分别输出层次遍历、先序遍历、中序遍历、后序遍历;

        所谓的遍历,指的是沿某条搜索路径周游二叉树,对树中的每一个节点访问一次且仅访问一次;

        对于二叉树的遍历方式:主要分为递归遍历和分层遍历实现。

        在对于二叉树的遍历过程中,如果去根节点,左子树和右子树也是二叉树,可以采用相同的遍历思路实现对左子树和右子树遍历过程。所以在对于二叉树的遍历可以采用递归遍历算法实现。

具体实现:

        1.树和队列结构类型定义

//节点数据域类型定义
typedef int data_t;
//节点数据类型的定义
typedef struct binTree{
    data_t data;//结点本身数据
    struct binTree *lchild;//左孩子节点空间地址
    struct binTree *rchild;//右孩子节点空间地址
}binTree_t;
//链队列定义
typedef struct node{
    binTree_t *addr;
    struct node *next;
}node_t;
typedef struct linkqueue{
    node_t *front;
    node_t *rear;
}linkqueue_t;

 2.创建二叉树和队列

//创建完全二叉树
binTree_t * CreateBinTree(int i,int n)
{
    binTree_t *btree;
    //创建根节点
    btree = malloc(sizeof(binTree_t));
    if(btree == NULL)
        return NULL;

    memset(btree,0,sizeof(binTree_t));
    btree->data = i; //根节点数据域存储的是节点编号
    //左子树设置
    if(2*i<=n)
        btree->lchild = CreateBinTree(2*i,n);
    else
        btree->lchild = NULL;
    
    //右子树设置
    if(2*i+1<=n)
        btree->rchild = CreateBinTree(2*i+1,n);
    else
        btree->rchild = NULL;

    return btree;
}
//创建链队列
linkqueue_t * CreateLinkQueue()
{
    linkqueue_t *queue;
    queue = malloc(sizeof(linkqueue_t));
    if(queue == NULL)
        return NULL;
    queue->front = malloc(sizeof(node_t));
    if(queue->front == NULL)
    {
        free(queue);
        return NULL;
    }
    queue->rear = queue->front;

    return queue;
}

 三、队列操作

//入队
int EnLinkQueue(linkqueue_t * queue,binTree_t *myaddr)
{
    node_t * p;
    if(queue == NULL)
        return -1;
    //创建入队结点并初始化
    p = malloc(sizeof(node_t));
    if(p == NULL)
        return -1;
    p->addr = myaddr;
    //入队
    p->next = NULL;
    queue->rear->next = p;
    queue->rear = p;

    return 0;
}
//获得队列元素
int GetLinkQueue(linkqueue_t *queue,binTree_t **myaddr)
{
    if(queue == NULL)
        return -1;
    if(queue->front->next == NULL)
        return -1;
    *myaddr = queue->front->next->addr;

    return 0;
}
//出队
int DeLinkQueue(linkqueue_t *queue)
{
    node_t *p;
    if(queue  == NULL)
        return -1;
    if(queue->front->next == NULL)
        return -1;
    //出队
    p = queue->front->next;
    queue->front->next = p->next;
    free(p);
    //出队的结点为最后一个结点
    if(queue->front->next == NULL)
        queue->rear = queue->front;
    
    return 0;
}
//判断链队列为空
int isEmptyLinkQueue(linkqueue_t *queue)
{
    return (queue->front == queue->rear);
}

四、分层遍历

//分层遍历
void layer_order(binTree_t * btree)
{
    binTree_t *myaddr;
    //创建空队列
    linkqueue_t * queue;
    queue = CreateLinkQueue();
    if(queue == NULL)
        return;
    //遍历根节点,并将节点入队
    printf("%d ",btree->data);
    EnLinkQueue(queue,btree);

    while(!isEmptyLinkQueue(queue))
    {
        GetLinkQueue(queue,&myaddr);
        DeLinkQueue(queue);
        //遍历左子节点
        if(myaddr->lchild != NULL)
        {
            printf("%d ",myaddr->lchild->data);
            EnLinkQueue(queue,myaddr->lchild);
        }
        //遍历右子节点
        if(myaddr->rchild != NULL)
        {
            printf("%d ",myaddr->rchild->data);
            EnLinkQueue(queue,myaddr->rchild);
        }
    }
    printf("\n");
}

五、树的遍历

//前序遍历
void pre_order(binTree_t * btree)
{
    if(btree == NULL)
        return ;
    printf("%d ",btree->data);//遍历根节点
    pre_order(btree->lchild);//遍历左节点
    pre_order(btree->rchild);//遍历右节点
}
//中序遍历
void mid_order(binTree_t * btree)
{
    if(btree == NULL)
        return ;
    pre_order(btree->lchild);//遍历左节点
    printf("%d ",btree->data);//遍历根节点
    pre_order(btree->rchild);//遍历右节点
}
//后序遍历
void after_order(binTree_t * btree)
{
    if(btree == NULL)
        return ;
    pre_order(btree->lchild);//遍历左节点
    pre_order(btree->rchild);//遍历右节点
    printf("%d ",btree->data);//遍历根节点
}

六、主函数调用

int main()
{
    binTree_t *btree;
    //创建完全二叉树:根节点编号为1,最大节点编号为12
    btree = CreateBinTree(1,12);
    if(btree == NULL)
        return -1;

    //分层遍历
    layer_order(btree);
    //先序遍历
    pre_order(btree);
    printf("\n");
    //中序遍历
    mid_order(btree);
    printf("\n");
    //后序遍历
    after_order(btree);
    printf("\n");
    return 0;
}
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值