当前位置: 首页 > 编程日记 > 正文

哈夫曼编码与解码

这是我的第一篇博客,希望大神们批评指正。

首先介绍以下什么是哈夫曼树(来自百度百科)

哈夫曼树─即最优二叉树,带权路径长度最小的二叉树,经常应用于数据压缩。 在计算机信息处理中,“哈夫曼编码”是一种一致性编码法(又称“熵编码法”),用于数据的无损耗压缩。这一术语是指使用一张特殊的编码表将源字符(例如某文件中的一个符号)进行编码。这张编码表的特殊之处在于,它是根据每一个源字符出现的估算概率而建立起来的(出现概率高的字符使用较短的编码,反之出现概率低的则使用较长的编码,这便使编码之后的字符串的平均期望长度降低,从而达到无损压缩数据的目的)。

构造哈夫曼树的主要思想:

构造哈夫曼树非常简单,将所有的节点放到一个队列中,用一个节点替换两个频率最低的节点,新节点的频率就是这两个节点的频率之和。这样,新节点就是两个被替换节点的父节点了。如此循环,直到队列中只剩一个节点(树根)。


这里用到了最小优先队列。

我这里用STL来实现。(这里有优先队列的介绍)

template<typename T>
struct cmp
{bool operator()(TreeNode<T>* t1, TreeNode<T>*  t2){return !(*t1 < *t2);}
};

优先队列的定义:

priority_queue<TreeNode*,vector<TreeNode* >,cmp > pri_que;

哈夫曼树节点结构

template<typename T>
class TreeNode
{
public:TreeNode():pfather(NULL),plchild(NULL),prchild(NULL){}T data;TreeNode *pfather;TreeNode *plchild;TreeNode *prchild;bool operator < (const TreeNode& rhs){return data < rhs.data;}};

构造哈夫曼树

每次从最小优先队列取头两个节点,合并后放回最小优先队列,如此重复。

template<typename T>
TreeNode<T>* MakeHuffmanTree(T* begin, T* end) //构造哈夫曼树
{priority_queue<TreeNode<T>*,vector<TreeNode<T>* >,cmp<T> > pri_que;T *iter = begin;TreeNode<T>* pNode;TreeNode<T>* pf = NULL;while(iter != end){pNode = new TreeNode<T>;pNode->data = *iter++;pNode->pfather = pf;pri_que.push(pNode);}TreeNode<T>* plchild;TreeNode<T>* prchild;while(pri_que.size() > 1)//取两个小的合并
    {plchild = pri_que.top();pri_que.pop();prchild = pri_que.top();pri_que.pop();pNode = new TreeNode<T>;pNode->plchild = plchild;pNode->prchild = prchild;pNode->data = plchild->data + prchild->data;pri_que.push(pNode);}pNode = pri_que.top();pri_que.pop();return pNode;
}

构造哈夫曼树这个函数的参数是一个结构体,保存着对应字符,其频率,编码值。

重载它的+运算符,为了合并时的+运算(只是频率相加)。

到此为止,已经可以把哈夫曼树生成出来了。

template<typename T>
struct mydata
{mydata(){}mydata(int i):freq(i){}string coded;int freq;T data;bool operator<(const mydata& rhs){return freq < rhs.freq;}mydata operator+(mydata& rhs){return mydata(freq + rhs.freq);}
};

我们可以通过DFS将每个叶子节点的路径记录下来(用一个全局变量数组path),然后得到它的编码。

当发现当前节点是叶子节点,就把当前的路径赋值至该叶子节点的编码属性(coded)。

const int MAXLEN = 20;
char path[MAXLEN] = {0};
template<typename T>
void DFS(T* root,int deep = -1, char a = '-')  //DFS 得到叶子节点的编码
{if(root == NULL)return;if(a != '-')path[deep] = a;if(root->plchild == NULL || root->prchild == NULL)//leaf(root->data).coded = string(path,path + deep + 1);if(root->plchild != NULL)DFS(root->plchild, deep + 1, '0');if(root->prchild != NULL)DFS(root->prchild, deep + 1, '1');
}

这样整个哈夫曼编码工作已经完成,为了查看我们的编码结果,我们可以用BFS跟DFS来看到我们的结果。在这里我选择了BFS。

当遍历到叶子节点,就将其编码属性(coded)和其对应字符输出。

