简易层次聚类算法(顺序表)&(哈希图)

请使用简易层次聚类算法,为所给数据集构造一棵分层的树。 简易层次聚类算法思想: 简易层次聚类是一层一层地进行聚类的算法,可以对数据集从下而上地聚集,即 每次找到距离最短的两个数据样本,然后进行合并,直到全部合并完为止。整个 过程就是建立一个树结构,类似于下图。

执行步骤: 1)从数据集中找出两个距离最近的点(一个点就是一个数据样本),将这两个点 合并成一颗树,树的双亲结点的值为两个点的平均值。

2)重复第一步,直到只有一棵树为止。 请用简易层次聚类算法,为下面数据集构造一个分层的树。

数据集:

点的距离公式为: 设两个点A、B以及坐标分别为,,则A和B两点之间的距离为:

要求:

(1) 请用文字描述该层次树的构造过程,如第一次哪两个样本组合成一棵 树,第二次哪两个样本组合在一起构成一颗树,依次类推,直到结束。画出这颗 层次树。

(2) 请编写代码实现上述层次树的构造(可以参考哈夫曼树算法的代码, 进行修改),并用先序遍历输出该树的结点编号(包括代码和运行结果的截图)。

(3) 请分析该算法和构造哈夫曼树算法的区别是什么?

(4) 请分析该算法的性能,如时间复杂度和空间复杂度等


(1) 请用文字描述该层次树的构造过程,如第一次哪两个样本组合成一棵 树,第二次哪两个样本组合在一起构成一颗树,依次类推,直到结束。画出这颗 层次树。

下标XYparentlchildrchild
15.13.5000
下标距离值编号编号
10.5412

 数据存储结构:

上方第一个:主要用来存储以上数据的各数据,利用函数对parent, lchild, rchild进行改变来实现树的构造。

 第二个:用来存储用公式计算的距离值,并记录当前被计算的两个花株,以便在search()函数中找到距离最短的两个花株的编码并返回。


请编写代码实现上述层次树的构造

存储结构定义和主函数

/****存储结构为顺序表******/
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#define MAX_SIZE 200
#define MAXInit  3367
typedef struct pt
{
	double x;double y;
	int parent;int lchild;int rchild;
}*PT;
typedef struct dis 
{
	double Distance;
	int Data1;int Data2;
}*DS;
void Creat_PointTree(PT &O,int m);
void Init_PointTree(PT &O,int m);
DS Creat_DIS(PT O,int m);
void Renew_DIS(PT O,DS &D,int w);
void Search(PT O,DS D,int &s1,int &s2,int i);
void print_Tree(PT O,int m);
int main()
{
	PT O;
	int m;
	scanf("%d",&m);
	Creat_PointTree(O,m);//创建树
	print_Tree(O,m);//输出树
	return 0;
}

 创建树的核心代码

void Creat_PointTree(PT &O,int m)//利用顺序表创建树
{
	int n,i,j,s1,s2,x;
	n = 2*m-1;
	O = (PT)malloc((n+1)*sizeof(pt));
	Init_PointTree(O,m);//赋值&&初始化

	DS D;

	D = Creat_DIS(O,m);//构造D[i]存储距离值

//	for(i = 1;i <= (1+m-1)*(m-1)/2;i++)
//		printf("%.2f\n",D[i].Distance);

	for(i = m+1;i <= n;i++)
    {
		Search(O,D,s1,s2,i);

		O[i].lchild = s1;//改变孩子编码
        O[i].rchild = s2; 

		O[i].x = (O[s1].x+O[s2].x) / 2.0;
		O[i].y = (O[s1].y+O[s2].y) / 2.0;

		Renew_DIS(O,D,i);//更新D[i]的值

		O[s1].parent = i;//改变双亲编码 
        O[s2].parent = i;
	}
}

核心作用代码

Creat_DIS()中:

 两种初始化方法,也就是空间的分配

