一、层序遍历的应用:
镜像:还需要引入队列,同上一篇博客。
.h
# pragma once
# include<assert.h>
# include<malloc.h>
# include<stdio.h>
# include<stdlib.h>
# include<string.h>
# include"Queue.h"
typedef char BTDataType;
typedef struct BinTreeBTNode
{
struct BinTreeBTNode* _pLeft;
struct BinTreeBTNode* _pRight;
BTDataType _data;
}BTBTNode,*PBTNode;
PBTNode BuyBinTreeBTNode(BTDataType data);
void _CreateBinTree(PBTNode* pRoot, BTDataType array[], int size, int* index, BTDataType invalid);
void CreateBinTree(PBTNode* pRoot, BTDataType array[], int size, BTDataType invalid);
//拷贝一棵树,根加左子树加右子树
PBTNode CopyBinTree(PBTNode pRoot);
//二叉树的前需遍历:根+左子树+右子树
void PreOrder(PBTNode pRoot);
//中序遍历:左子树+根节点+右子树
void InOrder(PBTNode pRoot);
//后序遍历:左子树+右子树+根节点
void PostOrder(PBTNode pRoot);
void DestroyBinTree(PBTNode* pRoot);
void MirrorBinTree(PBTNode pRoot);
void MirrorBinTreeNor(PBTNode pRoot);
.c
# include"BinaryTree.h"
//#define NULL 0
PBTNode BuyBinTreeNode(DataType data)
{
PBTNode pNewNode = (PBTNode)malloc(sizeof(Node));
if (NULL == pNewNode)
{
assert(0);
return NULL;
}
pNewNode->_data = data;
pNewNode->_pLeft = NULL;
pNewNode->_pRight = NULL;
return pNewNode;
}
void _CreateBinTree(PBTNode* pRoot, DataType array[], int size, int* index, DataType invalid)
{
assert(pRoot);//此时pRoot代表外部实参的地址,可以改变指向
assert(index);
if (*index < size&&invalid != array[*index]){
*pRoot = BuyBinTreeNode(array[*index]);
//创建根节点的左子树
++(*index);
_CreateBinTree(&(*pRoot)->_pLeft, array, size, index, invalid);
//创建根节点的右子树
++(*index);
_CreateBinTree(&(*pRoot)->_pRight, array, size, index, invalid);
}
}
void CreateBinTree(PBTNode* pRoot, DataType array[], int size, DataType invalid)
{
int index = 0;
_CreateBinTree(pRoot, array, size, &index, invalid);
}
//拷贝一棵树,根加左子树加右子树
PBTNode CopyBinTree(PBTNode pRoot){
PBTNode pNewRoot = NULL;
if (pRoot){
//拷贝根节点
pNewRoot = BuyBinTreeNode(pRoot->_data);
//拷贝根节点的左子树
if (pRoot->_pLeft)
pNewRoot->_pLeft = CopyBinTree(pRoot->_pLeft);
//拷贝根节点的右子树
if (pRoot->_pRight)
pNewRoot->_pRight = CopyBinTree(pRoot->_pRight);
}
return pNewRoot;
}
//二叉树的前需遍历:根+左子树+右子树
void PreOrder(PBTNode pRoot)
{
if (pRoot)
{
printf("%c ", pRoot->_data);
PreOrder(pRoot->_pLeft);
PreOrder(pRoot->_pRight);
}
}
//中序遍历:左子树+根节点+右子树
void InOrder(PBTNode pRoot)
{
if (pRoot)
{
InOrder(pRoot->_pLeft);
printf("%c ", pRoot->_data);
InOrder(pRoot->_pRight);
}
}
//后序遍历:左子树+右子树+根节点
void PostOrder(PBTNode pRoot)
{
if (pRoot)
{
PostOrder(pRoot->_pLeft);
PostOrder(pRoot->_pRight);
printf("%c ", pRoot->_data);
}
}
void LevelOrder(PBTNode pRoot)
{
Queue q;
if (NULL == pRoot)
return;
QueueInit(&q);//初始化根节点
//把根节点的地址加到树里面
QueuePush(&q, pRoot);
while (!QueueEmpty(&q)){
//遍历
PBTNode pCur = QueueFront(&q);
printf("%c ", pCur->_data);
//QueuePop(&q);出队列的操作也可以放在这个位置上
//把元素放到队列里
if (pCur->_pLeft)
QueuePush(&q, pCur->_pLeft);
if (pCur->_pRight)
QueuePush(&q, pCur->_pRight);
//从队列里面拿出去
QueuePop(&q);
}
}
void DestroyBinTree(PBTNode* pRoot)
{
assert(pRoot);
if (*pRoot){
//销毁左子树
DestroyBinTree(&(*pRoot)->_pLeft);
//销毁右子树
DestroyBinTree(&(*pRoot)->_pRight);
//销毁根节点
free(*pRoot);
*pRoot = NULL;
}
}
void Swap(PBTNode* pLeft, PBTNode* pRight)
{
PBTNode tmp = *pLeft;
*pLeft = *pRight;
*pRight = tmp;
}
//非递归实现
void MirrorBinTreeNor(PBTNode pRoot){
Queue q;
if (NULL == pRoot)
return;
QueueInit(&q);
QueuePush(&q, pRoot);
while (!QueueEmpty(&q))
{
//如果当前队列不为空,取对头元素
PBTNode pCur = QueueFront(&q);
//交换左右孩子
Swap(&(pCur->_pLeft),&(pCur->_pRight));
if (pCur->_pLeft)
QueuePush(&q, pCur->_pLeft);//将左孩子写入
if (pCur->_pRight)
QueuePush(&q, pCur->_pRight);
}
}
//递归实现镜像
void MirrorBinTree(PBTNode pRoot)
{
if (pRoot)
{
Swap(&(pRoot->_pLeft), &(pRoot->_pRight));
MirrorBinTree(pRoot->_pLeft);
MirrorBinTree(pRoot->_pRight);
}
}
void TestBinTree()
{
char* str = "ABD###CE##F";
PBTNode pRoot = NULL, pNewRoot;
CreateBinTree(&pRoot, str, strlen(str), '#');
pNewRoot = CopyBinTree(pRoot);
printf("前序遍历:");
PreOrder(pRoot);
printf("\n");
printf("中序遍历:");
InOrder(pRoot);
printf("\n");
printf("后序遍历:");
PostOrder(pRoot);
printf("\n");
printf("层序遍历:");
LevelOrder(pRoot);
MirrorBinTree(pRoot);
MirrorBinTreeNor(pRoot);
printf("层序遍历:");
LevelOrder(pRoot);
}
//A B D # # # C E #
二、
1、求二叉树中结点总的个数;
递归调用的时间复杂度:递归调用总的次数*每次递归调用的次数,一个结点两个指针域,n个结点则有2*n个指针域;每个指针域都是一次函数调用,递归程序总的调用次数为2n,每一次调用了两次,则为4n。所以节点总的个数为O(n)。
int BinTreeSize(PBTNode pRoot)
{
if (NULL == pRoot)
return 0;
int left = BinTreeSize(pRoot->_pLeft);
int right = BinTreeSize(pRoot->_pRight);
return left + right + 1;
}
测试的代码:
void TestBinTree()
{
char* str = "ABD###CE##F";
PBTNode pRoot = NULL, pNewRoot;
CreateBinTree(&pRoot, str, strlen(str), '#');
pNewRoot = CopyBinTree(pRoot);
printf("前序遍历:");
PreOrder(pRoot);
printf("\n");
printf("中序遍历:");
InOrder(pRoot);
printf("\n");
printf("后序遍历:");
PostOrder(pRoot);
printf("\n");
printf("层序遍历:");
LevelOrder(pRoot);
MirrorBinTree(pRoot);
MirrorBinTreeNor(pRoot);
printf("层序遍历:");
LevelOrder(pRoot);
printf("\n");
printf("二叉树中结点的个数为:%d\n", BinTreeSize(pRoot));
}
2、二叉树中叶子节点的总的个数
叶子节点:没有孩子的节点,度为0的节点
int BinTreeLeaf(PBTNode pRoot)
{
if (pRoot == NULL)
return 0;
if (NULL == pRoot->_pLeft&&NULL == pRoot->_pRight)
//左孩子和右孩子都为空,则只有一个叶子节点
return 1;
return BinTreeLeaf(pRoot->_pLeft) + BinTreeLeaf(pRoot->_pRight);
}
测试代码:
printf("二叉树中叶子结点的个数为:%d\n", BinTreeLeaf(pRoot));
3、判断一个节点是否在一棵二叉树中
struct BinaryTree
{
BinaryTree(char data)
:_pLeft(NULL)
, _pRight(NULL)
, _data(data)
{}
BinaryTree *_pLeft;
BinaryTree *_pRight;
char _data;
};
//创建二叉树
void CreateBinaryTree(BinaryTree *&pRoot, char *str,size_t size, size_t &index)
{
if (index < size && str[index] != '#')
{
pRoot = new BinaryTree(str[index]);
CreateBinaryTree(pRoot->_pLeft, str, size, ++index);
CreateBinaryTree(pRoot->_pRight, str, size, ++index);
}
}
//递归实现
bool IsNodeInTree(BinaryTree *pRoot,BinaryTree *pNode)
{
if (NULL == pRoot || NULL == pNode)
return false;
if (pRoot->_data == pNode->_data)
return true;
if (IsNodeInTree(pRoot->_pLeft, pNode) || IsNodeInTree(pRoot->_pRight, pNode))
return true;
return false;
}
4、获取一个节点的双亲节点
5、获取一个节点的左孩子节点
6、获取一个节点的右孩子节点
7、判断一棵二叉树是否为完全二叉树(层序遍历变形)
1>如果树为空,则直接返回错
2>如果树不为空:层序遍历二叉树
2.1>如果一个结点左右孩子都不为空,则pop该节点,将其左右孩子入队列;
2.1>如果遇到一个结点,左孩子为空,右孩子不为空,则该树一定不是完全二叉树;
2.2>如果遇到一个结点,左孩子不为空,右孩子为空;或者左右孩子都为空;则该节点之后的队列中的结点都为叶子节点;该树才是完全二叉树,否则就不是完全二叉树;
int IsCompleteBinTree(pNode pRoot)
{
Queue q;
int flag=0;
if (NULL==pRoot)
return 1;
QueueInit(&q);
QueuePush(&q,pRoot);
while (!QueueEmpty(&q))
{
pNode pCur=QueueFront(&q);
if (flag)
{
if (pCur->_pLeft||pCur->_pRight)
return 0;
}
else
{
if (pCur ->_pLeft&&pCur->_pRight)
{
QueuePush(&q,pRoot->_pLeft);
QueuePush(&q,pRoot->_pRight);
}
else if (pCur->_pRight)
return 0;
else if(pCur->_pLeft) {
QueuePush(&q,pRoot->_pLeft);
flag=1;
}
else
flag=1;
QueuePop(&q);
}
}
return 1;
}
bool IsCompleteTree(BinaryTreeNode *pRoot)
{
if(pRoot == NULL)
return false;
queue<BinaryTreeNode*> q;
q.push(pRoot);
BinaryTreeNode* pCur = q.front();
while(pCur != NULL)
{
q.pop();
q.push(pCur -> left);
q.push(pCur -> right);
pCur = q.front();
}
q.pop();//把空pop出来
//因为以经有一个空了,所以只要头不为空就不是完全二叉树
while(! q.empty())
{
if(q.front() != NULL)
return false;
q.pop();
}
return true;
}