二叉树的链式结构实现
前言
二叉树的结构特征在这节介绍了,这里就直接实现一个二叉树
提示:以下是本篇文章正文内容,下面案例可供参考
一、二叉树结构体的创建
这里用二叉链。
typedef char BTDataType;
typedef struct BinaryTreeNode
{
struct BinaryTreeNode* leftChild; //左孩子
struct BinaryTreeNode* rightChild; //右孩子
BTDataType data; //数据
}BTNode;
二、手动构建二叉树
1.开辟二叉树节点
BTNode* CreateTreeNode(BTDataType x)
{
BTNode* NewNode = (BTNode*)malloc(sizeof(BTNode));
if (NewNode == NULL)
{
perror("CreateTreeNode malloc fail");
return NULL;
}
NewNode->data = x;
NewNode->leftChild = NULL;
NewNode->rightChild = NULL;
return NewNode;
}
2.创建节点并链接
代码如下(示例):
BTNode* A = CreateTreeNode('A');
BTNode* B = CreateTreeNode('B');
BTNode* C = CreateTreeNode('C');
BTNode* D = CreateTreeNode('D');
BTNode* E = CreateTreeNode('E');
BTNode* F = CreateTreeNode('F');
A->leftChild = B;
A->rightChild = C;
B->leftChild = D;
B->rightChild = E;
C->leftChild = F;
三、二叉树的一些接口实现
前序遍历
前序遍历:访问根节点的操作发生在遍历其左右子树之前。(根->左->右)
void PrevOrder(BTNode* root)
{
if (root == NULL)
{
printf("NULL ");
return;
}
printf("%c ", root->data);
PrevOrder(root->leftChild);
PrevOrder(root->rightChild);
}
中序遍历
中序遍历:访问根节点的操作发生在遍历其左右子树之中。(左->根->右)
void InOrder(BTNode* root)
{
if (root == NULL)
{
printf("NULL ");
return;
}
InOrder(root->leftChild);
printf("%c ", root->data);
InOrder(root->rightChild);
}
后序遍历
中序遍历:访问根节点的操作发生在遍历其左右子树之后。(左->右->根)
void PostOrder(BTNode* root)
{
if (root == NULL)
{
printf("NULL ");
return;
}
PostOrder(root->leftChild);
PostOrder(root->rightChild);
printf("%c ", root->data);
}
层序遍历
层序遍历:自上而下、自左到右逐层访问树的节点的过程就是层序遍历。
这里要用到队列,但是c语言库本身中又没有,所以我们把以前写过的直接拿过来用
思路:第一个节点尾插到队列,然后保存下来,在头删,打印保存下来的值,接着把左右孩子尾插进去,再把左孩子节点删除,尾插左孩子节点的下两个,以此类推,直到队列为空就终止循环
void TreeLevelOrder(BTNode* root)
{
Queue q;
QueueInit(&q);
if (root != NULL)
{
QueuePushBack(&q, root);
}
while (!QueueEmpty(&q))
{
BTNode* front = QueueFront(&q);
QueuePopFront(&q);
printf("%c ", front->data);
if (front->leftChild)
{
QueuePushBack(&q, front->leftChild);
}
if (front->rightChild)
{
QueuePushBack(&q, front->rightChild);
}
}
QueueDestroy(&q);
}
二叉树的销毁
这里传的是一级指针,不能对root置空,等学到c++就可以用引用,可以完美解决,这里我们是在函数外手动置空。
void TreeDestory(BTNode* root)
{
if (root == NULL)
return;
TreeDestory(root->leftChild);
TreeDestory(root->rightChild);
free(root);
}
二叉树的节点个数
int TreeSize(BTNode* root)
{
return root == NULL ? 0 : TreeSize(root->leftChild) + TreeSize(root->rightChild) + 1;
}
二叉树的叶子节点个数
叶子节点:左右孩子都为空
int TreeLeafSize(BTNode* root)
{
if (root == NULL)
return 0;
if (root->leftChild == NULL && root->rightChild == NULL)
return 1;
return TreeLeafSize(root->leftChild) + TreeLeafSize(root->rightChild);
}
二叉树的第k层的节点个数
思路:求第k层的节点个数,可以拆解成求左右子树的k-1层的节点个数,用这个条件递归,直到k等于1时,返回1
int TreeKLevelSize(BTNode* root, int k)
{
if (root == NULL)
return 0;
if (k == 1)
return 1;
return TreeKLevelSize(root->leftChild, k - 1) + TreeKLevelSize(root->rightChild, k - 1);
}
二叉树的查找值为x的节点
BTNode* TreeFind(BTNode* root, BTDataType x)
{
if (root == NULL)
return NULL;
if (root->data == x)
return root;
BTNode* left = TreeFind(root->leftChild, x);
if (left)
return left;
BTNode* right = TreeFind(root->rightChild, x);
if (right)
return right;
return NULL;
}
判断二叉树是否是完全二叉树
思路:
完全二叉树:最后一层的节点是按顺序排序的,其他层都是满的
把每个不为空的节点的左右孩子都传进队列,然后再把队列中不为空的节点删除掉,遇到空就跳出循环
再对剩下的队列做循环,把空的节点都删除,遇到不为空的节点,就说明不是按顺序排序返回false,反之返回true
bool TreeComplete(BTNode* root)
{
Queue q;
QueueInit(&q);
if (root != NULL)
{
QueuePushBack(&q, root);
}
while (!QueueEmpty(&q))
{
BTNode* front = QueueFront(&q);
QueuePopFront(&q);
if (front==NULL)
break;
QueuePushBack(&q, front->leftChild);
QueuePushBack(&q, front->rightChild);
}
while (!QueueEmpty(&q))
{
BTNode* front = QueueFront(&q);
QueuePopFront(&q);
if (front)
return false;
}
QueueDestroy(&q);
return true;
}
总结
读者还是要自己动手画递归过程,理解深刻。
完整代码在这。