二叉树操作
一.二叉树的二叉链表的创建以及遍历
1.二叉链表的创建
对于二叉树的链表储存也是按遍历的过程来进行的,下面是按照先序遍历的方式来进行的,首先构建二叉树带空置指针的先序次序,依此作为输入顺序。代码如下(0代表空节点)
void CreatBiTree(BiTree* T)
{//使用二级指针将其返回
char ch;
cin >> ch;
if (ch == '0')
*T = NULL;
else
{
*T = new (TNode);//要注意数据类型,不要搞错了
(*T)->Data = ch;
CreatBiTree(&((*T)->Left));
CreatBiTree(&((*T)->Right));
}
}
//二叉树的递归创建(返回)
BiTree CreatBiTree()
{
char ch;
BiTree T;
T = new (TNode);
cin >> ch;
if (ch == '0')
T=NULL;
else
{
T->Data = ch;
T->Left = CreatBiTree();
T->Right = CreatBiTree();
}
return T;
}
### 2.遍历输出
对于二叉树的遍历输出可以有三种情况:先序,后续,中序。基于这三种情况有递归和非递归方法的实现,实现如下:
#### (1)递归
对于递归算法,首先我们确定结束条件为节点为空,然后递归的方法,先遍历根节点的左子树,在遍历右子树,而三种情况的输出,只不过是输出顺序不同。代码如下:
```c++
//二叉树的递归先序遍历
void BiTreePreOrder(BiTree T)
{
if (T == NULL)
return;
cout << T->Data;//输出
BiTreePreOrder(T->Left);
BiTreePreOrder(T->Right);
}
//二叉树的递归中序遍历
void BiTreeInOrder(BiTree T)
{
if (T == NULL)
return;
BiTreeInOrder(T->Left);
cout << T->Data;
BiTreeInOrder(T->Right);
}
//二叉树的递归后续遍历
void BiTreePostOrder(BiTree T)
{
if (T == NULL)
return;
BiTreePostOrder(T->Left);
BiTreePostOrder(T->Right);
cout << T->Data;
}
(2)非递归
对于非递归的实现,我们可以思考一下,以先序为例,第一个输出元素是最左边的最下面那个叶子节点,然而它相对于根结点的左子树,打印却是在第一个,它应该是根结点的左子树遍历的最后一个,却最先打印。刚刚好与栈的特性相似,后进先出。所以我们可以利用栈来实现二叉树的的非递归算法。代码如下:
void NoBiTreePreOrder(BiTree T)
{
stack<BiTree> s;
BiTree p;
if (T == NULL)
return;
p = T;
while (!(p == NULL && s.empty()))
{
while (p != NULL)
{
cout << p->Data;
s.push(p);//将非叶子节点存入
p = p->Left;//找完左子树,找子右树
}
if (s.empty())
return;
else
{
p = s.top();
s.pop();
p = p->Right;
}
}
}
void NoBiTreeInOrder(BiTree T)
{
stack<BiTree> s;
BiTree p;
if (T == NULL)
return;
p = T;
while (!(p == NULL && s.empty()))
{
while (p != NULL)
{
s.push(p);//将节点存入
p = p->Left;//找完左子树,找子右树
}
if (s.empty())
return;
else
{
p = s.top();
cout << p->Data;
s.pop();
p = p->Right;
}
}
}
void NoBiTreePostOrder(BiTree T)
{
stack<BiTree> s;
BiTree p;
if (T == NULL)
return;
p = T;
while (!(p == NULL && s.empty()))
{
while (p != NULL)
{
s.push(p);//将节点存入
p = p->Left;//找完左子树,找子右树
}
if (s.top()->flag== 1)//要注意是栈顶元素,不是p;
{
p = s.top()->Right;
s.top()->flag = 2;
}
else if(s.top()->flag ==2)
{
p = s.top();
cout << p->Data;
s.pop();
p = NULL;
}
}
}
(3)层次遍历
相对于上面的遍历方法,层次遍历需要一层层往下,先是根结点,在是根节点的左孩子,然后是右孩子,所以要把左右孩子都存入一个数据结构,然后根节点先存,先输出,所以我们选择队列,将根节点存入队列,出队列,打印,如果有左孩子存入,再判断如果有右孩子继续存入,再出队列,在判断出队列这个节点的左右孩子情况,有存入,无跳过。依次循环,直到队列为空。(也可以这样理解:自己将一个二叉树的层次遍历结果写出来,你会发现,先写如果要输出是先写先输出,最前面的最先输出,也可以看成队列)代码如下:
void LevelBiTree(BiTree T)
{
queue<BiTree> q;
BiTree b;
if (T == NULL)
return;
int i = 0;
q.push(T);//先存入根节点
while (!q.empty())
{
b = q.front();
q.pop();//出对列
cout << b->Data;
if (b->Left != NULL)//左孩子不为空存入
{
i++;
q.push(b->Left);
}
if (b->Right != NULL)//右孩子不为空存入
{
i++;
q.push(b->Right);
}
}
}
二.后序遍历求中序
eg:
7//节点个数
2 3 1 5 7 6 4//后序遍历
1 2 3 4 5 6 7//中序遍历
我们知道后续遍历的最后一个值就是根节点,在中序遍历中根节点左边为左子树,右边为右子树。通过这种我们可以采用递归,逐步的找根节点,拆分成左右子树。
以这题为例,后序遍历最后一个元素是4,所以4为根节点,在中序中找到4,前面为1,2,3。后面为5,6,7。4的左子树为1,2,3。
右子树为5,6,7。后序中的前3个元素就是左子树,然后排序为2,3,1,所以1为根节点,在到中序中1左边没有,即1只有右子树
2,3就为1的右子树,后序中排序为2,3。3为根节点,中序中2在3的左边,即2为3的左子树,到此4的左子树全部恢复(如下图)。右节点类似。
#include <iostream>
#include<string>
using namespace std;
typedef struct TNode* Position;
typedef Position BiTree;
struct TNode {
char Data;
BiTree Left;
BiTree Right;
};
BiTree ReBiTree(char s1[],char s2[],int n);
BiTree PreInOd(char s1[],int i,int j,char s2[],int m,int n);
void PreorderPrintLeaves(BiTree BT);
int main()
{
int n;
char s1[31], s2[31];
cin >> n;
int i;
for (i = 0; i < n; i++)
{
cin >> s1[i];
}
for (i = 0; i < n; i++)
{
cin >> s2[i];
}
BiTree B;
B=ReBiTree(s1, s2, n);
PreorderPrintLeaves(B);
return 0;
}
BiTree ReBiTree(char s1[], char s2[], int n)//如果n<0,不用恢复
{
if (n <= 0)
return 0;
else
return PreInOd(s1, 0, n-1, s2, 0, n-1);
}
BiTree PreInOd(char s1[], int i, int j, char s2[], int k, int h)//恢复
{ //i,j代表在后序中子树的范围,k,h代表在中序中子树的范围
struct TNode *B;
B = new struct TNode;
B->Data = s1[j];//后序最后一个元素为根节点
int m=0;
m=k;
while(s2[m]!=s1[j])//求根节点在中序的位置
m++;
if (m == k)
B->Left = NULL;
else
B->Left= PreInOd(s1,i,i+m-k-1, s2, k, m - 1);
if (m == h)
B->Right = NULL;
else
B->Right=PreInOd(s1, i + m-k, j-1, s2, m + 1, h);
return B;
}
void PreorderPrintLeaves(BiTree BT)
{
if (BT == NULL)
return;
cout << BT->Data;
PreorderPrintLeaves(BT->Left);
PreorderPrintLeaves(BT->Right);
}
三.前序遍历加中序恢复
与上面类似。
前序的第一元素为根节点,还是找根节点在中序中分成左右子树递归求解
代码如下:
#include <iostream>
#include<string>
using namespace std;
typedef struct TNode* Position;
typedef Position BiTree;
struct TNode {
char Data;
BiTree Left;
BiTree Right;
};
BiTree ReBiTree(char s1[],char s2[],int n);
BiTree PreInOd(char s1[],int i,int j,char s2[],int m,int n);
void PreorderPrintLeaves(BiTree BT);
int main()
{
int n;
char s1[31], s2[31];
cin >> n;
int i;
for (i = 0; i < n; i++)
{
cin >> s1[i];
}
for (i = 0; i < n; i++)
{
cin >> s2[i];
}
BiTree B;
B=ReBiTree(s1, s2, n);
PreorderPrintLeaves(B);
return 0;
}
BiTree ReBiTree(char s1[], char s2[], int n)//如果n<0,不用恢复
{
if (n <= 0)
return 0;
else
return PreInOd(s1, 0, n-1, s2, 0, n-1);
}
BiTree PreInOd(char s1[], int i, int j, char s2[], int k, int h)//恢复
{ //i,j代表在前序中子树的范围,k,h代表在中序中子树的范围
struct TNode *B;
B = new struct TNode;
B->Data = s1[i];//前序第一个一个元素为根节点
int m=0;
m=k;
while(s2[m]!=s1[i])//求根节点在中序的位置
m++;
if (m == k)
B->Left = NULL;
else
B->Left= PreInOd(s1,i+1,i+m-k, s2, k, m - 1);
if (m == h)
B->Right = NULL;
else
B->Right=PreInOd(s1, i + m-k+1, j, s2, m + 1, h);
return B;
}
void PreorderPrintLeaves(BiTree BT)
{
if (BT == NULL)
return;
cout << BT->Data;
PreorderPrintLeaves(BT->Left);
PreorderPrintLeaves(BT->Right);
}
三。二叉链表的创建以及