四叉樹

  1 #include <cmath> 
  2 #include <vector>
  3 #include <iostream>
  4 #include <algorithm>
  5 
  6 using namespace std;
  7 
  8 const int NUME_PLANETS = 10;//星球數量
  9 const int TIME_COUNT = 20;
 10 const int BORDER_LIMIT = 3200;//全部座標絕對值都不超過3200
 11 
 12 const double G = 1e-3;//萬有引力常量
 13 const double pi = acos(-1.0);//圓周率
 14 
 15 double sqr(double x) {//平方
 16     return x * x;
 17 };
 18 
 19 //二維向量
 20 class Vector {
 21 public:
 22     double x, y;
 23 
 24     Vector():x(0), y(0){}
 25     Vector(double x, double y):x(x), y(y){}
 26     ~Vector() {}
 27 
 28     void operator = (const Vector &v) {
 29         x = v.x;
 30         y = v.y;
 31     }
 32 
 33     Vector operator + (const Vector &v) {
 34         return Vector(x + v.x, y + v.y);
 35     }
 36 
 37     Vector operator - (const Vector &v) {
 38         return Vector(x - v.x, y - v.y);
 39     }
 40 
 41     Vector operator * (double f) {
 42         return Vector(x * f, y * f);
 43     }
 44 
 45     Vector operator / (double f) {
 46         //return (*this) * (1.0 / f);
 47         return Vector(x / f, y / f);
 48     }
 49 
 50     double length() {//返回長度的平方
 51         return sqr(x) + sqr(y);
 52     }
 53 
 54     void factor() {//將該向量變爲單位向量
 55         double len = sqrt(length());
 56         x /= len;
 57         y /= len;
 58     }
 59 
 60     void print() {
 61         cout << "(" << x << "," << y << ")";
 62     }
 63 };
 64 
 65 //星球結構體
 66 class Planet {
 67 public:
 68     Vector pos;//位置
 69     Vector v;//速度
 70     Vector a;//加速度
 71     double m;//質量
 72 };
 73 
 74 //封裝四叉樹 
 75 namespace QuatTree {
 76     const int SON = 4;//兒子個數,使用常量易於拓展,好比想拓展爲八叉樹只須要修改此常量爲8便可
 77     const int SIZE = 1e5 + 5;//預開SIZE個Node節點備用,應保證 SIZE >= NUME_PLANETS * log2(N), N表示初始邊界大小
 78 
 79     //四叉樹的節點
 80     struct Node {
 81         double mass;//質量
 82         Vector center;//重心
 83         bool isleaf;//是否爲葉子節點
 84         Node* child[SON];
 85         /*當前節點的四個兒子節點,分佈以下
 86          * 01
 87          * 23
 88          */
 89         
 90         Node():mass(0), isleaf(0), center(){
 91             for (int i = 0; i < SON; i ++)
 92                 child[i] = NULL;
 93         }
 94         ~Node() {}
 95 
 96         void init(Planet *p);//使用一個星球對四叉樹節點進行初始化
 97         void update();//使用四個兒子節點的信息更新當前節點的信息
 98     };
 99 
100     Node *null = new Node();//空指針,使用自定義null而不用NULL能夠減小 if(Node == NULL) 的判斷
101     Node *root;//四叉樹的根
102 
103     void Node::init(Planet *p) {
104         mass = p -> m;
105         isleaf = 1;
106         center = p -> pos;
107         child[0] = null;
108         child[1] = null;
109         child[2] = null;
110         child[3] = null;
111     }
112 
113     void Node::update() {
114         mass = 0;
115         isleaf = 1;
116         center.x = center.y = 0;
117         for (int i = 0; i < SON; i ++) {
118             if (child[i] == null) continue;
119             isleaf = 0;
120             mass += child[i] -> mass; 
121             center.x += child[i] -> mass * (child[i] -> center).x;
122             center.y += child[i] -> mass * (child[i] -> center).y;
123         }
124         center.x /= mass;
125         center.y /= mass;
126     }
127 
128     Node pool[SIZE];//內存池
129     int count;//內存池的計數器
130 
131     void init() {//四叉樹初始化
132         count = 0;
133         root = null;
134     }
135 
136     Node *getNewNode() {//從內存池中得到一個Node指針
137         return &(pool[count ++]);
138     }    
139 
140     void insert(Node *&o, Planet *p, 
141         double lx = -BORDER_LIMIT, double rx = BORDER_LIMIT, 
142         double ly = -BORDER_LIMIT, double ry = BORDER_LIMIT) {
143         //當前處理的二位平面爲 lx <= x < rx, ly <= y < ry
144         if (o == null) {
145             o = getNewNode();
146             o -> init(p);
147             return;
148         }
149         double midx = (lx + rx) / 2, midy = (ly + ry) / 2;
150         if ((p -> pos).x < midx) {
151             if ((p -> pos).y < midy) insert(o -> child[0], p, lx, midx, ly, midy);
152             else insert(o -> child[2], p, lx, midx, midy, ry);
153         }    
154         else {
155             if ((p -> pos).y < midy) insert(o -> child[1], p, lx, midx, ly, midy);
156             else insert(o -> child[3], p, lx, midx, midy, ry);
157         }
158         o -> update();
159     }
160 
161     Planet calc(Planet *p, Node *o, int tim = 1000) {
162         //計算星球p,在已建好的四叉樹o中,通過時間tim以後的狀態
163 
164     }
165 
166     vector<Planet> getQuatTree(vector<Planet> planets, int tim = 1000) {
167         //星球集合planets通過時間tim後的狀態,tim單位爲ms,默認爲1000ms
168         init();//初始化
169         int n = planets.size();//得到星球數量
170 
171         for (int i = 0; i < n; i ++) {
172             insert(root, &planets[i]);
173         }
174 
175         vector<Planet> result(n);
176         for (int i = 0; i < n; i ++) {
177             result[i] = calc(&planets[i], root, tim);
178         }
179 
180         return result;
181     }
182 } 
183 
184 int main() {
185     vector<Planet> planets(NUME_PLANETS);
186     int num = NUME_PLANETS;
187 
188     /*生成全部星球初始值
189      */ 
190 
191     /*每隔必定時間進行一次計算便可,使用方法以下
192      * for (int i = 0; i < times; i ++) {//計算times次
193      *     planets = QuatTree::getQuatTree(planets);
194      *        print(planets);//輸出全部星球信息
195      * }
196      */
197     return 0;
198 }
相關文章
相關標籤/搜索