36 C语言二叉树插入、删除、查找、遍历详解

36.1 前言

数据结构对于一个嵌软工程师来说,用到的最多的有数组、链表(单向、双向、循环链表等),对于其他的数据结构除非在开发存储模块,否则很难会用到其它的数据结构。但为了防范于未然,将来可能需要用到,因此我特地花了一些时间想要把那些软件工程师天天挂嘴边的二叉树啥的学习了一遍,并手写代码。写此篇博客,一是为了总结学习二叉树中获得的零散知识;二是希望把自己学习过程及理解分享,便于大家参考更快的学习二叉树这个东西!

36.2 概念

36.2.1 四种数据结构

在入手学习二叉树前,我一个舍友(已入坑机器学习)在学习数据结构的时候经常讲什么树啊、图啊、线性表啊,一大堆东西,对于没接触的我听了又听,还是不太懂;对于这些数据结构,新手入门时又一定难度,需要反复思考学习才能很好掌握,甚至使用。而现在的我可能是为了一口气(就想试试水到底是不是像别人说的那样难),前端时间终于抽出空想砍掉那复杂多变的二叉树(越学习,发现树这东西内容真多啊)。

数据结构分类为物理结构和逻辑结构,逻辑结构分为线性结构、几何结构、树形结构和图形结构四大结构。

常四种基本的数据结构:

(1)集合结构:结构中的元素关系为“属于同一个集合”。

集合这种数据结构应用还是挺广泛的吧,用于分类、区别,如现在热门的机器学习中,学习数据的不同类别,模型训练出来后,对输入的进行分类划分到一个集合里面等等。

2)线性结构:数据元素之间存在一对一的关系。

线性表属于数据结构中的逻辑结构中的线性结构,常用的线性结构有:线性表、栈、队列、数组等,

线性表特点:(1)一个有限序列;(2)第一个元素只有后继,最后一个元素只有前继;(3)只能依次访问(?);

(3)树型结构:元素之间存在一对多的关系。

树这种数据结构属于数据结构中的逻辑结构,即元素与元素之间的逻辑是怎样的。对于书这种数据结构,我现在知道的就是在数据存储方面(数据查找)有很大的实用吧。因此,此篇我们学习的二叉树的实际用处可能是在未来编写组织数据存储的时候会用到,其它一般开发情况下用线性表就可满足了吧。

(4)图形结构:数据元素之间存在多对多的关系,也称为网状结构,其每个结点的前驱结点数和后续结点数可以任意多个,元素关系也是任意的,主要研究形状和图形数据元素之间的关系,它主要谈论几何形体在计算机内部的表示以及期间进行运算的基本方法。(对此我就了解这么多,感觉图是挺诡异和难啊)。

36.2.2 树

前面说了那么多废话,现在开始继续废话介绍一下树及二叉树的基本知识。

(1)树:树其实就是不包含回路的连通无向图

特点:1、树中任意两节点,有且仅有一个唯一的一条路径联通;2、一棵树有n个节点,那么他必有n-1条边;3、在一棵树中加一条边将会构成一个回路;

(2)二叉树:树的一种特殊化,其每个节点最多有两个后继;

(3)完全二叉树:在一棵二叉树中,除最后一层外,若其余层都是满的,并且最后一层或者是满的,或者是在右边缺少连续若干节点,则此二叉树为完全二叉树(Complete Binary Tree);

(4)满二叉树:树中每个节点都有两个后继,所有叶节点深度相同;

特点:1、深度为h的二叉树,其有2^h -1个节点。

(5)二叉排序树(BST/搜索树):排序树中节点满足:左孩子小于根节点,右孩子大于根节点;

(6)平衡二叉树(AVL):它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且所有节点左右两个子树都是一棵平衡二叉树;

注(重要):平衡二叉树是对二叉排序树的改进,我们知道排序二叉树的生成,跟插入值和插入顺序有很紧密的关系,排序二叉树生成的最坏情况那就是,该树只有一个分支(即变成一条单链表),这以致于失去了二叉树的优势,而平衡二叉树则是在排序二叉树生成过程中对树的结构进行调整,以便于生成对数据组织最优化的数结构。

