4月13号总结

     是时候来写(水)今天的总结了,首先来填补昨天的遗憾,哈夫曼编码的实现,应老覃的要求我基本都是c语言手敲的代码,老规矩先讲思路。哈夫曼编码的来源是依次以叶子节点为出发点,向上回溯至根节点为止。回溯时走左分支则生成代码0(1),走右分支则生成代码1(0)。看下图:

 举个栗子,权值为2的哈夫曼编码是010,3的是110,实现也非常简单,从叶子节点开始递归搜索到根节点就行,附上完整的哈夫曼树操作代码(建树编码):

#include<stdio.h>
struct data{
	int fa,lc,rc,w;
};
struct data tree[100000];
int n,s1,s2,code[100][100];
void find(int k){
	for(int j=1;j<=2;j++){
		int min=99999999,minx;
	for(int i=1;i<=k-1;i++){
		if(i==s1||tree[i].fa!=0)
		continue;
		if(tree[i].w<min){
			min=tree[i].w;
			minx=i;
		}
	}
	if(j==1){
		s1=minx;
	}
	if(j==2){
		s2=minx;
	}
}
	
}
void dfs(int x){
	printf("%d ",tree[x].w);
	if(tree[x].lc==0&&tree[x].rc==0){
		return ;
	}
	if(tree[x].lc!=0) dfs(tree[x].lc);
	if(tree[x].rc!=0) dfs(tree[x].rc);
}
void hfmcode(int x){
	int p,c,i=1;
	p=tree[x].fa;
	c=x;
	while(p!=0){
		if(tree[p].lc==c){
			code[x][i]=0;
		}
		if(tree[p].rc==c){
			code[x][i]=1;
		}
		c=p;
		p=tree[p].fa;
		i++;
	}
	code[x][i]=-1;
}
int main(){
	scanf("%d",&n);
	int m=2*n-1;
	for(int i=1;i<=m;i++){
		tree[i].fa=tree[i].lc=tree[i].rc=tree[i].w=0;
	}
	for(int i=1;i<=n;i++){
		scanf("%d",&tree[i].w);
	}
	for(int i=n+1;i<=m;i++){
		find(i);
		tree[s1].fa=i,tree[s2].fa=i;
		tree[i].lc=s1,tree[i].rc=s2;
		tree[i].w=tree[s1].w+tree[s2].w;
	}
	dfs(m);
	printf("\n");
	for(int i=1;i<=n;i++){
    hfmcode(i);
    printf("%d: ",tree[i].w);
	for(int j=1;;j++){
		if(code[i][j]==-1){
			break;
		}
		printf("%d ",code[i][j]);
	}
	printf("\n");
}
	return 0;
}

 验证一下:

     还有一个坑,单调队列的实现,我觉得单调队列很值得去学习,可以用来处理滑动窗口又能用来优化dp(dp是个大坑),我写的是模板题:滑动窗口 /【模板】单调队列 - 洛谷,以下是我的AC代码:

#include<stdio.h>
long long a[1000005],n,q[1000005],vis[1000005],k;
int head=1,tail=0;
int main(){
	scanf("%lld%lld",&n,&k);
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]);
	}
	for(int i=1;i<=n;i++){
	   vis[i]=a[i];
	   if(tail>=head&&q[head]<=i-k){
	   	head++;
	   }
	   while(tail>=head&&vis[i]<vis[q[tail]]){
	   	tail--;
	   }
	   q[++tail]=i;
	   if(i>=k){
	   	printf("%d ",vis[q[head]]);
	   }
	}
	head=1,tail=0;
	printf("\n");
	for(int i=1;i<=n;i++){
	   if(tail>=head&&q[head]<=i-k){
	   	head++;
	   }
	   while(tail>=head&&vis[i]>vis[q[tail]]){
	   	tail--;
	   }
	   q[++tail]=i;
	   if(i>=k){
	   	printf("%d ",vis[q[head]]);
	   }
	}
	return 0;
}

最小生成树(prim ):两个最小生成树的代码实现我都还在努力,今天先总结prim 算法的思路。

给我们一张图:

 kruskal算法是选边而prim是选择点,我们从起点(假设是1)开始,我们把1打上标记代表他已经在最小数中了。

 很显然按照贪心的思想我们肯定是找从1出发走最少路径能走到的点,很明显是点2,我们将其标记纳入树中(后宫)。

 下一步就是找离1和2最近的点,是3,将其打上标记。

 在重复以上过程直到所有点都被打上标记,我们得到最小生成树:

 谢谢潘小蓝大佬的图片。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值