前言
在前一篇数据结构博文中,我们已经了解了基本的二叉树只是,今天就来详细讲解链式二叉树的遍历,以及各方面的操作。 链式二叉树的学习能很好锻炼我们递归思想以及分治思想。
链式二叉树的定义
怎么定义链式二叉树呢? 我们用一个结构体来表示二叉树的一个节点,其中有一个变量存放二叉树节点的值,再来两个此结构体指针存放它的左右节点的地址。代码如下:
typedef int BTDataType;
typedef struct BinaryTreeNode
{
BTDataType data;
struct BinaryTreeNode* left;
struct BinaryTreeNode* right;
}BTNode;
链式二叉树的遍历
前序遍历
前序遍历的口诀就是“根左右”,它的思想就是先访问树的根,再访问数的左孩子,最后访问树的右节点。例如如图这个二叉树:
遍历的过程: 我们是先访问它的根也就是4,然后再访问它的左孩子2,左孩子2从新作为根后先从自己2开始再访问2的左孩子1,左孩子1作为根,先访问自己1然后访问左孩子为NULL就返回到1,然后再访问1的右孩子为NULL返回到1,依次类推。就能得到遍历的顺序为:
4, 2, 1, 3, 6, 5 代码:
void PrevOrder(BTNode* root)
{
if(root == NULL)
{
printf("NULL");
return;
}
printf("%d ",root->data);
PrevOrder(root->left);
PrevOrder(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);
}
层序遍历
层序遍历就是从第一层的第一个节点然后到第二层一次每层从左到右遍历。 以这个树为例,他的层序遍历结果就是: 4 2 6 1 3 5 那要怎么实现这个代码呢? 这里我们就要借助一种数据结构队列了。 我们的方法是从根节点开始,先把根节点入队,然后遍历一个节点就把它的左子树入队然后再把他的右子树入队,NULL不入队,直到队列为空为止。代码如下:
void LevelOrder(BTNode* root)
{
if(root == NULL)
{
return;
}
Queue q;
QueueInit(&q);
QueuePush(&q, root);
while(!QueueEmpty(&q))
{
BTNode* front = QueueFront(&q);
QueuePop(&q);
printf("%d ",front->data);
if(front->left != NULL)
{
QueuePush(&q,root->left);
}
if(front->right!= NULL)
{
QueuePush(&q,root->right);
}
}
QueueDestroy(&q);
}
求二叉树的节点个数
求节点个数直接分治就行了 如果父亲节点不为空加一为空加0; 代码如下:
int BinTreeSize(BTNode* root)
{
return root == NULL ? 0 : (1 + BinTreeSize(root->left) + BinTreeSize(root->right));
}
求二叉树的叶子节点个数
首先我们的得知道怎么去判断叶子节点: 左右子树都为空的节点就是叶子节点。所以按照这个性质我们就可以判断了,代码如下:
int BinTreeLeafSize(BTNode* root)
{
if(root == NULL)
{
return 0;
}
return root->left == NULL && root->right == NULL ? 1 : BinTreeLeafSize(root->left) + BinTreeLeafSize(root->right);
}
求二叉树第K层的节点个数
思想就是:如果当前节点是第k层就加一,如果不是,就递归到下一层让k - 1.
int BinTreeLevelKSize(BTNode* root, int k)
{
if(root == NULL)
{
return 0;
}
if(k == 1)
{
return 1;
}
return BinTreeLevelKSize(root->left, k-1) + BinTreeLevelKSize(root->right, k-1);
}
求二叉树的最大深度
将这个问题简化就是把求左右子树较大的深度然后加1.因为根节点本身也是占用一个深度的。 代码如下:
int BinTreeDepth(BTNode* root)
{
if(root == NULL)
{
return 0;
}
int leftDepth = BinTreeDepth(root->left);
int rightDepth = BinTreeDepth(root->right);
return leftDepth > rightDepth ? leftDepth + 1 : rigthDepth + 1;
}
给一个数让给返回该节点
这个思想就是节点不是然后就从它的左子树和右子树找,直到找到为止。 代码如下:
BTNode* BinTreeNodeFint(BTNode* root, BTNDataType x)
{
if(root == NULL)
{
return NULL;
}
if(root->data == x)
{
return root;
}
BTNode* Left = BinTreeNodeFint(root->left, x);
if(Left != NULL)
{
return Left;
}
BTNode* Right = BinTreeNodeFint(root->right, x);
if(Left != NULL)
{
return Right ;
}
return NULL;
}
判断该数是不是完全二叉树
完全二叉树的判断就是层序遍历过程中,直到数结束为止中间不能有空节点的产生,就是完全二叉树。 代码如下:
bool BinTreeComplete(BTNode* root)
{
if(root == NULL)
{
return true;
}
Queue q;
QueueInit(&q);
QueuePush(&q, root);
while(!QueueEmpty(&q))
{
BTNode* Front = QueueFront(&q);
QueuePop(&q);
if(Front == NULL)
{
break;
}
else
{
QueuePush(&q, front->left);
QueuePush(&q, front->right);
}
}
while(!QueueEmpty(&q))
{
BTNode* front = QueueFront(&a);
QueuePop(&q);
if(front == NULL)
{
QueueDestroy(&q);
return false;
}
}
QueueDestroy(&q);
return true;
}
二叉树的销毁
二叉树的销毁必须以后序遍历,不然先把根销毁了就找不到左右节点了 代码如下:
void BinTreeDestroy(BTNode* root)
{
if(root == NULL)
{
return;
}
BinTreeDestroy(root->left);
BinTreeDestroy(root->right);
free(root);
}
|