二叉树(二叉树的建立,插入,删除,遍历)

二叉树是一种每个节点最多有两个子节点的树结构,分为左子树和右子树。它具有有序性,分为完全二叉树、满二叉树等类型。二叉树有五个性质,包括层节点数量、完全二叉树深度等。二叉树的遍历有前序、中序和后序三种方式。插入和删除节点需保持二叉查找树特性,删除操作要考虑节点是否有子树及其数量。
摘要由CSDN通过智能技术生成

二叉树

二叉树的逻辑结构

二叉树的定义

二叉树是n(n ≥ \ge 0)个结点的有限集合,该集合或者为空集(称为空二叉树),或者由一个根结点和两棵互不相交的、分别称为根结点的左子树和右子树的二叉树组成。

二叉树特点

1.每个结点最多有两颗子树。

2.二叉树是有序的,其次序不能任意颠倒。

注意:二叉树和树是两种树结构。

 

分类

了解好:斜树,满二叉树,完全二叉树

 

二叉树的基本性质

性质1:二叉树的第i层上最多有 2 i − 1 2^{i-1} 2i1个结点(i ≥ \ge 1)

性质2:一棵深度为k的二叉树中,最多有 2 k − 1 2^{k-1} 2k1个结点,最少有k个结点。

性质3:在一棵二叉树中,如果叶子结点数为 n 0 n_0 n0,度为2的结点数为 n 2 n_2 n2,则有: n 0 = n 2 + 1 n_0=n_2+1 n0=n2+1

性质4:具有n个结点的完全二叉树的深度为 ⌊ log ⁡ 2 n ⌋ + 1 \left\lfloor\log _{2} n\right\rfloor+1 log2n+1

性质5:对一棵具有n个结点的完全二叉树中从1开始按层序编号,则对于任意的序号为i( 1 ≤ i ≤ n 1\le i \le n 1in)的结点(简称为结点i),有:
(1)如果i>1,则结点的双亲结点的序号为i/2;如果i=1,则结点是根结点,无双亲结点。

(2)如果 2 i ≤ n 2i \le n 2in,则结点i的左孩子的序号为2i;如果2i>n,则结点i无左孩子。

(3)如果 2 i + 1 ≤ n 2i+1\le n 2i+1n,则结点i的右孩子的序号为2i+1;如果 2 i + 1 > n 2i+1>n 2i+1>n,则结点无右孩子。

 

顺序存储结构

二叉树的顺序存储结构就是用一维数组存储二叉树中的结点,并且结点的存储位置(下标)应能体现结点之间的逻辑关系-父子关系。

完全二叉树的顺序储存

R6CWa.png R6IjK.png

二叉树编号

按照完全二叉树编号

R6XhB.png

可以编号为:

R66Ig.png

没有编号的位置直接存储为空。

二叉链表

R6wyS.png
data数据域,存放该结点的数据信息
Ichild左指针域,存放指针指向左孩子的指针
rchild右指针域,存放指针指向右孩子的指针
class tree
{
    public:
    int data;
    class tree* Ichild;
    class tree* rchild;
}
typedef class tree node;
typedef node *btree;

 

二叉树的遍历

二叉树的组成:根结点D,左子树L,右子树R。

如果限定先左后右,则二叉树遍历方式有三种:

前序(Preorder):DLR

中序(Inorder):LDR

后序(Postorder):LRD

如下图所视

R8MsN.png

中序遍历

1.遍历左子树
2.遍历(或访问)树根
3.遍历右子树

中序遍历为:FDHGIBEAC

void Inorder(btree ptr)
{
if (ptr != NULL)
	{
	Inorder(ptr->left);   //遍历左子树
	cout<<ptr ->data;     //遍历并打印树根
	Inorder(ptr->right);   //遍历右子树
	}
}

 

后序遍历

1.遍历左子树
2.遍历右子树
3.遍历树根

中序遍历为:FHIGDEBCA

