【B战王卓】-数据结构与算法基础-树和二叉树

  • 树的定义

在这里插入图片描述

  • 树的有关概念

在这里插入图片描述
在这里插入图片描述

  • 森林:是m(m>=0)棵互不相交的树的集合

在这里插入图片描述

  • 树结构与线性结构的区别
    • 线性结构(一对一)
    • 树结构(一对多)

二叉树的定义

在这里插入图片描述

  • 二叉树性质和存储结构

在这里插入图片描述

  • 第i层上至少有1个结点
  • 性质2:深度为k的二叉树至多有2的k次方-1个结点(k>=1)
    • 深度为k的二叉树至少有k个结点

在这里插入图片描述

  • 满二叉树

在这里插入图片描述

  • 完全二叉树

在这里插入图片描述

  • 遍历二叉树

在这里插入图片描述

二叉树的遍历操作

#include <iostream>
#include <queue>
#include <vector>
#include <stack>

using namespace std;

typedef struct BiNode
{
    int data;
    struct BiNode *lchild, *rchild;
} *BiTree;

void visit(BiTree &TreeNode)
{
    vector<int> vec;
    if (!TreeNode)
    {
        cerr << "null node" << endl;
    }
    int val = TreeNode->data;
    vec.push_back(val);
    for (vector<int>::iterator it = vec.begin(); it != vec.end(); it++)
    {
        cout << *it << " ";
    }
}

// 先序遍历
bool PreOrderTraverse(BiTree &TreeNode)
{
    if (TreeNode == nullptr)
    {
        return true;
    }
    visit(TreeNode);
    PreOrderTraverse(TreeNode->lchild);
    PreOrderTraverse(TreeNode->rchild);
    return true;
}

// 中序遍历
bool InOrderTraverse(BiTree &Treenode)
{
    if (Treenode == nullptr)
    {
        return true;
    }
    InOrderTraverse(Treenode->lchild);
    visit(Treenode);
    // cout << Treenode->data << " ";
    InOrderTraverse(Treenode->rchild);
    return true;
}

// 后序遍历
bool PostOrderTraverse(BiTree &TreeNode)
{
    if (TreeNode == nullptr)
    {
        return false;
    }
    PostOrderTraverse(TreeNode->lchild);
    PostOrderTraverse(TreeNode->rchild);
    visit(TreeNode);
    return true;
}

// 中序遍历  非递归
void LDR(BiTree &TreeNode)
{
    stack<BiTree> st;
    BiTree cur = TreeNode;
    while (cur != NULL || !st.empty())
    {
        if (cur != NULL)
        {
            st.push(cur);
            cur = cur->lchild;
        }
        else
        {
            cur = st.top();
            st.pop();
            visit(cur);
            cur = cur->rchild;
        }
    }
}

// 层序遍历
void LevelOrder(BiTree &TreeNode)
{
    queue<BiTree> que;
    if (TreeNode != NULL)
    {
        que.push(TreeNode);
    }
    vector<vector<int>> res;
    while (!que.empty())
    {
        int size = que.size();
        vector<int> vec;
        for (int i = 0; i < size; i++)
        {
            BiTree node = que.front();
            que.pop();
            vec.push_back(node->data);
            if (node->lchild)
                que.push(node->lchild);
            if (node->rchild)
                que.push(node->rchild);
        }
        res.push_back(vec);
    }
    for (vector<vector<int>>::iterator iter = res.begin(); iter != res.end(); iter++)
    {

        for (vector<int>::iterator it = (*iter).begin(); it != (*iter).end(); it++)
        {
            cout << *it << " ";
        }
    }
}

// 二叉树的建立
void CreateTree(BiTree &TreeNode)
{
    int input;
    cin >> input;
    if (input == -1)
    {
        TreeNode = NULL;
    }
    else
    {
        TreeNode = new BiNode;
        TreeNode->data = input;
        CreateTree(TreeNode->lchild);
        CreateTree(TreeNode->rchild);
    }
}

