K-D(K-Dimensional)树在很多聚类算法中都有应用,例如CURE算法。K-D树的构造说明请参考
J_Outsider的博文,本文这里只给出其构造代码如下:
主程序代码:
clc;
clear;
%读取数据文件,生成点矩阵
fileID = fopen('D:\matlabFile\K-D tree\test.txt');
C=textscan(fileID,'%f %f');
fclose(fileID);
%构造数据集,第一列为x轴,第二列为y轴
D=cat(2,C{1},C{2});
%保存构造结果
KD_Tree=CreateKD_Tree(D);
%节点中包含有分割域的构造结果
KD_Tree_Dim=CreateKD_Tree_Dim(D);
%测试点
point=[5.1 4.1];
%搜索邻近点
R=KD_Tree_Search(KD_Tree_Dim,point);
树的构造函数:CreateKD_Tree
function KDTree=CreateKD_Tree(D)
%计算两个维度上的数据方差,然后比较两个维度的方差,确定分割的维度,1代表x轴,2代表y轴
dimension=1;
if var(D(:,1))<=var(D(:,2))
dimension=2;
end
%取出分割域
col=sort(D(:,dimension));
index=ceil(length(col)/2);
%确定分裂点
split=col(index,1);
%对数据分组
node=[]; %结点
left_data=[]; %左枝数据集
right_data=[];%右枝数据集
for i=1:size(D,1)
if (D(i,dimension)<split)
left_data=cat(1,left_data,D(i,:));
elseif(D(i,dimension)>split)
right_data=cat(1,right_data,D(i,:));
else
node=D(i,:);
end
end
%向下遍历左结点
if isempty(left_data)
left_node=[];
elseif size(left_data,1)==1
left_node=left_data;
else
left_node=CreateKD_Tree(left_data);
end
%向下遍历右结点
if isempty(right_data)
right_node=[];
elseif size(right_data,1)==1
right_node=right_data;
else
right_node=CreateKD_Tree(right_data);
end
%将左右结点的结果加入树中
KDTree={node,left_node,right_node};
包含分割域的构造函数CreateKD_Tree_Dim
%结点中包含分割域,例如结点[4 5 1],最后一位1代表分割域,目的是为了后续搜索K-D树:
function KDTree=CreateKD_Tree_Dim(D) %结点中包含分割域,如如[4 5 1],最后一位1代表分割域,目的是为了方便搜索
%计算两个维度上的数据方差,然后比较两个维度的方差,确定分割的维度,1代表x轴,2代表y轴
dimension=1;
if var(D(:,1))<=var(D(:,2))
dimension=2;
end
%取出分割域
col=sort(D(:,dimension));
index=ceil(length(col)/2);
%确定分裂点
split=col(index,1);
%对数据分组
node=[]; %结点
left_data=[]; %左枝数据集
right_data=[];%右枝数据集
for i=1:size(D,1)
if (D(i,dimension)<split)
left_data=cat(1,left_data,D(i,:));
elseif(D(i,dimension)>split)
right_data=cat(1,right_data,D(i,:));
else
node=D(i,:);
end
end
%向下遍历左结点
if isempty(left_data)
left_node=[];
elseif size(left_data,1)==1
left_node=left_data;
else
left_node=CreateKD_Tree_Dim(left_data);
end
%向下遍历右结点
if isempty(right_data)
right_node=[];
elseif size(right_data,1)==1
right_node=right_data;
else
right_node=CreateKD_Tree_Dim(right_data);
end
%增加分割域
node=cat(2,node,dimension);
%将左右结点的结果加入树中
KDTree={node,left_node,right_node};
邻近点搜索函数 KD_Tree_Search:
%针对二维数据的搜索近邻点,所构造的树需要具有分割域
function Nearest=KD_Tree_Search(KDTree,point)
%取出结点
node=KDTree{1,1};
%判定从左右枝搜索,默认为从左枝
Leaf=KDTree{1,2};
%判断是分割域,1为x轴,2为y轴
if node(1,3)==1
if node(1,1)<point(1,1)
Leaf=KDTree{1,3};
end
else
if node(1,2)<point(1,2)
Leaf=KDTree{1,3};
end
end
%判断是否是是叶子,如果是继续向下搜索,如果否,则计算其距离
if strcmp(class(Leaf),'cell')
Result=KD_Tree_Search(Leaf,point);
%将返回结果与当前结点的距离进行比较
dist=sqrt((node(1,1)-point(1,1))^2+(node(1,2)-point(1,2))^2);
%比较两个距离大小,取小
if Result{1,2}<dist
Nearest=Result{1,2};
else
Nearest={node(1:2),dist};
end
else
%判定是否为空值
if ~isempty(Leaf)
%计算两点的距离
dist1=sqrt((Leaf(1,1)-point(1,1))^2+(Leaf(1,2)-point(1,2))^2);
%计算与结点的距离
dist2=sqrt((node(1,1)-point(1,1))^2+(node(1,2)-point(1,2))^2);
%比较两个距离大小,取小
if dist1<dist2
Nearest={Leaf,dist1};
else
Nearest={node(1:2),dist2};
end
end
end
测试数据如下,请读者赋值保存为txt:
2 3
5 4
9 6
4 7
8 1
7 2