(1)第一种:开始奉陪一个较大的空间,将全部初始化为0或无穷,这会在之后的遍历操作中简单,但会浪费很多空间。在本文章中使用了这种。

(2)第二钟:根据等差数列的前n项和公式分配一个刚好那存储所有距离的空间,这里可以不用初始化,当需要更新D[i]时需要用realloc函数来对应增加空间,而且为了后续方便遍历,需要记录该表的长度。这可以大程度减少空间的浪费。

Search()函数中:

找到最小的距离&&O[D[i].Data1].parent ==0&&O[D[i].Data2].parent ==0)

再返回。

void Init_PointTree(PT &O,int m)
{
	int i;
	for(i = 1;i <= 2*m-1;i++)
    {
		O[i].parent = 0;
        O[i].lchild = 0;
        O[i].rchild = 0;
        O[i].x = 0;O[i].y = 0;
	}
	//动态赋值 
//  n = 2*m-1;
//	O = (OP)malloc(n+1*sizeof(op));
//	for(i = 1;i <= m;i++) 
 // scanf("%f%f",&O[i].x,&O[i].y);
	//静态赋值
	O[1].x = 5.1; O[1].y = 3.5;
	O[2].x = 4.9; O[2].y = 3.0;
	O[3].x = 4.7; O[3].y = 3.2;
	O[4].x = 6.1; O[4].y = 2.8;
	O[5].x = 6.3; O[5].y = 2.5;
	O[6].x = 6.1; O[6].y = 2.8;
	O[7].x = 6.3; O[7].y = 2.5;
	O[8].x = 6.5; O[8].y = 3.0;
	O[9].x = 6.2; O[9].y = 3.4;
}

DS Creat_DIS(PT O,int m)//初始化D[i]的值和对已有的数据集的
{
	DS D;
	int i,j,x,w;
	x = (m-1)*m/2+1; //可看成一个等差数列的和,以下有类似
	D = (DS)malloc(MAX_SIZE*sizeof(dis));

	for(w = 1;w < MAX_SIZE;w++)
		D[w].Distance = 0;
	w = 1;
	for(i = 1; i <= m;i++)
    {
		for(j = i+1;j <= m;j++)
        {
			D[w].Distance = sqrt(pow(O[i].x-O[j].x,2)+pow(O[i].y-O[j].y,2));
			D[w].Data1 = i;
			D[w].Data2 = j;
			w++;
		}
	}
	
	return D;
}

void Search(PT O,DS D,int &s1,int &s2,int i)//返回距离最小两个花株的编码
{
	int n,j,k;
	double min = 3266;
	n = 1;
	while(n <= (1+i-2)*(i-2)/2)
    {
		if(D[n].Distance < min&&O[D[n].Data1].parent ==0&&O[D[n].Data2].parent ==0){
			min = D[i].Distance;
			k = n;
			if(D[n].Distance == 0.0) 
                break;
		}
		n++;
	}
	s1 = D[k].Data1;
	s2 = D[k].Data2;
}

void Renew_DIS(PT O,DS &D,int w)
{
	int j,k;
	j = (1+w-2)*(w-2)/2+1;
	for(k = 1;k < w;k++)
	{
		D[j].Distance = sqrt(pow(O[w].x-O[k].x,2)+pow(O[w].y-O[k].y,2));
		D[j].Data1 = w;
		D[j].Data2 = k;
		j++;
	}
}

