二叉树
二叉树的构建:
1.通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
二叉树的声明:
typedef char BTDataType;
struct BinaryTreeNode
{
BTDataType _Data;
struct BinaryTreeNode* left;
struct BinaryTreeNode* right;
};
typedef struct BinaryTreeNode BTNode;
**
图例:
**
思路:
前序遍历:根节点->左子树节点->右子树节点
数组的第一个元素就是根节点,然后构建左子树,在构建右子树。我们可以采用递归的方式
结束的条件是根节点为’#’。
代码实现:
BTNode* BinaryTreeCreate(BTDataType* a, int* Index)
{
BTNode* root = (BTNode*)malloc(sizeof(BTNode));
if (a[*Index] == '#')
return NULL;
root->_Data = a[*Index];
++(*Index);
root->left = BinaryTreeCreate(a, Index);
++(*Index);
root->right = BinaryTreeCreate(a, Index);
return root;
}
2.输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。
假设输入的前序遍历和中序遍历的结果中都不含重复的数字
图例:
思路:
根据前序遍历确定根节点,在中序遍历的数组中找到根节点的位置,从而可以知道左子树的节点个数和右子树的节点个数,,只要节点个数大于0,就可以递归构建二叉树。
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
};
typedef struct TreeNode Node;
代码实现:
struct TreeNode* buildTree(int* preorder, int preorderSize, int* inorder, int inorderSize)
{
if(preorder==NULL||inorder==NULL||preorderSize<=0||inorderSize<=0)
{
return NULL;
}
//前序遍历的第一个元素为根节点,设置好根节点
Node* root=(Node*)malloc(sizeof(Node));
root->val=*preorder;
root->left=root->right=NULL;
if(preorder[0]==preorder[preorderSize-1])
return root;
//在中序遍历中寻找根节点的位置,找出左子树和右子树的节点
int Index=0;
while(Index<inorderSize&&inorder[Index]!=root->val)
++Index;
//确定左、右子树节点个数
int leftlength=Index;
int rightlength=preorderSize-1-Index;
if(leftlength>0)
{
root->left=buildTree(preorder+1,leftlength,inorder,leftlength);
}
if(rightlength>0)
{
root->right=buildTree(preorder+Index+1,rightlength,inorder+Index+1,rightlength);
}
return root;
}
3.返回与给定的前序和后序遍历匹配的任何二叉树。
代码实现:
struct TreeNode* constructFromPrePost(int* pre, int preSize, int* post, int postSize){
if(pre==NULL||preSize<=0||post==NULL||postSize<=0)
return NULL;
struct TreeNode* root=(struct TreeNode*)malloc(sizeof(struct TreeNode));
root->val=pre[0];
root->right=root->left=NULL;
if(preSize==1)
return root;
int Index=0;
while(post[Index]!=pre[1]&&Index<postSize)
++Index;
int leftlength=Index+1;
int rightlength=postSize-leftlength-1;
if(leftlength>0)
{
root->left=constructFromPrePost(pre+1,leftlength,post,leftlength);
}
if(rightlength>0)
{
root->right=
constructFromPrePost(pre+leftlength+1,rightlength,post+Index+1,rightlength);
}
return root;
}
4.根据一棵树的中序遍历与后序遍历构造二叉树
代码实现:
struct TreeNode* buildTree(int* inorder, int inorderSize, int* postorder, int postorderSize){
if(inorder==NULL||inorderSize<=0||postorder==NULL||postorderSize<=0)
return NULL;
//寻找二叉树的根节点
Node* root=(Node*)malloc(sizeof(Node));
root->val=postorder[postorderSize-1];
root->right=root->left=NULL;
//求左、右子树节点个数
int Index=0;
while(Index<inorderSize&&inorder[Index]!=root->val)
{
++Index;
}
int leftlength=Index;
int rightlength=inorderSize-Index-1;
//构建左、右子树
if(leftlength>0)
{
root->left=buildTree(inorder,leftlength,postorder,leftlength);
}
if(rightlength>0)
{
root->right=buildTree(inorder+Index+1,rightlength,postorder+leftlength,rightlength);
}
return root;
}
二叉树的遍历:
前序遍历:
思路:将二叉树看成左子树,根,右子树三部分。所以,根不是空节点的情况下,先打印根节点,再递归访问左子树,和右子树。
代码实现(递归):
void preorderTraversal_(struct TreeNode* root,int* a,int* Index)
{
if(root==NULL)
return ;
a[(*Index)++]=root->val;
preorderTraversal_(root->left,a,Index);
preorderTraversal_(root->right,a,Index);
}
int* preorderTraversal(struct TreeNode* root, int* returnSize){
int* ret=(int*)malloc(sizeof(int)*(1000));
int Index=0;
preorderTraversal_(root,ret,&Index);
*returnSize=Index;
return ret;
}
迭代:
图解:
思路:利用栈先进后出原则,现将根节点放入栈,再出栈,之后将右节点压进栈,再将左节点压进栈。将左节点作为根节点,迭代遍历完左子树。再将右节点作为根节点,迭代遍历完右子树。即完成前序遍历。
代码实现(迭代):
int* preorderTraversal(struct TreeNode* root, int* returnSize){
int* ret = (int*)malloc(sizeof(int) * 100);
int top = 0;
struct TreeNode** stack = (struct TreeNode**)malloc(sizeof(struct TreeNode*) * 100);
*returnSize = 0;
if(!root) return NULL;
stack[++top] = root;
while(top >0)
{
root = stack[top--];
ret[(*returnSize)++] = root->val;
if(root->right)
{
stack[++top] = root->right;
}
if(root->left)
{
stack[++top] = root->left;
}
}
return ret;
}
中序遍历、后序遍历思想和前序遍历相同。
层序遍历:
思路:
利用队列先进先出的性质,将结点一层一层的放入。
每一次打印一个节结的时候,如果该结点有子结点,则把该结点的子结点放到队列的末尾。到队列头部取出一个节点,重复操作,直到队列中所有结点全部被打印。
这样说,可能不太好理解,可以跟着代码理解思路,使用的队列函数都是自己实现的接口。
代码实现:
void BinaryTreeLevelOrder(BTNode* root)
{ //定义一个队列变量,并初始化
Queue q;
QueueInit(&q);
//如果不是空树,将根节点入队
if (root != NULL)
QueuePush(&q, root);
while (!QueueEmpty(&q))
{
//让队内的第一个元素出队并打印
BTNode* front = QueueFront(&q);
printf("%c ", front->_Data);
QueuePop(&q);
//如果出队的元素子树不为空,则入队。
if (front->left)
QueuePush(&q, front->left);
if (front->right)
QueuePush(&q, front->right);
}
//队内元素为0时层序遍历完整棵树。
}