哈夫曼树与哈夫曼编码【做题记录】

哈夫曼树的创建

Step1:创建一个数组,存放所有的结点。结点的个数是leafNum2-1

Step2:将叶子结点存放到数组中,对叶子结点进行初始化 parent,left,right设为未构建 权重按照weightArray数组赋值

Step3:对数组中其它的结点也进行初始化 parent,left,right设为未构建 权重按照weightArray=0

Step4:依次求子树结点存入数组 循环本轮要填的结点的位置k从leafNum开始,到leafNum2-1结束

        求本轮最小和次小权值的下标

        minIndex1和minIndex2两个结点构建子树 

        minIndex1和minIndex2的parent设为i

        第i个结点的权重为两个结点之和

        第i个结点的left为minIndex1

        第i个结点的right为minIndex2

参考函数头

void createHuffmanTree(HTNode * HTArray,int * weightArray,int leafNum)

【注意】 当前结点比最小权重小,标记它为最小权重。 当前结点比最小权重大,比次小权重小,标记为次小权重。 不要写成大于等于,或者小于等于,逻辑上可以,但是后续哈夫曼编码的某些测试数据可能不能通过。

【输入输出】

第一行输入叶子节点的个数。

第二行输入各个叶子节点的权值。

输出哈夫曼树的数组,直接调用打印函数printHufTree实现。

【测试数据】

输入: 4 2 4 5 3

输出:

0 weight= 2 parent= 4 leftChild=-1 rightChild=-1

1 weight= 4 parent= 5 leftChild=-1 rightChild=-1

2 weight= 5 parent= 5 leftChild=-1 rightChild=-1

3 weight= 3 parent= 4 leftChild=-1 rightChild=-1

4 weight= 5 parent= 6 leftChild= 0 rightChild= 3

5 weight= 9 parent= 6 leftChild= 1 rightChild= 2

6 weight=14 parent=-1 leftChild= 4 rightChild= 5

【题解代码】

 #include<iostream>
#include<string.h>
#include <iomanip>
#define UNCONSTRUCTED -1 //表示结点没有构建树
#define MAX 20
using namespace std;
/**哈夫曼树结点结构*/
struct HTNode
{
    int weight;//结点权重
    int parent, left, right;//父结点、左孩子、右孩子在数组中的位置下标
};

/**选择最小和次小结点*/
void selectMin(HTNode * HTArray,int k,int & minIndex1,int & minIndex2);
/**创建哈夫曼树*/
void createHuffmanTree(HTNode * HTArray,int * weightArray,int leafNum);
/**打印哈夫曼树*/
void printHufTree(HTNode * treeArray,int leafNum);




/**创建哈夫曼树
* @param HTArray为地址传递的存储哈夫曼树的数组
* @param weightArray为存储结点权重值的数组
* @param leafNum为结点个数
算法
创建一个数组,存放所有的结点。结点的个数是leafNum*2-1
将叶子结点存放到数组中,对叶子结点进行初始化
    parent,left,right设为未构建
    权重按照weightArray数组赋值
对数组中其它的结点也进行初始化
    parent,left,right设为未构建
    权重按照weightArray=0
依次求子树结点存入数组
循环本轮要填的结点的位置k位置从leafNum开始,到leafNum*2-1结束
    求最小和次小权值的下标
    minIndex1和minIndex2两个结点构建子树
        minIndex1和minIndex2的parent设为i
        第i个结点的权重为两个结点之和
        第i个结点的left为minIndex1
        第i个结点的right为minIndex2
*/
void createHuffmanTree(HTNode * HTArray,int * weightArray,int leafNum)
{
    //哈夫曼数组的长度
    int length=leafNum*2-1;
    //叶子结点初始化
    for(int i=0;i<leafNum;i++)
    {
        HTArray[i].parent=UNCONSTRUCTED;
        HTArray[i].left=UNCONSTRUCTED;
        HTArray[i].right=UNCONSTRUCTED;
        HTArray[i].weight=weightArray[i];
    }
    //非叶子结点初始化
    for(int i=leafNum;i<length;i++)
    {
        HTArray[i].parent=UNCONSTRUCTED;
        HTArray[i].left=UNCONSTRUCTED;
        HTArray[i].right=UNCONSTRUCTED;
        HTArray[i].weight=0;//权值为0
    }

    //构建哈夫曼树
    //k为当前要写的下标,从第一个非叶子结点开始
    for(int k=leafNum;k<length;k++)
    {
        int minIndex1,minIndex2;//两个最小值的下标
        selectMin(HTArray,k,minIndex1,minIndex2);//求最小和次小权值的下标
        //cout<<"\n本轮写的结点下标k="<<k<<" minIndex1="<<minIndex1<<" minIndex2="<<minIndex2<<endl;

        //minIndex1和minIndex2两个结点构建子树
        HTArray[k].weight=HTArray[minIndex1].weight+HTArray[minIndex2].weight;
        HTArray[k].left=minIndex1;
        HTArray[k].right=minIndex2;
        HTArray[minIndex1].parent=k;
        HTArray[minIndex2].parent=k;
        //cout<<"最小下标"<<minIndex1<<"次小下标"<<minIndex2<<endl;
        //printHufTree(HTArray,leafNum);//打印中间结果
    }
    return ;
}


