| 普通二叉树我们之前讲过完全二叉树的应用:【堆的数据结构】,在次我们使用的是顺序表来存储完全二叉树;但是对于普通的二叉树,是不建议使用顺序表的结构来存储的,会浪费空间,所以,我们搞出了一个链式存储结构来存储普通二叉树;
 
 对于普通二叉树我们需要明白几点: 普通二叉树的增删查改是没有任何意义的,因为普通二叉树增删查改的结构过于复杂,没有必要一定要用二普通二叉树的方式去增删查改;对于普通二叉树我们需要关注的问题是:遍历普通二叉树的结构问题,前中后层次遍历,关注这个问题的意义所在也是:第一为以后学习更加复杂的二叉排序树,AVL树,红黑树,B树做准备;第二也就是为了刷刷OJ题;因为OJ题关于二叉树的问题还是蛮多的;只有给普通二叉树加以一些性质的基础上,增删查改次啊有意义,比如二叉搜索树,AVL树等;
 
 二叉树的遍历遍历就是全部的结点都访问一遍,很自然的二叉树的遍历也是所有二叉树的结点都访问一遍;二叉树的遍历需要关注三个结点:根结点,左子树结点,右子树结点;
 
 这次以不同的视角理解以下二叉树的前序遍历,让你正真的吃透它;我们知道**前序遍历就是 先访问根,再访问左子树,再访问右子树,而中序就是先:左子树再根再右子树;后序就是先左再右后根;**我们之前学习遍历都是不画出NULL的,这次我们把NULL也画出来,这样才可以体会二叉树的遍历精髓所在!  假如我们有如上图的二叉树,用前序遍历和中序和后序遍历把NULL 画出来的结果是什么呢?
 前序遍历:
 
 
 
 中序遍历:
  
 后序遍历:
  
 二叉树遍历代码实现要遍历二叉树,首先得有二叉树的存储结构,还要有二叉树,我们一直都没有创建出二叉树的模样,所以我们首先得创建二叉树出来,再进行遍历;由于二叉树得创建并不是重点:所以我们使用了一种非常暴力的创建方式,具体如下:
 创建二叉树: typedef char BTDateType;
typedef struct BinaryTreeNode
{
	BTDateType data;
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
}BTNode;
BTNode* BuyNode(BTDateType x)
{
	BTNode* node = (BTNode*)malloc(sizeof(BTNode));
	node->data = x;
	node->left = node->right = NULL;
	
	return node;
}
BTNode* CreatBinaryTree()
{
	BTNode* nodeA = BuyNode('A');
	BTNode* nodeB = BuyNode('B');
	BTNode* nodeC = BuyNode('C');
	BTNode* nodeD = BuyNode('D');
	BTNode* nodeE = BuyNode('E');
	BTNode* nodeF = BuyNode('F');
	nodeA->left = nodeB;
	nodeA->right = nodeC;
	nodeB->left = nodeD;
	nodeC->left = nodeE;
	nodeC->right = nodeF;
return nodeA;
}
int main()
{
	BTNode* root = CreatBinaryTree();
	
	
	
	
	
	
	return 0;
}
 创建好二叉树开始前序遍历代码: void PreOrder(BTNode* root)
{
	if(root == NULL)
	{
		printf("NULL ");
		return;
	}
	printf("%c ",root->data);
	PreOrder(root->left);
	PreOrder(root->right);
}
 前序遍历很简单,我们再为空时候,打印了NULL,便于观察结果
  结果很正确嘛!
 
 中序遍历: 
void InOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	InOrder(root->left);
	printf("%c ", root->data);
	InOrder(root->right);
}
 
 
 后序遍历: 
void PostOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	PostOrder(root->left);
	PostOrder(root->right);
	printf("%c ", root->data);
}
 
 
 理解递归遍历二叉树的调用过程示例前序遍历的递归理解!!你把代码写出来,一个步骤一个步骤的走,去调用,去返回,这样来理解; 
 
 求二叉树的结点个数首先我们来看看一个计数的方式,能否求得二叉树结点个数 **思路:当我在递归遍历二叉树时候,同时用一个计数变量count去记录遍历过得结点,就可以得到二叉树得结点个数。**但是是否可行呢? 