上面简单介绍了一下树的几种,下面则介绍一下关于树的基本术语吧。

(1)深度:表示根节点到x节点的路径长度,故根节点深度为0;

(2)高度:高度是从下往上数的,往上路径数即为高度数,叶子节点高度为0;

(3)度:节点的子树个数,即为节点的度;

(4)森林:n颗互不相交的树构成的集合就是森林;

(5)兄弟节点:就是有共同父节点的节点是兄弟节点;

(6)层次:根节点在第一层,其它每向下一个孩子层次+1;

36.2.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;

性质5:如果二叉排序树是平衡的查找效率为O(log2 n),反之O(n),故查找性能在O(log2 n)-O(n);

性质6:完全二叉树总节点nn为偶数时,叶子节点数为:(n)/2n奇数时,叶子节点(n+1)/2;

性质7:完全二叉树总节点n,树的父节点为(n)/2;

性质8:完全二叉树总节点nn为偶数时,节点为2的父节点数为(n)/2n为奇数时,(n)/2 -1;

性质9:完全二叉树总节点n,该完全二叉树深度为log2 (n+1)(向上取整);

 

36.3 二叉排序树插入、遍历、查找、删除

在进行二叉树的插入、删除等讲解之前,我们先说一下节点的定义。由二叉树认识可知,二叉树节点有一个值代表着节点的大小;每个节点各有可能存在的两个子节点(或称为后继),所以节点中就有三个元素了,但节点如果想要知道自己的父节点是谁呢,是谁把它作为子节点的呢?这时就引出了第四个元素(用以保存指向父节点的地址)。本篇是基于c语言的二叉树实现,故以c的风格将节点定义如下:

/*节点*/  
typedef struct inode{  
int nValue;  
struct inode *left;  
struct inode *right;  
struct inode *parent;  
}stTreeNode;

36.3.1 二叉树插入

二叉树的生成需要一定规则,对于普通的排序二叉树生成,其规则为:父节点大于左孩子节点,且小于右孩子节点。如下图示,2<35<44,其中数据的插入顺序为35、2、44或35、44、2;

插入代码如下:

/************************************************ 
* 插入节点 
* 定义:插入规则为:左<根<右 
************************************************/  
int tree_insertNode(stTreeNode **ppRoot,stTreeNode *pNewInode)  
{  
    stTreeNode *pinodeTmp = NULL;  
      
    if(pNewInode ==NULL){  
        printf("%s input paras error\n",__FUNCTION__);  
        return -1;  
    }  
  
    /*如果是空树*/  
    if(*ppRoot==NULL)  
    {  
        *ppRoot = pNewInode;  
        pNewInode->parent = *ppRoot;  
    }  
    else  
    {  
        /*树根开始*/  
        pinodeTmp = *ppRoot;  
          
        while (pinodeTmp !=NULL)  
        {  
            /*插入节点小于当前节点*/  
            if(pNewInode->nValue< pinodeTmp->nValue)  
            {  
                if(pinodeTmp->left == NULL) //左孩子节点为空,插入  
                {  
                    pinodeTmp->left = pNewInode;  
                    pNewInode->parent = pinodeTmp;  
                    break;  
                }  
                else  
                {  
                    pinodeTmp = pinodeTmp->left;  
                }  
            }  
            /*插入节点大于当前节点*/  
            else  
            {  
                /*左孩子节点为空,插入*/  
                if(pinodeTmp->right == NULL)  
                {  
                    pinodeTmp->right = pNewInode;  
                    pNewInode->parent = pinodeTmp;  
                    break;  
                }  
                else  
                {  
                    /*左孩子节点非空,继续向左孩子节点找*/  
                    pinodeTmp = pinodeTmp->right;  
                }  
            }  
        }  
    }  
  
    return 0;  
} 

36.3.2 二叉树查找

在二叉树查找中又分为三种:(1)二叉树节点查找;(2)查找二叉树最小节点;(3)查找二叉树最大节点。

