1. 程式人生 > >【演算法】【python實現】二叉搜尋樹插入、刪除、查詢

【演算法】【python實現】二叉搜尋樹插入、刪除、查詢

二叉搜尋樹

定義:如果一顆二叉樹的每個節點對應一個關鍵碼值,且關鍵碼值的組織是有順序的,例如左子節點值小於父節點值,父節點值小於右子節點值,則這棵二叉樹是一棵二叉搜尋樹。

類(TreeNode):定義二叉搜尋樹各個節點

在該類中,分別存放節點本身的值,以及其左子節點,右子節點,父節點的值。

 

class TreeNode(object):
    def __init__(self,val):
        self.value = val    #存值
        self.left = None    #存本節點的左子節點
        self.right = None   #存本節點的右子節點
        self.father = None  #存本節點的父節點

類(BST):定義二叉搜尋樹的各種功能方法

此類用於存放定義二叉樹的插入,刪除,搜尋等方法。

class BST(object):
    def __init__(self,nodeList):
        self.root = None
        for node in nodeList:
            self.bfs_insert(node)

注:self.bfs_insert(node)中的bfs_insert方法在後面實現。放在建構函式中的目的是將一個列表生成一個二叉搜尋樹列表。

方法(bfs_insert):實現插入功能

 第一步:將根節點(self.root)設定成當前位置節點(cur),即從根節點開始遍歷。根節點的父節點(father)初始設定為None。 

def bfs_insert(self,node):
    cur = self.root      #設定當前節點為根節點
    father = None        #設定根節點的父節點為None

第二步:查詢可以插入的位置

1. 當前位置節點(cur)的值與待插入節點(node)的值相等,返回-1(代表無法進行插入操作)。並將父節點(father)值修改為當前位置節點(cur),代表該節點已經遍歷完成。

if cur.value == node.value:
    return -1
father = cur

2.當前位置節點(cur)的值大於待插入節點(node)的值時,表示待插入節點(node)需繼續在當前位置節點的左子樹中繼續查詢。故把當前位置節點(cur)的左節點賦值給當前位置節點(cur),作為下一個要訪問的節點物件。

if node.value < cur.value:
    cur = cur.left

 

 

3.當前位置節點(cur)的值小於待插入節點(node)的值時,表示待插入節點(node)需繼續在當前位置節點的右子樹中繼續查詢。故把當前位置節點(cur)的右節點賦值給當前位置節點(cur),作為下一個要訪問的節點物件。

if node.value > cur.value:
    cur = cur.right

 

第三步:找到插入位置後,將其設定為待插入值(node)的父節點

node.father = father

第四步:插入操作

1.父節點的值為空(即要插入的是個空二叉樹),將待插入節點(node)賦值給根節點(root)。

if father == None:
    self.root = node

2.待插入節點(node)的值小於父節點(father)的值,將其放到父節點的左子節點

if node.value <father.value:
    father.left = node

 

3.待插入節點(node)的值大於父節點(father)的值,將其放到父節點的右子節點

if node.value >father.value:
    father.right = node

 

插入功能程式碼彙總:

def insert(self,node):
    father = None
    cur = self.root

    while cur != None:
         if cur.value == node.value:
         	return -1
         father = cur
         if node.value < cur.value:
         	cur = cur.left
         else:
         	cur = cur.right
    node.father = father
    if father == None:
        self.root = node
    elif node.value < father.value:
        father.left = node
    else:
        father.right = node

方法(bfs):生成二叉搜尋樹列表

利用佇列先進先出的特性,將一個二叉搜尋樹存放到列表中。

def bfs(self):
    if self.root == None:
        return None
    retList = []
    q = queue.Queue()
    q.put(self.root)                
    while q.empty() is not True:
        node = q.get()
        retList.append(node.value)
        if node.left != None:
            q.put(node.left)
        if node.right != None:
            q.put(node.right)
    return retList

示例:針對如下二叉搜尋樹,遍歷存放到一個列表過程

 

ps:藍色:二叉樹列表 retList    橙色:佇列 q

方法(bfs_search):實現查詢功能

第一步:將根節點(self.root)設定成當前位置節點(cur),即從根節點開始遍歷。

def search(self,value):
    cur = self.root

如果cur值不為None,執行第二步。否則執行第三步

第二步:對比要查詢的值(value)與當前位置節點(cur)的值的大小

1. 如果當前位置節點(cur)的值等於要查詢的值(value),返回當前位置節點(cur)。

if cur.value == value:
    return cur

2. 如果當前位置節點(cur)的值小於要查詢的值(value),返回當前位置節點(cur)。

if cur.value < value:
    cur = cur.right

 

3. 如果當前位置節點(cur)的值小於要查詢的值(value),返回當前位置節點(cur)。

if cur.value > value:
    cur = cur.left

 

第三步:如果cur的值為None,返回空。即查詢的二叉搜尋樹為空樹。

return None

查詢功能程式碼彙總:

def search(self,value):
    cur = self.root
    while cur != None:
        if cur.value == value:
            return cur
        elif cur.value < value:
            cur = cur.right
        else:
            cur = cur.left
    return None

方法(bfs_delete):實現刪除功能

第一步:將待刪除節點(node)的父節點賦值給father變數。

def delete(self,node):
    father = node.father

第二步:判斷待刪除節點(node)的左子樹是否為空

1. 待刪除節點(node)的左子樹為空

if node.left == None:

a)     待刪除節點(node)為根節點

將待刪除節點(node)的右子節點置為新的根節點(root),且其如果為非空,將其父節點(node.right.father)賦值為空。

if father == None:
    self.root = node.right
    if node.right != None:
        node.right.father = None

 

b)     待刪除節點(node)為其父節點的左子節點

待刪除節點(node)的右子節點(node.right)取代其原來的位置,成為其父節點新的左子節點(father.left)。且其右子節點(node.right)不為空,將待刪除節點(node)的父節點賦值給它的父節點(node.right.father)

if father.left == node:
    father.left = node.right
    if node.right != None:
        node.right.father = father

 

c)     待刪除節點(node)為其父節點的右子節點

待刪除節點(node)的右子節點(node.right)取代其原來的位置,成為其父節點新的右子節點(father.right)。且其右子節點(node.right)不為空,將待刪除節點(node)的父節點賦值給它的父節點(node.right.father)

if father.right == node:
    father.right = node.right
    if node.right != None:
        node.right.father = father

2. 待刪除節點(node)的左子樹不為空

第一步:將待刪除節點(node)的右子樹掛到其左子樹最後一層的右子節點下

a)     將待刪除節點的左子節點(node.left)存到臨時變數tmpNode中

tmpNode = node.left

b)     遞迴找到node.left的最後一層右子節點

while tmpNode.right != None:
    tmpNode = tmpNode.right

c)     將待刪節點的右子樹(node.right)掛到node.left的最後一層右子節點下

tmpNode.right = node.right

d)     將node.right的父節點設定為待刪節點左子樹中的最後一層的右子節點

if node.right != None:
    node.right.father = tmpNode

 

第二步:開始刪除node

1.待刪除節點為根節點

將待刪除節點的左子節點(node.left)設定為根節點(self.root),並將其父節點設定為空。

if father == None:
    self.root = node.left
    node.left.father = None

2.待刪除節點為根節點的左子節點

待刪除節點的左子節點(node.left)取代待刪節點的位置,並將其父節點設定為待刪除節點的父節點。

if father.left == node:
    father.left = node.left
    node.left.father = father

3. 待刪除節點為根節點的右子節點

待刪除節點的左子節點(node.left)取代待刪節點的位置,並將其父節點設定為待刪除節點的父節點

if father.right == node:
    father.right = node.left
    node.left.father = father

刪除功能程式碼彙總:

def delete(self,node):
    father = node.father
    if node.left == None:
        if father == None:
            self.root = node.right
            if node.right != None:
                node.right.father = None
        elif father.left == node:
            father.left = node.right
            if node.right != None:
                node.right.father = father
        else:
            father.right = node.right
            if node.right != None:
                node.right.father = father
        return 'delete successfully'
    tmpNode = node.left
    while tmpNode.right != None:
        tmpNode = tmpNode.right

    tmpNode.right = node.right
    if node.right != None:
        node.right.father = tmpNode

    if father == None:
        self.root = node.left
        node.left.father = None
    elif father.left == node:
        father.left = node.left
        node.left.father = father
    else:
        father.right = node.left
        node.left.father = father
    node = None
    return 'delete successfully'

綜上,二叉搜尋樹程式碼

# encoding=utf-8
import queue

class TreeNode(object):
    def __init__(self,val):
        self.value = val
        self.left = None
        self.right = None
        self.father = None

class BST(object):
    def __init__(self,nodeList):
        self.root = None
        for node in nodeList:
            self.bfs_insert(node)

    def bfs_insert(self,node):
        father = None
        cur = self.root

        while cur != None:
            if cur.value == node.value:
                return -1
            father = cur
            if node.value < cur.value:
                cur = cur.left
            else:
                cur = cur.right
        node.father = father
        if father == None:
            self.root = node
        elif node.value < father.value:
            father.left = node
        else:
            father.right = node

    def bfs(self):
        if self.root == None:
            return None
        retList = []
        q = queue.Queue()
        q.put(self.root)
        while q.empty() is not True:
            node = q.get()
            retList.append(node.value)
            if node.left != None:
                q.put(node.left)
            if node.right != None:
                q.put(node.right)
        return retList

    def bfs_search(self,value):
        cur = self.root
        while cur != None:
            if cur.value == value:
                return cur
            elif cur.value < value:
                cur = cur.right
            else:
                cur = cur.left
        return None

    def bfs_delete(self,node):
        father = node.father
        if node.left == None:
            if father == None:
                self.root = node.right
                if node.right != None:
                    node.right.father = None
            elif father.left == node:
                father.left = node.right
                if node.right != None:
                    node.right.father = father
            else:
                father.right = node.right
                if node.right != None:
                    node.right.father = father
            return 'delete successfully'
        tmpNode = node.left
        while tmpNode.right != None:
            tmpNode = tmpNode.right

        tmpNode.right = node.right
        if node.right != None:
            node.right.father = tmpNode

        if father == None:
            self.root = node.left
            node.left.father = None
        elif father.left == node:
            father.left = node.left
            node.left.father = father
        else:
            father.right = node.left
            node.left.father = father
        node = None
        return 'delete successfully'

if __name__ == '__main__':
    varList = [24,34,5,4,8,23,45,35,28,6,29]
    nodeList = [TreeNode(var) for var in varList]
    bst = BST(nodeList)
    print (bst.bfs())
    node = bst.bfs_search(34)
    bst.bfs_delete(node)
    print (bst.bfs())