数据结构与算法实验2——二叉树的应用

一、实验目的

1.掌握二叉树的存储实现。

2.掌握二叉树的遍历思想。

3.掌握二叉树的常见算法的程序实现。

二、实验任务

1.输入字符序列,建立二叉链表。

2.中序遍历二叉树:递归算法。

3.中序遍历二叉树:非递归算法。(最好也实现先序,后序非递归算法)

4.求二叉树的高度。

5.求二叉树的叶子数。

6.借助队列实现二叉树的层次遍历。

7.在主函数中设计一个简单的菜单,调用上述算法。

三、源代码

源文件

/*
实验名称:二叉树的应用
实验目的:
1.掌握二叉树的存储实现。
2.掌握二叉树的遍历思想。
3.掌握二叉树的常见算法的程序实现。
实验内容:
1.输入字符序列,建立二叉链表。
2.中序遍历二叉树:递归算法。
3.中序遍历二叉树:非递归算法。(最好也实现先序,后序非递归算法)
4.求二叉树的高度。
5.求二叉树的叶子数。
6.借助队列实现二叉树的层次遍历。
7.在主函数中设计一个简单的菜单,调用上述算法。
实验日期:2020/12/6                                                                                                                                                                                                               
开发者:每天八杯水
*/
#include "BinTree.h"
int Out();
pBiTree DGCreatBinTree();//递归创建二叉树
void InOrder_Recursion();//递归中序遍历
pBiTree CreatBTree_NRecursion();//非递归创建二叉树
void InOrder_NRecursion();//非递归中序遍历
int CountLever();//统计二叉树的深度
int CoumtLeafNode();//统计二叉树的叶子数
void LevelOrder();//层次遍历二叉树
pBiTree SF();//释放空间-采用递归删除结点

int main()
{
    cout << "\n";
    pBiTree bt;//定义一个结点bt存放创建好的二叉树
    //bt=DGCreatBinTree(); //递归创建二叉链表
    bt= CreatBTree_NRecursion();//非递归创建
    bool opt = true;  //是否循环的一个标志
    while (opt == true) {
        //菜单列表
        cout << "\n\t\t************************************\n";
        cout << "\t\t*      WELCOM TO MY WORLD          *\n";
        cout << "\t\t*   1.    中序遍历-递归            *\n";
        cout << "\t\t*   2.    中序遍历-非递归          *\n";
        cout << "\t\t*   3.    求二叉树的高度           *\n";
        cout << "\t\t*   4.    求二叉树的叶子数         *\n";
        cout << "\t\t*   5.    层次遍历                 *\n";
        cout << "\t\t*   6.    释放空间                 *\n";
        cout << "\t\t*   7.      退 出                  *\n";
        cout << "\t\t************************************\n";
        //接收输入选择
        cout << "\t\t请选择:";
        char x;
        cin >> x;
        //判断用户的选择
        switch (x) {
        case '1':
            cout << "递归中序遍历:";
            InOrder_Recursion(bt);
            opt = Out();        //小目录选择1返回true到循环条件时再次执行主菜单;选择2返回false退出循环
            break;
        case '2':
            cout << "非递归中序遍历:";
            InOrder_NRecursion(bt);
;            opt = Out();        //小目录
            break;
        case '3':
            cout << "该二叉树的高度为:" << CountLever(bt);
            opt = Out();        //小目录
            break;
        case '4':
            cout << "该二叉树的叶子数个数为:" << CoumtLeafNode(bt);  
            opt = Out();        //小目录
            break;
        case '5':
            cout << "层次遍历该二叉树:" ;
            LevelOrder(bt);
            opt = Out();        //小目录
            break;
        case '6':          
            if (SF(bt)==NULL)
            {
                cout << "释放成功" << endl;
            }
            else
            {
                cout << "释放失败" << endl;
                cout << bt->data;
            }
           
            opt = Out();        //小目录
            break;
        case '7':
            cout << "\n\t\t你选择了6\n";
            opt = false;        //把标志位为假,就退出了循环
            break;
        default:
            cout << "\n\t\t输入非法,请重新选择!\n";
            break;
        }
    }
    cout << "\n\t\t菜单已退出!\n";
}


