数据结构-C语言描述(二叉树)

概述

二叉树是一种特殊的树,顾名思义,与一般的树不同的是二叉树的每个结点只有两个分叉,如图:

通过观察这张实物图,我们将其用图的方式抽象出来,即每个结点只有最多两个子结点,就像下面一样: 

 其次关于二叉树还有满二叉树和完全二叉树之分,在这里我们只是简单的建立一下二叉树的框架,其他的相关概念在这里不过多赘述,想要深入了解的可以在优快云中搜索相关博客二叉树的相关概念

 1.二叉树结点的定义

首先是头文件的预处理:

#include <stdio.h>
#include <stdlib.h>
#define eletype char  //这里我们存储的数据均为字符类型char

 然后我们先定义树结点TreeNode的结构体,相信大家已经比较熟悉,当然要包括数据域val、指针域。在这里我们回想一下普通树的结点定义(数据域data、子结点链表childrenhead),但是二叉树的子结点个数是固定的,最多只有两个,所以我们这里不需要定义这个子结点链表,只需要单独定义左右两个指针*left、*right(分别指向左右两个结点):

typedef struct TreeNode {
    eletype val;
    TreeNode* left;    //定义两个结点分别指向左右结点
    TreeNode* right;
} TreeNode;

2.二叉树结构体定义

二叉树的结构体定义与一般的树结构体定义没有区别,都要包括一个用来记录所有结点的数组*nodes,指向根结点的*root,树的大小size:

typedef struct Tree {
    TreeNode* nodes;
    TreeNode* root;
    int nodesize;
} Tree;

 3.二叉树的创建

再创建二叉树的时候我们要传入两个参数Tree* t、二叉树的大小size:

void TreeInit(Tree* t,int size) {
    t->nodes=(TreeNode*)malloc(sizeof(TreeNode)*size);
    t->root=NULL;
    t->nodesize=size;
}

4.二叉树的销毁

只需要将分配的空间和参数都释放、置空即可:

void TreeDestroy(Tree* t) {
    free(t->nodes);
    t->nodes=NULL;
    t->root=NULL;
    t->nodesize;
}

5.获取结点

因为所有的结点都被记录在数组nodes中,所以可以通过下标来找到结点,注意返回值是TreeNode类型的一个结点:

TreeNode* TreeGetNode(Tree* t,int nodeId) {
    return &t->nodes[nodeId];
}

6.访问结点

这里的访问结点就是访问结点中数据,即将其打印出来:

void TreeVisit(TreeNode* node) {
    printf("%c",node->val);
}

7.二叉树的初始化

这里的初始化指的将每个树结点赋值,所有结点的值会先记录在数组a[ ]中,所以参数表中要有Tree* t、a[ ]、二叉树长度size、结点的索引、空结点的标志nullnode:

TreeNode* creatRecursively(Tree* t,eletype a[],int size,int nodeId,eletype nullnode) {
    if(nodeId>=size||a[nodeId]==nullnode){
        return NULL;
    }
    TreeNode* nownode=TreeGetNode(t,nodeId);//先找到要赋值的结点,新定义一个nownode来接受
    nownode->val=a[nodeId];
    nownode->left=creatRecursively(t,a,size,nodeId*2,nullnode);   //然后分别对该结点的
    nownode->right=creatRecursively(t,a,size,nodeId*2+1,nullnode);  //左右子结点赋值
    return nownode;      //这里用的是简单的递归方式,故而返回值是当前结点
}
void TreeCreat(Tree* t,eletype a[],int size,eletype nullnode) {
    t->root=creatRecursively(t,a,size,nodeId,nullnode);
}

 8.二叉树的前序遍历

前序遍历是指从根结点开始遍历,然后先遍历左结点,然后遍历右结点,最后再遍历根结点:

void PreOrder(Tree* t,TreeNode* node) {
    if(node){
        TreeVisit(node);
        PreOrder(t,node->left);
        PreOrder(t,node->right);
    }   
}    
void TreePreOrderTraversal(Tree*t) {
    PreOrder(t,t->root);
}
    

