实验九数据结构严书5.10与5.11实现

本博文内容源于老师上课的数据结构,因为内容比较简单,所以在这里实现,本周的内容是哈夫曼编码。内容分为三步,看清题目、书写代码,进行测试

实验内容

实验9
写程序实现算法5.10、5.11

实验细节

5.10

在这里插入图片描述
写这段代码注意Select函数,一个是s1与s2,二是实现细节,代码如下
参考于leetcode找第一大与第二大,一般O(n)就可以完成.

void Select(HuffmanTree HT,int n,int &s1,int &s2) {
    
    
    int m1 = 1e6,m2 = 1e6;
    int i=1;
    for(i=1;i<=n;i++){
    
    
        if(HT[i].parent == 0){
    
    
            //find the minest weight
            if(HT[i].weight < m2){
    
     //它是取一个小值
                m1 = m2;
                s1 = s2;
                m2 = HT[i].weight;
                s2 = i;

            }else if(HT[i].weight < m1){
    
     //它是取另一个小值
                m1 = HT[i].weight;
                s1 = i;
            }
        }

    }
}

5.11

在这里插入图片描述
5.11的难点在于它的逻辑,它的逻辑是建立在你能创建一个已完成的霍夫曼树进行操作。

//有点类似于并查集,从1找父亲
typedef char **HuffmanCode; //dynamic malloc huffman code
void CreateHuffmanCode(HuffmanTree HT,HuffmanCode &HC,int n){
    
    
	HC = new char*[n+1];
	char *cd = new char[n];
	int i;
	cd[n-1]='\0';
	for(i=1;i<=8;i++){
    
    
	    int start = n-1;
        int c= i;
        int f = HT[i].parent;
        while(f!=0){
    
    
            cout <<f << " " << HT[f].lchild << " " << c ;
            --start;
            if(HT[f].lchild == c)
                cd[start] = '0';
            else
                cd[start] = '1';
            cout << " " << cd[start] << endl;
            c = f;
            f = HT[f].parent;

        }

        HC[i] = new char[n-start];
        strcpy(HC[i],&cd[start]);
	}
	delete cd;

}

实验效果测试

我想创建的树,与书上的类似。因为霍夫曼不唯一,比较一下书上的差不多。(潦草是我的)
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

完整代码

//dev c++ 6.3 running
#include<iostream>
#include<cstring>
#define Node 8
using namespace std;
typedef struct{
    
    
    int weight; //node weight
    int parent,lchild,rchild; //node parent,left child and right child
}HTNode,*HuffmanTree; // new huffman

void Select(HuffmanTree HT,int n,int &s1,int &s2) {
    
    
    int m1 = 1e6,m2 = 1e6;
    int i=1;
    for(i=1;i<=n;i++){
    
    
        if(HT[i].parent == 0){
    
    
            //find the minest weight
            if(HT[i].weight < m2){
    
    
                m1 = m2;
                s1 = s2;
                m2 = HT[i].weight;
                s2 = i;

            }else if(HT[i].weight < m1){
    
    
                m1 = HT[i].weight;
                s1 = i;
            }
        }

    }
}
void CreateHuffmanTree(HuffmanTree &HT,int n){
    
    
    if(n<=1) return;
    int m = 2*n-1,i;
    HT = new HTNode[m+1]; //0 unit not use HT[m] need root
    for(i=1;i<=m;++i){
    
    
        HT[i].parent = 0;
        HT[i].lchild = 0;
        HT[i].rchild = 0;
    }
    for(i =1;i<=n;++i){
    
    
        cin >> HT[i].weight;
    }
    for(i=n+1;i<=m;++i){
    
    
        int s1=1,s2=1;
        Select(HT,i-1,s1,s2);
        HT[s1].parent = i;
        HT[s2].parent = i;
        HT[i].lchild = s1;
        HT[i].rchild = s2;
        HT[i].weight = HT[s1].weight + HT[s2].weight;
    }

}

typedef char **HuffmanCode; //dynamic malloc huffman code
void CreateHuffmanCode(HuffmanTree HT,HuffmanCode &HC,int n){
    
    
	HC = new char*[n+1];
	char *cd = new char[n];
	int i;
	cd[n-1]='\0';
	for(i=1;i<=8;i++){
    
    
	    int start = n-1;
        int c= i;
        int f = HT[i].parent;
        while(f!=0){
    
    
           
            --start;
            if(HT[f].lchild == c)
                cd[start] = '0';
            else
                cd[start] = '1';
         
            c = f;
            f = HT[f].parent;

        }

        HC[i] = new char[n-start];
        strcpy(HC[i],&cd[start]);
	}
	delete cd;

}


int main(){
    
    
    HuffmanTree HT;
    int n = 8,i;
    CreateHuffmanTree(HT,n);
    for(i=1;i<=15;i++){
    
    
        cout << HT[i].weight << " " << HT[i].parent << " " <<HT[i].lchild << " "
        << HT[i].rchild << endl;
    }


    HuffmanCode HC;
    CreateHuffmanCode(HT,HC,8);
    for(i =1;i<=8;i++){
    
    
        cout << HC[i] << endl;
    }
    return 0;
}



