数据结构第五周笔记——树(下2)(慕课浙大版本--XiaoYu)

简介: 哈夫曼树的实现

5.2 哈夫曼树与哈夫曼编码

5.2.1 什么是哈夫曼树(Huffman Tree)

[例]将百分制的考试成绩转换成五分制的成绩

if(score<60 ) grade=1;

elseif(score<70) grade=2;

elseif(score<80) grade=3;

elseif(score<90) grade=4;

elsegrade=5;

上述代码中,其实对应着就有一棵树,如下图:

网络异常,图片无法展示
|

网络异常,图片无法展示
|

优化后的效率:

网络异常,图片无法展示
|

if(score<80)

{

   if(score<70 )

       if(score<60) grade=1;

   elsegrade=2;

}elseif(score<90 )grade=4;

elsegrade=5;

如何根据结点不同的查找频率构造更有效的搜索树?

哈夫曼树的定义

网络异常,图片无法展示
|

最优二叉树或哈夫曼树就是WPL最小的二叉树

一棵二叉树每一个叶结点的频率或者权重乘以这个叶结点到根结点的这个路径的长度就是带权路径的长度

权值 = 频率

[例]有五个叶子结点,它们的权值为{1,2,3,4,5},用此权值序列可以构造出形状不同的多个二叉树

网络异常,图片无法展示
|

网络异常,图片无法展示
|
是50

网络异常,图片无法展示
|

5.2.2 哈夫曼树的构造

  1. 每次把权值最小的两颗二叉树合并
  2. 网络异常,图片无法展示
    |

  3. 代码实现(如何选取两个最小的?)

typedefstructTreeNode*HuffmanTree;

structTreeNode{

   intWeight;

   HuffmanTreeLeft,Right;

}

HuffmanTreeHuffman(MinHeapH)

{

   //假设H->Size个权值已经存在H->Elements[]->Weight里

   inti; HuffmanTreeT;

   BuildMinHeap(H);//将H->Elements[]按权值调整为最小堆

   for(i=1;i<H->Size; i++){//做H->Size-1次合并

       T=malloc(sizeof(structTreeNode));//建立新结点

       T->Left=DeleteMin(H);//从最小堆中删除一个结点,作为新T的左子结点

       T->Right=DeleteMin(H);//从最小堆中删除一个结点,作为新T的右子结点

       T->Weight=T->Left->Weight+T->Right->Weight;//计算新权值

       Insert(H,T);//将新T插入最小堆

   }

   T=DeleteMin(H);

   returnT;

}

整体复杂度为O(NlogN)

  1. 哈夫曼树的特点:
  1. 没有度为1的结点;
  2. n个叶子结点的哈夫曼树共有2n-1个结点
  1. n0:叶结点总数
  2. n1:只有一个儿子的结点总数
  3. n2:有2个儿子的结点总数
  4. n2 = n0 - 1
  1. 哈夫曼树的任意非叶节点的左右子树交换后仍是哈夫曼树;
  2. 网络异常,图片无法展示
    |

5.2.3 哈夫曼编码

给定一段字符串,如何对字符进行编码,可以使得该字符串的编码存储空间最少?

网络异常,图片无法展示
|

分析:

  1. 用等长ASCII编码:58×8 = 464位
  2. 用等长3位编码:58×3 = 174位;
  3. 不等长编码:出现频率高的字符用的编码短些,出现频率低的字符则可以编码长些?

怎么进行不等长编码?

如何避免二义性(就是你这个编码不止一个意思)

  1. 前缀码prefix code:任何字符的编码都不是另一字符编码的前缀
  1. 可以无二义地解码(你的这个编码不能是其他编码的前缀)
  1. 二叉树用于编码:
  1. 左右分支:0、1
  2. 字符只在叶结点上
  3. 网络异常,图片无法展示
    |

  4. 网络异常,图片无法展示
    |

  5. 网络异常,图片无法展示
    |

  6. 怎么构造一颗编码代价最小的二叉树?
  1. 网络异常,图片无法展示
    |

小测验:哈夫曼树

网络异常,图片无法展示
|

5.3 集合及运算

5.3.1 集合的表示及查找

  1. 集合运算:交,并,补,差,判定一个元素是否属于某一集合
  2. 并查集:集合并、查某元素属于什么集合
  3. 并查集问题中集合存储如何实现?
  1. 可以用树结构表示集合,树的每个结点代表一个集合元素
  2. 网络异常,图片无法展示
    |
    对这样三棵树的存储方法
  1. 采用数组存储形式
  2. 网络异常,图片无法展示
    |

  3. 上图中没有父节点的用负数来表示,Parent是它父节点的下标

[例]:有10台电脑{1,2,3,.....,9,10},已知下列电脑之间已经实现了连接:

1和2、2和4、3和5、4和7、5和8、6和9、6和10

问:2和7之间,5和9之间是否是连通的?

2和7是连通的,5和9不连通

  1. 网络异常,图片无法展示
    |

集合运算

(1)查找某个元素所在的集合(用根结点表示)

intFind(SetTypeS[],ElementTypeX)

{

   //在数组S中查找值为X的元素所属的集合

   //MaxSize是全局变量,为数组S的最大长度

   inti;

   for(i=0;i<MaxSize&&S[i].Data!=X; i++);

   if(i>=MaxSize) return-1;//未找到X,返回-1

   for(;S[i].Parent>=0; i=S[i].Parent);//Parent的值为-1的时候就是找到根结点。i = S[i].Parent:原本指向i的位置现在跳到了s[i].Parent

   returni;//找到X所属集合,返回树根结点在数组S中的下标

}

