1. 程式人生 > >樹與二叉樹

樹與二叉樹

樹形結構是計算機最重要的資料結構,連結串列示特殊的樹.

特點:

  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 對應的位元長度為 l1,l2,l3ln

lsum=i=1naili

我們最終的目標是要實現期望lsum達到最小,那麼這也就說我們需要做到 amax 對應 lmin

深度大的說明他的編碼長度長,那麼該分配他出現概率低的字元

構建步驟:

  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;
}