/**
 * 从给定的哈希表数组中选择两个最小权重的元素的索引。
 *
 * @param HTArray 指向哈希表数组的指针。
 * @param k       要检查的哈希表数组的大小。
 * @param minIndex1 用于存储第一个最小权重元素的索引的引用。
 * @param minIndex2 用于存储第二个最小权重元素的索引的引用。
 */
void selectMin(HTNode * HTArray, int k, int & minIndex1, int & minIndex2)
{
    int i = 0; // 初始化循环变量i为0
    minIndex1 = -1; // 初始化第一个最小权重元素的索引为-1,表示未找到
    minIndex2 = -1; // 初始化第二个最小权重元素的索引为-1,表示未找到
    while (i < k) // 当i小于k时继续循环
    {
        if (HTArray[i].parent == UNCONSTRUCTED) // 如果当前元素未被构造
        {
            if (minIndex1 == -1 || HTArray[i].weight < HTArray[minIndex1].weight) // 如果当前元素权重小于已找到的第一个最小权重元素
            {
                minIndex2 = minIndex1; // 将第二个最小权重元素的索引更新为第一个最小权重元素的索引
                minIndex1 = i; // 更新第一个最小权重元素的索引为当前元素的索引
            }
            else if (minIndex2 == -1 || HTArray[i].weight < HTArray[minIndex2].weight) // 如果当前元素权重小于已找到的第二个最小权重元素
            {
                minIndex2 = i; // 更新第二个最小权重元素的索引为当前元素的索引
            }
        }
        i++; // 增加循环变量i的值
    }
}

/**
打印哈夫曼树
* @param HTNode * treeArray 哈夫曼树的数组
* @param int leafNum 叶子个数

*/
void printHufTree(HTNode * treeArray,int leafNum)
{
    //cout<<"\n哈夫曼树:\n";
    for(int i=0;i<leafNum*2-1;i++)
    {
        cout<<setw(2)<< i
        <<" weight="<<setw(2)<<treeArray[i].weight
        <<" parent="<<setw(2)<<treeArray[i].parent
        <<" leftChild="<<setw(2)<<treeArray[i].left
        <<" rightChild="<<setw(2)<<treeArray[i].right
        <<endl;
    }
    cout<<"----------------------\n";
    return;
}

int main()
{
    //叶子结点个数
    int leafNum;
    int i;
    int w[MAX]={0};
    //权值数组和字符数组
   cin>>leafNum;
   for(i=0;i<leafNum;i++)
   {
       cin>>w[i];
   }
    //哈夫曼树数组
    HTNode * HTArray=new HTNode[leafNum*2-1];
    //创建哈夫曼树
    createHuffmanTree(HTArray,w,leafNum);
    //打印哈夫曼树
    printHufTree(HTArray,leafNum);
    return 0;
}

哈夫曼编码

【哈夫曼编码】 是在哈夫曼树的基础上构建的,这种编码方式最大的优点就是用最少的字符包含最多的信息内容。

根据发送信息的内容,通过统计文本中相同字符的个数作为每个字符的权值,建立哈夫曼树。

对于树中的每一个子树,统一规定其左孩子标记为 0 ,右孩子标记为 1 。

用到哪个字符时,从哈夫曼树的根结点开始,依次写出经过结点的标记,最终得到的就是该结点的哈夫曼编码。

