在上一节中,讲了二叉树的顺序结构的存储,顺序结构适合于完全二叉树,那么不是完全二叉树的二叉树在内存中要怎么存储呢?这时候需要用到链式存储。
1、二叉树结点的创建
在链式二叉树中,一个结点需要保存其数值,以及左孩子和右孩子的指针。
typedef char BTDataType;
typedef struct BinaryTreeNode
{
BTDataType _data;
struct BinaryTreeNode* _left;
struct BinaryTreeNode* _right;
}BTNode;
2、二叉树的遍历
2、1二叉树的前序遍历
前序遍历也被称为先根遍历,也就是先遍历根,再左子树,最后右子树。
注意,这里当遍历完一个根后,不是遍历左孩子,而是左子树。
这里把空指针也打印出来,是为了能够更好的理解遍历的过程
void PrevOrder(BTNode* root)//前序遍历
{
if (root == NULL)
{
printf("NULL ");
return;
}
printf("%c ", root->_data);
PrevOrder(root->_left);
PrevOrder(root->_right);
}
2、2二叉树的中序遍历
中序遍历也被称为中根遍历,也就是先左子树,再根,最后右子树
void InOrder(BTNode* root)//中序遍历
{
if (root == NULL)
{
printf("NULL ");
return;
}
InOrder(root->_left);
printf("%c ", root->_data);
InOrder(root->_right);
}
2、3二叉树的后序遍历
后序遍历也被称为后根遍历,也就是先左子树,再右子树,最后根
void PostOrder(BTNode* root)//后序遍历
{
if (root == NULL)
{
printf("NULL ");
return;
}
PostOrder(root->_left);
PostOrder(root->_right);
printf("%c ", root->_data);
}
2、4二叉树的层序遍历
二叉树的前序遍历也就是一层一层的遍历二叉树,此时需要用到队列先进先出的性质。将队列中的结点树数据域存放二叉树结点的指针,首先将二叉树的根结点放入队列,然后出队列,出队列的同时,如果出的这个结点不为空,那么就将它的左右孩子也放进队列,直到二叉树结束。
void BinaryTreeLevelOrder(BTNode* root)//层序遍历,在队列中存放的是二叉树一个结点的指针,因为这样子才可以把左右子树带入队列
{
Queue q;
QueueInit(&q);
if (root == NULL)
return;
QueuePush(&q, root);
while (!QueueEmpty(&q))
{
BTNode* front = QueueFront(&q);
QueuePop(&q);
if (front)
{
printf("%c ", front->_data);
//带入下一层
QueuePush(&q, front->_left);
QueuePush(&q, front->_right);
}
else
{
printf("NULL ");
}
}
QueueDestory(&q);
printf("\n");
}
3、计算二叉树结点的个数
int TreeSize(BTNode* root)//返回总结点的个数
{
if (root == NULL)
return 0;
else
return 1 + TreeSize(root->_left) + TreeSize(root->_right);
}
注意,这里不是前序,而是后序
因为只有当左右子树的大小算出来后,才能算当前树,所以是后序
4、计算叶子结点的个数
int TreeLeafSize(BTNode* root)//返回叶子结点的个数
{
if (root == NULL)
return 0;
if (root->_left == NULL && root->_right == NULL)
return 1;
else
return TreeLeafSize(root->_left) + TreeLeafSize(root->_right);
}
5、求第k层结点个数
int BinaryTreeLevelKSize(BTNode* root, int k)//求第K层结点个数
{
if (root == NULL)
return 0;
if (k == 1)
return 1;
return BinaryTreeLevelKSize(root->_left, k - 1) + BinaryTreeLevelKSize(root->_right, k - 1);
}
6、计算树的深度
int TreeDepth(BTNode* root)//返回树的深度
{
//if (root == NULL)
// return 0;
//else
// return 1 + (TreeDepth(root->_left) > TreeDepth(root->_right) ? TreeDepth(root->_left) : TreeDepth(root->_right));
但这样会造成重复递归
if (root == NULL)
return 0;
int leftDepth = TreeDepth(root->_left);
int rightDepth = TreeDepth(root->_right);
return leftDepth > rightDepth ? leftDepth + 1 : rightDepth + 1;//这样子就不会重复递归了
}
7、查找值x是否在二叉树中
BTNode* binaryTreeFind(BTNode* root, BTDataType x)//查找值为x的结点是否在二叉树中
{
if (root == NULL)
return NULL;
if (root->_data == x)
return root;
BTNode* flag = binaryTreeFind(root->_left, x);//用一个flag来记录左子树有没有x,没有再到右子树取找
if (flag == NULL)
flag = binaryTreeFind(root->_right, x);
return flag;
}
8、判断一颗二叉树是否是完全二叉树
利用了层序遍历
void BinaryTreeComplete(BTNode* root)//判断一棵树是不是完全二叉树,是返回1,不是返回0
{//是完全二叉树,则在队列中数值和NULL是分开的,不是完全二叉树则数值和NULL是在一起的
Queue q;
QueueInit(&q);
if (root == NULL)
return 1;
QueuePush(&q, root);
while (!QueueEmpty(&q))
{
BTNode* front = QueueFront(&q);
QueuePop(&q);
if (front == NULL)
break;
QueuePush(&q, front->_left);
QueuePush(&q, front->_right);
}
while (!QueueEmpty(&q))//取出队列中的所有元素,如果有非空的就不是完全二叉树,返回0
{
BTNode* front = QueueFront(&q);
QueuePop(&q);
if (front)
return 0;
}
return 1;
}