头文件


#pragma once
#include <stdio.h>
#include <iostream>
#include <queue>
#include <stack>
using namespace std;

/*
    定义小目录-进入算法后如何退出的实现
*/
int Out() {
    cout << "\n";
    cout << "\t\t************\n";
    cout << "\t\t*1.返回菜单*\n";
    cout << "\t\t*2.退出程序*\n";//退出,程序结束
    cout << "\t\t************\n";
    cout << "\t\t选择:";
    char y;
    cin >> y;      //接受输入
    switch (y) {
    case '1':
        return true;
    case '2':
        return false;
    default:
        cout << "\t\t非法输入,已返回主目录!\n";//输入其他数字无效
        return true;
        break;
    }
}

/*
    结构类型定义
*/
#define ElemType char // 元素类型
typedef struct BiTNode
{
	ElemType data;
	BiTNode* Lchild, * Rchild;
} BiTNode, * pBiTree;

/*
    递归创建二叉链表
*/
//pBiTree DGCreatBinTree()
//{
//    pBiTree bt;//根结点
//    cout << "\t\t请输入字符建立二叉链表:";
//    ElemType data;
//    cin >> data;
//    if (data == '@')
//        bt = NULL;
//    else
//    {
//        bt = (pBiTree)malloc(sizeof(struct BiTNode));
//        bt->data = data;
//        bt->Lchild = DGCreatBinTree();
//        bt->Rchild = DGCreatBinTree();
//    }
//    return bt;
//}

/*
    非递归创建二叉链表
*/

pBiTree CreatBTree_NRecursion()//非递归创建二叉树-需要使用链队列
{
    pBiTree bt,s,p;
    bt = NULL;
    int count = -1;//计数器-结点编号
    queue<pBiTree>squeue;
    cout << "\t\t请输入字符创建二叉树(@代表空)以#号键结束:";
    char ch;
    ch = getchar();
    while (ch!='#')
    {
        s = NULL;//这里设置的原因是:如果接下来的ch是虚结点,就会跳过赋值,那么该结构体类型的指针为空了
        if (ch != '@')//判断输入的字符是正常地还是表示空的结点
        {
            s = (pBiTree)malloc(sizeof(BiTNode));//*************需要释放空间--递归删除结点**********

            s->data = ch;
            s->Lchild = s->Rchild = NULL;
        }

        squeue.push(s);
        count++;
        if (count == 0)bt = s;//根结点编号为0
        else//count为奇数,是左孩子;偶数是右孩子
        {
            p = squeue.front();//取出-作为父结点
            if(s!=NULL && p!=NULL)//
                if (count % 2 == 1) { p->Lchild = s; }//如果s为@,p左孩子就是空的,奇数就把从队列中取出来的结点左孩子指向它
                else { p->Rchild = s; }
                if (count % 2 == 0) {  squeue.pop(); } //该结点左右孩子已经赋值完毕,可以出队列了
        }
        ch = getchar();
    }
    return bt;
}

/*
    递归中序
*/
void InOrder_Recursion(pBiTree bt)
{
    if (bt == NULL)return;
    InOrder_Recursion(bt->Lchild);
    cout << bt->data;
    InOrder_Recursion(bt->Rchild);
}

/*
    非递归中序
*/
void InOrder_NRecursion(pBiTree bt)//需要使用栈
{
    stack<pBiTree>sstack;
    pBiTree p;
    p = bt;
    if (p == NULL)return;
    sstack.push(bt);
    p = p->Lchild;
    while (p||!sstack.empty())//栈为空返回的0,所以加上!
    {
        while (p != NULL)//一直入栈左孩子直到为空
        {
            sstack.push(p);
            p = p->Lchild;
        }//循环最后一次p为空的左孩子
        p = sstack.top();//给p赋值为栈顶元素->也就是上面那个空的左孩子的父结点   所以取出来输出
        sstack.pop();//因为该栈顶元素的左孩子为空,所以按照中序遍历,下一个应该是D结点,其次是R结点,
        cout << p->data;
        p = p->Rchild;//左孩子为空,就返回到
    }
}