5.3.2 集合的并运算

(2)集合的并运算

  1. 分别找到X1和X2两个元素所在集合树的根结点
  2. 如果它们不同根,则将其中一个根结点的父结点指针设置成另一个根结点的数组下标
  1. Union实现代码

voidUnion(SetTypeS[ ],ElementTypeX1,ElementTypeX2 )

{

   intRoot1,Root2;

   Root1=Find(S,X1);//得到X1与X2对应的树根

   Root2=Find(S,X2);

   if( Root1!=Root2 ) S[Root2].Parent=Root1;//判断如果不是本身就是同一个集合的,如果是同一个集合的话就不需要做这个并的操作。不同则合并

}

  1. 为了改善合并以后的查找性能,可以采用小的集合合并到相对大的集合中。(修改Union函数)。也许树的高度不会增加

小测验:集合

已知a、b两个元素均是所在集合的根结点,且分别位于数组分量3和2位置上,其parent值分别为-3,-2。问:将这两个集合按集合大小合并后,a和b的parent值分别是多少?

-5,3

集合的定义与并查

#define MAXN 1000                  /* 集合最大元素个数 */

typedefintElementType;           /* 默认元素可以用非负整数表示 */

typedefintSetName;               /* 默认用根结点的下标作为集合名称 */

typedefElementTypeSetType[MAXN]; /* 假设集合元素下标从0开始 */

voidUnion( SetTypeS, SetNameRoot1, SetNameRoot2 )

{ /* 这里默认Root1和Root2是不同集合的根结点 */

   /* 保证小集合并入大集合 */

   if ( S[Root2] <S[Root1] ) { /* 如果集合2比较大 */

       S[Root2] +=S[Root1];     /* 集合1并入集合2  */

       S[Root1] =Root2;

   }

   else {                         /* 如果集合1比较大 */

       S[Root1] +=S[Root2];     /* 集合2并入集合1  */

       S[Root2] =Root1;

   }

}

SetNameFind( SetTypeS, ElementTypeX )

{ /* 默认集合元素全部初始化为-1 */

   if ( S[X] <0 ) /* 找到集合的根 */

       returnX;

   else

       returnS[X] =Find( S, S[X] ); /* 路径压缩 */

目录
相关文章
|
26天前
|
算法
数据结构之博弈树搜索(深度优先搜索)
本文介绍了使用深度优先搜索(DFS)算法在二叉树中执行遍历及构建链表的过程。首先定义了二叉树节点`TreeNode`和链表节点`ListNode`的结构体。通过递归函数`dfs`实现了二叉树的深度优先遍历,按预序(根、左、右)输出节点值。接着,通过`buildLinkedList`函数根据DFS遍历的顺序构建了一个单链表,展示了如何将树结构转换为线性结构。最后,讨论了此算法的优点,如实现简单和内存效率高,同时也指出了潜在的内存管理问题,并分析了算法的时间复杂度。
44 0
|
19天前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
42 5
|
1月前
|
存储 搜索推荐 算法
【数据结构】树型结构详解 + 堆的实现(c语言)(附源码)
本文介绍了树和二叉树的基本概念及结构,重点讲解了堆这一重要的数据结构。堆是一种特殊的完全二叉树,常用于实现优先队列和高效的排序算法(如堆排序)。文章详细描述了堆的性质、存储方式及其实现方法,包括插入、删除和取堆顶数据等操作的具体实现。通过这些内容,读者可以全面了解堆的原理和应用。
71 16
|
26天前
|
算法
数据结构之文件系统模拟(树数据结构)
本文介绍了文件系统模拟及其核心概念,包括树状数据结构、节点结构、文件系统类和相关操作。通过构建虚拟环境,模拟文件的创建、删除、移动、搜索等操作,展示了文件系统的基本功能和性能。代码示例演示了这些操作的具体实现,包括文件和目录的创建、移动和删除。文章还讨论了该算法的优势和局限性,如灵活性高但节点移除效率低等问题。
43 0
|
2月前
|
存储 算法 关系型数据库
数据结构与算法学习二一:多路查找树、二叉树与B树、2-3树、B+树、B*树。(本章为了解基本知识即可,不做代码学习)
这篇文章主要介绍了多路查找树的基本概念,包括二叉树的局限性、多叉树的优化、B树及其变体(如2-3树、B+树、B*树)的特点和应用,旨在帮助读者理解这些数据结构在文件系统和数据库系统中的重要性和效率。
29 0
数据结构与算法学习二一:多路查找树、二叉树与B树、2-3树、B+树、B*树。(本章为了解基本知识即可,不做代码学习)
|
2月前
|
Java C++
【数据结构】探索红黑树的奥秘:自平衡原理图解及与二叉查找树的比较
本文深入解析红黑树的自平衡原理,介绍其五大原则,并通过图解和代码示例展示其内部机制。同时,对比红黑树与二叉查找树的性能差异,帮助读者更好地理解这两种数据结构的特点和应用场景。
37 0
|
2月前
|
存储 算法
数据结构与算法学习十六:树的知识、二叉树、二叉树的遍历(前序、中序、后序、层次)、二叉树的查找(前序、中序、后序、层次)、二叉树的删除
这篇文章主要介绍了树和二叉树的基础知识,包括树的存储方式、二叉树的定义、遍历方法(前序、中序、后序、层次遍历),以及二叉树的查找和删除操作。
31 0
|
2月前
05(数据结构考研)树相关操作代码
05(数据结构考研)树相关操作代码
29 0
|
2月前
|
存储 算法 Java
数据结构和算法--分段树
数据结构和算法--分段树
20 0