结点权值越高,在哈夫曼树中的体现就是越接近树根,编码的长度越短。

【哈夫曼编码方案】

从叶子到根逆向求每个字符的哈夫曼编码 算法

Step1:创建一个暂存字符串,来保存哈夫曼编码

Step2:循环,依次访问每一个叶子结点

如果结点还有双亲就进行循环 找到结点的双亲

如果它是双亲的左儿子,字符串标0

如果它是双亲的右儿子,字符串标1

访问下标进行移动,指向结点的双亲

当前叶子结点追溯到了根结点,将暂存的字符串导入结果字符串数组

【输入输出】

第一行输入结点的个数n,n小于100。

第二行输入n个结点的权值

第三行输入n个结点的内容,为n个字符

输出n行,为n个结点的哈夫曼编码。

【测试数据】

输入

7

9 11 5 7 8 2 3

A B C D E F G

输出

A:00

B:10

C:010

D:110

E:111

F:0110

G:0111

【题解代码】

#include<iostream>
#include<string.h>
#include <iomanip>
#define UNCONSTRUCTED -1 //表示结点没有构建树
#define MAX 20
using namespace std;
/**哈夫曼树结点结构*/
struct HTNode
{
    int weight;//结点权重
    int parent, left, right;//父结点、左孩子、右孩子在数组中的位置下标
};

/**选择最小和次小结点*/
void selectMin(HTNode* HTArray, int k, int& minIndex1, int& minIndex2);
/**创建哈夫曼树*/
void createHuffmanTree(HTNode* HTArray, int* weightArray, int leafNum);
/**打印哈夫曼树*/
//void printHufTree(HTNode* treeArray, int leafNum);




/**创建哈夫曼树
* @param HTArray为地址传递的存储哈夫曼树的数组
* @param weightArray为存储结点权重值的数组
* @param leafNum为结点个数
算法
创建一个数组,存放所有的结点。结点的个数是leafNum*2-1
将叶子结点存放到数组中,对叶子结点进行初始化
    parent,left,right设为未构建
    权重按照weightArray数组赋值
对数组中其它的结点也进行初始化
    parent,left,right设为未构建
    权重按照weightArray=0
依次求子树结点存入数组
循环本轮要填的结点的位置k位置从leafNum开始,到leafNum*2-1结束
    求最小和次小权值的下标
    minIndex1和minIndex2两个结点构建子树
        minIndex1和minIndex2的parent设为i
        第i个结点的权重为两个结点之和
        第i个结点的left为minIndex1
        第i个结点的right为minIndex2
*/
void createHuffmanTree(HTNode* HTArray, int* weightArray, int leafNum)
{
    //哈夫曼数组的长度
    int length = leafNum * 2 - 1;
    //叶子结点初始化
    for (int i = 0; i < leafNum; i++)
    {
        HTArray[i].parent = UNCONSTRUCTED;
        HTArray[i].left = UNCONSTRUCTED;
        HTArray[i].right = UNCONSTRUCTED;
        HTArray[i].weight = weightArray[i];
    }
    //非叶子结点初始化
    for (int i = leafNum; i < length; i++)
    {
        HTArray[i].parent = UNCONSTRUCTED;
        HTArray[i].left = UNCONSTRUCTED;
        HTArray[i].right = UNCONSTRUCTED;
        HTArray[i].weight = 0;//权值为0
    }

    //构建哈夫曼树
    //k为当前要写的下标,从第一个非叶子结点开始
    for (int k = leafNum; k < length; k++)
    {
        int minIndex1, minIndex2;//两个最小值的下标
        selectMin(HTArray, k, minIndex1, minIndex2);//求最小和次小权值的下标
        //cout<<"\n本轮写的结点下标k="<<k<<" minIndex1="<<minIndex1<<" minIndex2="<<minIndex2<<endl;

        //minIndex1和minIndex2两个结点构建子树
        HTArray[k].weight = HTArray[minIndex1].weight + HTArray[minIndex2].weight;
        HTArray[k].left = minIndex1;
        HTArray[k].right = minIndex2;
        HTArray[minIndex1].parent = k;
        HTArray[minIndex2].parent = k;
        //cout<<"最小下标"<<minIndex1<<"次小下标"<<minIndex2<<endl;
        //printHufTree(HTArray,leafNum);//打印中间结果
    }
    return;
}