int main()
{
    BiTree node;
    CreateTree(node);
    cout << "前序遍历:";
    PreOrderTraverse(node);
    cout << "中序遍历:";
    InOrderTraverse(node);
    cout << "中序遍历:";
    PostOrderTraverse(node);
    cout << "层次遍历:";
    LevelOrder(node);
    cout << "中序非递归遍历:";
    LDR(node);

    return 0;
}

  • 运行结果:

在这里插入图片描述

树和森林

在这里插入图片描述

哈夫曼树

基本概念

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • 满二叉树不一定是哈夫曼树
  • 权重值越大的离根节点越近
  • 具有相同带权结点的哈夫曼树不唯一

哈夫曼树的构造

在这里插入图片描述

  • 构造哈夫曼树示例

在这里插入图片描述

在这里插入图片描述

  • 总结

在这里插入图片描述

  • 哈夫曼树的实现
#include <iostream>
#include <queue>
#include <vector>
#include <stack>

using namespace std;
typedef struct HNode
{
    /* data */
    int weight;              // 权重
    int parent, left, right; // 双亲、左孩子、右孩子
} *Huffman;

// 哈夫曼树初始化
void HuffmanInit(Huffman &H, int n)
{
    // 数组大小为2n-1,下标从1开始所以是2n
    H = new HNode[2 * n];
    for (int i = 1; i < 2 * n; i++)
    {
        H[i].parent = H[i].left = H[i].right = 0;
    }
    int weight;
    for (int i = 1; i <= n; i++)
    {
        cin >> weight;
        H[i].weight = weight;
    }
}

// 寻找两个结点的函数
//s1 s2 为引用类型
void Select(Huffman &H, int n, int &s1, int &s2)
{
    vector<int> vec;
    for (int i = 1; i <= n; i++)
    {
        if (H[i].parent == 0)
        {
            // 双亲为0的结点放入数组
            vec.push_back(i);
        }
    }
    // 再找出下标最小的两个结点创建新树
    auto flag1 = vec.begin();
    for (auto it = vec.begin() + 1; it != vec.end(); it++)
    {
        if (H[*it].weight < H[*flag1].weight)
        {
            flag1 = it;
        }
    }
    s1 = *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;
        }
    }
    s2 = *flag2; // 第二个结点
}

// 哈夫曼树构造
void CreateHuffman(Huffman &H, int length)
{
    // 哈夫曼树初始化
    HuffmanInit(H, length);
    // 找出森林中最小的两棵树创建新树
    for (int i = length + 1; i < 2 * length; i++)
    {
        int s1 = 0, s2 = 0;
        // 在数组中找出两个双亲为0且权重值是最小的结点,并返回数组中结点序号
        // 在1-n的数组范围中寻找
        Select(H, i - 1, s1, s2);
        H[s1].parent = i;
        H[s2].parent = i;
        H[i].left = s1;
        H[i].right = s2;
        H[i].weight = H[s1].weight + H[s2].weight;
    }
    for (int i = 1; i < 2 * length; i++)
    {
        printf("节点 %d 权值为 :%d 双亲为:%d 左孩子为 :%d 右孩子为:%d \n", i, H[i].weight, H[i].parent, H[i].left, H[i].right);
    }
}

int main()
{
    Huffman H;
    int n = 6;
    CreateHuffman(H, n);
    return 0;
}

  • 运行结果

在这里插入图片描述

哈夫曼编码

  • 基本概念

在这里插入图片描述

  • 示例

在这里插入图片描述

  • 哈夫曼编码实现
// 实现哈夫曼编码
void HuffmanCode(Huffman &H, int n)
{
    // CreateHuffman(H, n);
    //  遍历哈夫曼树中前n个元素,寻找新树结点的左右孩子,根据左右孩子赋值0或1
    for (int i = 1; i <= n; i++)
    {
        int chd = i;
        int par = H[chd].parent;
        stack<int> st;
        // 父节点等于0表示访问到根节点,循环结束
        while (par != 0)
        {
            if (H[par].left == chd)
                st.push(0);
            else
                st.push(1);
            chd = par;
            par = H[chd].parent;
        }
        while (!st.empty())
        {
            int out = st.top();
            st.pop();
            cout << out;
        }
        cout << endl;
    }
}
  • 运行结果

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值