完整代码

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#define MAX_SIZE 200
#define MAXInit  3367
typedef struct pt
{
	double x;double y;
	int parent;int lchild;int rchild;
}*PT;
typedef struct dis 
{
	double Distance;
	int Data1;int Data2;
}*DS;
void Creat_PointTree(PT &O,int m);
void Init_PointTree(PT &O,int m);
DS Creat_DIS(PT O,int m);
void Renew_DIS(PT O,DS &D,int w);
void Search(PT O,DS D,int &s1,int &s2,int i);
void print_Tree(PT O,int m);
int main()
{
	PT O;
	int m;
	scanf("%d",&m);
	Creat_PointTree(O,m);
	print_Tree(O,m);
	return 0;
}
void Creat_PointTree(PT &O,int m)
{
	int n,i,j,s1,s2,x;
	n = 2*m-1;
	O = (PT)malloc((n+1)*sizeof(pt));
	Init_PointTree(O,m);//赋值&&初始化
	DS D;
	D = Creat_DIS(O,m);
//	for(i = 1;i <= (1+m-1)*(m-1)/2;i++)
//		printf("%.2f\n",D[i].Distance);
	for(i = m+1;i <= n;i++){
		Search(O,D,s1,s2,i);
		O[i].lchild = s1;O[i].rchild = s2;//改变孩子编码 
		O[i].x = (O[s1].x+O[s2].x) / 2.0;
		O[i].y = (O[s1].y+O[s2].y) / 2.0;
		Renew_DIS(O,D,i);
		O[s1].parent = i;O[s2].parent = i;//改变双亲编码 
	}
}
void Init_PointTree(PT &O,int m)
{
	int i;
	for(i = 1;i <= 2*m-1;i++){
		O[i].parent = 0;O[i].lchild = 0;O[i].rchild = 0;O[i].x = 0;O[i].y = 0;
	}
	//动态赋值 
//  n = 2*m-1;
//	O = (OP)malloc(n+1*sizeof(op));
//	for(i = 1;i <= m;i++) scanf("%f%f",&O[i].x,&O[i].y);
	//静态赋值
	O[1].x = 5.1; O[1].y = 3.5;
	O[2].x = 4.9; O[2].y = 3.0;
	O[3].x = 4.7; O[3].y = 3.2;
	O[4].x = 6.1; O[4].y = 2.8;
	O[5].x = 6.3; O[5].y = 2.5;
	O[6].x = 6.1; O[6].y = 2.8;
	O[7].x = 6.3; O[7].y = 2.5;
	O[8].x = 6.5; O[8].y = 3.0;
	O[9].x = 6.2; O[9].y = 3.4;
}
DS Creat_DIS(PT O,int m)
{
	DS D;
	int i,j,x,w;
	x = (m-1)*m/2+1; 
	D = (DS)malloc(MAX_SIZE*sizeof(dis));
	for(w = 1;w < MAX_SIZE;w++)
		D[w].Distance = 0;
	w = 1;
	for(i = 1; i <= m;i++){
		for(j = i+1;j <= m;j++){
			D[w].Distance = sqrt(pow(O[i].x-O[j].x,2)+pow(O[i].y-O[j].y,2));
			D[w].Data1 = i;
			D[w].Data2 = j;
			w++;
		}
	}
	
	return D;
}
void Search(PT O,DS D,int &s1,int &s2,int i)
{
	int n,j,k;
	double min = 3266;
	n = 1;
	while(n <= (1+i-2)*(i-2)/2){
		if(D[n].Distance < min&&O[D[n].Data1].parent ==0&&O[D[n].Data2].parent ==0){
			min = D[i].Distance;
			k = n;
			if(D[n].Distance == 0.0) break;
		}
		n++;
	}
	s1 = D[k].Data1;
	s2 = D[k].Data2;
}
void Renew_DIS(PT O,DS &D,int w)
{
	int j,k;
	j = (1+w-2)*(w-2)/2+1;
	for(k = 1;k < w;k++)
	{
		D[j].Distance = sqrt(pow(O[w].x-O[k].x,2)+pow(O[w].y-O[k].y,2));
		D[j].Data1 = w;
		D[j].Data2 = k;
		j++;
	}
}
void print_Tree(PT O,int m)
{
	int i;
	for(i = 1;i < 2*m;i++)
	{
		printf("%d %d %d %d %.2f %.2f\n",i,O[i].parent,O[i].lchild,O[i].rchild,O[i].x,O[i].y);
	}
}

 运行结果

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值