高级数据库的大作业,水过,代码写的不是很好,主要是处理I/O这块,没有找到更好的办法,时间问题,所以只能妥协了

可能我做的这个Quadtree比较奇怪,具体的可以参考UMD的那个Spatial Demo

网址如下:http://donar.umiacs.umd.edu/quadtree/

贴一下代码好了,有需要的人可以跟我一起讨论,以后如果有机会会改进这个代码的

IO操作类
  1 import java.io.*;
  2 import java.util.ArrayList;
  3 
  4 /*
  5  * This is a helper class
  6  * used to support file operation
  7  */
  8 public class FileOperator {
  9 
 10     //Input Stream
 11     FileInputStream fis;
 12     FileOutputStream fos;
 13     
 14     //Output Stream
 15     ObjectInputStream ois;
 16     ObjectOutputStream oos;
 17     
 18     String filename;
 19     
 20     public  FileOperator(String filename)
 21     {
 22         this.filename = filename;
 23     }
 24         
 25     /*
 26      * Get the entry in the position
 27      */
 28     public Object getObjectAt(long position)
 29     {
 30         int count = 0;
 31         try
 32         {
 33             fis = new FileInputStream(filename);
 34             ois = new ObjectInputStream(fis);
 35             
 36             Object temp = ois.readObject();
 37             while (count < position)
 38             {
 39                 temp = ois.readObject();
 40                 count++;
 41             }
 42             return temp;
 43         }
 44         catch (Exception e)
 45         {
 46             e.printStackTrace();        
 47         }
 48         
 49         //Close the stream
 50         try {
 51             fis.close();
 52             ois.close();            
 53         } catch (IOException e) {
 54             // TODO Auto-generated catch block
 55             e.printStackTrace();
 56         }
 57         return null;
 58     }
 59         
 60     /*
 61      * Append a new object into the file
 62      * just follow the last entry
 63      */
 64     public void appendObject(Object addin)
 65     {
 66         ArrayList<Object> arrayList = new ArrayList<Object>();
 67         try {
 68             fis = new FileInputStream(filename);
 69             ois = new ObjectInputStream(fis);
 70             
 71             Object temp;
 72             do
 73             {
 74                 temp = ois.readObject();
 75                 arrayList.add(temp);
 76             }
 77             while (temp!=null);
 78 
 79         } catch (Exception e) {
 80         }
 81         //Close the file
 82         try {
 83             fis.close();
 84             ois.close();
 85         } catch (Exception e) {
 86         }
 87         
 88         //Add the new object into the file
 89         try {
 90             fos = new FileOutputStream(filename);
 91             oos = new ObjectOutputStream(fos);
 92             for(Object i : arrayList)
 93             {
 94                 oos.writeObject(i);
 95             }
 96             oos.writeObject(addin);
 97         } catch (IOException e) {
 98             // TODO Auto-generated catch block
 99             e.printStackTrace();
100         }                
101         
102         //Close the file
103         try {
104             fos.close();
105             oos.close();
106         } catch (Exception e) {
107             e.printStackTrace();
108         }
109     }
110     
111     /*
112      * List the content of the file
113      * print the object using the toString method
114     */
115     public long fileContent()
116     {
117         long count = 0;
118         try {
119             fis = new FileInputStream(filename);
120             ois = new ObjectInputStream(fis);
121             
122             Object temp;
123             do
124             {
125                 temp = ois.readObject();
126                 count++;
127             // System.out.println(temp.toString());
128             }
129             while (temp!=null);
130         } catch (Exception e) {
131         }
132         return count;
133     }
134 }
135 

一维间距
 1 /*
 2  * This class is used to describe 1-D Space
 3  */
 4 public class Interval<Key extends Comparable> { 
 5     public final Key low;      // left endpoint
 6     public final Key high;     // right endpoint
 7    
 8     public Interval(Key low, Key high) {
 9         if (less(high, low)) throw new RuntimeException("Illegal argument");
10         this.low  = low;
11         this.high = high;
12     }
13 
14     // is x between low and high
15     public boolean contains(Key x) {
16         return !less(x, low) && !less(high, x);
17     }
18 
19     // does this interval intersect that interval?
20     public boolean intersects(Interval<Key> that) {
21         if (less(this.high, that.low)) return false;
22         if (less(that.high, this.low)) return false;
23         return true;
24     }
25 
26     // does this interval equal that interval?
27     public boolean equals(Interval<Key> that) {
28         return this.low.equals(that.low) && this.high.equals(that.high);
29     }
30 
31 
32     // comparison helper functions
33     private boolean less(Key x, Key y) {
34         return x.compareTo(y) < 0;
35     }
36 
37     // return string representation
38     public String toString() {
39         return "[" + low + "" + high + "]";
40     }
41 }

