The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / tools / splaytree.py @ 40c0f755

History | View | Annotate | Download (7.21 KB)

1
# Copyright 2008 the V8 project authors. All rights reserved.
2
# Redistribution and use in source and binary forms, with or without
3
# modification, are permitted provided that the following conditions are
4
# met:
5
#
6
#     * Redistributions of source code must retain the above copyright
7
#       notice, this list of conditions and the following disclaimer.
8
#     * Redistributions in binary form must reproduce the above
9
#       copyright notice, this list of conditions and the following
10
#       disclaimer in the documentation and/or other materials provided
11
#       with the distribution.
12
#     * Neither the name of Google Inc. nor the names of its
13
#       contributors may be used to endorse or promote products derived
14
#       from this software without specific prior written permission.
15
#
16
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27

    
28

    
29
class Node(object):
30
  """Nodes in the splay tree."""
31

    
32
  def __init__(self, key, value):
33
    self.key = key
34
    self.value = value
35
    self.left = None
36
    self.right = None
37

    
38

    
39
class KeyNotFoundError(Exception):
40
  """KeyNotFoundError is raised when removing a non-existing node."""
41

    
42
  def __init__(self, key):
43
    self.key = key
44

    
45

    
46
class SplayTree(object):
47
  """The splay tree itself is just a reference to the root of the tree."""
48

    
49
  def __init__(self):
50
    """Create a new SplayTree."""
51
    self.root = None
52

    
53
  def IsEmpty(self):
54
    """Is the SplayTree empty?"""
55
    return not self.root
56

    
57
  def Insert(self, key, value):
58
    """Insert a new node in the SplayTree."""
59
    # If the tree is empty, insert the new node.
60
    if self.IsEmpty():
61
      self.root = Node(key, value)
62
      return
63
    # Splay on the key to move the last node on the search path for
64
    # the key to the root of the tree.
65
    self.Splay(key)
66
    # Ignore repeated insertions with the same key.
67
    if self.root.key == key:
68
      return
69
    # Insert the new node.
70
    node = Node(key, value)
71
    if key > self.root.key:
72
      node.left = self.root
73
      node.right = self.root.right
74
      self.root.right = None
75
    else:
76
      node.right = self.root
77
      node.left = self.root.left
78
      self.root.left = None
79
    self.root = node
80

    
81
  def Remove(self, key):
82
    """Remove the node with the given key from the SplayTree."""
83
    # Raise exception for key that is not found if the tree is empty.
84
    if self.IsEmpty():
85
      raise KeyNotFoundError(key)
86
    # Splay on the key to move the node with the given key to the top.
87
    self.Splay(key)
88
    # Raise exception for key that is not found.
89
    if self.root.key != key:
90
      raise KeyNotFoundError(key)
91
    removed = self.root
92
    # Link out the root node.
93
    if not self.root.left:
94
      # No left child, so the new tree is just the right child.
95
      self.root = self.root.right
96
    else:
97
      # Left child exists.
98
      right = self.root.right
99
      # Make the original left child the new root.
100
      self.root = self.root.left
101
      # Splay to make sure that the new root has an empty right child.
102
      self.Splay(key)
103
      # Insert the original right child as the right child of the new
104
      # root.
105
      self.root.right = right
106
    return removed
107

    
108
  def Find(self, key):
109
    """Returns the node with the given key or None if no such node exists."""
110
    if self.IsEmpty():
111
      return None
112
    self.Splay(key)
113
    if self.root.key == key:
114
      return self.root
115
    return None
116

    
117
  def FindMax(self):
118
    """Returns the node with the largest key value."""
119
    if self.IsEmpty():
120
      return None
121
    current = self.root
122
    while current.right != None:
123
      current = current.right
124
    return current
125

    
126
  # Returns the node with the smallest key value.
127
  def FindMin(self):
128
    if self.IsEmpty():
129
      return None
130
    current = self.root
131
    while current.left != None:
132
      current = current.left
133
    return current
134

    
135
  def FindGreatestsLessThan(self, key):
136
    """Returns node with greatest key less than or equal to the given key."""
137
    if self.IsEmpty():
138
      return None
139
    # Splay on the key to move the node with the given key or the last
140
    # node on the search path to the top of the tree.
141
    self.Splay(key)
142
    # Now the result is either the root node or the greatest node in
143
    # the left subtree.
144
    if self.root.key <= key:
145
      return self.root
146
    else:
147
      tmp = self.root
148
      self.root = self.root.left
149
      result = self.FindMax()
150
      self.root = tmp
151
      return result
152

    
153
  def ExportValueList(self):
154
    """Returns a list containing all the values of the nodes in the tree."""
155
    result = []
156
    nodes_to_visit = [self.root]
157
    while len(nodes_to_visit) > 0:
158
      node = nodes_to_visit.pop()
159
      if not node:
160
        continue
161
      result.append(node.value)
162
      nodes_to_visit.append(node.left)
163
      nodes_to_visit.append(node.right)
164
    return result
165

    
166
  def Splay(self, key):
167
    """Perform splay operation.
168

169
    Perform the splay operation for the given key. Moves the node with
170
    the given key to the top of the tree.  If no node has the given
171
    key, the last node on the search path is moved to the top of the
172
    tree.
173

174
    This uses the simplified top-down splaying algorithm from:
175

176
    "Self-adjusting Binary Search Trees" by Sleator and Tarjan
177

178
    """
179
    if self.IsEmpty():
180
      return
181
    # Create a dummy node.  The use of the dummy node is a bit
182
    # counter-intuitive: The right child of the dummy node will hold
183
    # the L tree of the algorithm.  The left child of the dummy node
184
    # will hold the R tree of the algorithm.  Using a dummy node, left
185
    # and right will always be nodes and we avoid special cases.
186
    dummy = left = right = Node(None, None)
187
    current = self.root
188
    while True:
189
      if key < current.key:
190
        if not current.left:
191
          break
192
        if key < current.left.key:
193
          # Rotate right.
194
          tmp = current.left
195
          current.left = tmp.right
196
          tmp.right = current
197
          current = tmp
198
          if not current.left:
199
            break
200
        # Link right.
201
        right.left = current
202
        right = current
203
        current = current.left
204
      elif key > current.key:
205
        if not current.right:
206
          break
207
        if key > current.right.key:
208
          # Rotate left.
209
          tmp = current.right
210
          current.right = tmp.left
211
          tmp.left = current
212
          current = tmp
213
          if not current.right:
214
            break
215
        # Link left.
216
        left.right = current
217
        left = current
218
        current = current.right
219
      else:
220
        break
221
    # Assemble.
222
    left.right = current.left
223
    right.left = current.right
224
    current.left = dummy.right
225
    current.right = dummy.left
226
    self.root = current