二叉树操作——创建,遍历

二叉树操作

一.二叉树的二叉链表的创建以及遍历

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);
}

三。二叉链表的创建以及

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值