• Nem Talált Eredményt

3.2 Data structure

3.2.1 Linked vs. linear quadtrees

Commonly used quadtree data structures fall into two main categories: linked tree and linear storage.

Linked quadtrees use pointers to connect parents and their four children. The tree is traversed and the neighbors are enumerated using these two-way links. A typical mesh and its tree structure are depicted in Figure 6. Nodes (representing the cells) are numbered in the order of their creation; the simultaneously created four children of a parent are assigned an index in the order SW–SE–NW–NE. Due to the geometric ordering of the quadrants, there is a close connection between the physical position of a cell and its logical position in the tree, which allows fast identi…cation of the cell that contains a particular point. The re…nement level in the tree hierarchy is 1 for the root cell and increases towards children. An array o¤set pointing to the cell value of any …eld variable is stored at each node in the tree.

Figure 6. Quadtree mesh with indexed cells and the corresponding linked tree repres-entation. Non-leaf cell indexes are in parantheses.

Figure 7. Linear quadtree and its lookup table.

Linear quadtrees are similar to hash tables. Each cell is assigned a unique code which is calculated from its horizontal coordinates and its re…nement level.

Several coding schemes were developed, e.g. those presented by Balmelli et al.

(1999); Gargantini (1982), or the schemes speci…cally supplementing numerical models of Cruz-León (1999); Dommelen and Rundensteiner (1989). A common property of these coding schemes is that the code of potential neighbours can be derived e¢ ciently, usually implemented using fast bitwise operations on integers.

A lookup table must be provided to map cell codes to their corresponding array o¤sets. Figure 7 shows an example.

The appeal of linear quadtrees lies in their small memory overhead, they are therefore widely used in graphics and spatial database applications. In fact, only the compact cell code needs to be stored for each node. Furthermore, all non-leaf cells can be omitted from the table because cell codes contain the absolute path to leaves, which is especially useful if the quadtree structure remains constant after the initial assembly.

Since ensuring fast navigation on the quadtree is an important objective, it is worth comparing the performance of linked and linear quadtrees. On a linked tree the search of neighbours requires only four queries on average, independently of

3.2. DATA STRUCTURE 31 the depth of the tree (de Zeeuw, 1993). On the other hand, …nding the neighbour on a linear quadtree requires a binary search through the lookup table for every query which means on average log2n operations, where n is the cell count, and a level di¤erence cost additional binary searches. Obtaining the cell code of the neighbour may take extra time depending on the coding scheme.

A linked quadtree is therefore chosen as the basic data structure of the current model, because faster navigation in the tree is considered a greater bene…t than the smaller memory overhead o¤ered by linear quadtrees. The numerical test results of Yiu et al. (1996), who compared one linked and two linear quadtree implementations, also support this decision.

Because neighbor …nding is a low-level operation very often invoked in the code, the linked quadtree structure is optimised for speed by storing links to the four side-neighbours at the same level for each node. For example, the extra information stored for the quadtree on Figure 7 is presented in Table 1.

Cell index Neighbour index

W S E N

(0) – – – –

(1) – – 2 3

2 (1) – – 4

3 – (1) 4 –

4 3 2 – –

5 – – 6 7

6 5 – – 8

7 – 5 8 –

8 7 6 – –

Table 1. Side-neighbour indexes stored for each cell in the mesh records. A dash means that no neighbour of the same size exists on that side.

Supplementing the classical, vertically linked quadtree by horizontal links makes it a fully threaded tree. Considerable navigation run-time savings can be achieved using such a fully threaded quadtree since neighbour …nding now requires only 1 +j kj steps, where k is the node level di¤erence. In a regularised quadtree where the level of neighbour cells is limited to change at most by one, that is, a neighbour is located in one or two steps. As an example, the pseudo-code for

…nding the west neighbour is outlined in Appendix A, see Algorithm 1 The code executes without loops if the neighbour exists on the same level. In the case of smaller neighbours, the complexity of the algorithm increases because a tempor-ary stack must be used to collect the nodes. To avoid stack over‡ow, function WestNeighbour is not called recursively. In fact, a fully threaded quadtree bears similarity with unstructured quadrilateral grids where the element connectivity must be stored explicitly.

Figure 8. Staggered positions on a quadtree.

A natural order to visit the tree is the depth-…rst traversal, where …rst the children of a node are visited recursively then the node itself, yielding for the tree in Figure 6 the following order: 5-6-7-8-1-2-3-4-0. The depth-…rst visit ensures that children are always processed before the parents, which is essential for ag-gregating a function towards the root (in the case of cell coarsening). The visit was implemented without any recursion in the current work. This was desirable so as to prevent excessive stack use and to integrate the quadtree into the container framework of the C++ Standard Template Library. A depth-…rst iterator (a sort of pointer) is de…ned for quadtrees which addresses a quadtree node and can be incremented to point to the next node in depth-…rst order. The pseudo-code that searches the next node is given in Appendix A, see Algorithm 2.