Day10 树---哈夫曼树 家谱处理 搜索树判断 目录树
Posted 回忆过去,是最美好的事情。
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Day10 树---哈夫曼树 家谱处理 搜索树判断 目录树相关的知识,希望对你有一定的参考价值。
Huffman Codes
本题的思路是先创建哈夫曼树,求得最优WPL。之后先将待测作业的WPL计算得出,若不同于哈夫曼树的WPL必不正确;之后将待测作业编码建树来判断是否前缀冲突,若前缀冲突必不正确,反之正确。
检测编码是否冲突的核心
- 首先将所有作业中的编码按照长度递减排序
- 之后将编码建树,编码的最后一位应该落在空处;如果没有落在空处说明编码冲突。
#include<bits/stdc++.h>
#include<map>
#include<string>
#include<queue>
using namespace std;
struct Node{
char val;
int weight;
Node*left=nullptr;
Node*right=nullptr;
Node(){
}
Node(char val,int weight):val(val),weight(weight){
}
Node(char val,int weight,Node*left,Node*right):val(val),weight(weight),left(left),right(right){
}
};
//类的小根堆重载
struct cmp{
bool operator()(Node*a,Node*b){
return a->weight>b->weight;
}
};
//创建哈夫曼树
Node* buildHuffmanTree(priority_queue<Node*,vector<Node*>,cmp>pqueue){
while(pqueue.size()>1){
Node*left=pqueue.top();pqueue.pop();
Node*right=pqueue.top();pqueue.pop();
pqueue.push(new Node(' ',left->weight+right->weight,left,right));
}
return pqueue.top();
}
int N,M;
//存储字母及频率
map<char,int>Map;
//计算哈夫曼树的WPL
void getWPL(Node*root,int&WPL,int step){
if(root==nullptr)
return;
if(root->left==nullptr&&root->right==nullptr){
WPL+=Map[root->val]*step;
}
getWPL(root->left,WPL,step+1);
getWPL(root->right,WPL,step+1);
}
//判断第二步建树是否出现问题
bool flag=true;
//建树检查编码是否冲突
Node* build(Node*root,string&code,int pos){
if(pos>=code.size()){
return root;
}
if(pos==code.size()-1){
if((code[pos]=='0'&&root->left!=nullptr)||(code[pos]=='1'&&root->right!=nullptr)){
flag=false;
return nullptr;
}
}
if(code[pos]=='0'){
if(root->left==nullptr){
root->left=new Node();
}
root->left=build(root->left,code,pos+1);
}else{
if(root->right==nullptr){
root->right=new Node();
}
root->right=build(root->right,code,pos+1);
}
return root;
}
int main(){
cin>>N;
char c;int freq;
priority_queue<Node*,vector<Node*>,cmp>pqueue;
for(int i=0;i<N;++i){
cin>>c>>freq;
Map[c]=freq;
pqueue.push(new Node(c,freq));
}
Node*root=buildHuffmanTree(pqueue);
int WPL=0;
getWPL(root,WPL,0);
cin>>M;
while(M--){
string code;
int cost=0;
vector<string>testCode;
flag=true;
for(int i=0;i<N;++i){
cin>>c>>code;
cost+=Map[c]*code.size();
testCode.push_back(code);
}
if(cost!=WPL){
cout<<"No"<<endl;
}else{
Node*root=new Node();
sort(testCode.begin(),testCode.end(),[](string a,string b){
return a.size()>b.size();
});
for(string code:testCode){
root=build(root,code,0);
if(!flag){
cout<<"No"<<endl;
break;
}
}
if(flag){
cout<<"Yes"<<endl;
}
}
}
return 0;
}
家谱处理
使用栈寻找父亲结点,使用map连接虚关系<子节点,父节点>
#include<bits/stdc++.h>
#include<map>
#include<stack>
using namespace std;
//子节点-->父节点
map<string,string>Map;
//结点名称 缩进
stack<pair<string,int> >S;
int N,M;
int main(){
cin>>N>>M;
getchar();
string str;
string name;
while(N--){
getline(cin,str);
size_t pos=str.find_first_not_of(" ");
name=str.substr(pos);
if(S.empty()){
Map[name]="null";
S.push(make_pair(name,0));
}else{
while(!S.empty()&&S.top().second>=pos){
S.pop();
}
Map[name]=S.top().first;
S.push(make_pair(name,pos));
}
}
while(M--){
string x,relation,y,temp;
cin>>x>>temp>>temp>>relation>>temp>>y;
if(relation=="child"||relation=="parent"){
if(relation=="parent")
swap(x,y);
if(Map[x]==y)
cout<<"True"<<endl;
else
cout<<"False"<<endl;
}else if(relation=="ancestor"||relation=="descendant"){
if(relation=="descendant")
swap(x,y);
bool flag=false;
while(Map[y]!="null"){
if(x==Map[y]){
flag=true;
break;
}
y=Map[y];
}
if(flag)
cout<<"True"<<endl;
else
cout<<"False"<<endl;
}else{
if(Map[x]==Map[y])
cout<<"True"<<endl;
else
cout<<"False"<<endl;
}
}
return 0;
}
搜索树判断
本题给出二叉搜索树或者二叉镜像树的前序遍历,判断是否正确,并且给出后序遍历。
最初想的是将前序遍历排序得到中序遍历,利用前序遍历和中序遍历就可建树,不过过于麻烦,首先判断是二叉搜索树还是镜像搜索树,之后在建树的过程中还需根据树的类型查找中序遍历中根的位置。二叉搜索树的根在中序遍历为第一个大于等于根的值的位置;而二叉镜像树的根在最后一个大于等于根的值的位置。 不过最终没有满分。
现在该思路为利用先序遍历作为输入,建立二叉搜索树,求得前序遍历。二叉镜像树的前序遍历可由二叉搜索树得到,只需在前序遍历时先访问右子结点。相同方法得到后序遍历。判断输入遍历是否为二叉搜索树或二叉镜像树遍历的一种,之后输出后序遍历即可。
#include<bits/stdc++.h>
#include<vector>
using namespace std;
vector<int>originalPre;
vector<int>pre,preMirror,post,postMirror;
struct Node {
int val;
Node*left=nullptr;
Node*right=nullptr;
Node() {
}
Node(int val):val(val) {
}
Node(int val,Node*left,Node*right):val(val),left(left),right(right) {
}
};
Node* insert(Node*root,int newVal) {
if(root==nullptr) {
root=new Node(newVal);
} else if(newVal<root->val) {
root->left=insert(root->left,newVal);
} else
root->right=insert(root->right,newVal);
return root;
}
void preOrder(Node*root) {
if(root==nullptr) {
return;
}
pre.push_back(root->val);
preOrder(root->left);
preOrder(root->right);
}
void preMirrorOrder(Node*root){
if(root==nullptr){
return;
}
preMirror.push_back(root->val);
preMirrorOrder(root->right);
preMirrorOrder(root->left);
}
void postOrder(Node*root){
if(root==nullptr){
return;
}
postOrder(root->left);
postOrder(root->right);
post.push_back(root->val);
}
void postMirrorOrder(Node*root){
if(root==nullptr){
return;
}
postMirrorOrder(root->right);
postMirrorOrder(root->left);
postMirror.push_back(root->val);
}
int main() {
int N;
int val;
Node*root=nullptr;
cin>>N;
for(int i=0; i<N; ++i) {
cin>>val;
originalPre.push_back(val);
root=insert(root,val);
}
preOrder(root);
preMirrorOrder(root);
postOrder(root);
postMirrorOrder(root);
//二叉搜索树的先序遍历
if(originalPre==pre){
cout<<"YES"<<endl;
cout<<post[0];
for(int i=1;i<post.size();++i){
cout<<" "<<post[i];
}
cout<<endl;
}else if(originalPre==preMirror){
cout<<"YES"<<endl;
cout<<postMirror[0];
for(int i=1;i<postMirror.size();++i){
cout<<" "<<postMirror[i];
}
cout<<endl;
}else{
cout<<"NO"<<endl;
}
return 0;
}
目录树
根据目录归档文件重建目录树,需要注意的是目录需要在文件之前打印,需要在Node中设置一个表示isFolder来记录。递归建树,递归打印。
#include<bits/stdc++.h>
#include<map>
using namespace std;
struct Node {
//结点名称
string name;
//子节点名称,地址,递归使用
map<string,Node*>subFiles;
//判断该节点是否为文件夹
bool isFolder;
Node() {
}
Node(string name):name(name) {
}
Node(string name,bool isFolder):name(name),isFolder(isFolder){}
};
//加文件
Node* add(Node*root,string file) {
if(file.find("\\\\")==string::npos) { //文件
if(root->subFiles.find(file)==root->subFiles.end())//文件已存在不需重新创建
root->subFiles[file]=new Node(file,false);
} else if(file.find("\\\\")==file.size()-1) { //目录文件
if(root->subFiles.find(file.substr(0,file.size()-1))==root->subFiles.end())//目录已存在,不需重新创建
root->subFiles[file.substr(0,file.size()-1)]=new Node(file.substr(0,file.size()-1),true);
} else { //多级目录
size_t pos=file.find_first_of("\\\\");
string firstDir=file.substr(0,pos);
//目录不存在直接创建
if(root->subFiles.find(firstDir)==root->subFiles.end())
root->subFiles[firstDir]=new Node(firstDir,true);
root->subFiles[firstDir]=add(root->subFiles[firstDir],file.substr(pos+1));
}
return root;
}
void dfs(Node*root,int depth) {
if(root==nullptr)
return;
for(int i=0; i<depth; ++i)
cout<<" ";
cout<<root->name<<endl;
vector<Node*>subFiles;
for(auto it:root->subFiles) {
subFiles.push_back(it.second);
}
sort(subFiles.begin(),subFiles.end(),[](Node*a,Node*b) {
//同为文件或者目录
if(a->isFolder&&b->isFolder||!a->isFolder&&!b->isFolder){
return a->name<b->name;
}else
return a->isFolder;
});
for(Node*subFile:subFiles) {
dfs(subFile,depth+2);
}
}
int main() {
Node*root=new Node("root",true);
int N;
cin>>N;
string file;
for(int i=0; i<N; ++i) {
cin>>file;
root=add(root,file);
}
dfs(root,0);
return 0;
}
以上是关于Day10 树---哈夫曼树 家谱处理 搜索树判断 目录树的主要内容,如果未能解决你的问题,请参考以下文章