数据结构:二叉树(C++)

#include<iostream>
#include<vector>
using namespace std;

#define MAXSIZE 100
#define OK 1
#define ERROR 0

typedef int ElemType;
typedef int Status;

// 二叉树的定义
typedef struct BiNode
{
    ElemType data;
    struct BiNode* lchild, * rchild;
}BiNode, * BiTree;


// 二叉树的先序遍历 DLR
bool PreOrderTraverse(BiTree& T)
{
    if (T == nullptr)
    {
        return true;
    }
    //访问根结点
    // visit(T);
    cout << T->data << endl;
    //递归遍历左孩子
    PreOrderTraverse(T->lchild);
    //递归遍历右孩子
    PreOrderTraverse(T->rchild);
    return true;
}


// 二叉树的中序遍历 LDR
bool InOrderTraverse(BiTree& T)
{
    if (T == nullptr)
    {
        return true;
    }
    //第一步:访问左孩子
    InOrderTraverse(T->lchild);
    //第二步:访问根结点
    //visit(T);
    cout << T->data << endl;
    //第三步:访问右孩子
    InOrderTraverse(T->rchild);
    return true;
}


// 二叉树的后序遍历 LRD
bool PostOrderTraverse(BiTree& T)
{
    if (T == nullptr)
    {
        return true;
    }
    //第一步:访问左孩子
    PostOrderTraverse(T->lchild);
    //第二步:访问右孩子
    PostOrderTraverse(T->rchild);
    //第三步:访问根结点
    //visit(T);
    cout << T->data << endl;
    return true;
}

/*
三种算法的时间复杂度:O(n),空间复杂度:O(n)

三种算法的思想都是DFS(深度优先算法)
*/


// 二叉树的中序遍历——非递归算法
void LDR(BiTree& T)
{
    //第一步:创建一个栈,用于保存二叉树的结点
    SqStack S;
    InitSqStack(S);
    BiTree p = T;
    while (p || !IsEmpty(S))
    {
        if (p)
        {
            Push(S, p);
            p = p->lchild;
        }
        else
        {
            Pop(S, p);
            // visit(p);
            cout << p->data << endl;
            p = p->rchild;
        }
    }
}


// 二叉树的层次遍历算法
void LevelOrder(BiTree& S)
{
    /*
    算法设计思路:
    1.将根结点入队
    2.队列不为空时循环,从队列中出列一个元素,访问它,并作以下步骤:
        2.1 如果该元素的左孩子不为空,让该元素的左孩子入队
        2.2 如果该元素的右孩子不为空,让该元素的右孩子入队
    */
    SqQueue Q;
    InitSqQueue(Q);

    BiTree p;
    PushQueue(Q, S);
    while (!QueueEmpty(Q))
    {
        //将根结点出队
        DeQueue(Q, p);
        //访问根结点
        cout << p->data << endl;
        //if判断,是否能将根结点的左右孩子进队
        //p指针是在队列元素出队时所赋予的,
        //算法里让p指针移动的动作就是把出队元素的地址直接赋给p
        if (p->lchild != nullptr)
        {
            PushQueue(Q, p->lchild);
        }
        if (p->rchild != nullptr)
        {
            PushQueue(Q, p->rchild);
        }
    }
}
// 思想是广度优先算法BFS


//二叉树的建立(DLR先序遍历,递归算法)
bool CreatBiTree(BiTree& T)
{
    ElemType input;
    cin >> input;
    if (input == -1)//建立空结点的标志为 -1(这个自己设定一个就好)
        return false;
    T = new BiNode;
    //D
    T->data = input;
    //L
    CreatBiTree(T->lchild);
    //R
    CreatBiTree(T->rchild);
    return true;
}


// 二叉树的复制
bool CopyBiTree(const BiTree& T, BiTree& NewT)
{
    if (T == nullptr)
    {
        return false;
    }
    NewT = new BiNode;
    //D
    NewT->data = T->data;
    //L
    CopyBiTree(T->lchild, NewT->lchild);
    //R
    CopyBiTree(T->rchild, NewT->rchild);
    return true;
}


// 计算二叉树的深度
int Depth(BiTree& T)
{
    if (T == nullptr)
    {
        return 0;
    }
    int m = Depth(T->lchild);
    int n = Depth(T->rchild);
    if (m > n)
        return m + 1;
    else
        return n + 1;
}


// 求二叉树的结点数
int CountNode(BiTree& T)
{
    if (T == nullptr)
    {
        return 0;
    }
    // //L
    // int m = CountNode(T->lchild);
    // //R
    // int n = CountNode(T->rchild);
    // //
    // return m + n + 1;
    //更加简单的语句
    return CountNode(T->lchild) + CountNode(T->rchild) + 1;
}


// 求二叉树的叶子结点数
int Count0Node(BiTree& T)
{
    //③:递归函数将上一个结点剖分成左右子树,如果结点的孩子为空,那么返回0
    //这里不会出现结点的两个孩子都是空的,因为上一个结点执行这个递归函数的时候就已经判断了这种情况
    //这个语句只是为了以下两种情况而存在的:
    //1. 空树
    //2. 某个分支结点只有一个孩子
    if (T == nullptr)
    {
        return 0;
    }
    if (T->lchild == nullptr && T->rchild == nullptr)
    {
        return 1;
    }
    //如果不是这个情况,就说明这个根结点至少有一个孩子,还要继续剖分这个结点
    return Count0Node(T->lchild) + Count0Node(T->rchild);
}



// 哈夫曼树
// 哈夫曼树的定义
typedef struct HNode
{
    int weight;                 //权重
    int parent, lchild, rchild; //每个结点的双亲、左右孩子的数组下标
}HNode, * HuffmanTree;


