一、二叉树链式结构的遍历
1、概念:
所谓遍历(Traversal)是指沿着某条搜索路线,依次对树中每个结点均做一次且仅做一次访问。访问结点所做的操作依赖于具体的应用问 题。 遍历是二叉树上最重要的运算之一,是二叉树上进行其它运算之基础。
遍历:按照某种规则,对二叉树中的每个节点进行相应的操作(打印、每个节点值+1),并且每个节点只能操作一次
2、前序/中序/后序的递归结构遍历:是根据访问结点操作发生位置命名
- NLR:前序遍历(Preorder Traversal 亦称先序遍历)——访问根结点的操作发生在遍历其左右子树之前。【根左右】
- LNR:中序遍历(Inorder Traversal)——访问根结点的操作发生在遍历其左右子树之中(间)。【左中右】
- LRN:后序遍历(Postorder Traversal)——访问根结点的操作发生在遍历其左右子树之后。【左右中】
总结:三种遍历方式都是左子树在右子树之前进行遍历
由于被访问的结点必是某子树的根,所以N(Node)、L(Left subtree)和R(Right subtree)又可解释为根、根的左子树和根的右子树。NLR、LNR和LRN分别又称为先根遍历、中根遍历和后根遍历
3、层序遍历:
除了先序遍历、中序遍历、后序遍历外,还可以对二叉树进行层序遍历。设二叉树的根节点所在层数为1,层序遍历就是从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第2层上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。
二、实现链式数据结构的以下基本操作:
typedef struct Node
{
int val;
struct Node *left;
struct Node *right;
} Node;
typedef struct ReturnType
{
int use;// 创建树过程中用掉的值个数
Node *root;// 创建好树的根节点
} ReturnType;
//二叉树的构建及遍历
ReturnType createTree(char preordered[], int size)
{
char rootvalue = preordered[0];
if (rootvalue == '#')
{
ReturnType returnvalue;
returnvalue.root = NULL;
returnvalue.use = 1;
return returnvalue;
}
//前序遍历的第一个值就是根的值,
//所以,取第一个值,创建当前树的根节点
Node *root = (Node *)malloc(sizeof(Node));
root->val = rootvalue;
//用递归的思路创建当前树的
//1)左子树
//需要传入左子树的前序遍历值
ReturnType left = createTree(preordered + 1, size - 1);
//右子树
//需要传入右子树的前序遍历值
//右子树的前序遍历值,需要先计算创建左子树过程中用掉的值个树
ReturnType right = createTree(preordered + 1 + left.use, size - 1 - left.use);
root->left = left.root;
root->right = right.root;
//创建好后,返回
//1)创建好树的根节点
//2)创建树过程中用掉的节点个数
ReturnType returnvalue;
returnvalue.root = root;
returnvalue.use = 1 + left.use + right.use;
return returnvalue;
}
// 拷贝二叉树
Node* CopyBinTree(Node* pRoot)
{
if (pRoot == NULL)
{
return NULL;
}
else
{
Node *copytree = (Node *)malloc(sizeof(Node));
copytree->val = pRoot->val;
copytree->left = pRoot->left;
copytree->right = pRoot->right;
return copytree;
}
}
// 二叉树的三种遍历方式
//前序遍历
void PreOrder(Node* pRoot)
{
if (pRoot == NULL)
{
return;
}
printf("%d", pRoot->val);
PreOrder(pRoot->left);
PreOrder(pRoot->right);
}
//非递归前序遍历
void PreOrderNor(Node* pRoot)
{
Node * cur = pRoot;
std::stack<Node *> st;
while (cur != NULL || !st.empty())
{
while (cur != NULL)
{
printf("%d", cur->val);
st.push(cur);
cur = cur->left;
}
Node *top = st.top();
st.pop();
cur = top->right;
}
}
//中序遍历
void InOrder(Node* pRoot)
{
if (pRoot == NULL)
{
return;
}
InOrder(pRoot->left);
printf("%d", pRoot->val);
InOrder(pRoot->right);
}
//非递归中序遍历
void InOrderNor(Node* pRoot)
{
Node * cur = pRoot;
std::stack<Node *> st;
while (cur != NULL || !st.empty())
{
while (cur != NULL)
{
st.push(cur);
cur = cur->left;
}
Node *top = st.top();
printf("%d", top->val);
st.pop();
cur = top->right;
}
}
//后序遍历
void PostOrder(Node* pRoot)
{
if (pRoot == NULL)
{
return;
}
PostOrder(pRoot->left);
PostOrder(pRoot->right);
printf("%d", pRoot->val);
}
//非递归后序遍历
void PostOrderNor(Node* pRoot)
{
Node *cur = pRoot;
Node *last = NULL;
std::stack<Node *> st;
while (cur != NULL || !st.empty())
{
while (cur != NULL)
{
st.push(cur);
cur = cur->left;
}
Node *top = st.top();
if (top->right == NULL || top->right == last)
{
st.pop();
printf("%d", top->val);
last = top;
}
else
{
cur = top->right;
}
}
}
//层序遍历
void LevelOrder(Node* pRoot)
{
if (pRoot == NULL)
{
return;
}
std::queue<Node *> q;
q.push(pRoot);
while (!q.empty())
{
//取队头元素
Node *front = q.front();
//该元素出队列
q.pop();
printf("%d", front->val);
if (front->left != NULL)
{
//如果节点的左孩子存在--将左孩子存入队列
q.push(front->left);
}
if (front->right != NULL)
{
//如果节点的右孩子存在--将右孩子存入队列
q.push(front->right);
}
}
}
// 获取二叉树中节点的个数
int GetNodeCount(Node* pRoot)
{
if (pRoot == NULL)
{
return 0;
}
int left = GetNodeCount(pRoot->left);
int right = GetNodeCount(pRoot->right);
return left + right + 1;
}
// 求二叉树的高度
int Height(Node* pRoot)
{
if (pRoot == NULL)
{
return 0;
}
int left = Height(pRoot->left);
int right = Height(pRoot->right);
return (left > right ? left : right) + 1;
}
// 检测二叉树是否平衡O(N^2)
//1.判断以根结点的树是否为二叉平衡树。求出左右子树的高度,判断它们的高度差是否超过了1。
//2.递归判断根的左子树是否为平衡二叉树
//3.递归判断根的右子树是否为平衡二叉树
//注意:空树也是平衡二叉树
int IsBalanceTree(Node* pRoot)
{
if (pRoot == NULL)
{
return 1;
}
int left = Height(pRoot->left);
int right = Height(pRoot->right);
int dif = left - right;
if (dif> 1 || dif < -1)
{
return 0;
}
return IsBalanceTree(pRoot->left) && IsBalanceTree(pRoot->right);
}
// 获取二叉数中叶子节点的个数
int GetLeafNodeCount(Node* pRoot)
{
if (pRoot == NULL)
{
return 0;
}
else if (pRoot->left == NULL && pRoot->right == NULL)
{
return 1;
}
else
{
return GetLeafNodeCount(pRoot->left) + GetLeafNodeCount(pRoot->right);
}
}
// 获取二叉树第K层节点的个数
int GetKLevelNodeCount(Node* pRoot, int K)
{
assert(K >= 1);
if (pRoot == NULL)
{
return 0;
}
else if (K== 1)
{
return 1;
}
else
{
return GetKLevelNodeCount(pRoot->left, K - 1) + GetKLevelNodeCount(pRoot->right, K - 1);
}
}
// 判断二叉树是否是完全二叉树
int BinaryTreeComplete(BTNode* root)
{
std::queue<BTNode*> q;
int flag=0;
//空树也是完全二叉树
if (root == NULL)
return 1;
//非空
//1、按照层序遍历规则找第一个不饱和的节点
q.push(root);
while (!q.empty())
{
BTNode* cur = q.front();
if (flag)
{
//后续的节点不能有孩子
if (cur->left || cur->right)
return 0;
}
else
{
//找第一个不饱和的节点
if (cur->left && cur->right)
{
q.push(cur->left);
q.push(cur->right);
}
else if (cur->left)
{
//cur只有左孩子
q.push(cur->left);
flag = 1;
}
else if (cur->right)
{
//只有右孩子
return 0;
}
else
{
flag = 1;
}
}
q.pop();
}
return 1;
}
// 获取二叉树中某个节点的双亲节点
Node* GetNodeParent(Node* pRoot, Node* pNode)
{
if (pRoot == NULL)
{
return 0;
}
GetNodeParent(pRoot->left,pNode);
GetNodeParent(pRoot->right,pNode);
}
// 求二叉树的镜像
void Mirror(Node* pRoot)
{
if (pRoot == NULL)
{
return;
}
swap(pRoot->left,pRoot->right);
Mirror(pRoot->left);
Mirror(pRoot->right);
}