9.二叉树的中序遍历

void InOrder(Tree* t,TreeNode* node) {
    if(node){
        InOrder(t,node->left);
        InOrder(t,node->right);
        TreeVisit(node);
    }
}
void TreeInOrderTraversal(Tree* t) {
    InOrder(t,t->root);
}

10.二叉树的后序遍历

void PostOrder(Tree* t,TreeNode* node) {
    if(node){
        PostOrder(t,node->left);
        PostOrder(t,node->right);
        TreeVisit(node);
    }
}
void TreePostTraversal(Tree* t) {
    PostOrder(t,t->root);
}

 对于树的三种遍历方法不熟悉的可以参考下面这篇博客二叉树的三种遍历方法

 11.完整源码

#include <stdio.h>
#include <stdlib.h>
#define eletype char  //这里我们存储的数据均为字符类型char

typedef struct TreeNode {
    eletype val;
    struct TreeNode* left;    //定义两个结点分别指向左右结点
    struct TreeNode* right;
} TreeNode;

typedef struct Tree {
    TreeNode* nodes;
    TreeNode* root;
    int nodesize;
} Tree;

void TreeInit(Tree* t,int size) {
    t->nodes=(TreeNode*)malloc(sizeof(TreeNode)*size);
    t->root=NULL;
    t->nodesize=size;
}

void TreeDestroy(Tree* t) {
    free(t->nodes);
    t->nodes=NULL;
    t->root=NULL;
    t->nodesize=0;
}

TreeNode* TreeGetNode(Tree* t,int nodeId) {
    return &t->nodes[nodeId];
}

void TreeVisit(TreeNode* node) {
    printf("%c",node->val);
}

TreeNode* creatRecursively(Tree* t,eletype a[],int size,int nodeId,eletype nullnode) {
    if(nodeId>=size||a[nodeId]==nullnode){
        return NULL;
    }
    TreeNode* nownode=TreeGetNode(t,nodeId);//先找到要赋值的结点,新定义一个nownode来接受
    nownode->val=a[nodeId];
    nownode->left=creatRecursively(t,a,size,nodeId*2,nullnode);   //然后分别对该结点的
    nownode->right=creatRecursively(t,a,size,nodeId*2+1,nullnode);  //左右子结点赋值
    return nownode;      //这里用的是简单的递归方式,故而返回值是当前结点
}

void TreeCreat(Tree* t,eletype a[],int size,eletype nullnode) {
    t->root=creatRecursively(t,a,size,1,nullnode);
}

void PreOrder(Tree* t,TreeNode* node) {
    if(node){
        TreeVisit(node);
        PreOrder(t,node->left);
        PreOrder(t,node->right);
    }   
}    

void TreePreOrderTraversal(Tree*t) {
    PreOrder(t,t->root);
}
    
void InOrder(Tree* t,TreeNode* node) {
    if(node){
        InOrder(t,node->left);
        InOrder(t,node->right);
        TreeVisit(node);
    }
}

void TreeInOrderTraversal(Tree* t) {
    InOrder(t,t->root);
}

void PostOrder(Tree* t,TreeNode* node) {
    if(node){
        PostOrder(t,node->left);
        PostOrder(t,node->right);
        TreeVisit(node);
    }
}

void TreePostOrderTraversal(Tree* t) {
    PostOrder(t,t->root);
}

int main(){
	const char nullnode='-';
	eletype a[15]={nullnode,'a','b','c','d',nullnode,'e','f','g','h',nullnode,nullnode,nullnode,nullnode,'i'};
	
	Tree T;
	TreeInit(&T,15);
	
	TreeCreat(&T,a,15,nullnode);
	TreePreOrderTraversal(&T);printf("\n");
	TreeInOrderTraversal(&T);printf("\n");
	TreePostOrderTraversal(&T);printf("\n");
	
	TreeDestroy(&T);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值