// 哈夫曼树的初始化
void InitHTree(HuffmanTree& H, const int n)
{
    //哈夫曼树的存储结构为顺序存储
    //由哈夫曼树的构造过程得知,n个权重结点构造出的哈夫曼树具有2*n-1个结点
    //通常哈夫曼树的顺序存储结构下标从1开始计数,因此,如果我们使用数组实现的话
    //那么数组的长度应该是2*n
    H = new HNode[2 * n];
    for (int i = 1; i < 2 * n; i++)
    {
        H[i].parent = H[i].lchild = H[i].rchild = 0;//右结合律
    }
    int input;
    for (int i = 1; i <= n; i++)
    {
        cin >> input;
        H[i].weight = input;
    }
}


// 哈夫曼树的构造算法
/*
1、构造森林全是根
2、选用两小造新树
3、删除两小添新人
4、重复2、3剩单根
*/ 
// 哈夫曼树的结点的度数为0或1,没有度为1的结点
// 包含n个叶子结点的哈夫曼树共有2n-1个结点
void CreatHuffman(HuffmanTree& H, const int length)
{
    //第一步:对哈夫曼树进行初始化
    InitHTree(H, length);
    //第二步:找出当前森林中最小的两棵树,创建新树,并让原来的两个树作为新树的孩子
    for (int i = length + 1; i < 2 * length; i++)
    {
        int i1 = 0, i2 = 0;
        Select(H, i - 1, i1, i2);//重点是这个Select算法
        H[i].weight = H[i1].weight + H[i2].weight;//
        H[i1].parent = H[i2].parent = i;
        H[i].lchild = i1;
        H[i].rchild = i2;
    }
}
// Select算法
void Select(HuffmanTree& H, const int n, int& i1, int& i2)
{
    vector<int> vec;
    for (int i = 1; i <= n; i++)
    {
        if (H[i].parent == 0)// 插入没有双亲结点的结点
        {
            vec.push_back(i);// 在vec的最后一个元素后面插入元素,其值为i
        }
    }
    //找出最小的一个
    auto flag1 = vec.begin();
    for (auto it = vec.begin() + 1; it != vec.end(); it++)
    {
        if (H[*it].weight < H[*flag1].weight)
        {
            flag1 = it;
        }
    }
    i1 = *flag1; //最小的元素下标
    vec.erase(flag1);
    auto flag2 = vec.begin();
    for (auto it = vec.begin() + 1; it != vec.end(); it++)
    {
        if (H[*it].weight < H[*flag2].weight)
        {
            flag2 = it;
        }
    }
    i2 = *flag2; //第二小的元素的下标
}


// 哈夫曼编码算法
void HuffmanCode(HuffmanTree& H, const int n)
{
    //第一步:调用函数创建一个顺序存储结构的哈夫曼树,同上的函数一样
    CreatHuffman(H, n);
    //第二步:遍历哈夫曼树中每一个叶子结点,也即哈夫曼数组中的前n个元素
    for (int i = 1; i <= n; i++)
    {
        int chd = i;
        int par = H[chd].parent;
        //自下而上得到哈夫曼编码,用栈来保存再合适不过了
        SqStack S;
        InitStack(S);
        while (par != 0)
        {
            // 左分支标注0,右分支标注1
            H[par].lchild == chd ? /*0进栈*/ Push(S, 0) : /*1进栈*/ Push(S, 1);
            chd = par;
            par = H[chd].parent;
        }
        //出栈//黑框中打印编码
        while (!IsEmpty(S))
        {
            int out;
            Pop(S, out);
            cout << out;
        }
        cout << endl;
    }
}




  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,我可以回答你关于数据结构实验6的问题。C++实现二叉树类的具体实现如下: ```cpp #include <iostream> using namespace std; // 节点结构体 struct TreeNode { int val; TreeNode* left; TreeNode* right; TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} }; // 二叉树类 class BinaryTree { public: BinaryTree() : root(nullptr) {} // 插入节点 void insert(int val) { if (root == nullptr) { root = new TreeNode(val); return; } TreeNode* cur = root; while (cur != nullptr) { if (val < cur->val) { if (cur->left == nullptr) { cur->left = new TreeNode(val); return; } cur = cur->left; } else { if (cur->right == nullptr) { cur->right = new TreeNode(val); return; } cur = cur->right; } } } // 查找节点 bool find(int val) { TreeNode* cur = root; while (cur != nullptr) { if (cur->val == val) { return true; } else if (cur->val > val) { cur = cur->left; } else { cur = cur->right; } } return false; } // 删除节点 void remove(int val) { root = removeNode(root, val); } // 中序遍历 void inorder() { inorderTraversal(root); } private: // 根节点 TreeNode* root; // 删除节点 TreeNode* removeNode(TreeNode* root, int val) { if (root == nullptr) return root; if (val < root->val) { root->left = removeNode(root->left, val); } else if (val > root->val) { root->right = removeNode(root->right, val); } else { if (root->left == nullptr) { TreeNode* rightChild = root->right; delete root; return rightChild; } else if (root->right == nullptr) { TreeNode* leftChild = root->left; delete root; return leftChild; } else { TreeNode* minNode = findMin(root->right); root->val = minNode->val; root->right = removeNode(root->right, minNode->val); } } return root; } // 查找最小节点 TreeNode* findMin(TreeNode* root) { while (root->left != nullptr) { root = root->left; } return root; } // 中序遍历 void inorderTraversal(TreeNode* root) { if (root == nullptr) return; inorderTraversal(root->left); cout << root->val << " "; inorderTraversal(root->right); } }; ``` 以上是基本的二叉树类实现,包括了插入节点、查找节点、删除节点和中序遍历等操作。你可以根据需要进行修改和扩展。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

捕捉一只Diu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值