二叉树查找原理:因为二叉排序树特性,父节点大于左孩子节点且小于右孩子节点,因此,如果要查找的值小于当前节点的值,那么则往左查找,直到左孩子为空时结束;同理,大于当前节点时,往右查找,直到右孩子为空时结束;

下面为查找节点的代码:

/************************************************
* 查找节点
* 定义:查找规则,如果比根节点小则在左字数查找
************************************************/
stTreeNode *tree_searchInode(stTreeNode *pRoot,int nValue)
{	
	if(pRoot == NULL)
		return NULL;

	if(nValue == pRoot->nValue)
		return pRoot;
	else if(nValue < pRoot->nValue)
		return tree_searchInode(pRoot->left,nValue);
	else if(nValue > pRoot->nValue)
		return tree_searchInode(pRoot->right,nValue);
	else 
		return NULL;
}

而查找树最大节点则是从根节点开始,一直往右孩子节点,直到为空结束,代码如下:

/************************************************
* 查找最大节点
* 定义:查找规则,往右
************************************************/
stTreeNode *tree_findMax(stTreeNode *pRoot)
{
	if(pRoot){
		/*往右找到最底,最底的最大*/
		for(;pRoot->right!=NULL;pRoot = pRoot->right);
		return pRoot;
	}
	return NULL;
}

而查找树最小节点则是从根节点开始,一直往左孩子节点,直到为空结束,代码如下:

/************************************************
* 查找小节点
* 定义:查找规则,往左
************************************************/
stTreeNode* tree_findMin(stTreeNode *pRoot)
{
	if(pRoot){
		/*往左找到最底,最底的最小*/
		for(;pRoot->left!=NULL;pRoot=pRoot->left);
		return pRoot;
	}
	return NULL;
}

36.3.3 二叉树遍历

对于二叉树的遍历有三种:

(1)前序遍历(中左右);

(2)中序遍历(左中右);

(3)后序遍历(左右中)。

上述三种遍历这样记比较好:就是前中后,都是相对于父节点排序来说的。比如前序遍历,父节点先,再左孩子节点,再右孩子节点。其中,中序遍历结果是从小到大,即按一定的小大顺序输出的,如下列二叉树,对于先序遍历的逻辑结构为:

以下为三种遍历方式,遍历路径图示:

先序遍历代码(递归方式):

/************************************************
* 前序遍历
* 定义:先遍历根节点,然后左,再右
************************************************/
void tree_preScanLoop(stTreeNode *pRoot)
{
	if(pRoot == NULL)
		return;
	
	printf("nValue=%d\n",pRoot->nValue);
	tree_preScanLoop(pRoot->left);
	tree_preScanLoop(pRoot->right);
	return;
}

中序遍历代码(递归方式):

/************************************************
* 中序遍历
* 定义:先遍历左节点,然后根,再右
************************************************/
void tree_midScanLoop(stTreeNode *pRoot)
{
	if(pRoot == NULL)
		return;

	tree_midScanLoop(pRoot->left);
	printf("nValue=%d\n",pRoot->nValue);
	tree_midScanLoop(pRoot->right);

	return;
}

后序遍历代码(递归方式):

/************************************************
* 后序遍历
* 定义:先遍历左节点,然后右,再根
************************************************/
void tree_PostScanLoop(stTreeNode *pRoot)
{
	if(pRoot == NULL)
		return;

	tree_PostScanLoop(pRoot->left);
	tree_PostScanLoop(pRoot->right);
	printf("nValue=%d\n",pRoot->nValue);

	return;
}

36.3.4 二叉树深度计算

对于树深度定义,就是根节点到某一叶子节点经过路径最多的数称为树的深度。那么该如何代码实现去计算呢?那就是从根节点开始,向左右两边一直往下找,每往下一步累计一次,最后判断根节点的左右子树哪个步数最大,最大的为数的深度;

树深度计算代码实现(递归方式):

