数据结构 深入理解二叉树的实现

数据结构就是定义出某种结构:像数组结构、链表结构、树形结构等,实现数据结构就是我们主动去管理增删查改的实现函数

理解树的概念

树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,它是根朝上,而叶朝下的

树的相关特征

节点的度:一个节点含有的子树的个数称为该节点的度,如上图:A的为6

叶节点或终端节点:度为0的节点称为叶节点,如上图:B、C、H、I...

非终端节点或分支节点:度不为0的节点,如上图:D、E、F、G...

双亲节点或父节点:节点含有子节点,节点就称为其子节点的父节点, 上图:A是B的父节点

孩子节点或子节点:含有的子树的根节点称为该节点的子节点,上图:B是A的孩子节点

兄弟节点:具有相同父节点的节点互称为兄弟节点,如上图:B、C是兄弟节点

树的度:一棵树中,最大的节点的度称为树的度;如上图:树的度为6

节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推;

树的高度或深度:树中节点的最大层次;如上图:树的高度为4

堂兄弟节点:双亲在同一层的节点互为堂兄弟;如上图:H、I互为兄弟节点

节点的祖先:从根到该节点所经分支上的所有节点;如上图:A是所有节点的祖先

子孙:以某节点为根的子树中任一节点都称为该节点的子孙,图中:所有节点都是A的子孙

森林:由m(m>0)棵互不相交的树的集合称为森林;

二叉树的表示方法

二叉树非空的话是由根节点,根节点的左子树、根节点的右子树组成的

typedef int BTDateType;
typedef struct BinaryTreeNode
{
  struct BinaryTreeNode* left;//左子树
  struct BinaryTreeNode* right;//右子树
  BTDateType data;//节点域
}BTNode;

二叉树的遍历方法

  用代码实现二叉树的基本操作前,我们先按照上图先申请6个节点创建一棵二叉树

//定义函数
typedef int BTDateType;
typedef struct BinaryTreeNode
{
   struct BinaryTreeNode* left;//定义左子树节点
   struct BinaryTreeNode* right;//定义右子树节点
   BTDateType data;

}BTNode;

//申请节点函数
BTNode* BuyBTNode(BTDateType x)//按照上图申请6节点
{
   BTNode* node = (BTNode*)malloc(sizeof(BTNode));
   if (node == NULL)
   {
	printf("malloc fail\n");
	exit(-1);
   }
   node->data = x;
   node->left = node->right = NULL;
   return node;//...
}
//树的创建
BTNode* CreatBinaryTree()//先自己创建树
{
	BTNode* node1 = BuyBTNode(1);
	BTNode* node2 = BuyBTNode(2);
	BTNode* node3 = BuyBTNode(3);
	BTNode* node4 = BuyBTNode(4);
	BTNode* node5 = BuyBTNode(5);
	BTNode* node6 = BuyBTNode(6);

	node1->left = node2;//这里按照上图指向指定数据
	node1->right = node4;
	node2->left = node3;
	node4->left = node5;
	node4->right = node6;

	return node1;//根是node1
}

二叉树的前序遍历

//前序遍历(先根遍历) 根 左子树 右子树
void PreOrder(BTNode* root)
{
  if (root == NULL)
  {
	printf("NULL ");//
	return;
  }
  //根不为空的话
  printf("%d ", root->data);//打印根数据
  PreOrder(root->left);//走左子树
  PreOrder(root->right);//再走右子树
}

二叉树的中序遍历

//中序遍历(中根遍历) 左子树 根 右子树
void InOrder(BTNode* root)
{
  if (root == NULL)
  {
	printf("NULL ");//
	return;
  }
  //根不为空的话
  InOrder(root->left);//走左子树
  printf("%d ", root->data);//打印根数据
  InOrder(root->right);//再走右子树
}

二叉树的后序遍历

//后序遍历(后根遍历) 左子树 右子树 根
void PostOrder(BTNode* root)
{
  if (root == NULL)
  {
	printf("NULL ");//
	return;
  }
  //根不为空的话
  PostOrder(root->left);//走左子树
  PostOrder(root->right);//再走右子树
  printf("%d ", root->data);//打印根数据
}