/**选择最小和次小权重
*@param HTArray 存放哈夫曼树结点的数组
*@param k 为当前要写的结点的下标
*@param minIndex1,minIndex2最小和次小结点的下标
查找权重值最小的两个结点的思想是:从树组起始位置开始,首先找到两个无父结点的结点(说明还未使用其构建成树),然后和后续无父结点的结点依次做比较,有两种情况需要考虑:
如果比两个结点中较小的那个还小,就保留这个结点,删除原来较大的结点;
如果介于两个结点权重值之间,替换原来较大的结点;
*/
void selectMin(HTNode* HTArray, int k, int& minIndex1, int& minIndex2)
{
    int i = 0;
    minIndex1 = -1;
    minIndex2 = -1;
    while (i < k)
    {
        if (HTArray[i].parent == UNCONSTRUCTED)
        {
            if (minIndex1 == -1 || HTArray[i].weight < HTArray[minIndex1].weight)
            {
                minIndex2 = minIndex1;
                minIndex1 = i;
            }
            else if (minIndex2 == -1 || HTArray[i].weight < HTArray[minIndex2].weight)
            {
                minIndex2 = i;
            }
        }
        i++;
    }
}


/**生成哈夫曼编码的函数
HTArray 存放哈夫曼树的数组
code 存放编码的字符串
leafNum 叶子节点个数
从叶子结点一直找到根结点,逆向记录途中经过的标记。
是左儿子标记0,右儿子标记1。
*/
void huffmanCoding(HTNode* HTArray, char**& code, int leafNum)
{
    char *temp; //声明temp数组
    temp = new char[leafNum];//定义临时工作空间,存储临时产生的编码串
    temp[leafNum - 1] = '\0';  //因为是逆向,所以得从末尾开始,先把最后一位置为空
    int start, pos;  //start为temp数组正在处理位置de下标,pos记录正在处理的哈夫曼树的当前位置
    int parent;  //记录父节点
    for(int i=0;i<leafNum;i++)//依次遍历哈夫曼数组
    {
        start = leafNum - 1;
        pos = i;
        parent = HTArray[i].parent; //找到父节点
        while (parent != -1)
        {
            if (HTArray[parent].left == pos) //当前结点是左孩子的话,就存0
            {
                temp[--start] = '0'; //start前移一位,存入编码
            }
            else //右孩子,存1
            { 
                temp[--start] = '1';
            }
            pos = parent; //pos移动到父节点,以进行下一轮查找
            parent = HTArray[parent].parent;//更新父节点
        }
        code[i] = new char[leafNum - start]; //建立哈夫曼编码实际需要的内存空间
                                             //leafNum-start是正在处理结点的编码长度
        strcpy(code[i], &temp[start]);       //将临时存储的编码拷贝到code中
    }
    delete []temp; //释放工作空间
}
//打印哈弗曼编码
void printCode(char* *code, char* data, int leafNum)
{
    // cout<<"哈夫曼编码是\n";
    for (int i = 0; i < leafNum; i++)
    {
        cout << data[i]<<":";
        cout << code[i] << endl;
    }

}


int main()
{
    //叶子结点个数
    int leafNum;
    int i;
    int w[MAX] = { 0 };
    //权值数组和字符数组
    cin >> leafNum;
    for (i = 0; i < leafNum; i++)
    {
        cin >> w[i];
    }
    //输入字符数组
    char ch[MAX] = { 0 };
    char** code = new char* [leafNum]; //二级指针,指向指针的指针。为code分配内存空间,存储编码
    for (i = 0; i < leafNum; i++)
    {
        cin >> ch[i];
    }
    //哈夫曼树数组
    HTNode* HTArray = new HTNode[leafNum * 2 - 1];
    //创建哈夫曼树
    createHuffmanTree(HTArray, w, leafNum);
    //哈夫曼编码
    huffmanCoding(HTArray,code, leafNum);
    //打印哈夫曼编码
    printCode(code, ch,leafNum);
    //删除内存
    for(int j=0;j<leafNum;j++)
    {
        delete code[j];
    }
    delete []code;
    delete []HTArray;
    return 0;
}

计算WPL

【算法】

WPL为所有叶节点的带权路径长度之和,同时也是所有非叶子结点的权值之和。

【题解代码】