#include <iostream>
using namespace std;
#include <string>
#include <cstring>
//-----哈夫曼树的存储表示-----
typedef struct{
    
    
	int weight;//结点的权值
	int parent,lchild,rchild;//结点的双亲、左孩子、右孩子的下标
}HTNode,*HuffmanTree;//动态分配数组存储哈夫曼树

void Select(HuffmanTree HT,int n,int &s1,int &s2){
    
    
	int a= 1e4,b= 1e4;//选两个很大的值进行比大小
    for(int i=1;i<=n;i++){
    
    
        if(HT[i].parent == 0){
    
    //一开始双亲都为0
            if(HT[i].weight < b){
    
    
                a = b;
                s1 = s2;
			//如果找到比b还小的,则将a变为b,s2赋给s1,继承b(原来最小的值)
                b = HT[i].weight;
                s2 = i;//取出最小的结点编号
            }else if(HT[i].weight < a){
    
    
			/*第一个条件语句满足后,即便第二个条件语句也满足,也不会执行第二个括号。
			所以这是用来在第一个条件语句不满足后,用来比较出第二小的*/
                a = HT[i].weight;
                s1 = i;//取出第二小的结点编号
            }
        }
    }
}
//构造哈夫曼树
void CreateHuffmanTree(HuffmanTree &HT,int n){
    
    
//------------初始化哈夫曼树HT------------
	if(n<=1) return;
	int m=2*n-1;//n个结点构造出哈夫曼树后的结点总个数
	HT=new HTNode[m+1]; //0号单元未用,所以需要动态分配m+1个单元,HT[m]表示根节点//HT是指针,指向结点
	for(int i=1;i<=m;++i){
    
    //将1~m号单元中的双亲、左孩子,右孩子的下标都初始化为0
		HT[i].parent=0;
		HT[i].lchild=0;
		HT[i].rchild=0;
	}
	cout << n << endl;
	for(int i=1;i<=n;i++){
    
    
		cin>>HT[i].weight;//输入前n个单元各结点的权值
	}
//------------创建哈夫曼树------------
	for(int i=n+1;i<=m;i++){
    
    //n+1是新合并出来的第一个结点的编号i
		int s1,s2;//因为select函数传的是变量,所以要先声明,如果是定值就不需要先声明
		Select(HT,i-1,s1,s2);//在HT[k](1<=k<=i-1)中选择两个其双亲域为0且权值最小的结点,并返回它们在HT中的序号s1和s2
		//得到新结点i,从森林中删除s1和s2,将s1和s2的双亲域由0改为i
		HT[s1].parent=i;
		HT[s2].parent=i;
		//s1,s2分别作为i的左右孩子
		HT[i].lchild=s1; HT[i].rchild=s2;
		//i的权值为左右孩子权值之和
		HT[i].weight=HT[s1].weight+HT[s2].weight;
	}
}
//输出哈夫曼树
void printHuffmanTree(HuffmanTree &HT,int m){
    
    
    cout << "Huffman is:" << endl;
	for(int i=1;i<=m;i++){
    
    //注意i不要从0开始,因为0号位没有权值
		cout << HT[i].weight << " " << HT[i].parent << " " <<HT[i].lchild << " "<< HT[i].rchild << endl;
	}
}
//哈夫曼编码
typedef char **HuffmanCode;
void CreateHuffmanCode(HuffmanTree HT,HuffmanCode &HC,int n){
    
    
//从叶子到根逆向求每个字符的哈夫曼编码,存储在编码表HC中
	HC=new char*[n+1];//分配存储n个字符编码的编码表空间,指针HC指向他们
	char *cd=new char[n]; //分配临时存放每个字符编码的动态数组空间
	cd[n-1]='\0';//开辟了n个空间,cd[n-1]是最后一格,放'\0'
    int i;
	for(i=1;i<=8;i++){
    
    
		int start=n-1;//start开始时指向最后,即便编码结束符位置
		int c=i;
		int f=HT[i].parent;//f指向结点c的双亲结点
		while(f!=0){
    
    
			--start;//回溯一次start向前指一个位置
			if(HT[f].lchild==c)
				cd[start]='0';//结点c是f的左孩子,则生成代码0
			else
				cd[start]='1';//结点c是f的右孩子,则生成代码1
			c=f;
            f=HT[f].parent;//继续向上回溯
		}//求出第i个字符的编码
		HC[i]=new char[n-start];//为第i个字符编码分配空间
		strcpy(HC[i],&cd[start]);//将求得的编码临时从cd复制到HC的当前行中
	}
	delete cd;//释放临时空间
}
int main(){
    
    
	HuffmanTree HT;
	int n=8;
	CreateHuffmanTree(HT,n);
	printHuffmanTree(HT,2*n-1);

	HuffmanCode HC;
	CreateHuffmanCode(HT,HC,8);
	for(int i=1;i<=8;i++){
    
    
        cout<< HC[i] <<endl;
    }
	system("pause");
}

猜你喜欢

转载自blog.csdn.net/m0_37149062/article/details/124526343