温存温存10.2

格式
输入
一串小写字母组成的字符串(不超过1000000)。

输出
输出这个字符串通过Huffman编码后的长度。

样例
输入
abcdabcaba
输出
19

#include<iostream>
#include<string>
using namespace std;
struct HuffmanNode{
    
    //定义霍夫曼节点 
   int element;//权重 
   HuffmanNode *leftChild,*rightChild;//左右孩子 
   int line;//路线长度 
   HuffmanNode(){
    
    }
};
template <class T>//链表结构 
struct chainNode {
    
    
   T element;
   chainNode<T> *next;
   chainNode() {
    
    }
   chainNode(const T& element)
      {
    
    this->element = element;}
   chainNode(const T& element, chainNode<T>* next)
      {
    
    this->element = element;
       this->next = next;}
};
template<class T>
class linkedQueue{
    
    
   public:
      linkedQueue(int initialCapacity = 10):queueFront(NULL),queueSize(0){
    
    }//初始化队列 
      ~linkedQueue();//析构函数 
      bool empty()const {
    
    return queueSize == 0;}
      int size()const{
    
    return queueSize;}
      T& front(){
    
    
            if (queueSize == 0)
              exit(1);
            return queueFront->element;
         }
      T& back(){
    
    
            if (queueSize == 0)
               exit(1);
            return queueBack->element;
         }
      void pop();//删除队首 
      void push(const T&);//插入到队尾 
   private:
      chainNode<T>* queueFront;//头指针 
      chainNode<T>* queueBack;//尾指针 
      int queueSize;         
};
//析构函数 
template<class T>
linkedQueue<T>::~linkedQueue(){
    
    
   while (queueFront != NULL){
    
    
      chainNode<T>* nextNode = queueFront->next;
      delete queueFront;
      queueFront = nextNode;
   }
}
//删除队首 
template<class T>
void linkedQueue<T>::pop(){
    
    
   if (queueFront == NULL)
      exit(1);
   chainNode<T>* nextNode = queueFront->next;
   delete queueFront;
   queueFront = nextNode;
   queueSize--;
}
template<class T>
void linkedQueue<T>::push(const T& theElement){
    
    
   chainNode<T>* newNode = new chainNode<T>(theElement, NULL);
   if (queueSize == 0)
      queueFront = newNode;      
   else 
      queueBack->next = newNode;  
   queueBack = newNode;
   queueSize++;
}
//最小堆类 
class minHeap{
    
    
	public:
		minHeap(){
    
    length = 0;p=new HuffmanNode*[27]; }//定义一个HUffmanNide类型的数组 //27是因为第0位不用 
		~minHeap() {
    
     delete[]p; }
		void initialize(HuffmanNode* *a/*指针数组*/, int n);
		void insert(HuffmanNode *num);
		void pop();
		HuffmanNode* top() {
    
     return p[1];}
	private:
		int length;
		HuffmanNode **p;
};
void minHeap::initialize(HuffmanNode **a, int n){
    
    //初始化
	length = n;
	for (int i = 0; i < n; i++)
		p[i + 1] = a[i];
		//堆化 
	for (int root = length / 2; root >= 1; root--){
    
    
		HuffmanNode* rootelement = p[root];
		int child = 2 * root;
		//为element寻找位置 
		while (child <= length){
    
    //heap[child]应该为两兄弟的较小者 
			if (child<length&&p[child]->element>p[child + 1]->element){
    
    
				child++;
			}
			//可以把元素rootelement放在heap[child/2]吗 
			if (rootelement->element <= p[child]->element)
				break;//可以 
			else{
    
    //不可以 
				p[child / 2] = p[child];//把孩子向上移 
				child = child * 2;//移到下一层 
			}
		}
		p[child / 2] = rootelement;
	}
}
void minHeap::insert(HuffmanNode* num){
    
    //插入函数
	int current = ++length;//元素将要插入的位置
	while (current > 1 && p[current / 2]->element > num->element){
    
    
		//不能把元素element插入heap[current] 
		p[current] = p[current / 2];
		current = current / 2;
	}
	p[current] = num;
}
void minHeap::pop(){
    
    //删除函数 
	HuffmanNode* lastelement = p[length];
	int root = 1;
	int child = 2;
	length--;
	while (child <= length){
    
    
		if (child<length&&p[child]->element>p[child + 1]->element){
    
    //应为较小的孩子 
			child++;
		}
		//可以把元素lastelement放在heap[root]吗 
		if (lastelement->element <= p[child]->element)
			break;//可以 
		p[root] = p[child];
		root = child;
		child = child * 2;
	}
	p[root] = lastelement;
}
class Huffmantree{
    
    
	public:
		HuffmanNode *root;//定义根
		Huffmantree() {
    
    }//构造函数 
		~Huffmantree();//析构函数 
		void maketree(int *a,int n);//n为字符串的size
		void length();//霍夫曼编码长度
	private:
		int size; //
};
//析构函数 
Huffmantree::~Huffmantree(){
    
    
	linkedQueue<HuffmanNode*> q;//HuffmanNode结构的队列 
	q.push(root);
	for (int i = 0; i < size; i++){
    
    
		HuffmanNode* currentNode = q.front();
		q.pop();
		if (currentNode->leftChild != NULL){
    
    
			q.push(currentNode->leftChild);
		}
		if (currentNode->rightChild != NULL){
    
    
			q.push(currentNode->rightChild);
		}
		delete currentNode;
	}
}
//建立一棵霍夫曼树 
void Huffmantree::maketree(int *a, int n){
    
    
	HuffmanNode **hufnode = new HuffmanNode*[n];
	for (int i = 0; i < n; i++){
    
    //置空 
		hufnode[i] = new HuffmanNode();
		hufnode[i]->element = a[i];//赋予权值 
		hufnode[i]->leftChild = hufnode[i]->rightChild = NULL;
	}
	minHeap h;
	h.initialize(hufnode, n); 
	HuffmanNode *w, *x, *y;
	// 将配对堆中最小的两个节点取出,进行合并,将合并后的节点重新加入配对堆
	for (int i = 1; i < n; i++){
    
    //建立一棵霍夫曼树 
		x = h.top(); h.pop();//顶端即为最小,拿出后删除 
		y = h.top(); h.pop();
		w = new HuffmanNode();//合并最小的两个 
		w->leftChild = x;
		w->rightChild = y;
		w->element = x->element + y->element;//新权值 
		x = NULL;y = NULL;//删除 
		h.insert(w);//重新加入,不过这时只算做一个节点 
	}
	size = n;//代表有几个不同的字母 
	root = h.top();
	h.pop();
}
//计算霍夫曼编码的长度
void Huffmantree::length(){
    
    
	int result = 0;
	linkedQueue<HuffmanNode*> que;
	HuffmanNode *currentNode;
	que.push(root);//将堆首压入 
	root->line = 0;//初始化为0,只要有向左 或者向右 则路线加一 
	while (!que.empty()){
    
    
		currentNode = que.front();
		que.pop();
		//类似前序遍历的思路 
		if (currentNode->leftChild != NULL){
    
    
			que.push(currentNode->leftChild);
			currentNode->leftChild->line = currentNode->line + 1;
		}
		if (currentNode->rightChild != NULL){
    
    
			que.push(currentNode->rightChild);
			currentNode->rightChild->line = currentNode->line + 1;
		}
		if (currentNode->leftChild == NULL && currentNode->rightChild == NULL){
    
    
			result = result + currentNode->line*currentNode->element;//为当个字母的路线结束标志,即为叶节点了 代表这个字母总的占用的长度 
		}
	}
	cout << result;// 所有的长度综合 
}
int main(){
    
    
	string str;int index = 0,n= 0;
	cin>>str;
	int *a = new int[26];//统计各个字母出现频率 
	for (int i = 0; i < 26; i++)
		a[i] = 0;
	for (int j = 0; j < str.size(); j++){
    
    
		a[(int)str[j] - 97]++;
		if (a[(int)str[j] - 97] == 1)
			n++;//每个字母只算一次,计算不为0 的字符的个数 
	}
	int *b = new int[n];
	for (int k = 0;k < 26; k++){
    
    
		if (a[k] != 0){
    
    
			b[index]=a[k];//只包含不为0次数的字母 
			index++;
		}
	}
	Huffmantree Huff;
	Huff.maketree(b,n);
	Huff.length();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/m0_51406030/article/details/121463046