通过二叉树来实现哈夫曼编码树

第 4 节 树的企业级应用案例

4.1 哈夫曼编码 哈夫曼(Huffman)编码算法是基于二叉树构建编码压缩结构的,它是数据压缩中经典的一种算 法。算法根据文本字符出现的频率,重新对字符进行编码。 首先请大家阅读下面两段中外小学作文: 中国 - 今天天气晴朗,我和小明出去玩!小明贪玩,不小心摔了一跤,小明被摔得哇哇哭了,小明的爸爸闻 声赶来,又把小明痛扁了一阵。小明的小屁屁都被揍扁了,因为小明把妈妈刚买给他的裤子弄破了! 外国 - 今天天气晴朗,我和乔伊·亚历山大·比基·卡利斯勒·达夫·埃利奥特·福克斯·伊维鲁莫·马尔 尼·梅尔斯·帕特森·汤普森·华莱士·普雷斯顿出去玩!乔伊·亚历山大·比基·卡利斯勒·达夫·埃利奥 特·福克斯·伊维鲁莫·马尔尼·梅尔斯·帕特森·汤普森·华莱士·普雷斯顿贪玩,不小心摔了一跤,乔伊·亚 历山大·比基·卡利斯勒·达夫·埃利奥特·福克斯·伊维鲁莫·马尔尼·梅尔斯·帕特森·汤普森·华莱士·普 雷斯顿被摔得哇哇哭了,乔伊·亚历山大·比基·卡利斯勒·达夫·埃利奥特·福克斯·伊维鲁莫·马尔尼·梅 尔斯·帕特森·汤普森·华莱士·普雷斯顿的爸爸闻声赶来,又把乔伊·亚历山大·比基·卡利斯勒·达夫·埃 利奥特·福克斯·伊维鲁莫·马尔尼·梅尔斯·帕特森·汤普森·华莱士·普雷斯顿痛扁了一阵。乔伊·亚历 山大·比基·卡利斯勒·达夫·埃利奥特·福克斯·伊维鲁莫·马尔尼·梅尔斯·帕特森·汤普森·华莱士·普 雷斯顿的小屁屁都被揍扁了,因为乔伊·亚历山大·比基·卡利斯勒·达夫·埃利奥特·福克斯·伊维鲁莫·马 尔尼·梅尔斯·帕特森·汤普森·华莱士·普雷斯顿把妈妈刚买给他的裤子弄破了!

哈夫曼编码举例: 假设要对“we will we will r u”进行压缩。
压缩前,使用 ASCII 码保存:119 101 32 119 105 108 108 32 119 101 32 119 105 108 108 32 114 32 117

#pragma once
#include<stdio.h>

#define MAX_SIZE 1024
#define isLess(a,b) (a<b)
#define isEqual(a,b) (a==b)


typedef int ElemType;

typedef struct _Bnode{
     

	ElemType date;
	_Bnode *lchild,*rchild;


}Bnode,Btree;
//数据结构算法之二叉树,二叉树就是分成两叉的树
//
typedef  Bnode Elemdate;

typedef struct _Stack{
     
	Elemdate *base;
	Elemdate *top;

}Stack;


//栈的初始化
bool initStack(Stack &stack){
     
	
   stack.base = new Elemdate[MAX_SIZE];

   if(!stack.base){
     

	printf("栈初始化失败!\n");
	return false;

   }

   stack.top = stack.base;
   return true;

}

//获取栈顶元素
Elemdate* getTop(Stack &stack){
     
	return stack.top-1;
}
//入栈
bool PushStack(Stack &stack,Elemdate date){
     

	if(stack.top-stack.base==MAX_SIZE){
     
		
		printf("栈空间已满,入栈失败!\n");
		return false;
	}

	*(stack.top++) = date;
	return true;

}

//出栈
bool PopStack(Stack &stack,Elemdate &date){
     
	if(stack.base==stack.top){
     
		printf("无元素可出栈!\n");
		return false;
	}
	

	date = *(--stack.top);
	return true;

	}

//判断栈是否为空
bool isEmpty(Stack&stack){
     
	if(stack.base==stack.top){
     
		return true;

	}

	return false;
}
//判断栈是否已满
bool isFully(Stack &stack){
     

	if(stack.top-stack.base==MAX_SIZE){
     
		
		return true;
	}	
	return false;
}

//销毁栈
void destoyedStack(Stack &stack){
     
	
	if(!&stack) return;

	delete [MAX_SIZE] stack.base;

	stack.base = stack.top = NULL;


}

//获取以元素个数
int getElemdateCount(Stack &stack){
     
	

	return (stack.top-stack.base);
}
 在这里插入代码片
#include"Stack.h"
#include
#include



//树的插入,找到最大值、树的删除、树的前序遍栈实现,以及递归实现

//1、树的插入
bool InsertBnode(Bnode **root,Bnode *node){
     
	
	
	if(!node)return false;//防御性编程
	//插入元素,分为两种情况,如果没有父节点时直接把node变为父节点即可
	
	node->lchild = NULL;
	node->rchild = NULL; 

	Bnode *tmp = NULL;
	Bnode *parent = NULL;

	if(!*root){
     
	
	*root = node;	
	return false;
	
	}else{
     
	tmp = *root;

	}
	//开始不断查找合适位置插入,比较node->date和tmp->date大小,若node->date>tmp->date,就将tmp=tmp->rchild,反之同理
	
	while(tmp){
     

		parent = tmp;

		if(isLess(node->date,tmp->date)){
     //和当前根节点比较 is ok,parent是一定存在的
		
			tmp = tmp->lchild;

		}else{
     
			tmp = tmp->rchild;

			}	

	}

	if(isLess(node->date,parent->date)){
     
		
		parent->lchild = node;
	}else{
     
		
		parent->rchild = node;
	
	}


}