/************************************************
* 获取树的深度
* 定义:深度即为数的层数
* 一棵树若只有一个节点那么其深度为0
************************************************/
int tree_getDeeps(stTreeNode *pRoot)
{
	int ndeep = 0;
	int nleftDeep = 0;
	int nrightDeep = 0;

	if(pRoot!=NULL)
	{
		nleftDeep = tree_getDeeps(pRoot->left);
		nrightDeep = tree_getDeeps(pRoot->right);
		ndeep = (nleftDeep>nrightDeep)?(nleftDeep+1):(nrightDeep+1);
	}

	return ndeep;
}

36.3.5 二叉树叶子节点计算

根据树叶子节点的定义,如果一个节点无左右孩子节点,那么这个节点称为叶子节点;因此计算方式也是从根节点开始,向左右孩子节点进行遍历,如果某个节点无左右孩子节点,那么累计1。

计算叶子节点实现代码(递归):

/************************************************
* 获取叶子节点数
* 定义:叶子无左右子节点的节点
************************************************/
int tree_getLeafCnts(stTreeNode *pRoot)
{
	static int nCounts = 0;

	if(pRoot!=NULL)
	{
		if(pRoot->left==NULL && pRoot->right == NULL)
			nCounts++;
		tree_getLeafCnts(pRoot->left);
		tree_getLeafCnts(pRoot->right);
	}

	return nCounts;
}

36.3.5 二叉树节点删除

二叉树节点删除是二叉树编程中最为操作繁杂的一环,因为作为一颗有序树,删掉一个节点之后依然是要保持有序的状态,因此删除一个节点不是简单的将节点从树中剔除,另外删除树节点有以下三种情况:

(1)删除的节点是叶子节点;

(2)删除的节点有且只有一个孩子节点;

(3)删除的节点有两个孩子节点;

       因此上述问题导致二叉树删除变得复杂了一些,下面图文并茂解说二叉排序树节点的删除。

第一删除叶子节点:

如上图示,在先序遍历下树的逻辑结构是从小到大有序排列的,如果删除上述叶子节点,直接删除,其结果不会导致从小到大顺序的改变,其依然是有序的。因此,删除叶子节点是最简单的。

第二删除含有一个孩子节点的节点:

如上图示,如果要删除10这个节点,删除之后逻辑存储顺序依然要保持有序状态,删除10节点后,必须把21移到10原本这个位置,然后把32节点左孩子置空,这样才能保持有序树仍然为有序树。那么删除10节点之后,就必须找到自己右孩子的左边的孩子中的最小节点,然后将该最小节点替换到删除节点10的位置,并将32节点左孩子置空。如果32节点没有左孩子,那么直接删除10节点,并将2节点挂到8节点的右孩子节点即可。

第三删除含有两个子孩子的节点:

如上图示,如果要删除6节点,那么就需要找出自己右孩子节点8的左孩子节点7,并将7节点放置6节点位置,并将8节点的左孩子置空;如果删除8节点,同样需要查看自己右节点10是否有左孩子节点,如果有则将最左的左孩子节点替换8节点;

二叉树节点删除代码实现:

