2017-09-24 85 views
0

我一直在嘗試實現splay樹,但迄今爲止沒有成功。以前我成功實現了二叉搜索樹和avl樹,並且由於splay tree是二叉搜索樹的變體,所以插入代碼和旋轉編碼是唯一的罰款。我面對的是每次節點inserted.This移動節點到根本的問題是我的代碼Splay樹插入實現中的問題

class SplayTree: 

    def __init__(self): 
     self.root = None 
     self.size = 0 

    def moveUp(self, currentNode): 
     if currentNode.parent: 
      if currentNode.parent.parent is not None: 
       #zig zag 
       if currentNode.isRightChild() and currentNode.parent.isLeftChild(): 
        self.rotateLeft(currentNode.parent) 
        self.rotateRight(currentNode.parent) 

       elif currentNode.isLeftChild() and currentNode.parent.isRightChild(): 
        self.rotateRight(currentNode.parent) 
        self.rotateLeft(currentNode.parent) 

       #zig zig 
       if currentNode.isLeftChild() and currentNode.parent.isLeftChild(): 
        self.rotateRight(currentNode.parent.parent) 
        self.rotateRight(currentNode.parent) 

       elif currentNode.isRightChild() and currentNode.parent.isRightChild(): 
        self.rotateLeft(currentNode.parent.parent) 
        self.rotateLeft(currentNode.parent) 
       self.moveUp(currentNode) 

      #zig 
      if currentNode.isLeftChild(): 
       self.rotateRight(currentNode.parent) 
      elif currentNode.isRightChild(): 
       self.rotateLeft(currentNode.parent) 
      self.moveUp(currentNode) 

     else: 
      return 

    def put(self,key,val): 
     if self.root: 
      self._put(key,val,self.root) 
     else: 
      self.root = TreeNode(key,val) 
     self.size += 1 

    def _put(self,key,val,currentNode):    
     if key < currentNode.key: 
      if currentNode.hasLeftChild(): 
       self._put(key,val,currentNode.leftChild) 
      else: 
       currentNode.leftChild = TreeNode(key,val,parent=currentNode) 
      self.moveUp(currentNode.leftChild) 

     else: 
      if currentNode.hasRightChild(): 
       self._put(key,val,currentNode.rightChild) 
      else: 
       currentNode.rightChild = TreeNode(key,val,parent=currentNode) 
      self.moveUp(currentNode.rightChild) 

    def __setitem__(self, key, value): 
     self.put(key,value) 

    def rotateLeft(self, rotRoot): 
     newRoot = rotRoot.rightChild 
     if newRoot.leftChild is not None: 
      rotRoot.rightChild = newRoot.leftChild 
      newRoot.leftChild.parent = rotRoot 
     # if subtree is at top or somewhere in between 
     # make connection between node and parent 
     newRoot.parent = rotRoot.parent 
     if rotRoot.parent is None: 
      self.root = newRoot 
     # make connection between parent and node 
     else: 
      if rotRoot.isLeftChild(): 
       rotRoot.parent.leftChild = newRoot 
      else: 
       rotRoot.parent.rightChild = newRoot 
     newRoot.leftChild = rotRoot 
     rotRoot.parent = newRoot 

    def rotateRight(self, rotRoot): 
     newRoot = rotRoot.leftChild 
     if newRoot.rightChild is not None: 
      rotRoot.leftChild = newRoot.rightChild 
      newRoot.rightChild.parent = rotRoot 
     newRoot.parent = rotRoot.parent 
     if rotRoot.parent is None: 
      self.root = newRoot 
     else: 
      if rotRoot.isLeftChild(): 
       rotRoot.parent.leftChild = newRoot 
      else: 
       rotRoot.parent.rightChild = newRoot 
     newRoot.rightChild = rotRoot 
     rotRoot.parent = newRoot 

    def inorder(self): 
     print("INORDER") 
     if self.root: 
      self._inorder(self.root) 
      print() 
     else: 
      return None 

    def _inorder(self,currentNode): 
     if currentNode: 
      self._inorder(currentNode.leftChild) 
      print(currentNode.key,end=" ") 
      self._inorder(currentNode.rightChild) 

class TreeNode: 

    def __init__(self,key,val,left = None,right = None,parent = None): 
     self.key = key 
     self.payload = val 
     self.leftChild = left 
     self.rightChild = right 
     self.parent = parent 

    def hasLeftChild(self): 
     return self.leftChild 

    def hasRightChild(self): 
     return self.rightChild 

    def isLeftChild(self): 
     return self.parent and self.parent.leftChild == self 

    def isRightChild(self): 
     return self.parent and self.parent.rightChild == self 

    def isLeaf(self): 
     return not (self.leftChild or self.rightChild) 

    def hasAnyChildren(self): 
     return self.leftChild or self.rightChild 

    def hasBothChildren(self): 
     return self.leftChild and self.rightChild 

