了解二叉树的一系列,创建遍历,删除等

什么是二叉树: 在计算机科学中,二叉树是每个结点最多有两个子树的树结构。通常子树被称作“左子树”(left subtree)和“右子树”(right subtree)。
如图所示
在这里插入图片描述
关于树的术语

树的结点(node):包含一个数据元素及若干指向子树的分支;

孩子结点(child node):结点的子树的根称为该结点的孩子;

双亲结点:B 结点是A 结点的孩子,则A结点是B 结点的双亲;

兄弟结点:同一双亲的孩子结点;堂兄结点:同一层上结点;

祖先结点: 从根到该结点的所经分支上的所有结点

子孙结点:以某结点为根的子树中任一结点都称为该结点的子孙

结点层:根结点的层定义为1;根的孩子为第二层结点,依此类推;

树的深度:树中最大的结点层

结点的度:结点子树的个数

树的度:树中最大的结点度。

叶子结点:也叫终端结点,是度为 0 的结点;

分枝结点:度不为0的结点;

有序树:子树有序的树,比如家族树;

无序树:不考虑子树的顺序;

给定一个二叉树,找出其最大深度。二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
在这里插入图片描述
每个节点的深度与它左右子树的深度有关,且等于其左右子树最大深度值加上 1。即:
maxDepth(root) = max(maxDepth(root.left),maxDepth(root.right)) + 1
以 [3,9,20,null,null,15,7] 为例:
在这里插入图片描述
由此我们可以得到根节点的最大深度为
maxDepth(root-3)
=max(maxDepth(sub-4),maxDepth(sub-20))+1
=max(1,max(maxDepth(sub-15),maxDepth(sub-7))+1)+1
=max(1,max(1,1)+1)+1
=max(1,2)+1
=3
因此求最大深度就可以用递归来实现,不断遍历该树的左右子树最后判断谁最大
在递归中,如果层级过深,我们很可能保存过多的临时变量,导致栈溢出。这也是为什么我们一般不在后台代码中使用递归的原因
事实上,函数调用的参数是通过栈空间来传递的,在调用过程中会占用线程的栈资源。而递归调用,只有走到最后的结束点后函数才能依次退出,而未到达最后的结束点之前,占用的栈空间一直没有释放,如果递归调用次数过多,就可能导致占用的栈资源超过线程的最大值,从而导致栈溢出,导致程序的异常退出。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
二叉树也有很多性质
二叉树有以下几个性质:
性质1:二叉树第i层上的结点数目最多为 2^{i-1} (i≥1)。
性质2:深度为k的二叉树至多有2^{k}-1个结点(k≥1)。
性质3:包含n个结点的二叉树的高度至少为log2 (n+1)。
性质4:在任意一棵二叉树中,若终端结点的个数为n0,度为2的结点数为n2,则n0=n2+1。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
顺序结构中找孩子容易 孩子的节点分别是2i 和 2i+1
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
二叉树中常用的三种遍历方式
第一种 前序遍历又称 先序遍历 根左右
在这里插入图片描述

void PreOrder(BTNode *b)
{  if (b!=NULL)  
   {  printf("%c ",b->data); 	//访问根结点
      PreOrder(b->lchild);
      PreOrder(b->rchild);
   }
}

第二种中序遍历 左根右
在这里插入图片描述

void InOrder(BTNode *b)
{  if (b!=NULL)  
   {  InOrder(b->lchild);
      printf("%c ",b->data); 	//访问根结点
      InOrder(b->rchild);
   }
}

第三种后序遍历 左右根
在这里插入图片描述

void PostOrder(BTNode *b) 
{  if (b!=NULL)  
   {  PostOrder(b->lchild);
      PostOrder(b->rchild);
      printf("%c ",b->data); 	//访问根结点
   }
}

在这里插入图片描述
对应的递归算法如下

int Nodes(BTNode *b)
{  
   if (b==NULL) 
      return 0;
   else
      return Nodes(b->lchild)+Nodes(b->rchild)+1
}

在这里插入图片描述

在这里插入图片描述