//2、找最大值结点
//Btree *findMax(Btree *root){
     
//
//	/*if(!root) return NULL;
//
//	Btree *tmp = root;
//
//	while(tmp->rchild) tmp =tmp->rchild;
//
//	return tmp;*/
//
//	if(root->rchild==NULL){
     
//		return root;
//	}else{
     
//		
//		return findMax(root->rchild);
//	}
//
//}
int findMax(Btree *root){
     

	if(root->rchild==NULL){
     
		return root->date;
	}
	
		return findMax(root->rchild);
	
	
}
//树删除特定值的结点,略微复杂一点
/*
	分为四种情况
	1、如果查到的结点左右子节点都不存在那么就把这个东西置为NULL赋值给上面
	2、如果查到的结点存在左子结点那么就把左子结点给当前这个结点
	3、如果查到的结点存在右子结点那么就把左子结点给当前这个结点
	4、如果左右子节点都存在的话,还找先找到左侧最大的那个结点与当前这个结点的值交换,然后删掉那个最大的结点
*/
Btree *DeleNode(Bnode *root,int key,Bnode *&delenode){
     //delenode记录一下干点的结点

	if(!root) return NULL;

	if(root->date>key){
     
		root->lchild = DeleNode(root->lchild,key,delenode);
		return root;
	}

	if(root->date<key){
     
		
		root->rchild = DeleNode(root->rchild,key,delenode);
		return root;

	}

	//找到了与key值相等的元素
	delenode = root;
	//左右结点都不存在
	if(root->lchild==NULL&&root->rchild==NULL) return NULL;
	
	//存在左子结点
	if(root->lchild!=NULL&&root->rchild==NULL) return root->lchild;

	//存在右子节点
	if(root->lchild==NULL&&root->rchild!=NULL) return root->rchild;

	//左右子节点都存在时候
	//先找该key结点左子节点一侧的最大值
	
	int Val = findMax(root->lchild);
	
	root->date = Val;

	//此时干掉那个最大值原有的结点
	root->lchild = DeleNode(root->lchild,Val,delenode);
	return root;


}

//3、前序遍历递归法
void printFront(Btree *root){
     


	if(!root) return ;

	printf("-%d-",root->date);

	printFront(root->lchild);
	printFront(root->rchild);

}

//3.1、栈实现前序遍历
void printStackFront(Btree *root){
     

	if(!root) return ;

	Bnode cur;

	Stack stack;
	initStack(stack);
	PushStack(stack,*root);//跟新节点入栈

	while(!isEmpty(stack)){
     
		
		PopStack(stack,cur);
		printf("-%d-",cur.date);
		
		if(cur.rchild)PushStack(stack,*(cur.rchild));
	
		if(cur.lchild)PushStack(stack,*(cur.lchild));

		
	
	}
	destoyedStack(stack);
	//根节点入栈,如果右节点存在右先入,左边后人

}

//4、查找元素 非递归法
Btree* findElemdate(Btree *root,int key){
     

	if(!root) return NULL;
	Btree *tmp = root;

	while(tmp->date!=key&&tmp){
     
		
		if(tmp->date>key) {
     
			
			tmp = tmp->lchild;
		}else 
		{
     
			tmp = tmp->rchild;
			}

	}

	return tmp;
}

//4.1通过递归的方式来实现查找
Btree *findElemdateRbk(Btree *root,int key){
     

	if(!root||root->date==key) 
		return root;

	if(isLess(root->date,key)){
     
		
		return findElemdateRbk(root->rchild,key);
	}else{
     
		return findElemdateRbk(root->lchild,key);
	}
	


}

//非递归的方式
Btree* findElemdates(Btree *root, Elemdate e){
     
	
	if(!root) return NULL;

	while(root&&root->date!=e.date){
     
		if(root->date<e.date){
     
			
			root = root->rchild;
		}else{
     
			root = root->lchild;
		}

		return root;

		
	}

}

void main(){
     

	int test[]={
     19,7,25,5,11,15,21,61,3,6};
	//前序遍历19 7 5 3 6 11 15 25 21 61
	
	Bnode *root = NULL,*node = NULL;
	
	node = new Bnode;

	node->date = test[0];
	InsertBnode(&root,node);

	for(int i=1;i<sizeof(test)/sizeof(test[0]);i++){
     
		node =  new Bnode;
		node->date = test[i];

		if(InsertBnode(&root,node)){
     
			
			printf("节点 %d 插入成功\n",node->date);

		}else{
     
		
		}

	}

	printf("前序遍历结果\n");
	printFront(root);
	printf("\n");
	Btree *t = new Bnode;
	
	DeleNode(root,19,t);
	DeleNode(root,12,t);
	//DeleNode(root,61,t);
	
	int k =61;
	t = findElemdate(root,61);

	printf("find elemdate:%d\n",t->date);

	printStackFront(root);
	printf("\n");



	system("pause");
	return ;
	}在这里插入代码片

你可能感兴趣的:(数据结构,c/c++,二叉树)