数据结构(二叉树的相关操作)

树的概念:树是一种非线性的数据结构,它是由n(n>=0)个结点组成一个具有层次关系的集合
在这里插入图片描述

二叉树的概念:一棵二叉树是结点的一个有限集合,该集合有可能为空,也可能是由一个根节点加上左子树和右子树,子树也可以为空,也可以是二叉树
二叉树的特点

  1. 二叉树不存在度大于2的结点。
  2. 二叉树的子树有左右之分,其子树的次序不能颠倒。
    在这里插入图片描述
    下面我们主要使用c语言去实现二叉树的相关操作
    在实现之前,我们需要知道,因为二叉树会由根节点和左右子树构成,所以我们在定义结点的时候,需要去将将指针域分为左右指针与指向左右孩子(也可以定义三个指针域,分别指向左右孩子和父节点,这里我们不谈)。具体如下:
    一、结构的定义以及初始化
//二叉树结构定义
typedef char BinTreeData;
typedef struct BinTreeNode{
	BinTreeData Data;                //数据域
	struct BinTreeNode *LChild;      
	struct BinTreeNode *RChild;      //指针域
}BinTreeNode,*BinTree;
//初始化
void BinTreeInit(BinTree *p){
	*p = NULL;        //空二叉树
}

二、二叉树的建立
这里我们需要知道建立二叉树可以通过各种遍历方式进行建立,但是唯有前序遍历的方式,是我们非常熟悉的,所以通过前序建立,使得我们更容易自己建立二叉树。

//前序建立二叉树,传入一棵树进行建立
void CreateBinTree_1(BinTree *bt){
	assert(bt!=NULL);
	BinTreedata x;
	scanf("%c",&x);
	if (x == '#'){
		*bt = NULL;
	}
	else{
		*bt = (BinTreeNode*)malloc(sizeof(BinTreeNode));
		assert(*bt != NULL);
		(*bt)->val = x;
		CreateBinTree_1(&(*bt)->left);
		CreateBinTree_1(&(*bt)->right);
	}
}
//前序建立二叉树,建立之后返回一棵树
BinTree CreateBinTree_2(){
	BinTreedata x;
	scanf("%c",&x);
	if (x == '#'){
		return NULL;
	}
	else{
		BinTreeNode* p = (BinTreeNode*)malloc(sizeof(BinTreeNode));
		p->val = x;
		p->left = CreateBinTree_2();
		p->right = CreateBinTree_2();
		return p;
	}
}
//字符串建立二叉树
BinTree CreateBinTree_3(const BinTreedata*s,int *n){
	if (s[*n] == '\0' || s[*n] == '#'){
		return NULL;
	}
	else{
		BinTreeNode *p = (BinTreeNode*)malloc(sizeof(BinTreeNode));
		p->val = s[*n];
		(*n)++;
		p->left = CreateBinTree_3(s, n);
		(*n)++;
		p->right = CreateBinTree_3(s, n);
		return p;
	}
}
//通过前序序列和中序序列建立二叉树
BinTree CreateBinTree_4(const BinTreedata *vlr, const BinTreedata *lvr,int n){
	if (n == 0){
		return NULL;
	}
	int k = 0;
	while (vlr[0] != lvr[k]){
		k++;
	}
	BinTreeNode *p = (BinTreeNode*)malloc(sizeof(BinTreeNode));
	p->val = vlr[0];
	p->left = CreateBinTree_4(vlr + 1, lvr, k);
	p->right = CreateBinTree_4(vlr + k + 1, lvr + k + 1, n - k - 1);
	return p;
}

当然在建立二叉树时,还可以通过中序和后序建立二叉树,这个读者可以根据前序和中序的方法自行建立。
三、二叉树的遍历

//前序遍历
void Preorder(BinTree bt){
	if (bt != NULL){
		printf("%c ", bt->val);
		Preorder(bt->left);
		Preorder(bt->right);
	}
}
//中序遍历
void Middleorder(BinTree bt){
	if (bt != NULL){
		Preorder(bt->left);
		printf("%c ", bt->val);
		Preorder(bt->right);
	}
}
//后序遍历
void Postorder(BinTree bt){
	if (bt != NULL){
		Preorder(bt->left);
		Preorder(bt->right);
		printf("%c ", bt->val);
	}
}
//层次遍历,传入二叉树结点个数(利用数组保存每一层的结点)
void Level(BinTree bt,int n){
	if (n == 0){
		return;
	}
	int i = 0;
	int k = 0;
	//BinTreeNode *q = bt;
	BinTreeNode **p = (BinTreeNode**)malloc(sizeof(BinTreeNode)*n);
	p[i] = bt;
	i++;
	while (n > i){
		printf("%c ", p[k]->val);
		if (p[k]->left != NULL){
			p[i] = p[k]->left;
			i++;
		}
		if (p[k]->right != NULL){
			p[i] = p[k]->right;
			i++;
		}
		k++;
	}
	while (k < n){
		printf("%c ", p[k]->val);
		k++;
	}
}

这里我们的前、中、后序遍历都用了递归的方式,读者也可以通过非递归的方式,利用栈实现这些遍历。
四、结点的个数(所有结点以及叶子结点)

//所有结点个数
int CountNode(BinTree bt){
	if (bt == NULL){
		return 0;
	}
	else{
		return CountNode(bt->left) + CountNode(bt->right) + 1;
	}
}
//叶子结点个数
int LeafNode(BinTree bt){
	if (bt == NULL){
		return 0;
	}
	if (bt->left == NULL&&bt->right == NULL){
		return 1;
	}
	return LeafNode(bt->left) + LeafNode(bt->right);
}

五、二叉树的高度

//高度
int Height(BinTree bt){
	if (bt == NULL){
		return 0;
	}
	else{
		int left = Height(bt->left);
		int right = Height(bt->right);
		return left > right ? left + 1 : right + 1;
	}
}

六、查找

//某个结点的左孩子
BinTreeNode* Left(BinTreeNode* p){
	assert(p != NULL);
	return p->left;
}
//某个结点的右孩子
BinTreeNode* Right(BinTreeNode* p){
	assert(p != NULL);
	return p->right;
}
//某个结点的父节点
BinTreeNode* Parent(BinTree bt, BinTreeNode* p){
	if (bt == NULL || p == NULL || p == bt){
		return NULL;
	}
	if (bt->left == p || bt->right == p){
		return bt;
	}
	BinTreeNode* q = Parent(bt->left, p);
	if (q == NULL){
		q = Parent(bt->right, p);
	}
	return q;
}

关于二叉树的简单操作,今天就谈到这里!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值