void DispLeaf(BTNode *b)
{  if (b!=NULL)
   {  if (b->lchild==NULL && b->rchild==NULL)
	  printf("%c ",b->data);     //访问叶子结点
      DispLeaf(b->lchild);	        //输出左子树中的叶子结点
      DispLeaf(b->rchild);	        //输出右子树中的叶子结点
   }
}

在这里插入图片描述
在这里插入图片描述

A进栈 A出栈 C进栈 B进栈 B没有右孩子,B出栈 D进栈 D出栈 G进栈 G出栈
C出栈 F进栈 E进栈 E出栈 F出栈
算法如下

void PreOrder1(BTNode *b)
{  BTNode *p;
   SqStack *st;			//定义栈指针st
   InitStack(st);			//初始化栈st
   if (b!=NULL) 
   {  Push(st,b);			//根结点进栈
      while (!StackEmpty(st))		//栈不为空时循环
      {  Pop(st,p);			//退栈结点p并访问它
	  printf("%c ",p->data);
	  if (p->rchild!=NULL)	//有右孩子时将其进栈
	     Push(st,p->rchild);
	  if (p->lchild!=NULL)	//有左孩子时将其进栈
            Push(st,p->lchild);
      }
      printf("\n");
   }
   DestroyStack(st);			//销毁栈
}


在这里插入图片描述

void InOrder1(BTNode *b)
{  BTNode *p;  SqStack *st;	//定义一个顺序栈指针st
   InitStack(st);		//初始化栈st
   p=b;
   while (!StackEmpty(st) || p!=NULL)
   {  while (p!=NULL)		//扫描结点p的所有左下结点并进栈
      {  Push(st,p);		//结点p进栈
	  p=p->lchild;		//移动到左孩子
      }
      //以下考虑栈顶结点
      if (!StackEmpty(st))	//若栈不空
      {  Pop(st,p);		//出栈结点p,访问结点p
	  printf("%c ",p->data);
	  p=p->rchild;		//转向处理其右子树
      }
   }
   printf("\n");
   DestroyStack(st);		//销毁栈
}

在这里插入图片描述

void PostOrder1(BTNode *b)	//后序非递归遍历算法
{  BTNode *p,*r;
   bool flag;
   SqStack *st;		//定义一个顺序栈指针st
   InitStack(st);		//初始化栈st
   p=b;
   do
   {  while (p!=NULL)		//扫描结点p的所有左下结点并进栈
      {  Push(st,p);		//结点p进栈
	  p=p->lchild;		//移动到左孩子
      }
      r=NULL;			//r指向刚刚访问的结点,初始时为空
      flag=true;		
while (!StackEmpty(st) && flag)
     {  GetTop(st,p);	         //取出当前的栈顶结点p
        if (p->rchild==r)      //若结点p的右孩子为空或者为刚访问结点       
        {  printf("%c ",p->data);     //访问结点p
	    Pop(st,p);
	    r=p;		 //r指向刚访问过的结点
        }
        else
        {  p=p->rchild;	//转向处理其右子树
	    flag=false;	//表示当前不是处理栈顶结点
        }
     }
   } while (!StackEmpty(st));	//栈不空循环
   printf("\n");
   DestroyStack(st);		//销毁栈
}

以上的非递归思想都是建立于各种遍历的访问方法上
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

typedef struct 
{  BTNode *data[MaxSize];	//存放队中元素
   int front,rear;		//队头和队尾指针
} SqQueue;
void LevelOrder(BTNode *b)
{  BTNode *p;
   SqQueue *qu;			//定义环形队列指针
   InitQueue(qu);			//初始化队列
   enQueue(qu,b);			//根结点指针进入队列
   while (!QueueEmpty(qu))		//队不为空循环
   {  deQueue(qu,p);			//出队结点p
      printf("%c ",p->data);		//访问结点p
      if (p->lchild!=NULL)		//有左孩子时将其进队
	  enQueue(qu,p->lchild);
      if (p->rchild!=NULL)		//有右孩子时将其进队
	  enQueue(qu,p->rchild);
    } 
}

二叉树的构造
在这里插入图片描述
先序和中序

