树与二叉树

树形结构是计算机最重要的数据结构,链表示特殊的树.

特点:

  1. 节点抽象为集合,边抽象为关系。
  2. 树由节点与边构成。
  3. 子节点之间是没有交集的。
  4. 每个节点的指针域两个至多个(N叉树)。
  5. 节点数 = 边数 + 1。
  6. 图的度 = 出度 + 入度, 树的度 = 出度。

定理:

二叉树中度数为零的节点比度数为2的节点多一个。

满二叉树:没有度数为1的节点。

完全二叉树:除了最后一层的所有节点度数均为2。


树的遍历种类:

  • 先序遍历:1. 根节点 2. 左子树 3. 右子树
  • 中序遍历:1. 左子树 2. 根节点 3. 右子树
  • 后序遍历:1. 左子树 2. 右子树 3. 根节点

巧记:所谓前中后序,是根据根节点的位置的访问时序决定的。


哈夫曼树 :

哈夫曼编码用于数据压缩。

例子:具有三个字母的系统
若采用定长编码:
每个单元需要两个比特位,期望为2。
若采用变长编码:
根据a, b, c出现频率为 a:0.5 b:0.4 c:0.1,将a,b,c编码为0, 10, 11,则期望为1.5

哈夫曼树是一颗满二叉树,n个叶子节点, n - 1个中间节点(度数为2)。
至今为止人类发现的最优的变长编码(离线编码)。

思考与分析
具有n个字符的系统。
他们出现的概率分别是 a1,a2,a3an a 1 , a 2 , a 3 … a n 对应的比特长度为 l1,l2,l3ln l 1 , l 2 , l 3 … l n

lsum=ni=1aili l s u m = ∑ i = 1 n a i ∗ l i

我们最终的目标是要实现期望 lsum l s u m 达到最小,那么这也就说我们需要做到 amax a m a x 对应 lmin l m i n

深度大的说明他的编码长度长,那么该分配他出现概率低的字符

构建步骤:

  1. 首先找出出现频率最低的两个字符为他们分配前缀,然后进行合并。
  2. 接下来为树中每一条边进行赋值
  3. 不断合并最终仅剩一个根节点

演示代码:

二叉树:
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
    int key;
    struct Node *lchild, *rchild;
} Node;
Node *getNode(int);
void clear(Node *);
void pre_order(Node *);
void in_order(Node *);
void post_order(Node *);
int main(){
    Node *root = getNode(1);
    root->lchild = getNode(2);
    root->rchild = getNode(3);
    root->lchild->lchild = getNode(7);
    root->lchild->rchild = getNode(8);
    root->lchild->rchild->lchild = getNode(9);
    root->rchild->rchild = getNode(4);
    root->rchild->rchild->lchild = getNode(5);
    root->rchild->rchild->rchild = getNode(6);
    pre_order(root); printf("\n");
    in_order(root); printf("\n");
    post_order(root); printf("\n");
}

Node *getNode(int key) {
    Node *p = (Node *)malloc(sizeof(Node));
    p->key = key;
    p->lchild = p->rchild = NULL;
    return p;
}

void clear(Node *root) {
    if (root == NULL) return;
    clear(root->lchild);
    clear(root->rchild);
    free(root);
    return;
}
void pre_order(Node* root) {
    if (root == NULL) return;
    printf("%d ", root->key);
    pre_order(root->lchild);
    pre_order(root->rchild);
}
void in_order(Node *root) {
    if (root == NULL) return;
    in_order(root->lchild);
    printf("%d ", root->key);
    in_order(root->rchild);
}
void post_order(Node *root) {
    if (root == NULL) return;
    post_order(root->lchild);
    post_order(root->rchild);
    printf("%d ", root->key);
}
哈夫曼树:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define CHAR_NUM 26

#define swap(a, b) { \
    __typeof(a) temp; \
    temp = a; \
    a = b;  \
    b = temp; \
}

typedef struct HFNode {
    char ch;
    int freq;
    struct HFNode *lchild, *rchild;
} HFNode;

HFNode *getNode() {
    HFNode *p = (HFNode *)malloc(sizeof(HFNode));
    p->freq = p->ch = 0;
    p->lchild = p->rchild = NULL;
    return p;
}

void build(int n, HFNode *arr[]) {
    for (int times = 0; times < n - 1; times++) {
        HFNode *minNode = arr[0];
        int ind = 0;
        for (int i = 1; i < n - times; i++) {
            if (arr[i]->freq >= minNode->freq) continue;
            minNode = arr[i];
            ind = i;
        }
        swap(arr[ind], arr[n - times - 1]);
        minNode = arr[0];
        ind = 0;
        for (int i = 1; i < n - times - 1; i++) {
            if (arr[i]->freq >= minNode->freq) continue;
            minNode = arr[i];
            ind = i;
        }
        swap(arr[ind], arr[n - times - 2]);
        HFNode *new_node = getNode();
        new_node->lchild = arr[n - times - 1];
        new_node->rchild = arr[n - times - 2];
        new_node->freq = arr[n - times - 1]->freq + arr[n - times - 2]->freq;
        arr[n - times - 2] = new_node;
    }
    return ;
}

void extract(HFNode *root, char *buff, char (*huffman_code)[100], int n) {
    buff[n] = '\0';
    if (root->lchild == NULL && root->rchild == NULL) {
        strcpy(huffman_code[root->ch], buff);
        return;
    }
    buff[n] = '0';
    extract(root->lchild, buff, huffman_code, n + 1);
    buff[n] = '1';
    extract(root->rchild, buff, huffman_code, n + 1);
    return ;
}

int main() {
    HFNode *arr[CHAR_NUM] = {0};
    char buff[100];
    char huffman_code[256][100] = {0};
    int freq;
    for (int i = 0; i < CHAR_NUM; i++) {
        scanf("%s%d", buff, &freq);
        printf("read %s = %d\n", buff, freq);
        HFNode *new_node = getNode();
        new_node->ch = buff[0];
        new_node->freq = freq;
        arr[i] = new_node;
    }
    build(CHAR_NUM, arr);
    extract(arr[0], buff, huffman_code, 0);
    for (int i = 0; i < 256; i++) {
        if (huffman_code[i][0] == 0) continue;
        printf("%c : %s\n", (char)i, huffman_code[i]);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值