01 | #include <iostream> |
02 | using namespace std; |
03 | int h[16],n; |
04 |
05 | void swap(int x,int y) |
06 |
07 | { |
08 | int t=h[x]; |
09 | h[x]=h[y]; |
10 | h[y]=t; |
11 | } |
12 | //建立堆需要向下调整 |
13 | //建立向下调整函数。 |
14 | void siftdown(int i)//传入i从每一个小的堆(堆顶)向下调整。 |
15 | { |
16 | int t,flag=0;//flag用来标记是否需要继续向下调整 |
17 |
18 | //当i结点有儿子(至少有左儿子)并且有需要继续调整的时候循环就执行。 |
19 |
20 |
21 | while(i*2<=n&&flag==0) |
22 | { |
23 | if(h[i]>h[i*2])//首先判断他跟做儿子的关系 |
24 | t=i*2;//如果小于左儿子那就用t来记录较大值的位置,并没有进行交换, |
25 | else |
26 | t=i; |
27 | //判断完了左儿子在于右儿子比较。 |
28 | //首先得判断是否有右儿子。 |
29 | if(i*2+1<=n) |
30 | { |
31 | if(h[t]>h[i*2+1]) |
32 | t=i*2+1; |
33 | } |
34 | if(t!=i)//如果最后发现t不是i自己了那就进行交换。 |
35 | swap(t,i); |
36 | else |
37 | flag=1; |
38 | i=t;//无论是否交换,最后更新一下i的值。 |
39 | } |
40 | } |
41 | void creat() |
42 | { |
43 | int i; |
44 | //从最后一个非叶节点到第一个结点依次进行向下调整。 |
45 | for(i=n/2; i>=1; i--) |
46 | { |
47 | siftdown(i); |
48 | } |
49 | } |
50 | void heapsort() |
51 | { |
52 | while(n>1) |
53 | { |
54 | swap(1,n); |
55 | n--; |
56 | siftdown(1); |
57 | } |
58 | } |
59 | int main() |
60 | { |
61 | int x,i,num,t; |
62 | cin>>num>>x; |
63 | for( i=1; i<=x; i++) |
64 | cin>>h[i]; |
65 | n=x; |
66 | creat(); |
67 | for(i=x+1;i<=num;i++) |
68 | { |
69 | cin>>t; |
70 | if(t>h[1]) |
71 | { |
72 | h[1]=t; |
73 | creat(); |
74 | } |
75 | } |
76 | heapsort(); |
77 | for(i=1;i<x;i++) |
78 | cout<<h[i]<<" "; |
79 | cout<<h[x]<<endl; |
80 | return 0; |
81 | } |
82 |
example :有四个叶子结点a,b,c,d,权值分别为7,5,2,4构造有4个结点的二叉树。构造有4个叶子节点的二叉树。WPL取权值最小的两个构造成一个新的树,重复此操作,最终构成一个哈弗曼树。
1、路径和路径长度
在一棵树中,从一个结点往下可以达到的孩子或子孙结点之间的通路,称为路径。通路中分支的数目称为路径长度。若规定根结点的层数为1,则从根结点到第L层结点的路径长度为L-1。
2、结点的权及带权路径长度
若将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权。结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积。
3、树的带权路径长度
树的带权路径长度规定为所有叶子结点的带权路径长度之和,记为WPL;
树-堆结构练习——合并果子之哈夫曼树
#include<bits/stdc++.h>Time Limit: 1000MS Memory Limit: 65536KBProblem Description
在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过n-1次合并之后,就只剩下一堆了。多多在合并果子时总共消耗的体力等于每次合并所消耗体力之和。因为还要花大力气把这些果子搬回家,所以多多在合并果子时要尽可能地节省体力。假定每个果子重量都为1,并且已知果子的种类数和每种果子的数目,你的任务是设计出合并的次序方案,使多多耗费的体力最少,并输出这个最小的体力耗费值。例如有3种果子,数目依次为1,2,9。可以先将1、2堆合并,新堆数目为3,耗费体力为3。接着,将新堆与原先的第三堆合并,又得到新的堆,数目为12,耗费体力为12。所以多多总共耗费体力=3+12=15。可以证明15为最小的体力耗费值。Input
第一行是一个整数n(1<=n<=10000),表示果子的种类数。第二行包含n个整数,用空格分隔,第i个ai(1<=ai<=20000)是第i个果子的数目。Output
输出包括一行,这一行只包含一个整数,也就是最小的体力耗费值。输入数据保证这个值小于2^31。Example Input
3 1 2 9Example Output
15链表代码:
001#include<bits/stdc++.h>
002usingnamespacestd;
003intf;
004structnode
005{
006intdata;
007structnode *next;
008};
009intmain()
010{
011intn,z,i,sum=0;
012structnode *p,*head,*q1,*q2,*p1,*p2;
013head=newnode;
014head->next=NULL;
015cin>>n;
016if(n==1)
017{
018cin>>z;
019cout<<z<<endl;
020}
021else
022{
023p=newnode;
024cin>>p->data;
025p->next=NULL;//建一个结点。
026//每当有新的数输入就建造一个新的结点,
027//头结点为空用来链接这个链表(主要是用来链接第一个结点)
028head->next=p;//(进行链表的链接。)
029for(i=2;i<=n;i++)
030{
031p=newnode;
032cin>>p->data;
033q1=head;//这一步是准备遍历链表按照顺序插入了;
034q2=head->next;//两个游动指针才能插入一个新的结点。
035while(q2)
036{
037if(q2->data>p->data)
038{
039q1->next=p;
040p->next=q2;
041break;
042}
043else
044{
045q1=q1->next;
046q2=q2->next;
047}
048}
049if(q1->next==NULL)
050q1->next=p;//如果找到链表末尾都没有找到更大的值
051//就直接把这个值放在表尾。
052}
053p1=head;
054p2=head->next;
055
056//再次使用两个游动指针。
057
058while(p2->next!=NULL)
059{
060p1=p1->next;
061p2=p2->next;
062//两个游动指针是用来遍历 ,
063sum+=p1->data+p2->data;//求和。
064p=newnode;//求和之后重复新节点的建立
065p->data=p1->data+p2->data;//新节点的数据域等于上两个的和
066p->next=NULL;
067q1=p2;
068q2=p2->next;//使用两个游动指针把新建好的结点插入合适位置形成有序链表。
069while(q2)
070{
071if(q2->data>p->data)
072{
073q1->next=p;
074p->next=q2;
075break;
076}
077else
078{
079q1=q1->next;
080q2=q2->next;
081}
082}
083if(q1->next==NULL)
084q1->next=p;//重复(没有找到比他大的就往最后面插入)
085p1=p1->next;
086p2=p2->next;
087}
088cout<<sum<<endl;
089}
090return0;
091}
using namespace std;
int a[10000];
int main()
{
int n,a1,a2,i;
int sum=0;
cin>>n;
for(i=0;i<n;i++)
{
cin>>a[i];
}
priority_queue<int , vector<int> , greater<int> >q;//从小到大排列
for(i=0;i<n;i++)
{
q.push(a[i]);//进入队列
}
while(q.size()>1)//因为最后只剩下一组,所以控制长度大于1
{
a1=q.top();//将a1定义为首元素
q.pop();//出队列
a2=q.top();//将a2定义为首元素
q.pop();//出队列
sum+=a1+a2;
q.push(a1+a2);//这里注意将a1+a2进入队列,而不是sum
}
cout<<sum<<endl;//最后输出sum
return 0;
}
超时代码。
#include<bits/stdc++.h>
using namespace std;
int a[10005];
int cp(int a,int b)
{
return a>b;
}
int main()
{
int n,i;
int sum=0;
cin>>n;
for(i=0;i<n;i++)
cin>>a[i];
sort(a,a+n,cp);
for(i=0;n>1;i++)
{
sum=a[n-1]+a[n-2]+sum;
a[n-2]=a[n-1]+a[n-2];
n-=1;
sort(a,a+n,cp);
}
cout<<sum<<endl;
return 0;
}
字典树
Problem Description
遇到单词不认识怎么办? 查字典啊,已知字典中有n个单词,假设单词都是由小写字母组成。现有m个不认识的单词,询问这m个单词是否出现在字典中。
Input
含有多组测试用例。
第一行输入n,m (n>=0&&n<=100000&&m>=0&&m<=100000)分别是字典中存在的n个单词和要查询的m个单词.
紧跟着n行,代表字典中存在的单词。
然后m行,要查询的m个单词
n=0&&m=0 程序结束
数据保证所有的单词都是有小写字母组成,并且长度不超过10
Output
若存在则输出Yes,不存在输出No .
Example Input
3 2 aab aa ad ac ad 0 0
Example Output
No Yes
01#include<bits/stdc++.h>
02usingnamespacestd;
03intf;
04structnode
05{
06chardata[28];
07structnode *l,*r;
08};
09structnode*creat(structnode*root,charch[])//建立字典树唯一
10//不同于有序二叉树之处就是字符串的链接
11{
12if(root==NULL)
13{
14root=new(node);
15root->l=root->r=NULL;
16strcpy(root->data,ch);
17}
18else
19{
20if(strcmp(ch,root->data)<0)
21root->l=creat(root->l,ch);
22else
23root->r=creat(root->r,ch);
24}
25returnroot;
26}
27voidsearchtree(structnode*root,chars[])
28{
29if(root)
30{
31if(strcmp(root->data,s)>0)
32searchtree(root->l,s);
33elseif(strcmp(root->data,s)<0)
34searchtree(root->r,s);
35else
36f=1;
37}
38}
39intmain()
40{
41intn,m;
42chara[12],s[12];
43while(cin>>n>>m)
44{
45if(n==0&&m==0)
46break;
47structnode*t;
48t=NULL;
49while(n--)
50{
51cin>>a;
52t=creat(t,a);
53}
54while(m--)
55{
56cin>>s;
57f=0;
58searchtree(t,s);
59if(f==1)
60cout<<"Yes"<<endl;
61else
62cout<<"No"<<endl;
63}
64}
65return0;
66}
Fence Repair
Time Limit: 2000MS Memory Limit: 65536KBProblem Description
Line 1: One integer NLine 1: One integer: the minimum amount of money he must spend to make NExample Input
3 8 5 8Example Output
34
01#include<bits/stdc++.h>
02usingnamespacestd;
03structnode
04{
05longlongdata;
06structnode *next;
07};
08intmain()
09{
10longlongn,z,i,sum=0;
11structnode *p,*head,*q1,*q2,*p1,*p2;
12head=newnode;
13head->next=NULL;
14cin>>n;
15if(n==1)
16{
17cin>>z;
18cout<<z<<endl;
19}
20else
21{
22p=newnode;
23cin>>p->data;
24p->next=NULL;//建一个结点。
25//每当有新的数输入就建造一个新的结点,
26//头结点为空用来链接这个链表(主要是用来链接第一个结点)
27head->next=p;//(进行链表的链接。)
28for(i=2;i<=n;i++)
29{
30p=newnode;
31cin>>p->data;
32q1=head;//这一步是准备遍历链表按照顺序插入了;
33q2=head->next;//两个游动指针才能插入一个新的结点。
34while(q2)
35{
36if(q2->data>p->data)
37{
38q1->next=p;
39p->next=q2;
40break;
41}
42else
43{
44q1=q1->next;
45q2=q2->next;
46}
47}
48if(q1->next==NULL)
49q1->next=p;//如果找到链表末尾都没有找到更大的值
50//就直接把这个值放在表尾。
51}
52p1=head;
53p2=head->next;
54
55//再次使用两个游动指针。
56
57while(p2->next!=NULL)
58{
59p1=p1->next;
60p2=p2->next;
61//两个游动指针是用来遍历 ,
62sum+=p1->data+p2->data;//求和。
63p=newnode;//求和之后重复新节点的建立
64p->data=p1->data+p2->data;//新节点的数据域等于上两个的和
65p->next=NULL;
66q1=p2;
67q2=p2->next;//使用两个游动指针把新建好的结点插入合适位置形成有序链表。
68while(q2)
69{
70if(q2->data>p->data)
71{
72q1->next=p;
73p->next=q2;
74break;
75}
76else
77{
78q1=q1->next;
79q2=q2->next;
80}
81}
82if(q1->next==NULL)
83q1->next=p;//重复(没有找到比他大的就往最后面插入)
84p1=p1->next;
85p2=p2->next;
86}
87cout<<sum<<endl;
88}
89return0;
90}
数据结构实验之二叉树六:哈夫曼编码
Time Limit: 1000MS Memory Limit: 65536KBProblem Description
字符的编码方式有多种,除了大家熟悉的ASCII编码,哈夫曼编码(Huffman Coding)也是一种编码方式,它是可变字长编码。该方法完全依据字符出现概率来构造出平均长度最短的编码,称之为最优编码。哈夫曼编码常被用于数据文件压缩中,其压缩率通常在20%~90%之间。你的任务是对从键盘输入的一个字符串求出它的ASCII编码长度和哈夫曼编码长度的比值。
Input
输入数据有多组,每组数据一行,表示要编码的字符串。Output
对应字符的 ASCII 编码长度 la , huffman 编码长度 lh 和 la/lh 的值 ( 保留一位小数 ) ,数据之间以空格间隔。Example Input
AAAAABCD THE_CAT_IN_THE_HATExample Output
64 13 4.9 144 51 2.8
01#include<bits/stdc++.h>
02intcp(inta,intb)
03{
04returna>b;
05}
06usingnamespacestd;
07structnode
08{
09longlongdata;
10structnode *next;
11};
12intmain()
13{
14inti,sum1,sum2,d;
15inta[220],x[222];
16chars[11010];
17while(cin>>s)
18{
19memset(a,0,sizeof(a));
20sum2=0;
21intcnt=0;
22for(i=0; i<strlen(s); i++)
23{
24d=s[i];
25a[d]++;
26}
27sum1=strlen(s)*8;
28for(i=0; i<130; i++)
29{
30if(a[i]!=0)
31x[cnt++]=a[i];
32}
33if(cnt==1)
34cout<<"8 1 8.0"<<endl;
35else
36{
37sort(x,x+cnt,cp);
38for(i=0; cnt>1; i++)
39{
40sum2=x[cnt-1]+x[cnt-2]+sum2;
41x[cnt-2]=x[cnt-1]+x[cnt-2];
42cnt-=1;
43sort(x,x+cnt,cp);
44}
45printf("%d %d %.1f\n",sum1,sum2,sum1*1.0/sum2);
46}
47}
48return0;
49}
01#include<bits/stdc++.h>
02usingnamespacestd;
03intm,a[200005];
04intsw(intp,int i)交换函数
05{
06intt=a[i];
07a[i]=a[p];
08a[p]=t;
09}
10voidsd(inti) 搜索查找左右子跟。
11{
12intf=0,t;
13while(f==0&&i*2<=m)
14{
15if(a[i*2]>a[i])
16t=i*2;
17else
18t=i;
19if(i*2+1<=m)
20if(a[t]<a[i*2+1])
21t=i*2+1;
22if(t!=i)
23{
24sw(i,t);
25i=t;
26}
27else
28f=1; 标志(如果是他本身就比左子树 。右子树都大所以不交换)
29}
30}
31voidb()
32{
33intk;
34for(k=m/2;k>=1;k--)
35sd(k); 对M/2之前搜索就可以。
36}
37voidsortt()
38{
39while(m>1)
40{
41sw(m,1);
42m--;
43sd(1);
44} 每次把数组中的数放到首位进行建树。
45}
46intmain()
47{
48intn,i,t,g,j;
49while(cin>>m)
50{
51t=m;
52for(i=1;i<=m;i++)
53cin>>a[i];
54b();
55sortt();
56for(i=1;i<t;i++)
57cout<<a[i]<<" ";
58cout<<a[t]<<endl;
59}
60return0;
61}
本文详细介绍了哈夫曼树及其编码的应用,通过实例展示了如何构造哈夫曼树并利用其进行数据压缩,同时提供了具体的编码实现代码。
1190

被折叠的 条评论
为什么被折叠?