BTNode *CreateBT2(char *post,char *in,int n)
{  BTNode *b;  char r,*p;  int k;
   if (n<=0) return NULL;
   r=*(post+n-1);			     //根结点值
   b=(BTNode *)malloc(sizeof(BTNode));    //创建二叉树结点b
   b->data=r;
   for (p=in;p<in+n;p++)		     //在in中查找根结点
      if (*p==r) break;
   k=p-in;				     //k为根结点在in中的下标 
   b->lchild=CreateBT2(post,in ,k);  
   b->rchild=CreateBT2(post+k,p+1 ,n-k-1); 
}

在这里插入图片描述
创建二叉树可以用 括号表示法创建,也可以用 前序中序 ,或者中序后续来创建二叉树

#include <iostream>
using namespace std;
typedef  struct node 
{
 char data;
 struct node *lchild;
 struct node *rchild;
}BTNODE;
void CreateBTree(BTNODE * &b,char *str)
{
	BTNODE *St[50],*p;
	int top =-1,k,j=0;
	char ch;
	b=NULL;
	ch=str[j];
	while(ch!='\0')
	{
	   switch (ch)
	   {
     	   case'(': top++;St[top]=p;k=1;break;
	       case')':top--;break;
		   case',':k=2;break;
		   default :p=(BTNODE*)malloc(sizeof(BTNODE));
			   p->data=ch;
			   p->lchild =p->rchild =NULL;
			   if(b==NULL)
				   b=p;
			   else
			   {
			      switch (k)
				  {
				  case 1:St[top]->lchild =p;break;
				  case 2:St[top]->rchild =p;break;
				  }			   
			   } 
	   }
	   j++;
	ch=str[j];
	}
}
void PreOrder(BTNODE * b)
{
  if(b!=NULL)
  {
    printf("%c->",b->data );
    PreOrder(b->lchild );
    PreOrder(b->rchild );
  }
}
void InOrder(BTNODE * b)
{
  if(b!=NULL)
  {
		InOrder(b->lchild );
	     printf("%c->",b->data );
		InOrder(b->rchild );  
  }
}
void PostOrder(BTNODE * b)
{
  if(b!=NULL)
  {
		PostOrder(b->lchild );
	   PostOrder(b->rchild );
		printf("%c->",b->data ); 
  }
}
void DispLeaf(BTNODE *b)
{
  if(b!=NULL)
  {
    if(b->lchild ==NULL&&b->rchild ==NULL)
		printf("%c->",b->data );
	DispLeaf(b->lchild );
	DispLeaf(b->rchild );
  }
}
int main()
{
	BTNODE * b;
	char str[]={'A','(','B','(','D',',','E','(','H','(','J',',','K','(','L',',','M','(',',','N',')',')',')',')',')',',','C','(','F',',','G','(',',','I',')',')',')'};
	CreateBTree(b,str);
	printf("先序遍历的结果如下");
	 PreOrder( b);
	printf("\n");
	 printf("中序遍历的结果如下");
	 InOrder( b);
	 printf("\n");
	printf("后序遍历的结果如下");
	PostOrder( b);
	printf("\n");
	printf("所有的叶子结点的结果如下");
	DispLeaf(b);
	printf("\n");
	return 0;
}

在这里插入图片描述
在这里插入图片描述
二叉树的销毁
在这里插入图片描述
查找二叉树中的某个节点
在这里插入图片描述
输出二叉树,也可以用 前序中序后续来输出
在这里插入图片描述
最后关于二叉树的实际应用 ,参考这篇文章,这篇文章说的很详细,例如二叉排序树,平衡二叉树,二叉搜索树等
https://mp.weixin.qq.com/s?__biz=Mzg2NzA4MTkxNQ==&mid=2247487396&idx=2&sn=f4da5c1b78713d24abe715466cb153d3&chksm=ce404470f937cd6674273c20755bf760294ad6cdabbc0b358a8c12297db9063c43a7f383ddac&mpshare=1&scene=23&srcid=0517fE7g8NAdS1e0QcjMggx4&sharer_sharetime=1589710839347&sharer_shareid=ac11f0b33b3f01f55650b6c5eeb96ac0#rd

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凌晨里的无聊人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值