鱼C论坛

 找回密码
 立即注册
查看: 1577|回复: 0

[学习笔记] 009-树的遍历和创建、二叉线索树、霍夫曼树

[复制链接]
发表于 2018-9-30 21:28:00 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 moc 于 2018-9-30 21:32 编辑

1、树的遍历
二叉树有根、左子树、右子树构成,定义为D、L、R。
DLR组合可以定义6种遍历方案:  LDR 、LRD 、DLR  、DRL 、RDL 、RLD .
一般限定先左后右:于是有三种遍历方案:
        DLR  =>  先(根)序遍历
        LDR  =>  中(根)序遍历
        LRD  =>  后(根)序遍历
39.jpg

先序遍历:ABCDEFGH
中序遍历:BDCEAFHG
后序遍历:DECBHGFA
由于树本身就是一种递归结构,所以采用递归方式遍历树最合适;
先序遍历:
void preOrder(BiTNode *root)
{
        if (root == NULL)
        {
                return;
        }
        // 遍历根
        printf("%d", root->data);
        // 遍历左子树
        preOrder(root->lchild);
        // 遍历右子树
        preOrder(root->rchild);
}
中序遍历:
void inOrder(BiTNode *root)
{
        if (root == NULL)
        {
                return;
        }
        // 遍历左子树
        inOrder(root->lchild);
        // 遍历根
        printf("%d", root->data);
        // 遍历右子树
        inOrder(root->rchild);
}
后序遍历:
void postOrder(BiTNode *root)
{
        if (root == NULL)
        {
                return;
        }
        // 遍历左子树
        postOrder(root->lchild);
        // 遍历右子树
        postOrder(root->rchild);
        // 遍历根
        printf("%d", root->data);
}
分析:   上面三种遍历方法,如果将printf()语句去掉,三种算法完全相同,所以这三种遍历算法的访问路径是相同的,只是访问结点的时机不同。
树的非递归中序遍历:
        利用栈实现中序遍历的先走到的后访问,后走到的先访问。
算法步骤:
            步骤1: 如果结点有左子树,该结点入栈;
                        如果结点没有右子树,访问该结点;
            步骤2: 如果结点有右子树,重复步骤1;
                        如果结点没有右子树(结点访问完毕),根据栈顶指示回退,访问栈顶元素,并访问右子树,重复步骤1
                        如果栈为空,表示遍历结束。
注意: 入栈的结点  其本身和其右子树没有被访问。
// 借助于栈结构
BiTNode* goLeft(BiTNode* t, stack<BiTNode*> &s)
{
        if (!t)
        {
                return NULL;
        }
        while (t->lchild != NULL)
        {
                s.push(t);
                t = t->lchild;
        }
        return t;
}

void inOrder2(BiTNode* tree)
{
        stack<BiTNode*> st;
        BiTNode *tmp;
        if (tree == NULL)
        {
                return;
        }
        
        tmp = goLeft(tree, st);
        while (tmp)
        {
                printf("%d ", tmp->data);
                if (tmp->rchild != NULL)
                {
                        tmp = goLeft(tmp->rchild, st);
                }
                else if (tmp->rchild == NULL && !st.empty())
                {
                        tmp = st.top();
                        st.pop();
                }
                else
                {
                        tmp = NULL;
                }
        }
}
2、二叉树的创建
1. #法
// #号法  按照给定的先序序列创建二叉树
BiTNode* CreatBiTree()
{
        BiTNode *node = NULL;

        char h;
        scanf("%c", &h);
        if (h == '#')
        {
                return NULL;
        }
        else
        {
                node = (BiTNode*)malloc(sizeof(BiTNode));
                if (node == NULL)
                {
                        return NULL;
                }
                node->data = h;
                node->lchild = CreatBiTree();   // 递归创建左子树
                node->rchild = CreatBiTree();   // 递归创建右子树
                return node;
        }
}
2.   先序+中序   中序+后序
通过先序遍历和中序遍历结构创建二叉树,也可以通过中序遍历和后序遍历结构创建二叉树。
但是不能通过先序和后序遍历创建二叉树。
3、二叉线索树
普通二叉树只能找到结点的左右孩子信息,而该结点的直接前驱和直接后继只能在遍历过程中获得;若可以将遍历后对应的有关前驱和后继预存起来就可以“顺藤摸瓜”而遍历树。
实质:  把二叉树按照中序遍历的结果存在链表里面。
待续...
4、霍夫曼树
   树的帯权路径长度,组建一个网络,耗费最小WPL(帯权路劲长度)。
霍夫曼树的建立:
        1. 给定 n 个数值(v1, v2, v3, ..., vn);
        2. 根据这 n  个数值构造二叉树集合 F = (T1, T2, T3 ... Tn),  其中 Ti 的数据域为 vi ,左右子树为空;
        3. 在 F 中选择两颗根结点最小的树作为左右子树构造一颗新的二叉树,这颗新的二叉树的根结点中的值为左右子树根结点值的和;
        4. 在 F 中删除这两颗子树,并将构造的新的二叉树加入 F 中;
        5. 重复 3 和 4 步骤,直到只剩下最后一棵树为止,这棵树就是霍夫曼树。
结论: 霍夫曼树是一种特殊的二叉树;
           霍夫曼树应用于信息编码和数据压缩领域;
           霍夫曼树是现代压缩算法的基础。

本帖被以下淘专辑推荐:

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-7-1 03:05

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表