code is beautiful
运行结果:使用频率小的字符编码尽量短
详解:
1.构造(链表实现)
要点:
一.采用STL优先队列筛选出权值小的两个节点,重写比较方式
struct cmp { //重写仿函数
bool operator()(Node* a, Node* b)
{
return a->weight > b->weight;//小顶堆
}
};
priority_queue<Node*, vector<Node*>, cmp>q;
二.
HuffTree::HuffTree(vector<Node*>s)
{
depth = 0;
int sum = 0;
Node* parent = new Node();
Node* lchild = new Node();
Node* rchild = new Node();
priority_queue<Node*, vector<Node*>, cmp>q;
for (auto it : s) { q.push(it); }
while (q.size() > 1)
{
sum = 0;
//构建两个孩子结点
lchild = q.top();
sum += q.top()->weight;
q.pop();
rchild = q.top();
sum += q.top()->weight;
q.pop();
// 构建双亲结点,并添加
parent = new Node(sum);
q.push(parent);
//建立联系
parent->lchild = lchild;
parent->rchild = rchild;
lchild->parent = parent;
rchild->parent = parent;
}
root = parent;
}
2.编码
思想:采用字符数组存储路径上的01序列,遍历到叶子节点时就存在编码序列中
void HuffTree::encode(char* s, int depth, Node* node)
{
if (node->lchild == nullptr && node->rchild == nullptr)
{
int c = node->a - 'A';
s[depth] = '\0';
code[c] = _strdup(s);//字符串拷贝
return;
}
//给左右子树赋值
s[depth] = '0';
encode(s, depth + 1, node->lchild);
s[depth] = '1';//返回到一开始的depth
encode(s, depth + 1, node->rchild);
}
3.解码
1.根据编码序列,遇到’0‘往左子树走,遇到’1‘往右子树走 直到走到叶子节点进而存储相应的字符
string HuffTree::decode(char* target)
{
char result[50];
int resultCnt = 0;
int targetCnt = strlen(target);
Node* cur = root;
for (int i = 0; i < targetCnt; i++)
{
if (target[i] == '0')
{
cur = cur->lchild;
}
else {
cur = cur->rchild;
}
if (cur->lchild == nullptr && cur->rchild == nullptr)
{
result[resultCnt++] = cur->a;
cur = root;//重新遍历
}
}
if (cur != root)
{
return "invalid sequence";
}
else {
result[resultCnt] = '\0';
return _strdup(result);
}
}
这里注意 如果最终cur指针不等于root则说明该序列无法凑成完整的字符序列,是无效的编码
4.最后附上已知二叉树的前中序和中后序遍历来构造树的方法
要点:
一.找到根节点后 继续存储左右子树序列 然后递归继续执行此过程
二.递归不太理解的话可以试着自己手写模拟一下过程,就明白了
TreeNode<T>* Create(vector<T>pre,vector<T>vin)
{
int len = pre.size();
if (len == 0) { return nullptr; }
TreeNode<T>*tempRoot= new TreeNode<T>(pre[0]);
//cout << root->val << " ";
vector<T>pre_left, pre_right, vin_left, vin_right;
int _root;
for (int i = 0; i < len; i++)
{
if (vin[i] == pre[0])
{
_root = i;//求得中序遍历时根节点的位置
break;
}
}
for (int i = 0; i < _root; i++)
{
pre_left.push_back(pre[i + 1]);//绕过根节点
vin_left.push_back(vin[i]);
}
for (int i = _root + 1; i < len; i++)
{
pre_right.push_back(pre[i]);
vin_right.push_back(vin[i]);
}
tempRoot->left = Create(pre_left, vin_left);
tempRoot->right = Create(pre_right, vin_right);
return tempRoot;
}
中后序遍历构造树思想方法类似~~