• 数据结构 | 构造哈夫曼树


     1.向上调整为堆

    template
    void Heap::PercolateUp() //为了向上调整为堆,我们需要比较当前节点和其父节点的值,如果父节点的值比当前节点大,则交换它们的值。
    {

        int p = size - 1, c = (p - 1) / 2;//`c`表示当前节点的父节点,`p`表示当前节点。
        T temp = vec[p];
        while (p > 0) //为什么不是c>0
            

            //在`while`循环中,我们判断当前节点是否已经到达根节点,如果是根节点则停止循环。所以条件应该是`p > 0`,而不是`c > 0`。

            
        {
            if (vec[c] <= temp)
                break;
            else
            {
                vec[p] = vec[c];
                p = c;
                c = (p - 1) / 2;
            }
        }
        vec[p] = temp; //写在while 里面还是外面目前结点最后会空出来
    }


    2.向下调整为堆 

    template
    void Heap::PercolateDown(int h)// 向下调整为堆,如果父亲节点(目前结点)比孩子结点(较小值)大交换
    {
        int p = h, c = 2 * p + 1;// c为p的左孩子
        T temp = vec[h]; //不定类型  不用写成int
        while (c < size)  //怎么修改? 向下控制边界,不能让它超过size
        {
            if (c + 1 < size && vec[c + 1] < vec[c]) //左孩子的下标小于size-1(最后一个叶子结点)&&找到左右孩子的最小值

    //c < size表示当前节点有左孩子,而c + 1 < size表示当前节点有右孩子。根据堆的性质,选择较小的孩子进行交换。

            {
                ++c;
            }
            if (temp <= vec[c])
                break;
            else
            {
                vec[p] = vec[c];
                p = c;
                c = 2 * p + 1;
            }
        }
        vec[p] = temp;


      构造参考:

    赫夫曼树_关于huffman树,权值相同-CSDN博客

     编码参考:

    【数据结构与算法】-哈夫曼树(Huffman Tree)与哈夫曼编码_数据结构哈夫曼树编码-CSDN博客


    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. template<class T>
    6. struct BTNode
    7. {
    8. T data;
    9. BTNode* left, * right;
    10. BTNode(const T& item = T(), BTNode* lptr = NULL, BTNode* rptr = NULL) :
    11. data(item), left(lptr), right(rptr) {}
    12. };
    13. void Gotoxy(int x, int y)
    14. {
    15. static int level = 0, indent = 0;
    16. if (y == 0)
    17. {
    18. indent = 0;
    19. level = 0;
    20. }
    21. if (level != y)
    22. {
    23. cout << endl;
    24. indent = 0;
    25. level++;
    26. }
    27. cout.width(x - indent);
    28. indent = x;
    29. }
    30. template<class T>
    31. BTNode* GetBTNode(const T& item, BTNode* lp = NULL, BTNode* rp = NULL)
    32. {
    33. BTNode* p;
    34. p = new BTNode(item, lp, rp);
    35. if (p == NULL)
    36. {
    37. cout << "error!" << endl;
    38. }
    39. return p;
    40. }
    41. struct Location
    42. {
    43. int xindent, ylevel;
    44. };
    45. template<class T>
    46. void PrintBTree(const BTNode* t, int screenwidth)
    47. {
    48. if (t == NULL)
    49. {
    50. return;
    51. }
    52. int level = 0, offset = screenwidth / 2;
    53. Location floc, cloc;
    54. queue<const BTNode*> Q;
    55. queue LQ;
    56. floc.xindent = offset;
    57. floc.ylevel = level;
    58. Q.push(t);
    59. LQ.push(floc);
    60. while (!Q.empty())
    61. {
    62. t = Q.front();
    63. floc = LQ.front();
    64. Q.pop();
    65. LQ.pop();
    66. Gotoxy(floc.xindent, floc.ylevel);
    67. cout << t->data;
    68. if (floc.ylevel != level)
    69. {
    70. level++;
    71. offset = offset / 2;
    72. }
    73. if (t->left)
    74. {
    75. Q.push(t->left);
    76. cloc.ylevel = floc.ylevel + 1;
    77. cloc.xindent = floc.xindent - offset / 2;
    78. LQ.push(cloc);
    79. }
    80. if (t->right)
    81. {
    82. Q.push(t->right);
    83. cloc.ylevel = floc.ylevel + 1;
    84. cloc.xindent = floc.xindent + offset / 2;
    85. LQ.push(cloc);
    86. }
    87. }
    88. cout << endl;
    89. }
    90. template<class T>
    91. class Heap //小根堆 根->叶子 小到大
    92. {
    93. vector vec;
    94. int size;
    95. void BuildHeap(void);
    96. void PercolateUp();
    97. void PercolateDown(int h);
    98. public:
    99. Heap(int max = 100) : vec(max), size(0) {}
    100. Heap(const vector& vt);
    101. int Size()
    102. {
    103. return size;
    104. }
    105. void Insert(const T& item);
    106. void DeleteMin(void);
    107. void DeleteMin(T& item);
    108. };
    109. template<class T>
    110. void Heap::PercolateUp() //为了向上调整为堆,我们需要比较当前节点和其父节点的值,如果父节点的值比当前节点大,则交换它们的值。
    111. {
    112. int p = size - 1, c = (p - 1) / 2;//`c`表示当前节点的父节点,`p`表示当前节点。
    113. T temp = vec[p];
    114. while (p > 0) //为什么不是c>0
    115. //在`while`循环中,我们判断当前节点是否已经到达根节点,如果是根节点则停止循环。所以条件应该是`p > 0`,而不是`c > 0`。
    116. {
    117. if (vec[c] <= temp)
    118. break;
    119. else
    120. {
    121. vec[p] = vec[c];
    122. p = c;
    123. c = (p - 1) / 2;
    124. }
    125. }
    126. vec[p] = temp; //写在while 里面还是外面? 目前结点最后会空出来
    127. }
    128. template<class T>
    129. void Heap::PercolateDown(int h)// 向下调整为堆,如果父亲节点(目前结点)比孩子结点(较小值)大交换
    130. {
    131. int p = h, c = 2 * p + 1;// c为p的左孩子
    132. T temp = vec[h];
    133. while (c < size) //怎么修改?
    134. {
    135. if (c + 1 < size && vec[c + 1] < vec[c]) //左孩子的下标小于size-1(最后一个叶子结点)&&找到左右孩子的最小值
    136. {
    137. ++c;
    138. }
    139. if (temp <= vec[c])
    140. break;
    141. else
    142. {
    143. vec[p] = vec[c];
    144. p = c;
    145. c = 2 * p + 1;
    146. }
    147. }
    148. vec[p] = temp;
    149. }
    150. template<class T>
    151. void Heap::Insert(const T& item)
    152. {
    153. if (size == vec.size())
    154. {
    155. vec.resize(vec.size() *2);
    156. }
    157. vec[size] = item;
    158. size++;
    159. PercolateUp();
    160. }
    161. template<class T>
    162. void Heap::BuildHeap(void) //从最后一个非叶子结点(a)开始,size-1是最后一个叶子结点,a是它的parent
    163. {
    164. for (int i = size / 2 - 1; i >= 0; i--)
    165. {
    166. PercolateDown(i);//为该结点的子树调整成堆
    167. }
    168. }
    169. template<class T>
    170. void Heap::DeleteMin()
    171. {
    172. if (size == 0)
    173. {
    174. return;
    175. }
    176. vec[0] = vec[size - 1];
    177. size--;
    178. PercolateDown(0);
    179. }
    180. template<class T>
    181. void Heap::DeleteMin(T& item)
    182. {
    183. if (size == 0) //删除最小值需要判断堆是否为空
    184. {
    185. return;
    186. }
    187. item = vec[0];
    188. vec[0] = vec[size - 1];
    189. size--;
    190. PercolateDown(0);
    191. }
    192. template<class T>
    193. Heap::Heap(const vector& vt) : vec(vt.size() + 10), size(vt.size())
    194. {
    195. for (int i = 0; i < size; i++)
    196. {
    197. vec[i] = vt[i];
    198. }
    199. BuildHeap();
    200. }
    201. template<class T>
    202. struct HuffmanNode
    203. {
    204. BTNode* t;
    205. int operator<(const HuffmanNode& h)//穿入参数是哈夫曼节点 bool类型
    206. {
    207. return (t->data < h.t->data);
    208. }
    209. int operator<=(const HuffmanNode& h)//穿入参数是哈夫曼节点
    210. {
    211. return (t->data <= h.t->data);
    212. }
    213. };
    214. template<class T>
    215. BTNode* MakeHuffman(T* pa, int n)
    216. {
    217. BTNode* t, * right, * left;
    218. HuffmanNode hf;
    219. Heap> HF(n);
    220. //第一个循环将数组里的元素插入到哈夫曼堆
    221. for (int i = 0; i < n; i++)
    222. {
    223. t = GetBTNode<int>(pa[i]);
    224. hf.t = t;
    225. HF.Insert(hf);
    226. }
    227. //第二个循环找到最小的两个数,生成根节点后删除
    228. for (int i = 1; i < n; i++)
    229. {
    230. HF.DeleteMin(hf);
    231. left = hf.t;
    232. HF.DeleteMin(hf);
    233. right = hf.t;
    234. t = GetBTNode(left->data + right->data, left, right);//t的左孩子是left,右孩子是right
    235. hf.t = t;
    236. HF.Insert(hf);
    237. }
    238. HF.DeleteMin(hf);//是一个对象调用函数
    239. t = hf.t;
    240. return t;
    241. };
    242. int main()
    243. {
    244. int a[] = { 7,5,2,4 };
    245. BTNode<int>* root;
    246. root = MakeHuffman(a, 4);
    247. PrintBTree(root, 40);
    248. cout << endl;
    249. return 0;
    250. }

  • 相关阅读:
    redis的详解和项目应用(一)
    Python 多重继承时metaclass conflict问题解决与原理探究
    导出oracle远程数据库到本地
    分布式运用——存储系统Ceph
    如何做一个最便宜的小程序?
    世界前沿技术发展报告2023《世界信息技术发展报告》(四)电子信息技术
    前端面试,备考第 13 天 - 执行上下文 | 作用域链 | 闭包
    QT调用百度地图并返回点击地的经纬度
    【Kafka】Docker安装kafka、搭建kafka集群
    Xorm 使用手册,面向工作学习
  • 原文地址:https://blog.csdn.net/kazuma_hn/article/details/133929589