【二叉树系列】二叉树课程大作业

本博客将以代码的形式详细讲解二叉树的所有算法,包括创建二叉树,二叉树的三种遍历方式,二叉树的各种属性算法,如:求高度,求叶子节点数,求节点数,以及二叉树最常见的应用哈夫曼树,代码如下:

# include<stdio.h>
# include<string.h>
# include<conio.h>
# include<stdlib.h>
# define N 1
# define M 2*N-1
typedef char * HC[N+1];
typedef struct bt
{
	char x;
	struct bt *lchild;
	struct bt *rchild;
}bt,*pbt;
typedef struct 
{
	int parent;
	int weight, lchild, rchild;
}HT[M+1];
void creatbt(pbt *root)
{
	char ch=getchar();
	if(ch==' ')
		*root=NULL;
	else
	{
		*root=(pbt)malloc(sizeof(bt));
		(*root)->x=ch;
		creatbt(&((*root)->lchild));
		creatbt(&((*root)->rchild));
	}
}
void preorder(pbt root)
{
	if(root!=NULL)
	{
		printf("%c",root->x);
		preorder(root->lchild);
		preorder(root->rchild);
	}
}
void inorder(pbt root)
{
	if(root!=NULL)
	{
		inorder(root->lchild);
		printf("%c",root->x);
		inorder(root->rchild);
	}
}
void postorder(pbt root)
{
	if(root!=NULL)
	{
		postorder(root->lchild);
		postorder(root->rchild);
		printf("%c",root->x);
	}
}
int btdepth(pbt root,int h)
{
	static int depth=0;
	if(root!=NULL)
	{
		if(h>depth) depth=h;
		btdepth(root->lchild,h+1);
		btdepth(root->rchild,h+1);
	}
	return depth;
}
int nodenum(pbt root)
{
	static int n=0;
	if(root!=NULL)
	{ 
		n++;
		nodenum(root->lchild);
		nodenum(root->rchild);
	}
	return n;
}
int leafnum(pbt root)
{
	static int n=0;
	if(root!=NULL)
	{
		leafnum(root->lchild);
		leafnum(root->rchild);
		if((root->lchild==NULL)&&(root->rchild==NULL))
			n++;
	}
	return n;
}
void select(HT ht,int n,int *x,int *y)
{
	int i,min1=100,min2=200;
	for(i=1;i<=n;i++)
	{
		if(ht[i].parent==0&&ht[i].weight<min1)
		{
			min1=ht[i].weight;
			*x=i;
		}
	}
	for(i=1;i<=n;i++)
	{
		if(ht[i].parent==0&&ht[i].weight<min2&&i!=*x)
		{
			min2=ht[i].weight;
			*y=i;
		}
	}


}
void hafuman(HT ht,int w[],int n)
{
	int i,k,m,x,y;
	for(i=1;i<=n;i++)
	{
		ht[i].weight=w[i];
		ht[i].parent=ht[i].lchild=ht[i].rchild=0;
	}
	m=2*n-1;
	for(i=n+1;i<=m;i++)
	{
		ht[i].parent=ht[i].lchild=ht[i].rchild=0;
	}
	for(i=n+1;i<=m;i++)
	{
		select(ht,i-1,&x,&y);//选择parent为0且权值最小的结点
		ht[i].weight=ht[x].weight+ht[y].weight;
		ht[i].lchild=x;
		ht[i].rchild=y;
		ht[x].parent=ht[y].parent=i;
	}
}
void hafumancode(HT ht,HC hc,int n)
{
	int i,c,p,start;
	char * cd=(char *)malloc(n*sizeof(char));
	cd[n-1]='\0';//此处的cd用来存储当前哈夫曼码,可供循环利用,相当于一个暂存器
	for(i=1;i<=n;i++)//求n个叶子结点的哈夫曼码
	{
		start=n-1;
		c=i;//因为下面会循环更新孩子结点,所以不能用i(否则第一次for循环后i可能就不再是1),可将i的值提前赋给c
		p=ht[i].parent;
		while(p!=0)//只要p不是根结点
		{
			start--;//此语句用来循环更新存储下标
			if(ht[p].lchild==c)
				//cd[i]='0';//错误。注意应从叶子结点开始向上推
				cd[start]='0';
			else
				//cd[i]='1';
				cd[start]='1';
			c=p;//此语句用来循环更新孩子结点
			p=ht[p].parent;
		}
		hc[i]=(char *)malloc((n-start)*sizeof(char));
		strcpy(hc[i],&cd[start]);
	}
	free(cd);
	for(i=1;i<=n;i++)
	{
		//printf("%d的哈夫曼码为%s\n",ht[i],hc[i]);错误,ht[i]为结构数组,应写其成员
		printf("%d的哈夫曼码为%s\n",ht[i].weight,hc[i]);
	}

}
void main()
{
	int n;
	pbt root;
	printf("\t\t-----------------------------------------\n");
	printf("\t\t1.创建二叉树          2.遍历二叉树\n");
	printf("\t\t3.二叉树的属性        4.哈夫曼树\n");
	printf("\t\t5.退出\n");
	printf("\t\t-----------------------------------------\n");
	while(1)
	{
		printf("请选择功能模块(1-5)\n");
		scanf("%d",&n);
		//char ch=getche();
		getchar();
		switch(n)
		{
			case 1:{printf("请以先序扩展创建二叉树(空结点用空格代替)\n");creatbt(&root);}break;
			case 2:
			{
				
				printf("遍历二叉树\n");
				printf("\t\t[1]先序遍历\n");
				printf("\t\t[2]中序遍历\n");
				printf("\t\t[3]后序遍历\n");
				printf("\t\t[4]返回主菜单\n");
				while(1)
				{
					int n;
					printf("请选择(1-4):\n");
					scanf("%d",&n);
					if(1==n)
						preorder(root);
					if(2==n)
						inorder(root);
					if(3==n)
						postorder(root);
					//else//不能这样写,因为这个else只能与上一个if配对,所以当n!=3时break都会执行
					if(n==4)
						break;
				}
			   }break;
			case 3:
			{
				int h=1,n;
				printf("二叉树属性\n");
				printf("\t\t[1]二叉树高度\n");
				printf("\t\t[2]二叉树结点数\n");
				printf("\t\t[3]二叉树叶子结点\n");
				printf("\t\t[4]返回主菜单\n");
				while(1)
				{
					printf("请选择:(1-4)\n");
					scanf("%d",&n);
					if(1==n)
						printf("该二叉树的高度为%d\n",btdepth(root,h));
					if(2==n)
						printf("该二叉树的结点数为%d\n",nodenum(root));
					if(3==n)
						printf("该二叉树的叶子结点数为%d\n",leafnum(root));
					if(n==4)
						break;
				}

			}break;
			case 4:
				{
					HT ht;
					HC hc;
					int n,i;
					printf("请输入叶子结点的个数\n");
					scanf("%d",&n);
					int * w=(int *)malloc((n+1)*sizeof(int));//此语句必须位于scanf的下面
					for(i=1;i<=n;i++)
					{
						printf("请输入第%d个叶子结点的权值\n",i);
						scanf("%d",&w[i]);
					}
					hafuman(ht,w,n);hafumancode(ht,hc,n);
				}break;
			case 5:exit(1);
		}
	}

}

程序运行结果如下:


【二叉树系列】二叉树课程大作业_第1张图片

【二叉树系列】二叉树课程大作业_第2张图片

注意对于同一个二叉树,哈夫曼码的结果不唯一,上述输出只是一种情况。

你可能感兴趣的:(二叉树)