<p>I assume that you are interested in succinct external memory data structures that are efficient in practice. In that case, you can probably get what you want with a few basic techniques and some engineering.</p>

<p>For trees, I would start with reading Arroyuelo et al.: <a href="http://epubs.siam.org/doi/abs/10.1137/1.9781611972900.9" rel="nofollow">Succinct Trees in Practice</a>. The paper deals with trees in main memory, but most of the techniques can be used in external memory with similar choices as below.</p>

<p>As for your second question, the most important choice is deciding which encoding you use for the items. Given the distribution you describe, I would first try using <a href="https://en.wikipedia.org/wiki/Elias_gamma_coding" rel="nofollow">$\gamma$-codes</a> or <a href="https://en.wikipedia.org/wiki/Elias_delta_coding" rel="nofollow">$\delta$-codes</a>. When you have chosen the encoding, the next step is to encode the array in blocks of size $B$, where the block size is chosen so that random disk reads of size $B$ are efficient in practice.</p>

<p>To find the correct block quickly, you need a rank dictionary that resides in main memory. Assuming that you have $n$ items, you build a binary sequence $S$ of length $n$, where $S[i] = 1$ iff item $i$ starts a new block. Gap encoding compresses the sequence well; Gupta et al.: <a href="http://dx.doi.org/10.1016/j.tcs.2007.07.042" rel="nofollow">Compressed data structures: dictionaries and data-aware measures</a> gives one example of such index. If you want to find item $j$, then you need to retrieve block $rank(j)$ and decode it to get the item.</p>

<p>If you want to keep the rank index small, you have to make the block size quite large (probably kilobytes or tens of kilobytes), making the above basic solution CPU-intensive. This can be solved by adding a little overhead to the blocks stored on disk. Basically you apply the same solution recursively, so that each disk block stores a number of small blocks as well as another rank index. When you have retrieved the correct disc block, you use the rank index within it to find the right small block to decode, instead of decoding the entire block. With this secondary index, random accesses probably become I/O-bound even with the fastest solid-state drives available.</p>

CC BY-SA 3.0
2012-05-02T14:06:02.993Z
2015-06-03T17:37:03.683Z
2015-06-03T17:37:03.683Z
Jouni Sirén
<p>(already <a href="https://stackoverflow.com/questions/10387965/need-a-good-overview-for-succinct-data-structures">asked on main site</a>, but asking also here for better coverage, sorry)</p>

<p>Since I knew about <a href="http://en.wikipedia.org/wiki/Succinct_data_structure" rel="nofollow noreferrer">Succinct Data Structures</a> I'm in a desperate need of a good overview of most recent developments in that area.</p>

<p>I have googled and read a lot of articles I could see in top of google results on requests from top of my head. I still suspect I have missed something important here.</p>

<p>Here are topics of particular interest for me:</p>

<ol>
<li><p>Succinct encoding of binary trees with efficient operations of getting parent, left/right child, number of elements in a subtree.</p>

<p>The main question here is as following: all approaches I know of assume the tree nodes enumerated in breath-first order (like in the pioneer work in this area Jacobson, G. J (1988). Succinct static data structures), which does not seem appropriate for my task. I deal with huge binary trees given in depth-first layout and the depth-first node indices are keys to other node properties, so changing the tree layout has some cost for me which I'd like to minimize. Hence the interest in getting references to works considering other then BF tree layouts.</p></li>
<li><p>Large variable-length items arrays in external memory. The arrays are immutable: I don't need to add/delete/edit the items. The only requirement is O(1) element access time and as low overhead as possible, better then straightforward offset and size approach. Here is some statistics I gathered about typical data for my task:</p>

<p>typical number of items - hundreds of millions, up to tens of milliards;</p>

<p>about 30% of items have length not more then 1 <strong>bit</strong>;</p>

<p>40%-60% items have length less then 8 bits;</p>

<p>only few percents of items have length between 32 and 255 bits (255 bits is the limit)</p>

<p>average item length ~4 bit +/- 1 bit.</p>

<p>any other distribution of item lengths is theoretically possible but all practically interesting cases have statistics close to the described above.</p></li>
</ol>

<p>Links to articles of any complexity, tutorials of any obscurity, more or less documented C/C++ libraries, - anything what was useful for you in similar tasks or what looks like that by your educated guess - all such things are gratefully appreciated.</p>

<p><strong>Update</strong>: I forgot to add to the question 1: binary trees I'm dealing with are immutable. I have no requirements for altering them, all i need is only traversing them in various ways always moving from node to children or to parent, so that the average cost of such operations was O(1).</p>