st = SplayTree() 
st[32] = "Cat" 
st[55] = "Dog" 
st[10] = "Lion" 
st[41] = "Zebra" 
st[19] = "Fox" 
st[1] = "Wolf" 
st[16] = "Tiger" 
st[12] = "Pig" 
st.inorder() 

我覺得我爲moveUp()方法就是事情的進展但是我似乎無法弄清楚究竟發生了什麼問題?

+1

我覺得你的旋轉方法有點小錯誤。應該無條件地運行'rotateLeft'中的第一個'if'(和'rotateRight'中的等效行)中的'rotRoot.rightChild = newRoot.leftChild'行。否則,你可以從'rotRoot'連接到'newRoot',它應該被'None'替代。 – Blckknght

+0

@Blckknght這是一個很好的觀察。現在代碼正在運行,但給出了不正確的結果。最後添加的節點沒有進入根目錄!我重新檢查了moveUp()代碼,似乎沒有發現任何可疑內容。 –

+0

@Blckknght哦,現在它的工作正常......只是做了一些微小的調整。再次感謝! –

回答

1

有在你的代碼的兩個問題。

第一個是你在你的旋轉方法中有一個微妙的錯誤,你有時候在你應該的時候你沒有設置一個子鏈接到NonerotateLeft(和等效行rotateRight)中的第一個ifrotRoot.rightChild = newRoot.leftChild應無條件運行。只需將其移出if即可解決問題。

第二個問題是您經常打電話moveUp。您正在通過遞歸調用_put來運行它,但由於moveUp也以遞歸方式調用自身,這意味着它運行頻繁。在_put中縮進呼叫,以便它們成爲您創建新節點的else塊的一部分。這樣,您只會致電moveUp從最後的_put呼叫,而不是所有的呼叫。

def _put(self,key,val,currentNode):    
    if key < currentNode.key: 
     if currentNode.hasLeftChild(): 
      self._put(key,val,currentNode.leftChild) 
     else: 
      currentNode.leftChild = TreeNode(key,val,parent=currentNode) 
      self.moveUp(currentNode.leftChild)      # increase indent here! 

    else: 
     if currentNode.hasRightChild(): 
      self._put(key,val,currentNode.rightChild) 
     else: 
      currentNode.rightChild = TreeNode(key,val,parent=currentNode) 
      self.moveUp(currentNode.rightChild)     # here too 

def rotateLeft(self, rotRoot): 
    newRoot = rotRoot.rightChild 
    rotRoot.rightChild = newRoot.leftChild  # move this line up, out of the if 
    if newRoot.leftChild is not None: 
     newRoot.leftChild.parent = rotRoot 
    newRoot.parent = rotRoot.parent 
    if rotRoot.parent is None: 
     self.root = newRoot 
    # make connection between parent and node 
    else: 
     if rotRoot.isLeftChild(): 
      rotRoot.parent.leftChild = newRoot 
     else: 
      rotRoot.parent.rightChild = newRoot 
    newRoot.leftChild = rotRoot 
    rotRoot.parent = newRoot 

def rotateRight(self, rotRoot): 
    newRoot = rotRoot.leftChild 
    rotRoot.leftChild = newRoot.rightChild  # this one as well 
    if newRoot.rightChild is not None: 
     newRoot.rightChild.parent = rotRoot 
    newRoot.parent = rotRoot.parent 
    if rotRoot.parent is None: 
     self.root = newRoot 
    else: 
     if rotRoot.isLeftChild(): 
      rotRoot.parent.leftChild = newRoot 
     else: 
      rotRoot.parent.rightChild = newRoot 
    newRoot.rightChild = rotRoot 
    rotRoot.parent = newRoot 
+0

是的,正如你所說,特別是無條件地呼籲 rotRoot.rightChild = newRoot.leftChild和另一個 相同,這似乎是徹底解決問題。謝謝! –

0

試圖改變自己爲moveUp在兩個地方:

if currentNode.isRightChild() and currentNode.parent.isLeftChild(): 
    self.rotateLeft(currentNode.parent) 
    self.rotateRight(currentNode.parent.parent) // Here 
elif currentNode.isLeftChild() and currentNode.parent.isRightChild(): 
    self.rotateRight(currentNode.parent) 
    self.rotateLeft(currentNode.parent.parent) // Here 

這應該有助於

+0

這是不正確的。旋轉一圈後,'currentNode'已經在樹中取代了它的原始'父',所以原來的祖父母現在是直接父母。問題中的代碼得到了正確的結果。 – Blckknght