/************************************************
* 删除节点
************************************************/
void tree_deleteInode(stTreeNode *pRoot,int nDeleteValue)
{	
	stTreeNode *pRetNode = NULL;
	stTreeNode *pNode = pRoot;
	stTreeNode *parent = pRoot;
	int child = 0;  //0表示左子树,1表示右子树;

	if(pNode == NULL)
		return;

	while(pNode)
	{
		if(pNode->nValue == nDeleteValue)
		{
			if(pNode->left == NULL && pNode->right == NULL)/*删除叶子节点*/
			{
				if(pNode == pRoot)
				{
					tree_destoryInode(pNode);
				}
				else if(parent->left == pNode)
				{
					parent->left = NULL;
					tree_destoryInode(pNode);
				}
				else if(parent->right == pNode)
				{
					parent->left = NULL;
					tree_destoryInode(pNode);
				}
				pNode = NULL;
			}
			else if(pNode->left == NULL)/*左节点空,表示右节点不为空*/
			{
				if(parent->left == pNode)
				{
					parent->left = pNode->right;
					tree_destoryInode(pNode);
				}
				else if(parent->right == pNode)
				{
					parent->right = pNode->right;
					tree_destoryInode(pNode);
				}
				pNode = NULL;
			}
			else if(pNode->right == NULL)/*右节点空,表示左节点不为空*/
			{
				if(parent->left == pNode)
				{
					parent->left = pNode->left;
					tree_destoryInode(pNode);
				}
				else if(parent->right == pNode)
				{
					parent->right = pNode->left;
					tree_destoryInode(pNode);
				}
				pNode = NULL;

			}
			else  //删除有双节点的节点
			{
				/*找到最小的节点*/
				pRetNode = tree_findMin(pNode->right);
				/*替换内容*/
				pNode->nValue = pRetNode->nValue;
				if(pRetNode->right!=NULL)
					pRetNode->parent->left = pRetNode->right;
				else
					pRetNode->parent->left = NULL;
				tree_destoryInode(pRetNode);
				pRetNode = NULL;
			}
		}
		else if(nDeleteValue < pNode->nValue)/*往左*/
		{
			parent = pNode;
			pNode = pNode->left;
		}
		else if(nDeleteValue > pNode->nValue)/*往右*/
		{
			parent = pNode;
			pNode = pNode->right;
		}

	}

	return;
}

36.4 二叉树代码实现

二叉树插入、查找、遍历、删除完成代码:

#include <stdio.h>
#include <malloc.h>
#include <string.h>

/*节点*/
typedef struct inode{
	int nValue;
	struct inode *left;
	struct inode *right;
	struct inode *parent;
}stTreeNode;


/************************************************
* 前序遍历
* 定义:先遍历根节点,然后左,再右
************************************************/
void tree_preScanLoop(stTreeNode *pRoot)
{
	if(pRoot == NULL)
		return;
	
	printf("nValue=%d\n",pRoot->nValue);
	tree_preScanLoop(pRoot->left);
	tree_preScanLoop(pRoot->right);
	return;
}

/************************************************
* 中序遍历
* 定义:先遍历左节点,然后根,再右
************************************************/
void tree_midScanLoop(stTreeNode *pRoot)
{
	if(pRoot == NULL)
		return;

	tree_midScanLoop(pRoot->left);
	printf("nValue=%d\n",pRoot->nValue);
	tree_midScanLoop(pRoot->right);

	return;
}

/************************************************
* 后序遍历
* 定义:先遍历左节点,然后右,再根
************************************************/
void tree_PostScanLoop(stTreeNode *pRoot)
{
	if(pRoot == NULL)
		return;

	tree_PostScanLoop(pRoot->left);
	tree_PostScanLoop(pRoot->right);
	printf("nValue=%d\n",pRoot->nValue);

	return;
}

/************************************************
* 创建节点
* 定义:先遍历左节点,然后右,再根
************************************************/
stTreeNode *tree_CreateInode(void)
{
	stTreeNode *pinode = NULL;
	pinode = (stTreeNode*)malloc(sizeof(stTreeNode));
	if(pinode!=NULL)
	{
		memset(pinode,0,sizeof(stTreeNode));
		return pinode;
	}
	
	return NULL;
}


/************************************************
* 销毁节点
* 定义:
************************************************/
void tree_destoryInode(stTreeNode *pinode)
{
	if(pinode!=NULL)
	{
		free(pinode);
		pinode	= NULL;
	}
}


/************************************************
* 获取树的深度
* 定义:深度即为数的层数
* 一棵树若只有一个节点那么其深度为0
************************************************/
int tree_getDeeps(stTreeNode *pRoot)
{
	int ndeep = 0;
	int nleftDeep = 0;
	int nrightDeep = 0;

	if(pRoot!=NULL)
	{
		nleftDeep = tree_getDeeps(pRoot->left);
		nrightDeep = tree_getDeeps(pRoot->right);
		ndeep = (nleftDeep>nrightDeep)?(nleftDeep+1):(nrightDeep+1);
	}

	return ndeep;
}

