C++实现四叉树索引

3.四叉树索引实现
3.1指针实现

四叉树索引的基本思想是将地理空间递归划分为不同层次的树结构。它将已知范围的空间划分为四个相等的子空间,如此递归下去,直至树的层次达到一定深度或者满足某种要求后停止分割。四叉树的结构比较简单,并且当空间数据分布比较均匀时,具有比较高的空间数据插入和查询效率。这里介绍的四叉树结构中,所有的点位置信息都存储在叶子节点上,中间节点以及根结点不存储点信息。

为了快速检索点,设计了如下的数据结构来支持四叉树的操作。

  1. 最小外包矩形数据结构:定义了一个矩形区域的四条边的坐标范围
 //矩形区域
struct Region 
{
   
     double up;  //上边界
     double bottom; //下边界
     double left;  //左边界
     double right;  //右边界
};
  1. 点数据结构:定义了点的x和y坐标
//点结构体
struct ElePoint 
{
   
     double lng;  //x坐标
     double lat;  //y坐标
};

3.四叉树结点数据结构:四叉树结点是四叉树结构的主要组成部分,主要用于存储点的最小外包矩形,深度,子节点指针等,也是四叉树算法操作的主要部分。

//四叉树结点
struct QuadTreeNode
{
   
  int depth;  //结点的深度
  int is_leaf;  //是否是叶子节点
   struct Region region;  //区域范围
   struct QuadTreeNode *LU; //左上子节点指针
   struct QuadTreeNode *LB;  //左下子节点指针
   struct QuadTreeNode *RU;  //右上子节点指针
   struct QuadTreeNode *RB;  //右下子节点指针
   int ele_num;   //矩形区域中位置点数
   struct ElePoint *ele_list[MAX_ELE_NUM];  //矩形区域中位置点列表
};

四叉树的主要操作:

  1. 插入元素:将元素插入到叶子节点中,其步骤如下:

(1)判断结点是否已经分裂,已分裂的选择合适的子节点,进行插入;

(2)未分裂的查看是否过载,过载的分裂结点,重新插入;

(3)未过载的直接插入。

示例代码如下:

void insertEle(QuadTreeNode *node, ElePoint ele)
{
   
	//是叶子结点
	if (1 == node->is_leaf) 
	{
   
		if (node->ele_num + 1 > MAX_ELE_NUM) 
		{
   
			splitNode(node);

			//分裂后的 node 不是叶子节点,所以新插入的元素会插入到 node 的子节点上
			insertEle(node, ele);  //将新插入的元素插入到node的子节点上
		}
		else 
		{
   
			ElePoint *ele_ptr = ( ElePoint *) malloc(sizeof(ElePoint));
			ele_ptr->lat = ele.lat;
			ele_ptr->lng = ele.lng;

			//将新插入的点加入到父节点的位置点列表中
			node->ele_list[node->ele_num] = ele_ptr;
			node->ele_num++;
		}

		return;
	}

	//不是叶子结点
	double mid_vertical = (node->region.up + node->region.bottom) / 2;
	double mid_horizontal = (node->region.left + node->region.right) / 2;
	if (ele.lat > mid_vertical)
	{
   
		if (ele.lng > mid_horizontal) 
		{
   
			insertEle(node->RU, ele);
		}
		else
		{
   
			insertEle(node->LU, ele);
		}
	}
	else 
	{
   
		if (ele.lng > mid_horizontal)
		{
   
			insertEle(node->RB, ele);
		}
		else
		{
   
			insertEle(node->LB, ele);
		}
	}
}

2.分裂结点:对父节点进行分裂,分成四个子区域,其步骤如下:

(1)通过父节点获取子节点的深度和范围;

(2)父节点分裂出四个子节点;

(3)将父节点的元素插入到子节点上,然后释放父节点元素空间

(4)父节点的位置点数-1

示例代码如下:

void splitNode(struct QuadTreeNode *node)
{
   
	double mid_vertical = (node->region.up + node->region.bottom) / 2;  //垂直放向的中间线
	double mid_horizontal = (node->region.left + node->region.right) / 2;  //水平方向的中间线

	node->is_leaf = 0;
	//生成四个孩子结点
	node->RU = createChildNode(node, mid_vertical, node->region.up, mid_horizontal, node->region.right);
	node->LU = createChildNode(node, mid_vertical, node->region.up, node->region.left, mid_horizontal);
	node->RB = createChildNode(node, node->region.bottom, mid_vertical, mid_horizontal, node->region.right);
	node->LB = createChildNode(node, node->region.bottom, mid_vertical, node->region.left, mid_horizontal);

	for (int i = 0; i < node->ele_num; i++) 
	{
   
		//此时插入的时候,node不是叶子节点,此时执行 insert 函数,会将元素插入到孩子节点上
		insertEle(node, *node->ele_list[i]);   // 将父节点元素 插入到子节点
		free(node->ele_list[i]);   //释放父节点元素
		node->ele_num--;     //每插入一个元素,父节点的元素数-1
	}
}
 

