在完成二叉树里面的操作时得先明白二叉树的概念,二叉树有两种情况:
1、空树
2、根节点 + 根节点的左子树 + 根节点的右子树 (这里的左子树和右子树又是一颗二叉树)
可以看出在定义二叉树的时候就是用递归的方式定义的,后面的操作大多也都用到这样的思想。
一、二叉树的遍历
1、前序遍历
规则:访问根节点 --> 前序遍历左子树 --->前序遍历右子树
代码:
void BinaryTreePrevOrder(BTNode* root) {
if (root == NULL) {
return;
}
printf("%d ", root->_data);
BinaryTreePrevOrder(root->_left);
BinaryTreePrevOrder(root->_right);
}
对上图来说,遍历的结果为1、2、3、4、5、6,具体情况如下:
2、中序遍历
规则:中序遍历左子树 ----> 访问根节点 ------> 中序遍历右子树
代码:
void BinaryTreeInOrder(BTNode* root) {
if (root == NULL) {
return;
}
BinaryTreeInOrder(root->_left);
printf("%d ", root->_data);
BinaryTreeInOrder(root->_right);
}
对上图来说遍历结果为3、2、1、5、4、6。
3、后序遍历
规则:后序遍历左子树---->后序遍历右子树---->访问根节点
代码:
void BinaryTreePostOrder(BTNode* root) {
if (root == NULL) {
return;
}
BinaryTreePostOrder(root->_left);
BinaryTreePostOrder(root->_right);
printf("%d ", root->_data);
}
对上图的遍历结果为3、2、5、6、4、1。
4、层序遍历
层序遍历就是从上往下、从左至右逐层访问节点的过程。这个过程显然递归难以实现,这里可以借助队列来实现。具体方法如下:
第一步:将根节点入队列
第二步:如果队列不为空就访问队头元素
第三步:如果队头元素有孩子节点,就将孩子节点入队列
第四步:对头元素出队列
第五步:重复第二步到第四步直至队列为空
代码实现:
void BinaryTreeLevelOrder(BTNode* root) {
if (root == NULL) {
return;
}
Queue q;
QueueInit(&q);
//1、根节点入队列
QueuePush(&q, root);
while (!QueueEmpty(&q)) {
BTNode* frontroot = QueueFront(&q);
//2、判断队列不为空就访问队头元素
printf("%d ", frontroot->_data);
//3、如果队头节点有孩子,就将孩子入队列
if (frontroot->_left != NULL) {
QueuePush(&q, frontroot->_left);
}
if (frontroot->_right != NULL) {
QueuePush(&q, frontroot->_right);
}
//3、队头节点出队列
QueuePop(&q);
}
QueueDestroy(&q);
}
二、二叉树的创建(前序遍历)
在二叉树的创建过程中,为了能让每个节点确认是否有左右孩子,我们得对它进行扩展。扩展二叉树就可以做到一个遍历序列确定一颗二叉树。 如下图这样:
建立二叉树的过程,也使用了递归的原理。只不过在原来打印节点的地方改成了生成节点。这里还有一些细节要注意,放在了注释中。
代码:
//形参为前序遍历的数组array,二叉树的节点数size,数组索引index(这里得是指针,因为
//在递归得过程中值得带出去),扩展二叉树用的数invalid
BTNode* BinaryTreeCreate(BTDataType array[],int size,int* index, BTDataType invalid) {
BTNode* root = NULL;
if (*index < size && array[*index] != invalid) {
root = BuyNode(array[*index]);
//注意索引的变换
(*index)++;
root->_left = BinaryTreeCreate(array, size, index, invalid);
(*index)++;
root->_right = BinaryTreeCreate(array, size, index, invalid);
}
return root;
}
三、求节点个数(注意递归思想的建立)
节点数 = 根节点 + 左子树的节点数 + 右子树的节点数
这里的出口是根节点为空。
int BinaryTreeSize(BTNode* root) {
if (root == NULL) {
return 0;
}
return 1 + BinaryTreeSize(root->_left) + BinaryTreeSize(root->_right);
}
四、求叶子节点个数(注意递归思想的建立)
叶子节点数 = 左子树叶子节点个数 + 右子树叶子节点个数
这里的出口是根节点为叶子节点。
int BinaryTreeLeafSize(BTNode* root) {
if (root == NULL) {
return 0;
}
if (root->_left == NULL && root->_right == NULL) {
return 1;
}
return BinaryTreeLeafSize(root->_left) + BinaryTreeLeafSize(root->_right);
}
五、求第k层节点个数(注意递归思想的建立)
第k层节点个数 = 左子树第k-1层节点的个数 + 右子树第k-1层的个数
这里的出口为层数为1。
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);
}
六、判断是否为完全二叉树
判断方法为层序遍历二叉树,不同的是不管队头节点的孩子节点是否为空,都让它入队列。当队头元素为空指针时跳出循环,检测此时队列里是否还有二叉树的节点。如果没有,则是完全二叉树。
int BinaryTreeComplete(BTNode* root) {
if (root == NULL) {
return 1;
}
//层序遍历二叉树
Queue q;
QueueInit(&q);
QueuePush(&q, root);
while (!QueueEmpty(&q)) {
BTNode* frontroot = QueueFront(&q);
if (frontroot == NULL) {
//遇到空指针停止
break;
}
QueuePush(&q, frontroot->_left);
QueuePush(&q, frontroot->_right);
QueuePop(&q);
}
//检查队列中除了空指针是否还有节点
while (!QueueEmpty(&q)) {
if (QueueFront(&q) != NULL) {
return 0;
}
QueuePop(&q);
}
return 1;
}