/************************************************
* 获取叶子节点数
* 定义:叶子无左右子节点的节点
************************************************/
int tree_getLeafCnts(stTreeNode *pRoot)
{
	static int nCounts = 0;

	if(pRoot!=NULL)
	{
		if(pRoot->left==NULL && pRoot->right == NULL)
			nCounts++;
		tree_getLeafCnts(pRoot->left);
		tree_getLeafCnts(pRoot->right);
	}

	return nCounts;
}



/************************************************
* 查找节点
* 定义:查找规则,如果比根节点小则在左字数查找
************************************************/
stTreeNode *tree_searchInode(stTreeNode *pRoot,int nValue)
{	
	if(pRoot == NULL)
		return NULL;

	if(nValue == pRoot->nValue)
		return pRoot;
	else if(nValue < pRoot->nValue)
		return tree_searchInode(pRoot->left,nValue);
	else if(nValue > pRoot->nValue)
		return tree_searchInode(pRoot->right,nValue);
	else 
		return NULL;
}

/************************************************
* 查找大节点
* 定义:查找规则,如果比根节点小则在左字数查找
************************************************/
stTreeNode *tree_findMax(stTreeNode *pRoot)
{
	if(pRoot){
		/*往右找到最底,最底的最大*/
		for(;pRoot->right!=NULL;pRoot = pRoot->right);
		return pRoot;
	}
	return NULL;
}

/************************************************
* 查找小节点
* 定义:查找规则,如果比根节点小则在左字数查找
************************************************/
stTreeNode* tree_findMin(stTreeNode *pRoot)
{
	if(pRoot){
		/*往左找到最底,最底的最小*/
		for(;pRoot->left!=NULL;pRoot=pRoot->left);
		return pRoot;
	}
	return NULL;
}


/************************************************
* 删除节点
************************************************/
void tree_deleteInode(stTreeNode *pRoot,int nDeleteValue)
{	
	stTreeNode *pRetNode = NULL;
	stTreeNode *pNode = pRoot;
	stTreeNode *parent = pRoot;
	int child = 0;  //0表示左子树,1表示右子树;

	if(pNode == NULL)
		return;

	while(pNode)
	{
		if(pNode->nValue == nDeleteValue)
		{
			if(pNode->left == NULL && pNode->right == NULL)/*删除叶子节点*/
			{
				if(pNode == pRoot)
				{
					tree_destoryInode(pNode);
				}
				else if(parent->left == pNode)
				{
					parent->left = NULL;
					tree_destoryInode(pNode);
				}
				else if(parent->right == pNode)
				{
					parent->left = NULL;
					tree_destoryInode(pNode);
				}
				pNode = NULL;
			}
			else if(pNode->left == NULL)/*左节点空,表示右节点不为空*/
			{
				if(parent->left == pNode)
				{
					parent->left = pNode->right;
					tree_destoryInode(pNode);
				}
				else if(parent->right == pNode)
				{
					parent->right = pNode->right;
					tree_destoryInode(pNode);
				}
				pNode = NULL;
			}
			else if(pNode->right == NULL)/*右节点空,表示左节点不为空*/
			{
				if(parent->left == pNode)
				{
					parent->left = pNode->left;
					tree_destoryInode(pNode);
				}
				else if(parent->right == pNode)
				{
					parent->right = pNode->left;
					tree_destoryInode(pNode);
				}
				pNode = NULL;

			}
			else  //删除有双节点的节点
			{
				/*找到最小的节点*/
				pRetNode = tree_findMin(pNode->right);
				/*替换内容*/
				pNode->nValue = pRetNode->nValue;
				if(pRetNode->right!=NULL)
					pRetNode->parent->left = pRetNode->right;
				else
					pRetNode->parent->left = NULL;
				tree_destoryInode(pRetNode);
				pRetNode = NULL;
			}
		}
		else if(nDeleteValue < pNode->nValue)/*往左*/
		{
			parent = pNode;
			pNode = pNode->left;
		}
		else if(nDeleteValue > pNode->nValue)/*往右*/
		{
			parent = pNode;
			pNode = pNode->right;
		}

	}

	return;
}