template<typename T,typename U>
void BFS(T* root, mydata<U>* data) //BFS 将叶子节点的编码,提到data指向的数据
{queue<T*> que;que.push(root);T* pT = NULL;while(!que.empty()){pT = que.front();//cout<<pT->data.freq<<endl;
        que.pop();if(pT->plchild != NULL)que.push(pT->plchild);if(pT->prchild != NULL)que.push(pT->prchild);if(pT->plchild == NULL || pT->prchild == NULL)// leaf 提取叶子节点的编码
        {//cout<<(pT->data).data<<":"<<(pT->data).coded<<endl;mydata<U>* pd = data;while((pT->data).data != pd->data)pd++;assert(pd->data == (pT->data).data);pd->coded = (pT->data).coded;}}
}

测试驱动代码

    mydata<char> *pdata = new mydata<char>[4];pdata[0].data = 'a';pdata[0].freq = 7;pdata[1].data = 'b';pdata[1].freq = 5;pdata[2].data = 'c';pdata[2].freq = 2;pdata[3].data = 'd';pdata[3].freq = 4;TreeNode<mydata<char> >* pihuffmanTree = MakeHuffmanTree(pdata, pdata + 4);DFS(pihuffmanTree);BFS(pihuffmanTree);


为了更方便的使用我将这些封装到一个类里面。

template<typename T>
class Huffman
{
public:void Coded(string& coded);//传入待输出的编码void DeCode(const string& codedstr,string& decodestr);//输入待解码字符串,输出解码字符串void InputData(T* begin,T* end);//传入数据private:string FindVal(char c);void m_CalcFreq(T* begin, T* end);//计算输入数据的频率TreeNode<mydata<T> > *root;//huffman根节点mydata<T>* data;int data_size;T* m_begin;//保存原始数据的开始与结束的位置T* m_end;//string codedstr;

};

输入数据并计算其频率。

用map容器来统计输入字符每个出现的个数。

template<typename T>
void Huffman<T>::InputData(T* begin, T* end)
{this->m_begin = begin;this->m_end = end;m_CalcFreq(begin, end);}template<typename T>
void Huffman<T>::m_CalcFreq(T* begin, T* end)
{int len = end - begin;//data_size = len;if(len == 0)return;map<T,int> countMap;map<T,int>::iterator mapIter = countMap.begin();T *pT = begin;while(pT != end){mapIter = countMap.find(*pT);if(mapIter != countMap.end())//在map里有没有字符*iter++mapIter->second;else{countMap.insert(make_pair(*pT,1));}pT++;}data_size = countMap.size();data = new mydata<T>[data_size];int i = 0;for (mapIter = countMap.begin(); mapIter != countMap.end(); ++mapIter){data[i].data = mapIter->first;        data[i].freq = mapIter->second;i++;}}

编码

template<typename T>
void Huffman<T>::Coded(string& coded)
{root = MakeHuffmanTree(data,data + data_size);DFS(root);BFS(root,data);cout<<"code:"<<endl;for (int i = 0; i < data_size; ++i){cout<<data[i].data<<":"<<data[i].coded<<endl;}T *begin = m_begin;while (begin != m_end){coded += FindVal(*begin);begin++;}//string subcode = 
}

解码

template<typename T>
void Huffman<T>::DeCode(const string& codedstr,string& decodestr)
{string::const_iterator iter = codedstr.begin();TreeNode<mydata<T> >* curNode = root;while (iter != codedstr.end()){if (curNode->plchild == NULL || curNode->prchild == NULL){decodestr += (curNode->data).data;curNode = root;continue;}if (*iter == '0')curNode = curNode->plchild;if(*iter == '1')curNode = curNode->prchild;iter++;}
}

测试驱动程序

        char *pmystr = "cbcddddbbbbaaaaaaa";Huffman<char> h;h.InputData(pmystr, pmystr + 18);cout<<"originstr: "<<pmystr<<endl;string coded;h.Coded(coded);cout<<"coded: "<<coded<<endl;string decode;h.DeCode(coded,decode);cout<<"decode: "<<decode<<endl;

完整程序(环境:VS2012)

#include <iostream>
//#include <algorithm>
#include <queue>
#include <string>
#include <vector>
#include <cassert>
#include <map>
using namespace std;template<typename T>
class TreeNode
{
public:TreeNode():pfather(NULL),plchild(NULL),prchild(NULL){}T data;TreeNode *pfather;TreeNode *plchild;TreeNode *prchild;bool operator < (const TreeNode& rhs){return data < rhs.data;}};template<typename T>
struct cmp
{bool operator()(TreeNode<T>* t1, TreeNode<T>*  t2){return !(*t1 < *t2);}
};template<typename T>
TreeNode<T>* MakeHuffmanTree(T* begin, T* end) //构造哈夫曼树
{priority_queue<TreeNode<T>*,vector<TreeNode<T>* >,cmp<T> > pri_que;T *iter = begin;TreeNode<T>* pNode;TreeNode<T>* pf = NULL;while(iter != end){pNode = new TreeNode<T>;pNode->data = *iter++;pNode->pfather = pf;pri_que.push(pNode);}TreeNode<T>* plchild;TreeNode<T>* prchild;while(pri_que.size() > 1)//取两个小的合并
    {//cout<<static_cast<TreeNode<T>* >(pri_que.top())->data<<endl;//pri_que.pop();plchild = pri_que.top();pri_que.pop();prchild = pri_que.top();pri_que.pop();pNode = new TreeNode<T>;pNode->plchild = plchild;pNode->prchild = prchild;pNode->data = plchild->data + prchild->data;pri_que.push(pNode);}pNode = pri_que.top();pri_que.pop();return pNode;
}template<typename T>
struct mydata
{mydata(){}mydata(int i):freq(i){}string coded;int freq;T data;bool operator<(const mydata& rhs){return freq < rhs.freq;}mydata operator+(mydata& rhs){return mydata(freq + rhs.freq);}
};template<typename T,typename U>
void BFS(T* root, mydata<U>* data) //BFS 将叶子节点的编码,提到data指向的数据
{queue<T*> que;que.push(root);T* pT = NULL;while(!que.empty()){pT = que.front();//cout<<pT->data.freq<<endl;
        que.pop();if(pT->plchild != NULL)que.push(pT->plchild);if(pT->prchild != NULL)que.push(pT->prchild);if(pT->plchild == NULL || pT->prchild == NULL)// leaf 提取叶子节点的编码
        {//cout<<(pT->data).data<<":"<<(pT->data).coded<<endl;mydata<U>* pd = data;while((pT->data).data != pd->data)pd++;assert(pd->data == (pT->data).data);pd->coded = (pT->data).coded;}}
}const int MAXLEN = 20;
char path[MAXLEN] = {0};
template<typename T>
void DFS(T* root,int deep = -1, char a = '-')  //DFS 得到叶子节点的编码
{if(root == NULL)return;if(a != '-')path[deep] = a;if(root->plchild == NULL || root->prchild == NULL)//leaf(root->data).coded = string(path,path + deep + 1);if(root->plchild != NULL)DFS(root->plchild, deep + 1, '0');if(root->prchild != NULL)DFS(root->prchild, deep + 1, '1');
}template<typename T>
class Huffman
{
public:void Coded(string& coded);void DeCode(const string& codedstr,string& decodestr);void InputData(T* begin,T* end);private:string FindVal(char c);void m_CalcFreq(T* begin, T* end);TreeNode<mydata<T> > *root;mydata<T>* data;int data_size;T* m_begin;T* m_end;//string codedstr;
};template<typename T>
void Huffman<T>::InputData(T* begin, T* end)
{this->m_begin = begin;this->m_end = end;m_CalcFreq(begin, end);}template<typename T>
void Huffman<T>::m_CalcFreq(T* begin, T* end)
{int len = end - begin;//data_size = len;if(len == 0)return;map<T,int> countMap;map<T,int>::iterator mapIter = countMap.begin();T *pT = begin;while(pT != end){mapIter = countMap.find(*pT);if(mapIter != countMap.end())++mapIter->second;else{countMap.insert(make_pair(*pT,1));}pT++;}data_size = countMap.size();data = new mydata<T>[data_size];int i = 0;for (mapIter = countMap.begin(); mapIter != countMap.end(); ++mapIter){data[i].data = mapIter->first;        data[i].freq = mapIter->second;i++;}}template<typename T>
void Huffman<T>::Coded(string& coded)
{root = MakeHuffmanTree(data,data + data_size);DFS(root);BFS(root,data);cout<<"code:"<<endl;for (int i = 0; i < data_size; ++i){cout<<data[i].data<<":"<<data[i].coded<<endl;}T *begin = m_begin;while (begin != m_end){coded += FindVal(*begin);begin++;}//string subcode = 
}template<typename T>
void Huffman<T>::DeCode(const string& codedstr,string& decodestr)
{string::const_iterator iter = codedstr.begin();TreeNode<mydata<T> >* curNode = root;while (iter != codedstr.end()){if (curNode->plchild == NULL || curNode->prchild == NULL){decodestr += (curNode->data).data;curNode = root;continue;}if (*iter == '0')curNode = curNode->plchild;if(*iter == '1')curNode = curNode->prchild;iter++;}
}template<typename T>
string Huffman<T>::FindVal(char c)
{for (int i = 0; i < data_size ; ++i){if (c != data[i].data)continue;return data[i].coded;}return string();
}int main()
{//mydata<char> *pdata = new mydata<char>[4];//pdata[0].data = 'a';//pdata[0].freq = 7;//pdata[1].data = 'b';//pdata[1].freq = 5;//pdata[2].data = 'c';//pdata[2].freq = 2;//pdata[3].data = 'd';//pdata[3].freq = 4;////int a[12]={14,10,56,7,83,22,36,91,3,47,72,0};//TreeNode<mydata<char> >* pihuffmanTree = MakeHuffmanTree(pdata, pdata + 4);//DFS(pihuffmanTree);//BFS(pihuffmanTree);//string str = "cbcddddbbbbaaaaaaa";char *pmystr = "cbcddddbbbbaaaaaaa";Huffman<char> h;h.InputData(pmystr, pmystr + 18);cout<<"originstr: "<<pmystr<<endl;string coded;h.Coded(coded);cout<<"coded: "<<coded<<endl;string decode;h.DeCode(coded,decode);cout<<"decode: "<<decode<<endl;return 0;
}




转载于:https://www.cnblogs.com/Honkee/p/3780517.html

相关文章:

012-python基础-数据运算

1、算数运算&#xff1a; 2、比较运算 3、赋值运算 4、逻辑运算 5、成员运算&#xff1a; 6、身份运算&#xff1a; 7、位运算&#xff1a; 8、运算符优先级&#xff1a; 转载于:https://www.cnblogs.com/chhphjcpy/p/6064572.html

优化XCode的编译速度

1.将Debug Information Format改为DWARF 在工程对应Target的Build Settings中&#xff0c;找到Debug Information Format这一项&#xff0c;将Debug时的DWARF with dSYM file改为DWARF。 这一项设置的是是否将调试信息加入到可执行文件中&#xff0c;改为DWARF后&#xff0c;如…

给windows装个Mac黑苹果虚拟机

点击上方↑↑↑蓝字[协议分析与还原]关注我们“ windows下安装使用苹果Mac虚拟机。”平常的生活工作中&#xff0c;我大部分时候使用Windows&#xff0c;偶尔用用Mac。实在是用不惯Mac&#xff0c;但有的时候&#xff0c;有些工作还是需要在Mac上搞&#xff0c;不得不用&#x…

Ajax基础讲解 1

随着web的不断发展&#xff0c;Ajax的运用越来越普及&#xff0c;但是对很多同学来说Ajax稍微有些难懂&#xff0c;今天呢就简单给大家讲解一下Ajax的一些基础入门的知识&#xff0c;希望可以帮到刚学习Ajax的同学。 第一步&#xff1a;首先就是服务器的搭建&#xff0c;关于服…

在虚拟机linux环境下编译windows版adb fastboot

原文出自&#xff1a;http://blog.chinaunix.net/uid-20546441-id-1746200.html我根据虚拟机编译遇到的问题进行一些添加【前提条件】Linux Android源码完整虚拟机磁盘空间100G左右&#xff08;60G用来存放代码和编译后的文件&#xff09;swap 30G左右&#xff0c;若太小会导致…

PC端微信小程序wxapkg解密

sh点击上方↑↑↑蓝字[协议分析与还原]关注我们“ 解密PC端wxapkg文件。”用过微信pc版的应该都知道&#xff0c;PC上也可以使用微信小程序。这个小程序用起来和手机端差不多&#xff0c;不过&#xff0c;在分析时&#xff0c;确是有差别的——PC上的wxapkg文件是加密的。无论如…

cron 定时器简单入门

cron:计划任务&#xff0c;是任务在约定的时间执行已经计划好的工作&#xff0c;根据配置文件约定的时间来执行特定的任务。 编写测试类继承 IJob &#xff0c;实现Execute 此方法就是用于定时的任务 配置定时时间&#xff1a; 先创建windows服务&#xff0c;服务创建详情 Inst…

PHP5.5.13 + Apache2.4.7安装配置流程详解

---恢复内容开始--- 自学PHP的这段时间里&#xff0c;真是倍感辛酸&#xff0c;相信广大的菜鸟们应该很我感同身受吧&#xff0c;在查阅了网上和众多数资料后&#xff0c;总结出来想当比较全面的安装方法&#xff0c;拿出来与广大的编程爱好者一起分享哈。 首先到官网上下载相关…

cocos2dx小游戏数据签名算法破解

点击上方↑↑↑蓝字[协议分析与还原]关注我们“ 快速破解小游戏常见的数据签名算法。”最近在分析各种小游戏的协议&#xff0c;本文以《我不是无双》这款小游戏为样例介绍这类小游戏的分析方法。01—抓包在分析开始&#xff0c;首先明确分析的目的是学习这款游戏的网络协议算法…

laravel5 MAC is invalid

如果本机的环境更换过,项目中用来加密Crypt组件中的参数会变更. 如果出现这个问题,得更换数据库中加密后的变量 stackoverflow上找到的解决方法都是 composer dump-autoload composer clear-cache 之后再清空浏览器缓存 其实最简单的解决方法是将数据库中的所有数据重新encrpt一…

不大于N的所有素数

算法如下&#xff1a; #include<stdio.h> #include<math.h> void Sieve(int n) {int p,j,i;int A[n1],L[n1];for(p2;p<n;p)A[p]p;for(p2;p<sqrt(n);p){if(A[p]!0){jp*p;while(j<n){A[j]0;jjp;}}}i0;for(p2;p<n;p){if(A[p]!0){L[i]A[p];i;}}for(p0;p<…

3集合与函数类型

import UIKit var str “Hello, playground” // 1 数组 // 创建一个空的数组 var arr1 Int; arr1.append(6); // 创建一个特定大小 并且所有数据都被默认的构造方法 // 以下数组有6个5 var arr2 Array(repeating: 5, count: 6); // 通过两个数组相加创建一个数组 var a…

非凡推崇_2015年值得推崇的25位编码者

非凡推崇by freeCodeCamp通过freeCodeCamp 2015年值得推崇的25位编码者 (25 Coders Worth Following on Twitter in 2015) Our community upvoted the following 25 coders, in no particular order, as “Coders Worth Following in 2015”:我们的社区对以下25位编码员进行了…

CSS中各种各样居中方法的总结

在开发前端页面的时候&#xff0c;元素的居中是一个永远都绕不开的问题。看似简单的居中二字&#xff0c;其实蕴含着许许多多的情况&#xff0c;对应着很多的处理方法&#xff0c;本文就试图对页面布局中的居中问题进行总结~~ 居中问题分为水平居中和竖直居中两种&#xff1b;而…

iOS 流式播放音频文件

方式一&#xff1a; https://github.com/tumtumtum/StreamingKit 方式二&#xff1a; https://github.com/AlexanderYeah/SK_PlayOnWavFileDemo

java 创建 HMAC 签名

ava 创建 HMAC 签名 psd素材 1. []ComputopTest.java package com.javaonly.hmac.test; import java.io.IOException; import java.security.InvalidKeyException; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import …

2014年数字:我的人生在命令行中

by freeCodeCamp通过freeCodeCamp 2014年数字&#xff1a;我的人生在命令行中 (2014 in Numbers: My Life Behind the Command Line) For 2014, I decided to simplify my life. Rather than pursuing a variety of human experiences, as I had previously, I wanted to focu…

c# unity PlayerPrefs 游戏存档,直白点就是讲游戏数据本地保存下来

在游戏会话中储存和访问游戏存档。这个是持久化数据储存&#xff0c;比如保存游戏记录。 我的理解是通过某个特殊的标签来保存在本地&#xff0c;而且该标签为key的意思&#xff0c;初始值不用赋值。 在游戏开发中较为实用。 暂时用到了 SetInt(string key, int value); 还有Ge…

4-类和结构体和可选类型

import UIKit var str “Hello, playground” // 1 枚举语法 // 与 C 和 Objective-C 不同&#xff0c;Swift 的枚举成员在被创建时不会被赋予一个默认的整型值 // 书写方式一 enum sizeType{ case small case middle case large } // 书写方式二 enum sizeNumber { case x,…

android处理url中的特殊字符

java处理url中的特殊字符&#xff08;如&,%...&#xff09; URL(Uniform Resoure Locator&#xff0c;统一资源定位器)是Internet中对资源进行统一定位和管理的标志。 一个完整的URL包括如下内容&#xff1a; 应用协议名称&#xff0c;包括http,ftp,file等标志 资源定位…

图的连通性和连通分量_英语,人口,连通性和露营地

图的连通性和连通分量by Evaristo Caraballo通过Evaristo Caraballo 英语&#xff0c;人口&#xff0c;连通性和露营地 (English, Population, Connectivity and Campsites) 在世界范围内推动使用Free Code Camp的因素 (Factors driving the use of Free Code Camp worldwide)…

jQuery源码分析系列:属性操作

属性操作 1.6.1相对1.5.x最大的改进&#xff0c;莫过于对属性.attr()的重写了。在1.6.1中&#xff0c;将.attr()一分为二&#xff1a; .attr()、.prop()&#xff0c;这是一个令人困惑的变更&#xff0c;也是一个破坏性的升级&#xff0c;会直接影响到无数的网站和项目升级到1.6…

HDU 5972 Regular Number(ShiftAnd+读入优化)

【题目链接】 http://acm.hdu.edu.cn/showproblem.php?pid5972 【题目大意】 给出一个字符串&#xff0c;找出其中所有的符合特定模式的子串位置&#xff0c;符合特定模式是指&#xff0c;该子串的长度为n&#xff0c;并且第i个字符需要在给定的字符集合Si中 【题解】 利用Sh…

把握机缘_机缘巧合,蒙太奇训练以及我的朋友如何使自己失业

把握机缘by Wiley Jones通过威利琼斯 机缘巧合&#xff0c;蒙太奇训练以及我的朋友如何使自己失业 (Serendipity, training montages, and how my friend automated himself out of a job) “No one person’s Hollywood success story has anything in common with anybody e…

Servlet(一)

BS架构的优势 1.数据库之负责数据库的管理 2.Web服务器负责业务逻辑的处理 3.浏览器提供操作界面 4.不需要单独安装客户端 5.开发相对于CS简单&#xff0c;客户端和服务器的通信模块都是使用标准的HTTP协议进行通信 CS架构 1.数据库作为Server,使用数据库特定的编程语言编写业务…

visual webgui theme designer

转载于:https://www.cnblogs.com/jintan/p/3804095.html

51单片机编码自学_这是9个月的自学式编码看起来像什么

51单片机编码自学by Stephen Mayeux斯蒂芬马约(Stephen Mayeux) 这是9个月的自学式编码看起来像什么 (Here’s What 9 Months of Self-Taught Coding Looks Like) 只是划伤表面 (Just Scratching the Surface) Today marks 9 months since I embarked on my journey as a self…

19.Remove Nth Node From End of List

方法1&#xff1a;由于链表不能随机访问&#xff0c;所以很自然的想法是第一遍得到链表长度&#xff0c;然后计算倒数第n个结点的位置&#xff0c;但这样时间复杂度O(n2)&#xff0c;想到用空间换取时间&#xff0c;可以用一个地址数组存储每个结点的地址&#xff0c;然后直接删…

HTML 5中SEO可以用那些代码来做优化

头部代码 1、标题标签(title标签) 在HTML5中标题标签依然存在&#xff0c;其仍然具有不可替代的作用;不过我们看到还有更多的可供搜索引擎识别的代码&#xff0c;我们将改代码的等级微降。 2、元标签(meta标签) 字符集编码声明标签 该标签原本就是搜索引擎必看且首先要看的标签…

XCode 导入头文件不提示解决

File --> WorkSpace Settings ---> Build Sysytem ---> Legacy Build System