C语言数据结构-二叉树(二叉链表实现)

        二叉树在数据结构中是很重要的一环,实现他的方式主要有两种一种为顺序表存储,另外一种为二叉链表实现,一个结点带两个指针,这里我们采用二叉链表实现。听起来很复杂其实不算难,里面主要的是要理解递归的方法,如果之前不熟悉递归、链表可以补一下相关基础再看,递归这块看经典的斐波那契数列、阶乘、汉诺塔这些帮助理解递归,代码里面涉及递归的地方建议自己画一个3-4层的二叉树从叶子结点往上对比着代码看,把代码每一步过一遍手动算一下每一步每一个变量的值,就容易理解里面的递归思想。链表这块要理解单链表。本文了实现二叉树的初始化、添加、前中后三种遍历方法、叶子、总结点、树的深度计算方法。

我们将实现下图这个二叉树的创建、橙色为创建的结点

//基本头文件,包含printf这些最基本的函数
#include<stdio.h>
//引入malloc函数用于动态开辟二叉树结点
#include<stdlib.h>
//宏定义OK、False用于解决C语言中没有OK、False这些关键字,也可以引入其他关键字头文件,宏定义替换只是一种简单的表示方法也可以单纯的用0,1在函数中表示
#define OK 1
#define False 0
//重命名 int为Status和Element方便后面使用
typedef int Status;
typedef int Element;
//定义二叉树结点,typedef是把struct BiTree重命名为BiTree,方便后续声明二叉树结点减少代码量
typedef struct BiTree {
	Element infos;
	BiTree* lchild;
	BiTree* rchild;
};
//初始化二叉树,根节点元素设置为0
Status InitBiTree(BiTree &T) {
	T.infos = 0;
	T.lchild = NULL;
	T.rchild = NULL;
	return OK;
}

//InsertChild函数 添加新节点在二叉树上,插入方式可以自己修改,这个函数较简单只实现了每一层放一个结点
//T要被添加新结点的二叉树
//形参**p意思是要接受指针的地址,用于*p = NewTree;这里改变p指针的位置,如果是一个*那么在函数内p指针更新生效,但是main函数中p指针就没有更新,下一次使用本函数指针p仍然指向的是根节点导致插入覆盖的错误
//LR参数0表示插入到左子树,1表示插入到右子树,e为新结点的元素值
Status InsertChild(BiTree* T, BiTree** p,int LR,Element e) {
	if (T) {
		BiTree* NewTree = (BiTree*)malloc(sizeof(BiTree));
		if (!NewTree)return False;
		NewTree->infos = e;
		//必须设置为NULL后续数结点个数需要用NULL值判断是否是叶子/空结点
		NewTree->lchild = NULL;
		NewTree->rchild = NULL;
		if (LR == 0) {
			//**p表示找到指针p所指向的结点位置
			(**p).lchild = NewTree;	
		}
		else if (LR == 1) {
			//**p表示找到指针p所指向的结点位置
			(**p).rchild = NewTree;
		}
		//*表示找到传入的指针p,并更新指针p的值
		*p = NewTree;
	}
	return OK;
}
//访问当前结点元素
void visit(Element e) {
	printf("%d->", e);
}
//递归法计算叶子结点个数,先序思想
int LeftNodeNum(BiTree* T) {
	if (!T)return False;
	if (T->lchild == NULL && T->rchild == NULL)return 1;
	return LeftNodeNum(T->lchild)+ LeftNodeNum(T->rchild);
}
//递归法计算总结点数,包括根结点,先序思想
int TreeNodeNum(BiTree* T) {
	if (!T)return False;
	return 1 + TreeNodeNum(T->lchild) + TreeNodeNum(T->rchild);
}
//递归法计算数的深度,建议纸上画一个3-4层的二叉树理解,从叶子结点的空指针开始数
int TreeDepth(BiTree* T) {
	if (!T)return False;
	int left = TreeDepth(T->lchild);
	int right = TreeDepth(T->rchild);
	return left > right ? left + 1 : right + 1;
}
//递归法先序遍历
Status PreOrderTraverse(BiTree* T) {
	if (T) {
		visit(T->infos);
		PreOrderTraverse(T->lchild);
		PreOrderTraverse(T->rchild);
	}
	return OK;
}
//递归法中序遍历
Status InOrderTraverse(BiTree* T) {
	if (T) {
		InOrderTraverse(T->lchild);
		visit(T->infos);
		InOrderTraverse(T->rchild);
	}
	return OK;
}
//递归法后续遍历
Status PostOrderTraverse(BiTree* T) {
	if (T) {
		PostOrderTraverse(T->lchild);
		PostOrderTraverse(T->rchild);
		visit(T->infos);
	}
	return OK;
}
int main() {
	BiTree bitree;
	InitBiTree(bitree);
	//p指针用于后面指向二叉树添加新结点的位置
	BiTree* p = &bitree;
	InsertChild(&bitree,&p,0,5);
	InsertChild(&bitree,&p,1,6);
	InsertChild(&bitree,&p,0,7);
	InsertChild(&bitree,&p,1,10);
	//手动在最后一层添加两个结点,用于验证LeftNodeNum计算叶子结点函数是否正确,InsertChild函数暂时只能一层插入一个结点
	p->lchild= (BiTree*)malloc(sizeof(BiTree));
	p->lchild->infos = 17;
	p->lchild->lchild = NULL;
	p->lchild->rchild = NULL;
	p->rchild = (BiTree*)malloc(sizeof(BiTree));
	p->rchild->infos = 3;
	p->rchild->lchild = NULL;
	p->rchild->rchild = NULL;
	printf("先序遍历\n");
	PreOrderTraverse(&bitree);
	printf("end\n");
	printf("中序遍历\n");
	InOrderTraverse(&bitree);
	printf("end\n");
	printf("后序遍历\n");
	PostOrderTraverse(&bitree);
	printf("end\n");
	printf("总结点数:%d\n", TreeNodeNum(&bitree));
	printf("树的深度:%d\n", TreeDepth(&bitree));
	printf("叶子结点的个数:%d\n", LeftNodeNum(&bitree));
	return 0;
}

运行结果

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值