/************************************************
* 插入节点
* 定义:插入规则为:左<根<右
************************************************/
int tree_insertNode(stTreeNode **ppRoot,stTreeNode *pNewInode)
{
	stTreeNode *pinodeTmp = NULL;
	
	if(pNewInode ==NULL){
		printf("%s input paras error\n",__FUNCTION__);
		return -1;
	}

	/*如果是空树*/
	if(*ppRoot==NULL)
	{
		*ppRoot = pNewInode;
		pNewInode->parent = *ppRoot;
	}
	else
	{
		/*树根开始*/
		pinodeTmp = *ppRoot;
		
		while (pinodeTmp !=NULL)
		{
			/*插入节点小于当前节点*/
			if(pNewInode->nValue< pinodeTmp->nValue)
			{
				if(pinodeTmp->left == NULL) //左孩子节点为空,插入
				{
					pinodeTmp->left = pNewInode;
					pNewInode->parent = pinodeTmp;
					break;
				}
				else
				{
					pinodeTmp = pinodeTmp->left;
				}
			}
			/*插入节点大于当前节点*/
			else
			{
				/*左孩子节点为空,插入*/
				if(pinodeTmp->right == NULL)
				{
					pinodeTmp->right = pNewInode;
					pNewInode->parent = pinodeTmp;
					break;
				}
				else
				{
					/*左孩子节点非空,继续向左孩子节点找*/
					pinodeTmp = pinodeTmp->right;
				}
			}
		}
	}

	return 0;
}


/************************************************
* 插入节点
* 定义:插入规则为:左<根<右
************************************************/
void tree_destory(stTreeNode *pRoot)
{
	stTreeNode *pleft = NULL;	
	stTreeNode *pright = NULL;

	if(pRoot==NULL)
		return;
	else
	{
		pleft	= pRoot->left;
		pright	= pRoot->right;
		tree_destoryInode(pRoot);
		tree_destory(pleft);
		tree_destory(pright);
	}
	return;
}


int main()
{
	int ni = 0;
	int nRet = -1;
	int nSqe[]={35,2,1,6,8,10,6,3,44,32,65,7,21};
	
	stTreeNode *pTreeRoot = NULL;
	stTreeNode *pNewTreeNode = NULL;
	
	for(ni= 0;ni<(sizeof(nSqe)/sizeof(int));ni++)
	{
		pNewTreeNode = tree_CreateInode();
		if(pNewTreeNode==NULL){
			printf("%s tree_CreateInode failed at (%d) line\n",__FUNCTION__,__LINE__);
			break;
		}
		pNewTreeNode->nValue = nSqe[ni];

		nRet = tree_insertNode(&pTreeRoot,pNewTreeNode);
		if(nRet<0){
			printf("%s tree_insertNode failed at (%d) line\n",__FUNCTION__,__LINE__);
			break;
		}
	}
	
	printf("------------------------------------------------------\n");
	tree_preScanLoop(pTreeRoot);	
	printf("------------------tree_midScanLoop2--------------------\n");
	tree_midScanLoop(pTreeRoot);
	printf("------------------------------------------------------\n");
	tree_PostScanLoop(pTreeRoot);
	printf("------------------------------------------------------\n");
	nRet = tree_getDeeps(pTreeRoot);
	printf("tree_getDeeps=%d\n",nRet);
	nRet = tree_getLeafCnts(pTreeRoot);
	printf("tree_getLeafCnts=%d\n",nRet);


	if(tree_searchInode(pTreeRoot,8)!=NULL)
		printf("tree_searchInode find\n");
	else
		printf("tree_searchInode not find\n");

	tree_deleteInode(pTreeRoot,8);
	printf("------------------tree_midScanLoop2--------------------\n");
	tree_midScanLoop(pTreeRoot);
	
	if(tree_searchInode(pTreeRoot,8)!=NULL)
		printf("tree_searchInode find\n");
	else
		printf("tree_searchInode not find\n");

	tree_destory(pTreeRoot);
	return 0;
}

Over!!第一次写一篇blog用时这么长的,用了6/7个小时吧

 

 

 

Guess you like

Origin blog.csdn.net/Chasing_Chasing/article/details/94332356
36