int BinaryTreeSize(BTNode* root)
{
	if (root == NULL)
	{
		
		return 0;
	}
	int count = 0;
	count++;
	BinaryTreeSize(root->left);
	BinaryTreeSize(root->right);
	return count;
}
 
 
 那这么说:是否可以设置一个静态遍历呢?staitc int count; 这样 count 就不会因为栈帧的问题而影响了.但是是否可以行呢?
 
int BinaryTreeSize(BTNode* root)
{
	if (root == NULL)
	{		
		return 0;
	}
	static int count = 0;
	count++;
	BinaryTreeSize(root->left);
	BinaryTreeSize(root->right);
	return count;
}
 
 
 上面的方式都不行,但是我们可以在main设置一个变量,把变量地址传递过去,给函数,函数设置一个形参指针变量,去保持函数里面的值返回给外面;因为在main函数的变量的栈帧和在递归函数里面的栈帧不一样,所以可以这么做;
 void BinaryTreeSize(BTNode* root,int* pn)
{
	if (root == NULL)
	{
		return ;
	}	
	++(*pn);
	BinaryTreeSize(root->left,pn);
	BinaryTreeSize(root->right, pn);	
}
 
 
 其实上面的方式都不是最好的:最好的是直接递归返回就行!
 
int BinaryTreeSize(BTNode* root)
{
	if (NULL == root)
	{
		return 0;
	}
	
	return BinaryTreeSize(root->right) + BinaryTreeSize(root->left) + 1;
	
}
 
 
 求二叉树的叶子结点求二叉树的叶子结点也可以用递归的思路思考:当root为空,直接返回0,表示叶子结点为0;
 当root只有根结点,直接返回1,表示叶子结点就是根结点;
 其他情况,直接计算左子树的叶子结点+右子树的叶子结点即可。
 int BinaryTreeLeafSize(BTNode* root)
{
	if (root == NULL) 
		return 0;
	
	if (root->left == NULL || root->right == NULL) 
		return 1;
	int leftLeaf = BinaryTreeLeafSize(root->left);
	int rightLeaf = BinaryTreeLeafSize(root->right);
	return  leftLeaf + rightLeaf;
}
 
 求二叉树的第K层节点个数当树为空时候,直接返回0;当k == 1时候表示只有一层,那只能是根结点,直接返回1;
 其他情况就是第k层结点数=第k-1层的左子树的结点数+第k层右子树的结点树之和;
 
int BinaryTreeLevelKSize(BTNode* root,int k)
{
	if (root == NULL) return 0;
	if (k == 1) return 1;
	return BinaryTreeLevelKSize(root->left, k - 1) +
		BinaryTreeLevelKSize(root->right, k - 1);
}
 
 求二叉树的深度或者高度当树为空时候,直接返回;当树不为空时候,树的深度 = max(左子树的深度,右子树的深度)+根的结点;
 
int BinaryDepth(BTNode* root)
{
	if (root == NULL) return 0;
	
	int LeftDepth = BinaryDepth(root->left);
	int rightDepth = BinaryDepth(root->right);
	return LeftDepth > rightDepth ? LeftDepth + 1 : rightDepth + 1;
}
 在二叉树查找x值,返回结点当树为空时候,不用找;当树为根结点,判断根节点的值是否和x相等;
 其他情况去左子树找,判断是否找到,找到就返回;再去右树找,找到就返回;假如左子树右子树都没找到,直接返回空;
 
 常见的错误代码分析 
BTNode* BinaryTreeFind(BTNode* root,int x)
{
	if (root == NULL) return NULL;
	if (root->data == x) return root;
	BinaryTreeFind(root->left, x);
	BinaryTreeFind(root->right, x);
}
 这段代码很明显会有错误!以为直接找左树和右树就可以了,可是写这个代码时候,忽略了递归返回只会返回到上一层调用它的地方,不会直接返回到刚开始调用的地方,这样就会导致返回到上一层时候,如果返回的是NULL的那么就会问题; 
 正确的代码 
BTNode* BinaryTreeFind(BTNode* root,int x)
{
	if (root == NULL) return NULL;
	if (root->data == x) return root;
	BTNode* left = BinaryTreeFind(root->left, x);
	if (left) 
		return left;
	BTNode* right = BinaryTreeFind(root->right, x);
	if (right) 
		return right;
	return NULL;
}
 |