3.查询:输入一个检索点,然后输出与这个点在同一个四叉树结点中的所有点,步骤如下:

(1)先判断该点是否是叶子节点;

(2)是叶子结点直接输出该点所在区域的周边点;

(3)不是叶子结点,递归搜索其子节点;

示例代码如下:

void queryEle(struct QuadTreeNode node, struct ElePoint ele) 
{
   
	//是叶子结点
	if (node.is_leaf == 1) 
	{
   
		cout << "附近点有" << node.ele_num << "个,分别是:" << endl;
		for (int j = 0; j < node.ele_num; j++)
		{
   
			cout << "(" << node.ele_list[j]->lng << "," << node.ele_list[j]->lat << ")";
		}
		return;
	}

	//不是叶子节点
	double mid_vertical = (node.region.up + node.region.bottom) / 2;
	double mid_horizontal = (node.region.left + node.region.right) / 2;

	if (ele.lat > mid_vertical) 
	{
   
		if (ele.lng > mid_horizontal) 
		{
   
			queryEle(*node.RU, ele);
		}
		else 
		{
   
			queryEle(*node.LU, ele);
		}
	}
	else
	{
   
		if (ele.lng > mid_horizontal)
		{
   
			queryEle(*node.RB, ele);
		}
		else
		{
   
			queryEle(*node.LB, ele);
		}
	}
}

任意区域查询:

//任意区域查询
void queryArea(QuadTreeNode *node, Region *region)
{
   	//是叶子节点
	if (node->is_leaf == 1
  • 2
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
叉树是一种二叉树的变体,它将平面空间递归分成四个象限。下面是C++代码实现: ```cpp #include <iostream> #include <vector> using namespace std; // 定义节点结构体 struct Node { int x, y, val; Node *nw, *ne, *sw, *se; Node(int x, int y, int val) : x(x), y(y), val(val), nw(NULL), ne(NULL), sw(NULL), se(NULL) {} }; // 定义四叉树类 class QuadTree { private: Node *root; // 根节点 int size; // 树的大小 // 插入节点 Node* insert(Node *node, int x, int y, int val) { if (node == NULL) { // 如果节点为空,则新建一个节点 size++; return new Node(x, y, val); } if (node->x == x && node->y == y) { // 如果节点已存在,则更新节点的值 node->val = val; return node; } if (x < node->x && y < node->y) { // 如果点在左下象限,则递归到左下子树 node->sw = insert(node->sw, x, y, val); } else if (x < node->x && y >= node->y) { // 如果点在左上象限,则递归到左上子树 node->nw = insert(node->nw, x, y, val); } else if (x >= node->x && y < node->y) { // 如果点在右下象限,则递归到右下子树 node->se = insert(node->se, x, y, val); } else { // 如果点在右上象限,则递归到右上子树 node->ne = insert(node->ne, x, y, val); } return node; } // 查询节点 Node* query(Node *node, int x, int y) { if (node == NULL) { // 如果节点为空,则返回NULL return NULL; } if (node->x == x && node->y == y) { // 如果节点匹配,则返回节点 return node; } if (x < node->x && y < node->y) { // 如果点在左下象限,则递归到左下子树 return query(node->sw, x, y); } else if (x < node->x && y >= node->y) { // 如果点在左上象限,则递归到左上子树 return query(node->nw, x, y); } else if (x >= node->x && y < node->y) { // 如果点在右下象限,则递归到右下子树 return query(node->se, x, y); } else { // 如果点在右上象限,则递归到右上子树 return query(node->ne, x, y); } } public: // 构造函数 QuadTree() : root(NULL), size(0) {} // 插入节点 void insert(int x, int y, int val) { root = insert(root, x, y, val); } // 查询节点 Node* query(int x, int y) { return query(root, x, y); } // 获取树的大小 int getSize() { return size; } }; int main() { QuadTree tree; tree.insert(0, 0, 1); tree.insert(1, 1, 2); tree.insert(2, 2, 3); tree.insert(3, 3, 4); Node *node = tree.query(1, 1); if (node != NULL) { cout << "Node value: " << node->val << endl; } else { cout << "Node not found!" << endl; } cout << "Tree size: " << tree.getSize() << endl; return 0; } ``` 以上代码实现了四叉树的插入和查询功能,可以根据需要进行修改。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

*Heygirl

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值