void Postorder (btree ptr)
{
if (ptr != NULL)
{
	Postorder(ptr->left);     //遍历左子树
	Postorder(ptr->right);    //遍历右子树
	cout<<ptr->data;          //遍历并打印树根
}

 

前序遍历

1.遍历树根
2.遍历左子树
3.遍历右子树

中序遍历为:ABDFGHIEC

void Preorder(btree ptr)
{
if (ptr != NULL)
	{
    cout<<ptr ->data;     //遍历并打印树根
	Inorder(ptr->left);   //遍历左子树
	Inorder(ptr->right);   //遍历右子树
	}
}

 

二叉树节点的插入和删除

在二叉树建立的过程中,是根据左子树<树根<右子树的原则建立的。

查找

只需从树根出发比较键值,如果比树根大就往右,否则往左而下,直到相等就找到了要查找的值,如果比到NULL,无法再前进就代表查找不到此值。

btree search (btree ptr,int val)  //查找二叉树某键值得函数
{
	while(1)
	{
		if(ptr==NULL)     //没找到就返回NULL
			return NULL;
		if(ptr->data==val)   //节点值等于查找值
			return ptr;
		else if(ptr->data>val)  //节点值大于查找值
			ptr=ptr->left;
		else                  //小于查找值
			ptr=ptr->right;    
	}
}
插入操作

插入节点的情况和查找相似,关键是插入后仍要保持二叉查找树的特性(左子树<树根<右子树)。如果插入的节点在二叉树中没有找到,就是出现查找失败的情况,就相当于找到了要插入的位置。我们可以修改,只要多加一条if判断语句,当查找到键值时输出“二叉树中有此节点了!”,如果找不到,再将此节点加到此二叉树中。算法如下所示。

	btree ptr=NULL;
if((search(ptr,data))!=NULL)     //查找二叉树
    cout<<"二叉树中有此节点了-"<<data<<endl;
else
	{
    	ptr=creat_tree(ptr,data);//将此键值加入到此二叉树中
    	inorder(ptr);
	}

btree creat_tree(btree root,int val)
{  
	btree newnode,current,backup;
	newnode=(btree)malloc(sizeof(node));//创建一个新结点
	newnode->data=val;
	newnode->left=NULL;
	newnode->right=NULL;
	if(root==NULL)    //如果树根为空
	{  
		root=newnode;
		return root;
	}
	else     //树不为空
	{  
		for(current=root;current!=NULL;)   //把树赋给root
		{  
			backup=current;    //current赋给backup
			if(current->data > val)    //val小于此结点的data
				current=current->left; //current被赋为右树的节点
			else
				current=current->right;//current被赋为左树的节点
		}
		if(backup->data >val) //节点数据域大于val值说明新结点是它的左孩子
			backup->left=newnode;
		else
			backup->right=newnode;
	}
	return root;
}

}
void inorder(btree ptr)			//中序遍历子程序
{  
  if(ptr!=NULL)
     {  
      inorder(ptr->left);
      cout<<"["<<ptr->data<<"]";
      inorder(ptr->right);
      }
}

 

二叉树的删除

1.删除的结点为树叶:只要将其相连的父节点指向NULL即可。

2.删除的节点只有一颗子树,如下图,要删除节点1,就要将其右指针放到其父节点的左指针

3.删除的节有两颗子树,如下图,要删除节点4,方式有两种

​ 3.1 找出中序立即先行者(inorder immediate predecessor)

即是将欲删除节点的左子树中最大者向上提,在此即为图中的节点2,简单来说,就是在该节点的左子树,往右寻找,直到右指针为NULL,这个节点就是中序立即先行者。

​ 3.2 找出中序立即后继者(inorder immediate successor)

即是将欲删除节点的右子树中最小者向上提,在此即为图中的节点5,简单来说,就是在该节点的右子树,往左寻找,直到左指针为NULL,这个节点就是中序立即后继者。

R8aaC.png

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
二叉树 遍历 插入 二叉树的三种遍历,先,中,后遍历 二叉树遍历分为以下三种: 先序遍历遍历顺序规则为【根左右】 中序遍历遍历顺序规则为【左根右】 后序遍历遍历顺序规则为【左右根】 什么是【根左右】?就是先遍历根,再遍历左孩子,最后遍历右孩子; 举个例子,看下图(图从网上找的): 先序遍历:ABCDEFGHK 中序遍历:BDCAEHGKF 后序遍历:DCBHKGFEA 以中序遍历为例: 中序遍历的规则是【左根右】,我们从root节点A看起; 此时 是根节点,遍历A的左子树; A的左子树存在,找到B,此时B看做根节点,遍历B的左子树; B的左子树不存在,返回B,根据【左根右】的遍历规则,记录B,遍历B的右子树; B的右子树存在,找到C,此时C看做根节点,遍历C的左子树; C的左子树存在,找到D,由于D是叶子节点,无左子树,记录D,无右子树,返回C,根据【左根右】的遍历规则,记录C,遍历C的右子树; C的右子树不存在,返回B,B的右子树遍历完,返回A; 至此,A的左子树遍历完毕,根据【左根右】的遍历规则,记录A,遍历A的右子树; A的右子树存在,找到E,此时E看做根节点,遍历E的左子树; E的左子树不存在,返回E,根据【左根右】的遍历规则,记录E,遍历E的右子树; E的右子树存在,找到F,此时F看做根节点,遍历F的左子树; F的左子树存在,找到G,此时G看做根节点,遍历G的左子树; G的左子树存在,找到H,由于H是叶子节点,无左子树,记录H,无右子树,返回G,根据【左根右】的遍历规则,记录G,遍历G的右子树; G的右子树存在,找到K,由于K是叶子节点,无左子树,记录K,无右子树,返回G,根据【左根右】的遍历规则,记录F,遍历F的右子树; F的右子树不存在,返回F,E的右子树遍历完毕,返回A; 至此,A的右子树也遍历完毕; 最终我们得到上图的中序遍历为BDCAEHGKF,无非是按照遍历规则来的; 根据“中序遍历”的分析,相信先序遍历和后序遍历也可以轻松写出~
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

y江江江江

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

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

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

打赏作者

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

抵扣说明:

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

余额充值