IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 【数据结构】kd树实现,范围查询,邻近查询笔记【1】2d树的构造 -> 正文阅读

[数据结构与算法]【数据结构】kd树实现,范围查询,邻近查询笔记【1】2d树的构造

k dimension tree,一种高维几何搜索的数据结构,一维对应二叉搜索树,适用于多个搜索特征的数据类型。


1.2d树类实现

2d-树的构造核心思想:

每次选取一个维度进行划分

点深度为偶(奇)时,则沿垂直(水平)方向切分

如何保证每次划分尽量居中?

每次切分都在中位点(对应坐标居中点),保证全树不高于O(logn)

代码实现:? ?

先做一个Point类,2D Tree的节点继承Point:

class Point//点类
{
public:
    //使用初始化表初始化点类
    Point(double a = 0, double b = 0 ,char na='a'):x(a), y(b),name(na){}
    Point(const Point &p); //复制构造函数
    const double getX();//得到x坐标
    const double getY();//得到y坐标
    const char getName();//得到name
    void setX(double sx);//更改x坐标
    void setY(double sy);//更改y坐标
    void setName(char sc);//更改y坐标
    // bool isSmaller(int dimension,Point &p);
    // bool isEqual(Point &p);
    // bool isBigger(int dimension,Point &p);

    //重载运算符
    friend ostream& operator<<(ostream &output, Point &p);
    bool operator >(Point &p);
	bool operator <(Point &p);
	bool operator ==(Point &p);

    int P_dimension=0;

protected:
    double x;//x坐标
    double y;//y坐标
    char name;
};

Point::Point(const Point &p){
    x=p.x;
    y=p.y;
    name=p.name;
}

//得到x的值
const double Point::getX(){ return x;}
 
//得到y的值
const double Point::getY(){ return y;}

//得到name
const char Point::getName(){  return name;}

//更改x的值
void Point::setX(double sx){ x=sx; }

//更改y的值
void Point::setY(double sy){ y=sy; }
 
//更改name
void Point::setName(char sc){ name=sc; }

//重载运算符
ostream& operator<<(ostream &output, Point &p)
{
    output<<"("<<p.x<<","<<p.y<<")"<<endl;
    return output;
}

bool Point::operator >(Point &p){
    if (P_dimension>=2) return 0;
       double coor1[2]={x,y} ;
       double coor2[2]={p.getX(),p.getY()} ;
       if(coor1[P_dimension]>coor2[P_dimension]) return 1;
       else return 0;
}

bool Point::operator <(Point &p){
    if (P_dimension>=2) return 0;
       double coor1[2]={x,y} ;
       double coor2[2]={p.getX(),p.getY()} ;
       if(coor1[P_dimension]<coor2[P_dimension]) return 1;
       else return 0;
}

bool Point::operator ==(Point &p){
       double px=p.getX();
       double py=p.getY();
       if((x==px)&&(y==py)) return 1;
       else return 0;
}

// //根据维度demension比较大小
//     bool Point::isSmaller(int dimension,Point &p){
//        if (dimension>=2) return 0;
//        double coor1[2]={x,y} ;
//        double px=p.getX();
//        double py=p.getY();
//        double coor2[2]={px,py} ;
//        if(coor1[dimension]<coor2[dimension]) return 1;
//        else return 0;
//     }

//     bool Point::isEqual(Point &p){
//        double px=p.getX();
//        double py=p.getY();
//        if((x==px)&&(y==py)) return 1;
//        else return 0;
//     }

//     bool Point::isBigger(int dimension,Point &p){
//        if (dimension>=2) return 0;
//        double coor1[2]={x,y} ;
//        double px=p.getX();
//        double py=p.getY();
//        double coor2[2]={px,py} ;
//        if(coor1[dimension]>coor2[dimension]) return 1;
//        else return 0;
//     }


struct Coordinate{
    double m_coor[2]; // 点的坐标
};
struct TreeNode{
    Point p;
    int m_dimesion; 
    // 0为x方向划分,1为y方向划分
    TreeNode(const Point &p1): p(p1){}
    TreeNode* m_pLeftChild; // 左孩子
    TreeNode* m_pRightChild; // 右孩子
};
struct RecArea{
    // 存放矩形区域左下和右上坐标
    Coordinate m_minCoor;
    Coordinate m_maxCoor;
};

