C语言数据结构学习笔记(15)-哈夫曼树的创建及哈夫曼编码

/*
哈夫曼编码
输出结果:
请输入初始结点个数:5
请输入5个权值:2 5 7 8 6
最小元素为2下标为0, 次小元素为5下标为1
最小元素为6下标为4, 次小元素为7下标为2
最小元素为7下标为5, 次小元素为8下标为3
最小元素为13下标为6, 次小元素为15下标为7
下标    weight  parent  lchild  rchild
0       2       5       -1      -1
1       5       5       -1      -1
2       7       6       -1      -1
3       8       7       -1      -1
4       6       6       -1      -1
5       7       7       0       1
6       13      8       4       2
7       15      8       5       3
8       28      -1      6       7
中序遍历:6 13 7 28 2 7 5 15 8
树的带权路径长度WPL = 63
哈夫曼编码:
100
101
01
11
00
请按任意键继续. . .
*/
# include
# include
# include
typedef struct HuffmanTreeNode{
    int weight;//权值
    int parent;//父结点下标
    int lchild, rchild;//左右孩子结点下标
}HFNode, *HFTree;
HFTree CreateHuffmanTree(HFTree HF, int n);//创建哈夫曼树
void SeleteMin(HFTree HF, int i, int * min1, int * min2);//寻找无父结点元素合集中的最小和次小元素及其对应下标
void PrintHuffmanTree(HFTree HF, int n);//打印哈夫曼树数组
void InOrderHuffmanTree(HFTree HF, int index);//中序遍历哈夫曼树
int HuffmanWPL(HFTree HF, int n);//哈夫曼树的带权路径长度
void HuffmanCoding(HFTree HF, char ** coding, int n);//哈夫曼编码
int main(void)
{    
    int n;
    HFTree HF = NULL;
    printf("请输入初始结点个数:");
    scanf("%d", &n);
    HF = CreateHuffmanTree(HF, n);
    PrintHuffmanTree(HF, 2*n-1);
    printf("中序遍历:");
    InOrderHuffmanTree(HF, 2*n-2);
    printf("\n");
    printf("树的带权路径长度WPL = %d\n", HuffmanWPL(HF, n));
    printf("哈夫曼编码:\n");
    char ** coding = (char**)malloc(n * sizeof(char*));
    if(!coding)
        exit(-1);
    HuffmanCoding(HF, coding, n);
    for(int i = 0; i < n; i++)
        printf("%s\n", coding[i]);
    for(int i = 0; i < n; i++)
    {
        free(coding[i]);
        coding[i] = NULL;
    }
    free(coding);
    coding = NULL;
    free(HF);
    HF = NULL;
    system("pause");
    return 0;
}
//创建哈夫曼树
HFTree CreateHuffmanTree(HFTree HF, int n)
{    
    int total = 2*n - 1;
    HF = (HFTree)malloc(total*sizeof(HFNode));
    if(!HF)
        exit(-1);
    for(int i = 0; i < total; i++)
    {    
        HF[i].parent = -1;
        HF[i].lchild = -1;
        HF[i].rchild = -1;
    }
    printf("请输入%d个权值:", n);
    for(int i = 0; i < n; i++)
    {
        scanf("%d", &HF[i].weight);
    }
    int min1, min2;
    for(int i = n; i < total; i++)
    {
        SeleteMin(HF, i, &min1, &min2);
        HF[i].weight = HF[min1].weight + HF[min2].weight; 
        HF[i].lchild = min1;
        HF[i].rchild = min2;
        HF[min1].parent = i;
        HF[min2].parent = i;
    }
    return HF;
}
//寻找无父结点元素合集中的最小和次小元素及其对应下标
void SeleteMin(HFTree HF, int i, int * min1, int * min2)
{    
    int Min1, Min2;//定义最小值和次小值
    Min1 = Min2 = INT_MAX;//明示常量INT_MAX:int类型的最大值
    for(int j = 0; j < i; j++)
    {
        if(HF[j].weight < Min1 && -1 == HF[j].parent)
        {
            Min2 = Min1;
            *min2 = *min1;
            Min1 = HF[j].weight;
            *min1 = j;
        }
        else if(HF[j].weight < Min2 && -1 == HF[j].parent)
        {
            Min2 = HF[j].weight;
            *min2 = j;
        }
    }
    printf("最小元素为%d下标为%d, 次小元素为%d下标为%d\n", HF[*min1].weight, *min1, HF[*min2].weight, *min2);
}
//打印哈夫曼树数组
void PrintHuffmanTree(HFTree HF, int num)
{
    printf("下标\tweight\tparent\tlchild\trchild\n");
    for(int i = 0; i < num; i++)
    {
        printf("%d\t%d\t%d\t%d\t%d\n", i, HF[i].weight, HF[i].parent, HF[i].lchild, HF[i].rchild);
    }
}
//中序遍历哈夫曼树
void InOrderHuffmanTree(HFTree HF, int index)
{
    if(index != -1)
    {
        InOrderHuffmanTree(HF, HF[index].lchild);
        printf("%d ", HF[index].weight);
        InOrderHuffmanTree(HF, HF[index].rchild);
    }
}
//哈夫曼树的带权路径长度
int HuffmanWPL(HFTree HF, int n)
{    
    int sum = 0;
    for(int i = 0; i < n; i++)
    {    
        int wpl = 0;
        int pos = i;
        int p_index = HF[i].parent;
        while(p_index != -1)
        {    
            pos = p_index;
            p_index = HF[p_index].parent;
            wpl++;
        }
        sum += HF[i].weight * wpl;
    }
    return sum;
}
void HuffmanCoding(HFTree HF, char ** coding, int n)
{    
    char * code = (char*)malloc(n *sizeof(char));//临时存放编码
    if(!code)
        exit(-1);
    code[n-1] = '\0';
    for(int i = 0; i < n; i++)
    {    
        int start = n-1;
        int pos = i;//当前处理结点下标
        int p_index = HF[i].parent;
        while(p_index != -1)
        {    
            if(pos == HF[p_index].lchild)
                code[--start] = '0';
            else
                code[--start] = '1';
            pos = p_index;//当前位置向上移动
            p_index = HF[p_index].parent;//当前位置的父节点向上移动
        }
        coding[i] = (char*)malloc((n-start) *sizeof(char));//创建实际编码空间
        if(!coding[i])
            exit(-1);
        strcpy(coding[i], &code[start]);
    }
    free(code);
    code = NULL;
}
 

你可能感兴趣的:(数据结构,c语言,huffman,tree)