/*
    统计二叉树的深度
*/
int CountLever(pBiTree bt)//递归思想
{
    if (bt == NULL)return 0;//左孩子为空返回个数0,右孩子为空返回0.一次循环结束返回值为1
    else
    {
        int i = CountLever(bt->Lchild);//一直递归到根结点最后一个左孩子、结束该递归条件是左孩子为空
        int j = CountLever(bt->Rchild);//当上一条左孩子为空时,进入右孩子
            return(i > j ? i : j) + 1;//三目运算符
    }

}

/*
    统计二叉树的叶子数
*/
int CoumtLeafNode(pBiTree bt)//有个数的前提条件是该结点的左右孩子都为空时个数加1
{
    if (bt == NULL)return  0;
    else if ((bt->Lchild == NULL) && (bt->Rchild == NULL))return 1;//只要遇见一个左右孩子都是空的结点就个数加1
    else
        return(CoumtLeafNode(bt->Lchild) + CoumtLeafNode(bt->Rchild));//相当于兵分两路,从根结点左孩子和右孩子分别进入
}

/*
    层次遍历二叉树
*/
void LevelOrder(pBiTree bt)//使用队列思想-与非递归建立二叉树思想相同,根结点先入队列,再取队头元素为索引,若孩子不空,把索引左右孩子依次入队,该索引用了就出队
{
    queue<pBiTree>squeue;
    if (bt == NULL)return;
    pBiTree p;
    p = bt;
    squeue.push(bt);
    while (!squeue.empty())//栈空循环结束
    {
        p = squeue.front();
        squeue.pop();
        cout << p->data;
        if(p->Lchild != NULL)//左孩子入队列
            squeue.push(p->Lchild);
        if(p->Rchild != NULL)//紧接着右孩子入队列
            squeue.push(p->Rchild);
    }
}


pBiTree SF(pBiTree bt)
{
    if (bt == NULL)return bt;
    SF(bt->Lchild);
    //cout << bt->data;
    SF(bt->Rchild);
     free(bt);
     bt = NULL;//
    return bt;
}

四、运行结果

 

  • 1
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
1. 什么是二叉树二叉树是一种树形结构,其中每个节点最多有两个子节点。一个节点的左子节点比该节点小,右子节点比该节点大。二叉树通常用于搜索和排序。 2. 二叉树的遍历方法有哪些? 二叉树的遍历方法包括前序遍历、中序遍历和后序遍历。前序遍历是从根节点开始遍历,先访问根节点,再访问左子树,最后访问右子树。中序遍历是从根节点开始遍历,先访问左子树,再访问根节点,最后访问右子树。后序遍历是从根节点开始遍历,先访问左子树,再访问右子树,最后访问根节点。 3. 二叉树的查找方法有哪些? 二叉树的查找方法包括递归查找和非递归查找。递归查找是从根节点开始查找,如果当前节点的值等于要查找的值,则返回当前节点。如果要查找的值比当前节点小,则继续在左子树中查找;如果要查找的值比当前节点大,则继续在右子树中查找。非递归查找可以使用栈或队列实现,从根节点开始,每次将当前节点的左右子节点入栈/队列,直到找到要查找的值或者栈/队列为空。 4. 二叉树的插入与删除操作如何实现二叉树的插入操作是将要插入的节点与当前节点的值进行比较,如果小于当前节点的值,则继续在左子树中插入;如果大于当前节点的值,则继续在右子树中插入。当找到一个空节点时,就将要插入的节点作为该空节点的子节点。删除操作需要分为三种情况:删除叶子节点、删除只有一个子节点的节点和删除有两个子节点的节点。删除叶子节点很简单,只需要将其父节点的对应子节点置为空即可。删除只有一个子节点的节点,需要将其子节点替换为该节点的位置。删除有两个子节点的节点,则可以找到该节点的后继节点(即右子树中最小的节点),将其替换为该节点,然后删除后继节点。 5. 什么是平衡二叉树? 平衡二叉树是一种特殊的二叉树,它保证左右子树的高度差不超过1。这种平衡可以确保二叉树的查找、插入和删除操作的时间复杂度都是O(logn)。常见的平衡二叉树包括红黑树和AVL树。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值