机器学习 KD树_递归_回溯_搜索(matlab实现)

思路

第一个版本:链接

KD树基本思路:
建立KD树(Kd_Tree_Create)
递归搜索:回溯搜索的起点, 建立回溯栈(Kd_Tree_Search)

回溯搜索:从起点向着根节点回溯(Kd_Tree_Recall_Search)


测试节点:test_x
当前最优节点:predicted_x_point
当前最短距离:predicted_x_distance
当前回溯节点:cuurent_point
测试节点与当前节点距离:Dis_current_test
回溯规则:
若Dis_current_test >= predicted_x_distance,说明当前节点并非当前最优节点
再判断以测试节点为球心形成的超球是否与当前节点形成的超面相交
若未相交且回溯栈非空
向上回溯(回溯栈顶弹出元素)
若相交
需向下遍历当前节点,寻找最优节点
若Dis_current_test < predicted_x_distance,说明当前节点为当前最优节点
更新当前最优节点与当前最短距离
再判断以测试节点为球心形成的超球是否与当前节点形成的超面相交(此时一般来说都会相交, 因为当前最优节点处于超面)
若未相交且回溯栈非空
向上回溯(回溯栈顶弹出元素)
若相交
需向下遍历当前节点,寻找最优节点

效果

待优化

1、当前代码仅实现向上回溯,超球与超面相交需向下遍历这一步被略去(因为目前我也没想到怎么去写)

代码

mian

clear all;
clc;
%% 数据导入
Dataset=csvread("iris_dataset.csv");
rows=150;
columns=5;

%% 数据分割
Train_set=Dataset(1:120,:);
Test_set=Dataset(121:150,:);

%% kd树生成
%1:columns列为属性和类别, columns+1列节点存活状态
global Kd_Tree;
Kd_Tree_Create(Train_set);
size_Kd_Tree=size(Kd_Tree);

%% 方法1 递归搜索 测试
%{
global stack_point;
scores=0;
for i=1:30
    test_x=Test_set(i,1:columns-1);
    Kd_Tree_Search(1,size_Kd_Tree(1),columns-1,1,test_x);
    if (Kd_Tree(stack_point(1),columns)==Test_set(i,columns))
        scores=scores+1;
    end
    stack_point=[];
end
disp("递归搜索准确率:"+scores/30);
%}
%% 方法2 递归 & 回溯搜索 测试

global stack_point;
global x_i_array;
global predicted_x_point;
global predicted_x_distance;

scores=0;
for i=1:30
    test_x=Test_set(i,1:columns-1);
    
    Kd_Tree_Search(1,size_Kd_Tree(1),columns-1,1,test_x);
    
    predicted_x_point=stack_point(1);
    predicted_x_distance=Distant(Kd_Tree(predicted_x_point,1:columns-1),test_x);
    
    Kd_Tree_Recall_Search(stack_point(1),x_i_array(1),columns,test_x);
    
    if (Kd_Tree(predicted_x_point,columns)==Test_set(i,columns))
        scores=scores+1;
    end
    stack_point=[];
    x_i_array=[];
end
disp("递归 & 回溯搜索准确率:"+scores/30);

%% 方法3 递归 & 回溯 & 超球越界 搜索 测试

Kd_Tree_Create

function [] = Kd_Tree_Create(Dataset)
%二叉树数据结构在c语言中容易表示,可在matlab中却不那么容易
%但是c语言需要自己造轮子(sortrows()用c得写死我), matlab有现成的, 所以思考一下如何在matlab中表示二叉树呢
%参考大堆小堆利用数组表示二叉树, 从而避开指针构建kdtree(哇噢, 感觉自己就是个小机灵鬼诶)
%给每个节点添加下标以实现父子访问
%提示:节点下标为i, 左孩子下标为2*i,左孩子下标为2*i+1
%因为kdtree不是完全二叉树, 所以需要增加状态信息栏表示某节点是否为空
%好了, 开整吧

%Dataset共有rows行数据,1:columns-1列为属性,columns列为类别
size_Dataset=size(Dataset);
recursive(Dataset,1,1,size_Dataset(1),size_Dataset(2)-1);
end

recursive

function [] = recursive(Dataset,pos,x_i,rows,columns)
%Dataset:需要二分的数据集
%rows:需分类的个体数
%columns:用于分类的属性数
%pos:Kd_Tree插入位置
%x_i:排序依据
global Kd_Tree;
if(rows>1)
    %排序
    Dataset=sortrows(Dataset,mod(x_i-1,columns)+1);
    %二分
    Divi_Index=fix(rows/2);
    Kd_Tree(pos,1:columns+1)=Dataset(Divi_Index+1,:);
    Kd_Tree(pos,columns+2)=1;
    %递归
    recursive(Dataset(1:Divi_Index,:),2*pos,x_i+1,Divi_Index,columns);
    recursive(Dataset(Divi_Index+2:rows,:),2*pos+1,x_i+1,rows-Divi_Index-1,columns);