<p>Also, typical tree has milliards of nodes and should not be fully stored in RAM.</p>

<reference-request><ds.data-structures><advice-request><space-time-tradeoff>
Need a good overview for Succinct Data Structure algorithms
datjko
# Need a good overview for Succinct Data Structure algorithms

(Asked by: username_0 on 2012-05-02)

(already [asked on main site](https://stackoverflow.com/questions/10387965/need-a-good-overview-for-succinct-data-structures), but asking also here for better coverage, sorry)

Since I knew about [Succinct Data Structures](http://en.wikipedia.org/wiki/Succinct_data_structure) I'm in a desperate need of a good overview of most recent developments in that area.

I have googled and read a lot of articles I could see in top of google results on requests from top of my head. I still suspect I have missed something important here.

Here are topics of particular interest for me:

1. Succinct encoding of binary trees with efficient operations of getting parent, left/right child, number of elements in a subtree.

   The main question here is as following: all approaches I know of assume the tree nodes enumerated in breath-first order (like in the pioneer work in this area Jacobson, G. J (1988). Succinct static data structures), which does not seem appropriate for my task. I deal with huge binary trees given in depth-first layout and the depth-first node indices are keys to other node properties, so changing the tree layout has some cost for me which I'd like to minimize. Hence the interest in getting references to works considering other then BF tree layouts.
2. Large variable-length items arrays in external memory. The arrays are immutable: I don't need to add/delete/edit the items. The only requirement is O(1) element access time and as low overhead as possible, better then straightforward offset and size approach. Here is some statistics I gathered about typical data for my task:

   typical number of items - hundreds of millions, up to tens of milliards;

   about 30% of items have length not more then 1 **bit**;

   40%-60% items have length less then 8 bits;

   only few percents of items have length between 32 and 255 bits (255 bits is the limit)

   average item length ~4 bit +/- 1 bit.

   any other distribution of item lengths is theoretically possible but all practically interesting cases have statistics close to the described above.

Links to articles of any complexity, tutorials of any obscurity, more or less documented C/C++ libraries, - anything what was useful for you in similar tasks or what looks like that by your educated guess - all such things are gratefully appreciated.

**Update**: I forgot to add to the question 1: binary trees I'm dealing with are immutable. I have no requirements for altering them, all i need is only traversing them in various ways always moving from node to children or to parent, so that the average cost of such operations was O(1).

Also, typical tree has milliards of nodes and should not be fully stored in RAM.

**Tags:** reference-request, ds.data-structures, advice-request, space-time-tradeoff

---

## 1 answers

### Answer by username_1 on 2012-05-02. Score: 12 | Accepted answer

I assume that you are interested in succinct external memory data structures that are efficient in practice. In that case, you can probably get what you want with a few basic techniques and some engineering.

For trees, I would start with reading Arroyuelo et al.: [Succinct Trees in Practice](http://epubs.siam.org/doi/abs/10.1137/1.9781611972900.9). The paper deals with trees in main memory, but most of the techniques can be used in external memory with similar choices as below.

As for your second question, the most important choice is deciding which encoding you use for the items. Given the distribution you describe, I would first try using [$\gamma$-codes](https://en.wikipedia.org/wiki/Elias_gamma_coding) or [$\delta$-codes](https://en.wikipedia.org/wiki/Elias_delta_coding). When you have chosen the encoding, the next step is to encode the array in blocks of size $B$, where the block size is chosen so that random disk reads of size $B$ are efficient in practice.

To find the correct block quickly, you need a rank dictionary that resides in main memory. Assuming that you have $n$ items, you build a binary sequence $S$ of length $n$, where $S[i] = 1$ iff item $i$ starts a new block. Gap encoding compresses the sequence well; Gupta et al.: [Compressed data structures: dictionaries and data-aware measures](http://dx.doi.org/10.1016/j.tcs.2007.07.042) gives one example of such index. If you want to find item $j$, then you need to retrieve block $rank(j)$ and decode it to get the item.

If you want to keep the rank index small, you have to make the block size quite large (probably kilobytes or tens of kilobytes), making the above basic solution CPU-intensive. This can be solved by adding a little overhead to the blocks stored on disk. Basically you apply the same solution recursively, so that each disk block stores a number of small blocks as well as another rank index. When you have retrieved the correct disc block, you use the rank index within it to find the right small block to decode, instead of decoding the entire block. With this secondary index, random accesses probably become I/O-bound even with the fastest solid-state drives available.


---