class KdTree {
    private:
        int count;

    public:
        TreeNode* m_pRoot;
        KdTree() : m_pRoot(nullptr),count(0){}; //无参构造函数
        //KdTree(TreeNode*& rhs) : m_pRoot(rhs),count(0){}; //复制构造函数
        bool Empty(); // 判断二叉树是否为空
        //void Traverse(int key,void (*visit)(T));//用于遍历二叉树
        TreeNode* buildTree(std::vector<Point>&pList, int d);
};//BinartTree  二叉树类

Point findMedialPoint(int dimension, vector<Point>&pList){
    int len=pList.size();
    //for (int i = 0; i < len; i++) pList[i].P_dimension=dimension;
    sort(pList.begin(),pList.end());                    // algorithm.h 中的向量排序算法
    Point mp=pList[len/2];
    cout<<"mp:"<<mp<<endl;
    return mp;
}


TreeNode* KdTree::buildTree(std::vector<Point>&pList, int d)
{      // 在深度为d的层次,构造一棵对应于(子)集合pointList(pL)的(子)2d-树
    if (pList.empty()) return NULL;
    int dimension = d % 2;        
    for (int i = 0; i < pList.size(); i++) pList[i].P_dimension=dimension;                      // 确定划分方向
    Point medianP = findMedialPoint(dimension, pList);
                                                            // 确定中位点
    std::vector<Point> pListLeft, pListRight;       // 左右子树的点集
    for (int i = 0; i < pList.size(); i++)
    {
        if (medianP>pList[i])  //点pList[i]的dimension轴坐标小于中位点
		pListLeft.push_back(pList[i]);              // 归入左子树
        else if (medianP< pList[i])  // 轴坐标大于中位点
		pListRight.push_back(pList[i]);             // 归入右子树
        else if (!( medianP==pList[i]))       // 多个点落在中位线的情况
		pListRight.push_back(pList[i]);             // 除了中位点外其它归入右子树
    }
    TreeNode* pTreeNode = new TreeNode(medianP); //创建子树根,复制节点数据为mediaP
    pTreeNode->m_pLeftChild = buildTree(pListLeft, d + 1);   // 深度d+1构建左子树      
    pTreeNode->m_pRightChild = buildTree(pListRight, d + 1); // 深度d+1构建右子树 
    pTreeNode->m_dimesion = dimension;                 // 设置节点的分割轴方向
    return pTreeNode;
}

构建树思路:

如上图所示的7个点构建二维搜索树,维度定义:dimension 1--x, 0--y;

首先 dimension=1,把七个点按x周排序,找到x轴坐标中点“C”,作为根节点,然后比Cx小的入左子树,比Cx大的入右子树。然后再递归生成子树,次数深度+1,维度改变。

以左子树为例,输入点向量(G B A ),此时dimension=0,?按y坐标排序,为: G-B-A,中位点为B,则G入B左子树,A入右子树,再递归就完成了二维搜索树的构造。

测试:

int main( )
{  
    int pointnum,quirynum;
    cin>>pointnum>>quirynum;
    vector<Point > pList;

    Point parray[pointnum];

    double m_x,m_y;
    char m_name;
    for(int i=0;i<pointnum;i++){
        cin>>m_x>>m_y;
        cin>> m_name;
        parray[i]=Point(m_x,m_y,m_name);
        pList.push_back(parray[i]);
    }
    //vector<Point> pList(parray,parray+pointnum);
    cout<<pList.size()<<endl;

    for(int i=0;i<pointnum;i++){
        cout<<pList[i]<<endl;
    }


    KdTree m_2dtree;
    m_2dtree.m_pRoot=m_2dtree.buildTree( pList, 1);

    system("pause");
    return 0;
}

输入输出:

首先输入测试点个数,然后输出生成的点向量

在构建2D树时,每生成一个节点,输入节点Point?

根节点b,左子树a,右子树c,和预期的相符。

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-11-18 11:25:30  更:2021-11-18 11:26:31 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 11:59:57-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码