Open main menu
Home
Random
Recent changes
Special pages
Community portal
Preferences
About Wikipedia
Disclaimers
Incubator escapee wiki
Search
User menu
Talk
Dark mode
Contributions
Create account
Log in
Editing
Persistent data structure
(section)
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
==Applications of persistent data structures== ===Next element search or point location=== One of the useful applications that can be solved efficiently using persistence is the Next Element Search. Assume that there are {{mvar|n}} non intersecting line segments that don't cross each other that are parallel to the x-axis. We want to build a data structure that can query a point {{mvar|p}} and return the segment above {{mvar|p}} (if any). We will start by solving the Next Element Search using the naïve method then we will show how to solve it using the persistent data structure method. ====Naïve method==== We start with a vertical line segment that starts off at infinity and we sweep the line segments from the left to the right. We take a pause every time we encounter an end point of these segments. The vertical lines split the plane into vertical strips. If there are {{mvar|n}} line segments then we can get <math>2\cdot n+1</math> vertical strips since each segment has {{val|2}} end points. No segment begins and ends in the strip. Every segment either it doesn't touch the strip or it completely crosses it. We can think of the segments as some objects that are in some sorted order from top to bottom. What we care about is where the point that we are looking at fits in this order. We sort the endpoints of the segments by their {{mvar|x}} coordinate. For each strip <math>s_{i}</math>, we store the subset segments that cross <math>s_{i}</math> in a dictionary. When the vertical line sweeps the line segments, whenever it passes over the left endpoint of a segment then we add it to the dictionary. When it passes through the right endpoint of the segment, we remove it from the dictionary. At every endpoint, we save a copy of the dictionary and we store all the copies sorted by the {{mvar|x}} coordinates. Thus we have a data structure that can answer any query. In order to find the segment above a point {{mvar|p}}, we can look at the {{mvar|x}} coordinate of {{mvar|p}} to know which copy or strip it belongs to. Then we can look at the {{mvar|y}} coordinate to find the segment above it. Thus we need two binary searches, one for the {{mvar|x}} coordinate to find the strip or the copy, and another for the {{mvar|y}} coordinate to find the segment above it. Thus the query time takes <math>O(\log(n))</math>. In this data structure, the space is the issue since if we assume that we have the segments structured in a way such that every segment starts before the end of any other segment, then the space required for the structure to be built using the naïve method would be <math>O(n^{2})</math>. Let us see how we can build another persistent data structure with the same query time but with a better space. ====Persistent data structure method==== We can notice that what really takes time in the data structure used in the naïve method is that whenever we move from a strip to the next, we need to take a snap shot of whatever data structure we are using to keep things in sorted order. We can notice that once we get the segments that intersect <math>s_{i}</math>, when we move to <math>s_{i+1}</math> either one thing leaves or one thing enters. If the difference between what is in <math>s_{i}</math> and what is in <math>s_{i+1}</math> is only one insertion or deletion then it is not a good idea to copy everything from <math>s_{i}</math> to <math>s_{i+1}</math>. The trick is that since each copy differs from the previous one by only one insertion or deletion, then we need to copy only the parts that change. Let us assume that we have a tree rooted at {{mvar|T}}. When we insert a key {{mvar|k}} into the tree, we create a new leaf containing {{mvar|k}}. Performing rotations to rebalance the tree will only modify the nodes of the path from {{mvar|k}} to {{mvar|T}}. Before inserting the key {{mvar|k}} into the tree, we copy all the nodes on the path from {{mvar|k}} to {{mvar|T}}. Now we have 2 versions of the tree, the original one which doesn't contain {{mvar|k}} and the new tree that contains {{mvar|k}} and whose root is a copy of the root of {{mvar|T}}. Since copying the path from {{mvar|k}} to {{mvar|T}} doesn't increase the insertion time by more than a constant factor then the insertion in the persistent data structure takes <math>O(\log(n))</math> time. For the deletion, we need to find which nodes will be affected by the deletion. For each node {{mvar|v}} affected by the deletion, we copy the path from the root to {{mvar|v}}. This will provide a new tree whose root is a copy of the root of the original tree. Then we perform the deletion on the new tree. We will end up with 2 versions of the tree. The original one which contains {{mvar|k}} and the new one which doesn't contain {{mvar|k}}. Since any deletion only modifies the path from the root to {{mvar|v}} and any appropriate deletion algorithm runs in <math>O(\log(n))</math>, thus the deletion in the persistent data structure takes <math>O(\log(n))</math>. Every sequence of insertion and deletion will cause the creation of a sequence of dictionaries or versions or trees <math>S_{1}, S_{2}, \dots S_{i}</math> where each <math>S_{i}</math> is the result of operations <math>S_{1}, S_{2}, \dots S_{i}</math>. If each <math>S_{i}</math> contains {{mvar|m}} elements, then the search in each <math>S_{i}</math> takes <math>O(\log(m))</math>. Using this persistent data structure we can solve the next element search problem in <math>O(\log(n))</math> query time and <math>O(n\cdot \log(n))</math> space instead of <math>O(n^{2})</math>. Please find below the source code for an example related to the next search problem.
Edit summary
(Briefly describe your changes)
By publishing changes, you agree to the
Terms of Use
, and you irrevocably agree to release your contribution under the
CC BY-SA 4.0 License
and the
GFDL
. You agree that a hyperlink or URL is sufficient attribution under the Creative Commons license.
Cancel
Editing help
(opens in new window)