二叉树的节点个数

//打印节点个数 有多少个值
//思想方法 子问题 分治思想
int BTreeSize(BTNode* root)
{
//不是空 左节点+右节点+1
return root == NULL ? 0 : 
	BTreeSize(root->left)
	+ BTreeSize(root->right)+1;
}

二叉树求叶子节点个数

//求叶子节点个数
int BTreeLeafSize(BTNode* root)
{
if (root == NULL)
	return 0;

if (root->left == NULL && root->right == NULL)
	return 1;

return  BTreeLeafSize(root->left) 
	+ BTreeLeafSize(root->right);
}

二叉树第k层节点个数

//求第k层的节点个数 k=1
int BTtreekLeveSize(BTNode* root, int k)
{
assert(k >= 1);
//空树 是0
if (root == NULL)
	return 0;

//非空且k==1 返回1
if (k == 1)
	return 1;
//非空且k>1 转换求左子树k-1层+右子树k-1层节点个数
return  BTtreekLeveSize(root->left, k - 1)
	+ BTtreekLeveSize(root->right, k - 1);

}

二叉树查找值为x的节点

//查找值是x的节点 返回节点指针(地址)同时可修改
BTNode* BTreeFind(BTNode* root, BTDateType x)
{
  //..不一定一开始是空
  if (root == NULL)
	return NULL;
	
  //先从根找 
  if (root->data == x)
	return root;
	
  // 递归左数找
  BTNode* ret1 = BTreeFind(root->left, x);
  if (ret1)
  {
	return ret1;
  }
  // 左数没有 递归右数找
  BTNode* ret2 = BTreeFind(root->right, x);
  if (ret2)
  {
	return ret2;
  }
  //都没有返回空
  return NULL;
}

编程实现二叉树的深度

//求二叉树深度
int BTreeDepth(BTNode* root)
{
//左子树高度和右子树高度,大的加1
if (root == NULL)
	return 0;

//递归分别求左右深度
int leftDepth = BTreeDepth(root->left);
int rightDepth = BTreeDepth(root->right);

// 返回高度大的+1
return leftDepth > rightDepth ? leftDepth + 1 : rightDepth + 1;
}

编程实现二叉树的销毁

//销毁 后序遍历 置空二级
void BTreeDestroy(BTNode* root)
{
  if (root == NULL)
  {
   return;
  }

  // 先删左数 再删右数 最后删根
  BTreeDestroy(root->left);
  BTreeDestroy(root->right);

  free(root);
  root = NULL;
}

上面的方法测试案例

int main()
{
  BTNode* tree = CreatBinaryTree();
  //遍历
  PreOrder(tree);//前序 
  printf("\n");//1 2 3 NULL NULL NULL 4 5 NULL NULL 6 NULL NULL
  InOrder(tree);//中序
  printf("\n");//NULL 3 NULL 2 NULL 1 NULL 5 NULL 4 NULL 6 NULL
  PostOrder(tree);//后序
  printf("\n");//NULL NULL 3 NULL 2 NULL NULL 5 NULL NULL 6 4 1

  printf("size:%d\n", BTreeSize(tree));//6
  printf("leafsize:%d\n", BTreeLeafSize(tree));//3
  printf("kleafsize:%d\n", BTtreekLeveSize(tree,3));//
  printf("Depth:%d\n", BTreeDepth(tree));//3

  //查找6个节点 返回地址
  //程序对不对 要靠测试来检验的
  for (int i = 1; i < 7; i++)
  {
	printf("Find:%d,%p\n", i,BTreeFind(tree, i));
  }
  BTreeDestroy(tree);//销毁
  tree = NULL;
  return 0;
}

在Java和C++的学习当中,前期学习数据结构当中的顺序表、链表、二叉树等便于我们后面更好的学习容器,后面会继续分享搜索二叉树和算法的实现

希望这篇文章大家有所收获,我们下篇见

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值