正常思路是遍历整个哈夫曼树,对于树中的每个叶子结点,计算其权重与从根结点到该叶子结点的路径长度的乘积。然后将所有叶子结点的这个乘积相加,得到整棵树的WPL。

但是通过观察可以发现WPL也可以通过用叶子结点的权值乘以其哈弗曼编码的长度求得。下面展示的是这种方法的代码。

哈夫曼树的创建和其编码的函数代码和上面一样,以下是计算WPL的函数。


/*求哈夫曼树的权值*/
//首先找到叶子结点,然后用叶子结点的数字*其哈夫曼编码的长度,再求和
int seekWPL(HTNode* HTArray, int leafNum, char** code)
{
    int i = 0;
    int sum = 0;
    while (i < leafNum)
    {
        if (HTArray[i].left == -1&&HTArray[i].right==-1)//找到叶子结点
        {
            int length = strlen(code[i]);
            sum += HTArray[i].weight * length;
        }
        i++;
    }
    return sum;
}

这里的code 是一个二级指针,因为它是用来存储哈夫曼编码的字符串数组的地址。通过使用二级指针,seekWPL 函数可以直接修改 code 数组中的字符串。

字符串的哈夫曼编码

【题目要求】

输入一行字符串,例如:

Hooray! It's snowing! It's time to make a snowman.James runs out. He makes a big pile of snow.

统计上面的英文字母出现的次数作为权值,不区分大小写,对字母进行哈夫曼编码,输出各个字母的哈夫曼编码。字符个数不超过1000个,不少于2个,英文字符的种类不唯一。

【测试数据】

输入

Hooray! It's snowing! It's time to make a snowman.James runs out. He makes a big pile of snow.

输出

A:000

B:100110

E:1101

F:100111

G:00110

H:00111

I:1110

J:101000

K:10000

L:101001

M:1011

N:1111

O:010

P:101010

R:10001

S:011

T:1100

U:10010

W:0010

Y:101011

注意:输出结果中不包含统计个数为0的字母,应该想办法去除,在生成哈夫曼编码时就将他们去掉。

【题解代码】

#include<iostream>
#include<string.h>
#include <iomanip>
#include<string>
#define UNCONSTRUCTED -1 //表示结点没有构建树
#define MAX 20
using namespace std;
/**哈夫曼树结点结构*/
struct HTNode
{
	int weight;//结点权重
	int parent, left, right;//父结点、左孩子、右孩子在数组中的位置下标

};

/**选择最小和次小结点*/
void selectMin(HTNode* HTArray, int k, int& minIndex1, int& minIndex2);
/**创建哈夫曼树*/
void createHuffmanTree(HTNode* HTArray, int* weightArray, int leafNum);




/**创建哈夫曼树*/
void createHuffmanTree(HTNode* HTArray, int* weightArray, int leafNum)
{
	//哈夫曼数组的长度
	int length = leafNum * 2 - 1;
	//叶子结点初始化
	for (int i = 0; i < leafNum; i++)
	{
		HTArray[i].parent = UNCONSTRUCTED;
		HTArray[i].left = UNCONSTRUCTED;
		HTArray[i].right = UNCONSTRUCTED;
		HTArray[i].weight = weightArray[i];
	}
	//非叶子结点初始化
	for (int i = leafNum; i < length; i++)
	{
		HTArray[i].parent = UNCONSTRUCTED;
		HTArray[i].left = UNCONSTRUCTED;
		HTArray[i].right = UNCONSTRUCTED;
		HTArray[i].weight = 0;//权值为0
	}

	//构建哈夫曼树
	//k为当前要写的下标,从第一个非叶子结点开始
	for (int k = leafNum; k < length; k++)
	{
		int minIndex1, minIndex2;//两个最小值的下标
		selectMin(HTArray, k, minIndex1, minIndex2);//求最小和次小权值的下标
		//cout<<"\n本轮写的结点下标k="<<k<<" minIndex1="<<minIndex1<<" minIndex2="<<minIndex2<<endl;

		//minIndex1和minIndex2两个结点构建子树
		HTArray[k].weight = HTArray[minIndex1].weight + HTArray[minIndex2].weight;
		HTArray[k].left = minIndex1;
		HTArray[k].right = minIndex2;
		HTArray[minIndex1].parent = k;
		HTArray[minIndex2].parent = k;
		//cout<<"最小下标"<<minIndex1<<"次小下标"<<minIndex2<<endl;
		//printHufTree(HTArray,leafNum);//打印中间结果

	}
	return;
}


