// data是否在多个象限内 // 多象限内,放到父节点上 private bool isInMultipleSub(QuadNode node, QuadData data) { int cnt = 0; if (null == node.Sub) { split(node); } for (int i = 0; i < 4; ++i) { if (isRegionCross(node.Sub[i].mbr, data.mbr)) { cnt++; } } if (0 == cnt) // 大于整个象限了 { return(true); } else if (cnt > 1) // 处于多个象限 { return(true); } else { return(false); } }
// 删除 // 从四叉树中移除,调用时需要data数据修改前调用,如果data数据修改后调用,可能无法找到。 // 导致数据错误 public bool Remove(QuadData data) { var tmp = _root; bool rm = false; bool success = false; // 没有节点 do { // 节点数 满足,或者处于多个象限中 if ((tmp.Cnt <= MAX_DATA_CNT && null == tmp.Sub) || isInMultipleSub(tmp, data)) { // 跳出循环 rm = true; // 重复删除同一个数据 if (null == tmp.Child) { break; } // 本节点查找 var curNode = tmp.Child; var preNode = tmp.Child; do { if (curNode == data) { // 头 if (curNode == tmp.Child) { tmp.Child = curNode.Next; } else { preNode.Next = curNode.Next; } success = true; tmp.Cnt--; TotalCnt--; LevelCnt[tmp.Level]--; break; } preNode = curNode; curNode = curNode.Next; } while (null != curNode); } else { // 获取所在象限 tmp = GetSubNode(tmp, data); } } while (false == rm); return(success); }
// 更新 // 跟新data在四叉树中的位置 public bool Update(QuadData data, QuadData newData) { bool success = Remove(data); if (false == success) { // 失败了,逻辑错误 log($"error remove data. {data.Id}"); return(false); } Add(newData); return(true); }
public QuadNode GetSubNode(QuadNode node, QuadData data) { QuadNode sub = null; for (int i = 0; i < MAX_QUADRANT; ++i) { if (false == isRegionCross(node.Sub[i].mbr, data.mbr)) { continue; } sub = node.Sub[i]; break; } return(sub); }
// 添加 public bool Add(QuadData data) { // 节点node数量判定 // 寻找符合节点插入 bool success = false; QuadNode tmp = _root; do { bool addToParentNode = false; // 当前节点child个数小于最大child个数,并且没有分裂过 if (tmp.Cnt + 1 <= MAX_DATA_CNT && null == tmp.Sub) { addToParentNode = true; } // 节点个数<MAX_DATA_CNT && 为分裂的 // 多象限内直接插入本节点 if (addToParentNode || isInMultipleSub(tmp, data)) { // 加入本节点 var n1 = tmp.Child; tmp.Child = data; data.Next = n1; tmp.Cnt++; TotalCnt++; addLevelCnt(tmp.Level); success = true; // 跳出 break; } else { split(tmp); // 获取插入的指定象限, tmp = GetSubNode(tmp, data); } }while (true); return(success); }
static void Main(string[] args) { QuadTree tree = new QuadTree(); Random ran = new Random((int)DateTime.Now.Ticks); // 长宽2000 int hl = 1000; tree.Init(new MBR(-hl, hl, hl, -hl)); var qd1 = (new QuadData() { Id = 1, mbr = new MBR(1, 20, 30, 1), Next = null, }); var qd2 = (new QuadData() { Id = 2, mbr = new MBR(-30, -1, 10, 1), Next = null, }); var qd3 = new QuadData() { Id = 3, mbr = new MBR(-30, -1, -1, -10), Next = null, }; var qd4 = new QuadData() { Id = 4, mbr = new MBR(1, 20, -1, -40), Next = null, }; // 1,2,3,4象限个插入一个 tree.Add(qd1); tree.Add(qd2); tree.Add(qd3); tree.Add(qd4); // 随机插入100个 int insertCnt = 1000000; float x, z; int minwidth = 1, maxwidth = 10, minlen = 1, maxlen = 60; List <QuadData> rmList = new List <QuadData>(); QuadData randomSelect = null; int randomSelectIndex = ran.Next(0, insertCnt); for (int i = 0; i < insertCnt; ++i) { var qd = new QuadData(); qd.Id = i; float l, r, t, b; // 坐标 x = ran.Next(-hl, hl); z = ran.Next(-hl, hl); // float hwidth = ran.Next(minwidth, maxwidth); float hlen = ran.Next(minlen, maxlen); // l = x - hwidth; r = x + hwidth; t = z + hlen; b = z - hlen; qd.mbr = new MBR(l, r, t, b); qd.Next = null; tree.Add(qd); rmList.Add(qd); if (i == randomSelectIndex) { randomSelect = qd; } } string info = ""; foreach (var levelData in tree.LevelCnt) { info += $"({levelData.Key}:{levelData.Value})-"; } Console.WriteLine($"tree level:{tree.Current_Max_Level} {info}"); // var circle = new Circle() { x = 30, z = 30, radius = 30, }; var circle1 = new Circle() { x = 0, z = 0, radius = 500, }; Stopwatch sw = new Stopwatch(); // 每秒一次搜索, 这些单位平均一秒执行搜索次数 double ms = 0; find(sw, tree, circle, insertCnt); find(sw, tree, circle1, insertCnt); sw.Restart(); int rmCnt = 0; bool rm = tree.Remove(qd1); if (rm) { rmCnt++; } ms = sw.Elapsed.TotalMilliseconds; //for (int i = 0; i < rmList.Count; ++i) //{ // rm = tree.Remove(rmList[i]); // if (rm) // rmCnt++; // if (false == rm) // Console.WriteLine($"rm rmList[i] {rmList[i].Id} not success"); //} Console.WriteLine($"remove qd1 ms={ms} rm:{rm} rmCnt:{rmCnt}"); sw.Restart(); rm = tree.Remove(randomSelect); ms = sw.Elapsed.TotalMilliseconds; Console.WriteLine($"remove randomSelect index={randomSelectIndex} ms={ms} rm:{rm} rmCnt:{rmCnt}"); sw.Restart(); tree.Remove(qd2); tree.Clear(); tree.Remove(qd3); ms = sw.Elapsed.TotalMilliseconds; Console.WriteLine($"clear ms={ms}"); Console.WriteLine("Hello World!"); }