二维间距
 1 /*
 2  * This class is used to describe 2-D Space
 3  */
 4 public class Interval2D<Key extends Comparable> { 
 5     public final Interval<Key> intervalX;   // x-interval
 6     public final Interval<Key> intervalY;   // y-interval
 7    
 8     public Interval2D(Interval<Key> intervalX, Interval<Key> intervalY) {
 9         this.intervalX = intervalX;
10         this.intervalY = intervalY;
11     }
12 
13     // does this 2D interval a intersect b?
14     public boolean intersects(Interval2D<Key> b) {
15         if (intervalX.intersects(b.intervalX)) return true;
16         if (intervalY.intersects(b.intervalY)) return true;
17         return false;
18     }
19 
20     // does this 2D interval contain (x, y)?
21     public boolean contains(Key x, Key y) {
22         return intervalX.contains(x) && intervalY.contains(y);
23     }
24 
25     // return string representation
26     public String toString() {
27         return intervalX + " x " + intervalY;
28     }
29 }

Quadtree
  1 import java.io.FileInputStream;
  2 import java.io.FileOutputStream;
  3 import java.io.ObjectInputStream;
  4 import java.io.ObjectOutputStream;
  5 import java.io.Serializable;
  6 import java.util.*;
  7 /*
  8  * The Quadtree built in this class is Point-Quadtree 
  9  *             |
 10  *      SW        |    SE
 11  *             |
 12  * -------------------
 13  *             |
 14  *     NW        |    NE
 15  *            |
 16  */
 17 public class QuadTree<Key extends Comparable, Value>  implements Serializable {
 18 
 19     private static final long serialVersionUID = 2478226174742279217L;
 20     //The root of the quadtree, the variable here is to represent the whole quadtree
 21     private Node root;
 22     //The page size as required
 23     public static int PageSize = 4;
 24     
 25     private ArrayList<IndexEntry> pointarray;
 26     
 27     private long pointposition = -1;
 28     
 29     public static long dataID = 0;
 30     
 31     //The data class type
 32     private class IndexEntry implements Serializable{
 33         private static final long serialVersionUID = 5520800067960787705L;
 34         Key x,y;
 35         long id;
 36         
 37         public IndexEntry(Key x, Key y, long id) {
 38             // TODO Auto-generated constructor stub
 39             this.x = x;
 40             this.y = y;
 41             this.id = id;
 42         }
 43         
 44         public boolean equals(IndexEntry that)
 45         {
 46             if ( this.x.equals(that.x) && this.y.equals(this.y) && this.id==that.id)       
 47                 return true;
 48             else
 49                 return false;
 50         }            
 51     }
 52     
 53     // helper node data type
 54     private class Node implements Serializable{ 
 55 
 56         private static final long serialVersionUID = 5226775272372026596L;
 57         //A node contains a few data entries 
 58         ArrayList<IndexEntry> indexArrayList; 
 59         int DataCount;
 60         private boolean split;
 61         //If the node has been split, then it should contain 4 branches
 62         Node NW, NE, SE, SW;   // four subtrees
 63         
 64         
 65         //The value that belongs to the node
 66         //and we use this x,y as a standard to dispatch other nodes
 67         Key x,y;
 68         long id;
 69         
 70         //Constructor
 71         Node() {
 72             indexArrayList = new ArrayList<IndexEntry>(PageSize);
 73             DataCount = 0;
 74             split = false;
 75         }
 76         
 77         public boolean isSplit()
 78         {
 79             return split;
 80         }
 81         
 82         public void setSplit()
 83         {
 84             split = true;
 85         }
 86         
 87         public void assignvalue(IndexEntry input)
 88         {
 89             this.x = input.x;
 90             this.y = input.y;
 91             this.id = input.id;
 92         }
 93     }
 94 
 95     
 96     public QuadTree()
 97     {
 98         importIndex();
 99     }
100     
101     public void exportIndex()
102     {
103         ObjectOutputStream out;     
104         try {
105             out = new ObjectOutputStream(new FileOutputStream("index.dat"));
106             out.writeObject(root);
107             out.close();
108         }
109         catch (Exception e){
110             e.printStackTrace();           
111         }
112     }
113     
114     public void importIndex()
115     {
116         ObjectInputStream in;
117         try
118         {
119             in = new ObjectInputStream(new FileInputStream("index.dat"));
120             root =  (Node) in.readObject();
121             in.close();
122         }
123         catch (Exception e){
124             e.printStackTrace();
125         }
126     }
127   /***********************************************************************
128     *  Insert (x, y) into appropriate quadrant
129     ***********************************************************************/
130     public void insert(Key x, Key y, Value value) {
131                 
132         //found the number of the data entries
133         FileOperator fo = new FileOperator("data.dat");
134         dataID = fo.fileContent();
135         
136         //Insert
137         root = insert(root, x, y, dataID);
138         
139         exportIndex();
140         
141         //update the data file
142         fo.appendObject(value);
143     }
144 
145     private Node insert(Node h, Key x, Key y, long ID) {
146         //if there is a slot for the value, then insert it
147         
148         if (h==null)
149         {
150             Node tempnode = new Node();
151             IndexEntry tempdata = new IndexEntry(x,y,ID);
152             tempnode.indexArrayList.add(tempdata);
153             tempnode.DataCount++;
154             return tempnode;
155         }
156         else 
157         {        
158             if (h.isSplit())
159             {  
160                     if ( less(x, h.x) &&  less(y, h.y)) h.SW = insert(h.SW, x, y, ID);
161                     else if ( less(x, h.x) && !less(y, h.y)) h.NW = insert(h.NW, x, y, ID);
162                     else if (!less(x, h.x) &&  less(y, h.y)) h.SE = insert(h.SE, x, y, ID);
163                     else if (!less(x, h.x) && !less(y, h.y)) h.NE = insert(h.NE, x, y, ID);
164             }
165             else
166             {
167                 if (h.DataCount<PageSize)
168                 {
169                     //create an object containing the value
170                     IndexEntry tempDataEntry = new IndexEntry(x,y,ID);
171                     //put the new object into the node
172                     h.indexArrayList.add(tempDataEntry);
173                     //count number ++
174                     h.DataCount++;
175                 }
176                 //need to split
177                 else
178                 {
179                     //Set the standard
180                     IndexEntry temp = new IndexEntry(x,y,ID);
181                     h.assignvalue(temp);
182                     
183                     //Mark the flag that the node has already been split
184                     h.setSplit();
185                     
186                     for (IndexEntry i: h.indexArrayList)
187                     {    
188                         if ( less(i.x, h.x) &&  less(i.y, h.y)) h.SW = insert(h.SW, i.x, i.y, i.id);
189                         else if ( less(i.x, h.x) && !less(i.y, h.y)) h.NW = insert(h.NW, i.x, i.y, i.id);
190                         else if (!less(i.x, h.x) &&  less(i.y, h.y)) h.SE = insert(h.SE, i.x, i.y, i.id);
191                         else if (!less(i.x, h.x) && !less(i.y, h.y)) h.NE = insert(h.NE, i.x, i.y, i.id);
192                     }
193                     
194                     //Clear the data array
195                     h.indexArrayList.clear();
196                     h.DataCount = 0;
197                 }
198             }
199          return h;
200         }
201     }
202 
203   /***********************************************************************
204     *  Point search.
205     ***********************************************************************/
206    public void queryPoint(Key x, Key y)
207    {
208 
209        long position = queryPoint(root,x,y);
210        
211        FileOperator fo = new FileOperator("data.dat");
212        
213        System.out.println("********************************");
214        System.out.println(position);
215        System.out.println("The value at (" + x + "," + y + ") is " + fo.getObjectAt(position).toString());
216        System.out.println("********************************");       
217    }
218    
219    private long queryPoint(Node h, Key x, Key y)
220    {
221        //the base condition
222        if (h==nullreturn -1;
223        //found the value
224        if (h.isSplit())
225        {
226               if (h.x.equals(x) && h.y.equals(y)) 
227               {
228                   System.out.println(h.id);
229                   pointposition = h.id;
230               }       
231               else if ( less(x, h.x) &&  less(y, h.y)) queryPoint(h.SW, x,y);
232               else if ( less(x, h.x) && !less(y, h.y)) queryPoint(h.NW, x,y);
233               else if (!less(x, h.x) &&  less(y, h.y)) queryPoint(h.SE, x,y);
234               else if (!less(x, h.x) && !less(y, h.y)) queryPoint(h.NE, x,y);              
235        }
236        else {
237           for (IndexEntry i: h.indexArrayList)
238           {
239               if (i.x.equals(x) && i.y.equals(y))
240                   {
241                       System.out.println(i.id);
242                       pointposition = i.id;
243                   }
244           }
245        }
246     return pointposition;
247    }
248    
249   /***********************************************************************
250     *  Range search.
251     ***********************************************************************/
252 
253     public void query2D(Interval2D<Key> rect) {
254         pointarray = new ArrayList<IndexEntry>();
255         query2D(root, rect);
256         
257         FileOperator fo = new FileOperator("data.dat");
258            
259         System.out.println("********************************");
260         
261         for (IndexEntry i: pointarray)
262         {
263                System.out.println("   The value at (" + i.x + "," + i.y + ") is " + fo.getObjectAt(i.id).toString());
264         }
265         System.out.println("********************************");    
266     }
267 
268     private void query2D(Node h, Interval2D<Key> rect) {
269         if (h == nullreturn;
270         Key xmin = rect.intervalX.low;
271         Key ymin = rect.intervalY.low;
272         Key xmax = rect.intervalX.high;
273         Key ymax = rect.intervalY.high;
274         
275         //found one
276        if (h.isSplit())
277            {
278            if (rect.contains(h.x, h.y))
279                {
280                        //System.out.println("    (" + h.x + ", " + h.y + ") " + h.id);                       
281                        pointarray.add(new IndexEntry(h.x,h.y,h.id));
282                }
283 
284             //search the points in the four partitions
285             if ( less(xmin, h.x) &&  less(ymin, h.y)) query2D(h.SW, rect);
286             if ( less(xmin, h.x) && !less(ymax, h.y)) query2D(h.NW, rect);
287             if (!less(xmax, h.x) &&  less(ymin, h.y)) query2D(h.SE, rect);
288             if (!less(xmax, h.x) && !less(ymax, h.y)) query2D(h.NE, rect);
289            }
290        else
291        {
292            for (IndexEntry i: h.indexArrayList)
293            {
294                if (rect.contains(i.x, i.y))
295                    {
296                            //System.out.println("    (" + i.x + ", " + i.y + ") " + i.id);
297                            pointarray.add(i);
298                    }
299            }
300        }
301     }
302 
303 
304    /*************************************************************************
305     *  helper comparison functions
306     *************************************************************************/
307 
308     private boolean less(Key k1, Key k2) { return k1.compareTo(k2) <  0; }
309     private boolean eq  (Key k1, Key k2) { return k1.compareTo(k2) == 0; }
310 }

JUnit 测试类
 1 import java.io.IOException;
 2 
 3 import junit.framework.TestCase;
 4 
 5 
 6 public class QuadTreeTest extends TestCase {
 7     QuadTree<Integer, String> qt;
 8     
 9     protected void setUp() throws Exception {
10         super.setUp();
11     }
12 
13     protected void tearDown() throws Exception {
14         super.tearDown();
15     }
16 
17     public void testInsert() throws IOException {
18         qt = new QuadTree<Integer, String>();
19         for (int i = 0; i < 20; i++)
20             for (int j = 0; j < 20; j++)
21             {
22                 qt.insert(i, j, "Point " + i + j);
23             }
24     }
25 
26     public void testQueryPoint() throws IOException {
27         qt = new QuadTree<Integer, String>();
28         
29         for (int i = 0; i < 20; i++)
30             for (int j = 0; j < 20; j++)
31                 {            
32                     qt.queryPoint(i*2,j*2);
33                 }
34     }
35 
36     public void testQuery2D() throws IOException {
37         qt = new QuadTree<Integer, String>();
38         
39         for (int i = 0; i < 1000; i++)
40         {
41                 Integer xmin = (int) (20 * Math.random());
42                 Integer ymin = (int) (20 * Math.random());
43                 Integer xmax = xmin + (int) (10 * Math.random());
44                 Integer ymax = ymin + (int) (10 * Math.random());
45                 Interval<Integer> intX = new Interval<Integer>(xmin, xmax);
46                 Interval<Integer> intY = new Interval<Integer>(ymin, ymax);
47                 Interval2D<Integer> rect = new Interval2D<Integer>(intX, intY);
48                 qt.query2D(rect);
49         }
50     }
51 
52 }
53