何为二叉树
概念:一棵二叉树是结点的一个有限集合,该集合或者为空,或者是由一个根节点加上两棵分别称为左子树和右子树的二叉树组成
特点:
- 每个结点最多有两棵子树
- 二叉树的子树有左右之分,其子树的次序不能颠倒
基本操作介绍
- 二叉树的遍历(递归和非递归),可以说是所有操作中最重要的
- 求树的结点个数
- 求树的叶子结点的个数
- 求第K层结点的个数
- 求树的高度
- 在树中查找指定元素
- 给定一个结点,查找它的父结点
- 复制一棵二叉树
- 求一个二叉树的镜像(递归和非递归)
- 构建一个二叉树(给出前序遍历结果,带有空结点)
- 还原一个二叉树(给出前序和中序遍历结果,不带空节点)
话不多说,直接附上代码来解释这些操作
结构体声明:
typedef char TreeNodeType;
typedef struct TreeNode{
struct TreeNode* lchild;//左孩子结点
struct TreeNode* rchild;//右孩子结点
TreeNodeType data;
}TreeNode;
函数体声明:
//初始化二叉树
void TreeNodeInit(TreeNode** root);
//先序遍历二叉树
void PreOrder(TreeNode* root);
//中序遍历
void InOrder(TreeNode* root);
//后序遍历
void PostOrder(TreeNode* root);
//层序遍历
void LevelOrder(TreeNode* root);
//求树的节点个数
size_t TreeSize(TreeNode* root);
//求树的叶节点的个数
size_t LeafTreeSize(TreeNode* root);
//求第K层节点的个数
size_t TreeLevelSize(TreeNode* root,size_t k);
//求树的高度
size_t TreeHeight(TreeNode* root);
//在树中查找指定元素
TreeNode* TreeFind(TreeNode* root, TreeNodeType to_find);
//给一个节点,找它的父节点
TreeNode* Parents(TreeNode* root,TreeNode* node);
//非递归遍历二叉树
void PreOrderByLoop(TreeNode* root);//前
void InOrderByLoop(TreeNode* root);//中
void PostOrderByLoop(TreeNode* root);//后
//求一个二叉树的镜像
//递归版
void TreeMirror(TreeNode* root);
//非递归版
void TreeMirrorByLoop(TreeNode* root);
//销毁一棵树
TreeNode* TreeDestroy(TreeNode* root);
嘿嘿,下面开始疯狂的粘贴代码了
简单明了初始化和销毁,不解释
//初始化
void TreeNodeInit(TreeNode** root)
{
if(root == NULL)
{
//非法输入
return;
}
*root = NULL;
}
//销毁单个结点
void Destroy(TreeNode* root)
{
free(root);
}
下面进行递归和非递归的遍历,这个才是最重要的,其他的都可以不管,这个必须要仔细看
//先序遍历(根节点,左子树,右子树)
void PreOrder(TreeNode* root)
{
if(root == NULL)
{
//遇到空节点就返回,递归出口
return;
}
//访问该节点
printf("%c ",root->data); //先访问根节点
PreOrder(root->lchild);//再访问左子树
PreOrder(root->rchild);//再访问右子树
}
//中序遍历(左子树,根节点,右子树)
void InOrder(TreeNode* root)
{
if(root == NULL)
{
return;
}
InOrder(root->lchild);//遍历到最后一个左子树叶子结点
printf("%c ",root->data);//和前序遍历不同就是访问语句调了个位置
InOrder(root->rchild);
}
//后序遍历(左子树,右子树,根节点)
void PostOrder(TreeNode* root)
{
if(root == NULL)
{
return;
}
PostOrder(root->lchild);
PostOrder(root->rchild);
printf("%c ",root->data);//看到这里应该懂了前中后遍历了吧
}
//层序遍历(比较复杂,各位得好好捋一捋)
void LevelOrder(TreeNode* root)
{
if(root == NULL)
{
return;
}
//1.先把根节点插入队列
SeqQueue seq;
SeqQueueInit(&seq);
SeqQueuePush(&seq,root);
//2.循环的取队首元素
while(1){
SeqQueueType node;
int ret = SeqQueueGetTop(&seq,&node);
if(ret == 0)
{
return;
}
//3.访问队首元素并出队列
SeqQueuePop(&seq);
if(node != NULL)
{
printf("%c ",node->data);
//4.将队首元素的左子树节点和右子树节点都依次入队列
SeqQueuePush(&seq,node->lchild);
//5.进入下一次循环,直到队列为空,说明遍历完了
SeqQueuePush(&seq,node->rchild);
}
}
}
//非递归遍历二叉树(前序)
void PreOrderByLoop(TreeNode* root)
{
if(root == NULL)
{
return;
}
SeqStack stack;
SeqStackInit(&stack);
SeqStackPush(&stack,root);
while(1)
{
//取栈顶元素
SeqStackType cur;
int ret = SeqStackFindTop(&stack,&cur);
//如果栈空的话说明已经遍历完了
if(ret == 0)
{
break;
}
//访问栈顶元素并且出栈
SeqStackPop(&stack);
printf("%c ",cur->data);
//先把每个节点的右孩子节点入栈,
//再把左孩子节点入栈,
//保证每次访问完自身后,再访问左子树
if(cur->rchild != NULL)
{
SeqStackPush(&stack,cur->rchild);
}
if(cur->lchild != NULL)
{
SeqStackPush(&stack,cur->lchild);
}
}
printf("\n");
}
//非递归遍历二叉树(中序)
void InOrderByLoop(TreeNode* root)
{
if(root == NULL)
{
return;
}
SeqStack stack;
SeqStackInit(&stack);
SeqStackType cur = root;
while(1)
{
while(cur != NULL)
{
SeqStackPush(&stack,cur);
cur = cur -> lchild;
}
SeqStackType top;
int ret = SeqStackFindTop(&stack,&top);
if(ret == 0)
{
break;
}
printf("%c ",top->data);
SeqStackPop(&stack);
cur = top->rchild;
}
}
//非递归遍历二叉树(后序)
void PostOrderByLoop(TreeNode* root)
{
if(root == NULL)
{
return;
}
SeqStack stack;
SeqStackInit(&stack);
TreeNode* cur = root;
//保存上一个访问的元素
TreeNode* pre = NULL;
while(1)
{
//循环的将左子树入栈
while(cur!=NULL)
{
SeqStackPush(&stack,cur);
cur = cur -> lchild;
}
//取出栈顶元素
SeqStackType top;
int ret = SeqStackFindTop(&stack,&top);
if(ret == 0)
{
return;
}
//在访问前要判断
// 1.它的右子树是否为空
// 2.或者判断它的右子树是否刚被访问过
//满足任意一个条件就可以访问当前元素并将其出栈
if(top->rchild == NULL || top->rchild == pre)
{
printf("%c ",top->data);
SeqStackPop(&stack);
pre = top;
}
//否则cur = cur->rchild ,跳到循环开始继续
else{
cur = top->rchild;
}
}
}
其余小操作
//在树中查找指定元素
TreeNode* TreeFind(TreeNode* root, TreeNodeType to_find)
{
if(root == NULL)
{
return NULL;
}
if(root->data == to_find)
{
return root;
}
TreeNode* Lresult = TreeFind(root->lchild,to_find);
TreeNode* Rresult = TreeFind(root->rchild,to_find);
//时间复杂度为O(n),最坏的情况是所有元素都遍历了也没找到
//空间复杂度也是O(n)
return Lresult == NULL?Rresult:Lresult;
}
//求树的高度
size_t TreeHeight(TreeNode* root)
{
if(root == NULL)
{
return 0;
}
//比较左右两子树的深度,返回深度大的那个
size_t lheight = TreeHeight(root->lchild);
size_t rheight = TreeHeight(root->rchild);
//相当于是调用次数的比较
return lheight >= rheight? lheight+1:rheight+1;
//下面的代码也可以实现相同功能,
//但是函数会被递归调用三次,上一种方式只会被递归调用两次
//所以效率比较低
//return TreeHeight(root->lchild) >= TreeHeight(root->rchild)?TreeHeight(root->lchild):TreeHeight(root->rchild);
}
//求树的叶节点个数
size_t LeafTreeSize(TreeNode* root)
{
if(root == NULL)
{
return 0;
}
if(root->lchild == NULL && root->rchild == NULL)
{
return 1;
}
return LeafTreeSize(root->lchild) + LeafTreeSize(root->rchild);
}
//求第K层节点的个数
size_t TreeLevelSize(TreeNode* root,size_t k)
{
//我们规定树从第一层开始
if(root == NULL || k < 1)
{
return 0;
}
if(k == 1)
{
return 1;
}
return TreeLevelSize(root->lchild,k-1) + TreeLevelSize(root->rchild,k-1);
}
//复制一棵树
TreeNode* TreeClone(TreeNode* root)
{
if(root == NULL)
{
return NULL;
}
TreeNode* newnode = CreateTreeNode(root->data);
newnode->lchild = TreeClone(root->lchild);
newnode->rchild = TreeClone(root->rchild);
return newnode;
}
//求树的节点个数
size_t TreeSize(TreeNode* root)
{
if(root == NULL)
{
return 0;
}
return 1 + TreeSize(root->lchild) + TreeSize(root->rchild);
}
//给一个节点,找它的父节点
TreeNode* Parents(TreeNode* root,TreeNode* node)
{
if(root == NULL)
{
return NULL;
}
if(root->lchild == node || root->rchild == node)
{
return root;
}
TreeNode* Lresult = Parents(root->lchild,node);
TreeNode* Rresult = Parents(root->rchild,node);
return Lresult != NULL? Lresult:Rresult;
}
//求一个二叉树的镜像(递归版)
void TreeMirror(TreeNode* root)
{
if(root == NULL)
{
return;
}
TreeNode* tmp = root->lchild;
root->lchild = root->rchild;
root->rchild = tmp;
TreeMirror(root->lchild);
TreeMirror(root->rchild);
}
//非递归版
void TreeMirrorByLoop(TreeNode* root)
{
if(root == NULL)
{
return;
}
SeqStack stack;
SeqStackInit(&stack);
SeqStackPush(&stack,root);
while(1)
{
SeqStackType top;
int ret = SeqStackFindTop(&stack,&top);
if(ret == 0)
{
return;
}
TreeNode* tmp = top->lchild;
top->lchild = top->rchild;
top->rchild = tmp;
SeqStackPop(&stack);
if(top -> lchild != NULL)
{
SeqStackPush(&stack,top->lchild);
}
if(top -> rchild != NULL)
{
SeqStackPush(&stack,top->rchild);
}
}
}