/**选择最小和次小权重*/
void selectMin(HTNode* HTArray, int k, int& minIndex1, int& minIndex2)
{
	int i = 0;
	minIndex1 = -1;
	minIndex2 = -1;
	while (i < k)
	{
		if (HTArray[i].parent == UNCONSTRUCTED)//找无父结点的结点(未构建树的结点)
		{
			if (minIndex1 == -1 || HTArray[i].weight < HTArray[minIndex1].weight)//比最小的还小
			{
				minIndex2 = minIndex1;
				minIndex1 = i;
			}
			else if (minIndex2 == -1 || HTArray[i].weight < HTArray[minIndex2].weight)//在两者之间
			{
				minIndex2 = i;
			}
		}
		i++;
	}
}




/**生成哈夫曼编码的函数
HTArray 存放哈夫曼树的数组
code 存放编码的字符串
leafNum 叶子节点个数
从叶子结点一直找到根结点,逆向记录途中经过的标记。
是左儿子标记0,右儿子标记1。
*/
void huffmanCoding(HTNode* HTArray, char**& code, int leafNum)
{
	char* temp; //声明temp数组
	temp = new char[leafNum];//定义临时工作空间,存储临时产生的编码串
	temp[leafNum - 1] = '\0';  //因为是逆向,所以得从末尾开始,先把最后一位置为空
	int start, pos;  //start为temp数组正在处理位置de下标,pos记录正在处理的哈夫曼树的当前位置
	int parent;  //记录父节点
	for (int i = 0; i < leafNum; i++)//依次遍历哈夫曼数组
	{
		start = leafNum - 1;
		pos = i;
		parent = HTArray[i].parent; //找到父节点
		while (parent != -1)
		{
			if (HTArray[parent].left == pos) //当前结点是左孩子的话,就存0
			{
				temp[--start] = '0'; //start前移一位,存入编码
			}
			else //右孩子,存1
			{
				temp[--start] = '1';
			}
			pos = parent; //pos移动到父节点,以进行下一轮查找
			parent = HTArray[parent].parent;//更新父节点
		}
		code[i] = new char[leafNum - start]; //建立哈夫曼编码实际需要的内存空间
		//leafNum-start是正在处理结点的编码长度
		strcpy(code[i], &temp[start]);       //将临时存储的编码拷贝到code中    
	}
	delete[]temp; //释放工作空间
}
//打印编码
void printCode(HTNode* HTArray, char** code, char* data, int leafNum)
{
	// cout<<"哈夫曼编码是\n";
	for (int i = 0; i < leafNum; i++)
	{
		cout << data[i] << ":";
		cout << code[i] << endl;
	}

}

int main()
{
	string s;
	int i;
	int word[27] = { 0 };//记录从a到z的每个字母的个数
	getline(cin, s); //获取带空格的字符串
	//计算字母个数
	for (i = 0; i < s.length(); i++)
	{
		if (isalpha(s[i])) //判断当前字符是否是字母
		{
			s[i] = tolower(s[i]); //如果是的话,将大写转换成小写
			word[s[i] - 'a']++; //记录个数
		}

	}
	int count = 0;// 计算有多少个字母个数不为0
	for (i = 0; i < 26; i++)
	{
		if (word[i] != 0)
			count++;
	}
	int weightArray[27] = { 0 };
	char data[27] = { 0 }; //记录实际个数不为0的字母
	int j = 0;
	for (i = 0; i < 26; i++)
	{
		if (word[i] != 0)
		{
			weightArray[j] = word[i];
			data[j] = 'A' + i;
			j++;
		}
	}
	char** code = new char* [count]; //为code分配内存空间,存储编码

	//哈夫曼树数组
	HTNode* HTArray = new HTNode[count * 2 - 1];
	//创建哈夫曼树
	createHuffmanTree(HTArray, weightArray, count);

	//生成哈夫曼编码
	huffmanCoding(HTArray, code, count);

	//打印编码
	printCode(HTArray, code, data, count);

	//删除内存
	for (int j = 0; j < count; j++)
	{
		delete code[j];
	}
	delete[]code;
	delete[]HTArray;
	return 0;
}

  • 11
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值