目录
二叉树的创建
根据二叉树的结构,我们用链表来链接每个结点的左右孩子,并且给每个结点定义一个数值。
如图所示:
代码如下:
typedef char BTDataType;//老样子 便于控制数据类型
typedef struct BinaryTreeNode
{
BTDataType data;
struct BinaryTreeNode* left;
struct BinaryTreeNode* right;
}BTNode;
构建一颗二叉树
// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi)
{
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;
}
二叉树的销毁
这里利用递归来进行销毁,先销毁除叶子节点的其他节点,然后再释放叶子节点。
代码如下:
// 二叉树销毁
void BinaryTreeDestory(BTNode* root)
{
if (root == NULL)
return;
BinaryTreeDestory(root->left);
BinaryTreeDestory(root->right);
free(root);
}
创建一个新结点
如果要插入一个新结点的时候就可以很好的利用这个函数,方法跟链表中的创建新结点类似。
//创建一个新结点
BTNode* BuyNode(BTDataType x)
{
BTNode* newNode = (BTNode*)malloc(sizeof(BTNode));
if (newNode == NULL)
{
printf("malloc failed");
exit(-1);
}
newNode->data = x;
newNode->left = newNode->right = x;
return newNode;
}
计算二叉树的结点个数
这里同样是利用递归来遍历每一个结点。
// 二叉树节点个数
int BinaryTreeSize(BTNode* root)
{
if (root == NULL)
return 0;
return BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
//+1是因为还有自身的结点
}
计算二叉树的叶子结点个数
方法跟上一个结算结点个数类似,只不过要加一个判断条件,当左右孩子都为空时就找到了。
// 二叉树叶子节点个数
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那么继续遍历下一层,同时让k-1。
// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{
assert(k >= 1);
if (root == NULL)
{
return 0;
}
if (k == 1)
{
return 1;
}
// root不等空,k也不等于1,说明root这颗树的第k节点在子树里面
// 转换成求左右子树的第k-1等的节点数量
return BinaryTreeLevelKSize(root->left, k - 1)
+ BinaryTreeLevelKSize(root->right, k - 1);
}
二叉树查找值为x的节点
这个就比较简单了,挨个遍历二叉树的所有结点,当找到哪一个结点的data=x的时候就返回该结点。
// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
if (root == NULL)
return NULL;
if (root->data == x)
return root;
BTNode* LeftRet = BinaryTreeFind(root->left, x);
//这里最好赋值一下,要不到时候返回的时候还要进行递归会有巨大的时间损耗
if (LeftRet->data == x)
return LeftRet;
BTNode* RightRet = BinaryTreeFind(root->right, x);
//这里最好赋值一下,要不到时候返回的时候还要进行递归会有巨大的时间损耗
if (RightRet->data == x)
return RightRet;
return NULL;
}
二叉树前序遍历
前序遍历的意思其实很容易理解,就是以根左右的顺序遍历,这里我们运用递归的方法进行遍历,
中序遍历与后序遍历同样如此。
// 二叉树前序遍历
void BinaryTreePrevOrder(BTNode* root)
{
if (root == NULL)
{
return;
}
printf("%c ", root->data);
BinaryTreePrevOrder(root->left);
BinaryTreePrevOrder(root->right);
}
二叉树中序遍历
// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root)
{
if (root == NULL)
return;
BinaryTreePrevOrder(root->left);
printf("%c ", root->data);
BinaryTreePrevOreder(root->right);
}
二叉树的后序遍历
// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root)
{
if (root == NULL)
return;
BinaryTreePrevOrder(root->left);
BinaryTreePrevOrder(root->right);
printf("%c ", root->data);
}
二叉树的层序遍历
这里我们要运用我们之前学习的队列,至于层序遍历其实就是一层一层的进行遍历,理解起来也没有很难。我们首先将二叉树的根节点给入队,如果需要出队数据的时候,需要出队的结点会让自身的左右孩子结点给带入到队列当中,所以我们在队列中存储的其实是二叉树的结点,而不是二叉树的值,如图所示:
// 层序遍历
void BinaryTreeLevelOrder(BTNode* root)
{
if (root == NULL)
{
return;
}
Queue q;//定义一个队列
QueueInit(&q);//初始化队列
QueuePush(&q, root);//将root结点插入
while (!QueueEmpty(&q))
{
BTNode* front = QueueFront(&q);
//保存结点的值 以便往后遍历
QueuePop(&q);//出队头数据
printf("%c ", front->data);//打印队头数据
//队头出队后 将他的左右孩子入队
if (front->left)
{
QueuePush(&q, front->left);
}
if (front->right)
{
QueuePush(&q, front->right);
}
}
printf("\n");
QueueDestroy(&q);
}
判断二叉树是否是完全二叉树
完全二叉树的特点是前k-1层是一颗满二叉树,第k层的结点是连续的,那么我们得知一个特点,在对一棵二叉树进行层序遍历的时候如果出现空节点后,之后就不能在出现非空结点,若再次出现非空结点,那此二叉树就不是完全二叉树。
// 判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root)
{
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);
}
}
//遇到空以后,检查队列中剩下的结点
//1、剩下的全是空,则是完全二叉树
//2、剩下的有非空,则不是完全二叉树
while (!QueueEmpty(&q))
{
BTNode* front = QueueFront(&q);
QueuePop(&q);
if (front != NULL)
{
QueueDestroy(&q);
return false;
}
}
QueueDestroy(&q);
return true;
}