else
    if(rows==1)
        Kd_Tree(pos,1:columns+1)=Dataset;
        Kd_Tree(pos,columns+2)=1;
    else
        Kd_Tree(pos,columns+2)=0;
    end
end

end

Kd_Tree_Search

function [] = Kd_Tree_Search(current_point,rows,x_dim,i_x,test_x)
global Kd_Tree;
global stack_point;
stack_point=[current_point stack_point];
if(Kd_Tree(current_point,i_x)<=test_x(1,i_x))%进入右子节点
    if(2*current_point+1<=rows && Kd_Tree(2*current_point+1,x_dim+2)==1)
        Kd_Tree_Search(2*current_point+1,rows,x_dim,mod(i_x,x_dim)+1,test_x)
    else%父与右子之间 && 右子为空
    end
else%进入左子节点
    if(2*current_point<=rows && Kd_Tree(2*current_point,x_dim+2)==1)
        Kd_Tree_Search(2*current_point,rows,x_dim,mod(i_x,x_dim)+1,test_x)
    else%父与左子之间 && 左子为空
    end
end


end

Kd_Tree_Recall_Search

function []= Kd_Tree_Recall_Search(current_x_point,x_i,columns,test_x)
global Kd_Tree;
global stack_point;
global x_i_array;
global predicted_x_point;
global predicted_x_distance;

size_stack_point=size(stack_point);
size_x_i_array=size(x_i_array);

stack_point=stack_point(1,2: size_stack_point(2));%待回溯节点
x_i_array=x_i_array(1,2: size_x_i_array(2));%待回溯节点所在x_i

Dis_current_predicted=Distant(Kd_Tree(current_x_point,1:columns-1),test_x);
if(Dis_current_predicted >= predicted_x_distance)%当前current距离 >= 最优predicted_x距离
    if(size_stack_point(2)>1)%未回溯到根节点
        Kd_Tree_Recall_Search(stack_point(1),x_i_array(1),columns,test_x);
    end
    
    %t1= (test(1,x_i)+predicted_x_distance)-Kd_Tree(current_x_point,x_i);
    %t2= (test(1,x_i)-predicted_x_distance)-Kd_Tree(current_x_point,x_i);
    %if(t1*t2 > 0 && size_stack_point>1)%与当前节点所在超面无交点 && 未回溯到根节点
        %Kd_Tree_Recall_Search(stack_point(1),x_i_array(1),columns,test_x);
    %else% 与当前节点所在超面有交点
        %遍历current的另一子树
    %end
else %当前current距离 < 最优predicted_x距离
    if(size_stack_point(2)>1)% 未回溯到根节点
        predicted_x_point=current_x_point;
        predicted_x_distance=Distant(Kd_Tree(predicted_x_point,1:columns-1),test_x);
        %遍历current的另一子树
        Kd_Tree_Recall_Search(stack_point(1),x_i_array(1),columns,test_x);
    end
end
end
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回溯算法是一种常用的搜索算法,用于解决一些组合优化问题。在Matlab实现回溯算法可以通过归的方式来实现。下面是一个简单的示例代码: ```matlab function backtrackAlgorithm(input) % 初始化参数 solution = []; % 存储解决方案 backtrack(input, solution); end function backtrack(input, solution) % 判断是否满足终止条件 if isSolution(input, solution) % 处理解决方案 processSolution(solution); return; end % 生成候选解 candidates = generateCandidates(input, solution); % 遍历候选解 for i = 1:length(candidates) % 做出选择 makeChoice(input, solution, candidates(i)); % 归调用 backtrack(input, solution); % 撤销选择 undoChoice(input, solution, candidates(i)); end end % 判断是否满足终止条件的函数 function isSol = isSolution(input, solution) % 判断是否满足终止条件的逻辑 % 返回值为布尔类型,true表示满足终止条件,false表示不满足 end % 处理解决方案的函数 function processSolution(solution) % 处理解决方案的逻辑 end % 生成候选解的函数 function candidates = generateCandidates(input, solution) % 生成候选解的逻辑 % 返回值为候选解的集合 end % 做出选择的函数 function makeChoice(input, solution, candidate) % 做出选择的逻辑 end % 撤销选择的函数 function undoChoice(input, solution, candidate) % 撤销选择的逻辑 end ``` 以上是一个简单的回溯算法的实现示例,你可以根据具体的问题进行相应的修改和扩展。希望对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值