c ++ハフマンツリーの構築

前書き

ハフマンツリーは、文字をエンコードするためのデータ構造であり、文字の使用頻度に応じて文字のバイナリ表現を決定できるため、変換後のバイナリ列をできるだけ短くすることができます。
ハフマンツリーの具体的な紹介については、このブログ参照して、漫画でハフマンツリーを紹介してください。

次に、ハフマンツリーの作成方法を紹介します。n個の文字とそれに対応する頻度(出現数)を指定して、ハフマンエンコード後のエンコードされた文字列の長さを見つけます。
といった:

4 //字符个数
a 1
b 2
c 3
d 4

19を返します。(カウント方法がわからない場合は、上記のリンクのブログを参照してください)

c ++の構造

方法1

まず、優先度キューを使用して、頻度情報を含むノードをキューに追加し、2つの最小ノードaとbを毎回キューから取り出し、頻度の合計を求め、新しい子ノードを構築します。 b、新しいノードをキューに追加します。キューにノードが1つだけ残るまで、このプロセスを繰り返します。
上記の手順では、ハフマンツリーの構築プロセスをシミュレートし、実際にツリーを構築します。次に、ツリーのルートノードをトラバースし、各リーフノードを見つけて、その値(周波数)と深度(つまり、コード長)の積の合計が必要な結果です。
時間の複雑さ:O(nlogn)
ps:このコードはポインターを解放しませんが、これは重要ではないため、無視されます。

#include<iostream>
#include<queue>
#include<unordered_map>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
struct Node {
    
    
	long long val;
	Node* left, *right;
	Node(long long val) {
    
    
		this->val = val;
		left = NULL;
		right = NULL;
	}
};

struct cmp {
    
    
	bool operator()(const Node* a, const Node* b) const{
    
    
		return a->val > b->val;
	}
};

long long search(Node* root, long long level) {
    
     
	if (root == NULL) return 0;
	if (root->left == NULL && root->right == NULL) return root->val * level;
	return search(root->left, level + 1) + search(root->right, level + 1);
}
int main() {
    
    
	long long n;
	cin >> n;
    if (n == 0) {
    
    
    	cout << 0;
    	return 0;
    }
    long long arr[n];
    char c;
    for (long long i = 0; i < n; ++i) {
    
    
        cin >> c >> arr[i];
    }
    if (n == 1) {
    
    
    	cout << arr[0];
    	return 0;
    }
    priority_queue<Node*, vector<Node*>, cmp> pq;
    for (long long i = 0; i < n; ++i) {
    
    
    	//if (arr[i] <= 0) continue;
    	Node* t = new Node(arr[i]);
    	pq.push(t);
	}
	
	if (pq.size() == 1) {
    
    
		cout << pq.top()->val << endl;
		return 0;
	}
	Node* root;
    while(pq.size() > 1) {
    
    
        Node* a = pq.top();
        pq.pop();
        Node* b = pq.top();
        pq.pop();
        Node* sum = new Node(a->val + b->val);
        sum->left = a;
        sum->right = b;
        root = sum;
        pq.push(sum);
    }
    cout << search(root, 0) << endl;
}
    
    

方法2

プライオリティキューを使用したくない場合や、比較関数を自分で作成したくない場合は、どのように記述できますか?
ルールに注意してください。最小の2つのノードがキューから取り出され、値によって追加されるたびに、新しいノードの値が増加します。通常の配列のみを使用して元のノードを格納し、別の配列を使用するとします新しいノードを格納するには、2つのポインターを使用して2つの配列の添え字をポイントします。これは、特定の制御(左の配列から取得するか、右の配列から取得)を通じて実行できます。詳細はコードをご覧ください。

#include<cstring>
#include<algorithm>
#include<vector>
#include<iostream>
using namespace std;
int n;
vector<long long> a[2];
int idx[2];

inline long long popleft(int i) {
    
    
	return a[i][idx[i]++];
}

inline long long getmin() {
    
    
	if (idx[0] >= (int)a[0].size()) {
    
      
  		return popleft(1);
	}
 	if (idx[1] >= (int)a[1].size()) {
    
    
  		return popleft(0);
 	}
 	if (a[0][idx[0]] < a[1][idx[1]]) {
    
    
  		return popleft(0);
 	}
 	return popleft(1);
}

int main() {
    
    
 	cin >> n;
 	if (n == 0) {
    
    
  		cout << 0 << endl;
  		return 0;
 	}
 	long long t1, t2;
 	char c;
 	for (int i = 0; i < n; ++i) {
    
    
  		cin >> c >> t2;
  		a[0].push_back(t2);
	}
 	if (n == 1) {
    
    
  		cout << t2 << endl;
  		return 0;
 	}
 	sort(a[0].begin(), a[0].end());

 	long long ans = 0;
 	for (int i = 1; i < n; ++i) {
    
    
	  	t1 = getmin();
	  	t2 = getmin();
  		ans += t1 + t2;
  		a[1].push_back(t1 + t2);
 	}
 	cout << ans << endl;
 	return 0;
}

時間の複雑さはまだO(nlogn)です。

おすすめ

転載: blog.csdn.net/weixin_43867940/article/details/106003378