ผู้ใช้:Kacha001/ต้นไม้เอเอ

จากวิกิพีเดีย สารานุกรมเสรี

ต้นไม้เอเอในวิทยาการคอมพิวเตอร์เป็นรูปแบบของต้นไม้สมดุลที่ใช้สำหรับจัดเก็บและเรียกข้อมูลได้อย่างมีประสิทธิภาพ ต้นไม้เอเอมีชื่อมาจาก Arne Andersson, ซึ่งเป็นผู้คิดค้นต้นไม้เอเอขึ้นมา

ต้นไม้เอเอเป็นรูปแบบของต้นไม้ดำแดงมีลักษณะเป็นต้นไม้ค้นหาแบบไบนารีที่สนับสนุนประสิทธิภาพการเพิ่มและการลบรายการ ไม่เหมือนต้นไม้ดำแดงที่โหนดสีแดงบนต้นไม้เอเอจะสามารถเพิ่มเป็นโหนดลูกทางขวาเท่านั้น กล่าวคือไม่มีโหนดสีแดงใดที่สามารถเป็นโหนดลูกได้ ซึ่งส่งผลให้เกิดการจำลองแบบต้นไม้ 2-3 แทนที่จะเป็นโครงสร้างต้นไม้ 2-3-4 ซึ่งช่วยลดความยุ่งยากในการดำเนืนการ อัลกอริธึมการดำเนืนการสำหรับต้นไม้ดำแดงจำเป็นต้องพิจารณารูปทรงที่แตกต่างกันเจ็ดอย่างเพื่อให้ต้นไม้สสมดุล:

ต้นไม้ AA นั้นจะต้องพิจารณาสองรูปร่างเนื่องจากเงื่อนไขที่เข้มงวดที่มีเพียงการเชื่อมโยงทางขวาที่เป็นสีแดงได้:

สมดุลการหมุน[แก้]

ต้นไม้สีแดงดำจะใช้บิตของข้อมูลเป็นสีในการสมดุลต่อโหนด ในขณะที่ต้นไม้เอเอต้องมีบิตของข้อมูลในการรักษาสมดุลต่อโหนดในรูปแบบ"ระดับ":

  1. ทุกๆระดับของโหนดใบเป็นหนึ่ง
  2. ทุกๆระดับของโหนดลูกทางซ้ายจะมีค่าน้อยกว่าโหนดพ่อ 1 ระดับ
  3. ทุกๆระดับของโหนดลูกทางขวาจะมีค่าเท่ากับโหนดพ่อหรือน้อยกว่าโหนดพ่อ 1 ระดับ
  4. ทุกๆระดับของโหนดหลานทางขวาจะต้องมีค่าน้อยกว่าโหนดปู่
  5. ทุกๆโหนดที่มีระดับมากกว่าหนึ่งต้องมีโหนดลูกอย่างน้อยสองโหนด

การเชื่องต่อโหนดลูกที่มีระดับเท่ากันจะเรียกว่าการเชื่อมต่อแนวนอน อนุญาตให้ใช้การเชื่อมต่อทางขวาเป็นการเชื่อมต่อแนวนอนได้แต่ไม่สามารถเชื่อมต่อทางซ้ายเป็นการเชื่อมต่อแบบแนวนอนได้ ข้อจำกัดเหล่านี้มีความเข้มงวดมากกว่าต้นไม้ดำแดงซึ่งมีผลทำให้ต้นไม้เอเอมีการปรับสมดุลง่ายกว่าต้นไม้ดำแดง

การเพิ่มและการลบข้อมูลของต้นเอเอจะทำให้ต้นไม้เอเอไม่สมดุลชั่วคราวดังนั้นจะต้องมีการดำเนินงานสองอย่างเพื่อปรับสมดุลของต้นไม้เอเอคือ "การเอียง" และ "การแบ่ง" การเอียงเป็นการหมุนทางขวาให้ต้นไม้ย่อยที่มีการเชื่อมต่อในแนวนอนทางด้านซ้ายไปแทนที่ส่วนที่มีการเชื่อมต่อแนวนอนทางขวา ส่วนการแบ่งคือการหมุนซ้ายและเพิ่มระดับเพื่อแทนที่ต้นไม้ย่อยที่มีการเชื่อมโยงแนวนอนทางขวาตั้งแต่สองโหนดขึ้นไป

การดำเนินการแทรกและการลบจะปรับสมดุลง่ายขึ้นโดยการอาศัยการเอียงและการแยกเพื่อปรับเปลี่ยนโครงสร้างเฉพาะเมื่อจำเป็นโดยให้ผู้ใช้ตัดสินใจเองว่าจะเอียงหรือแยกออก

การเอียง:

function skew is
    input: T, a node representing an AA tree that needs to be rebalanced.
    output: Another node representing the rebalanced AA tree.

    if nil(T) then
        return Nil
    else if nil(left(T)) then
        return T
    else if level(left(T)) == level(T) then
        Swap the pointers of horizontal left links.
        L = left(T)
        left(T) := right(L)
        right(L) := T
        return L
    else
        return T
    end if
end function
Skew: AA Tree Skew2.svg

ตัวอย่างโค้ด python

def Skew(root):
        global null
        if root == null:
            return null
        elif root.left == null:
            return root
        elif root.left.level == root.level:
            save = root.left
            root.left = save.right
            save.right = root
            return save
        else:
            return root

การแบ่ง:

function split is
    input: T, a node representing an AA tree that needs to be rebalanced.
    output: Another node representing the rebalanced AA tree.

    if nil(T) then
        return Nil
    else if nil(right(T)) or  nil(right(right(T))) then
        return T
    else if level(T) == level(right(right(T))) then
        We have two horizontal right links.  Take the middle node, elevate it, and return it.
        R = right(T)
        right(T) := left(R)
        left(R) := T
        level(R) := level(R) + 1
        return R
    else
        return T
    end if
end function

ตัวอย่างโค้ด python

def Split(root):
    global null
    if root == null:
        return null
    elif root.level == root.right.right.level:
        save = root.right
        root.right = save.left
        save.left = root
        save.level += 1
        return save
    else:
        return root

การเพิ่มข้อมูล[แก้]

การแทรกจะเริ่มต้นด้วยการค้นหาและการแทรกทับเหมือนต้นไม้ทวิภาคแบบปกติ หากมีการเชื่อมโยงแนวนอนทางซ้ายเกิดขึ้นจะมีการเอียงและหากมีการเชื่อมโยงแนวนอนทางขวาเกิดขึ้นจะมีการแบ่ง

function insert is
    input: X, the value to be inserted, and T, the root of the tree to insert it into.
    output: A balanced version T including X.

    Do the normal binary tree insertion procedure. Set the result of the
    recursive call to the correct child in case a new node was created or the
    root of the subtree changes.
    if nil(T) then
        Create a new leaf node with X.
        return node(X, 1, Nil, Nil)
    else if X < value(T) then
        left(T) := insert(X, left(T))
    else if X > value(T) then
        right(T) := insert(X, right(T))
    end if
    Note that the case of X == value(T) is unspecified. As given, an insert
    will have no effect. The implementor may desire different behavior.

    Perform skew and then split. The conditionals that determine whether or
    not a rotation will occur or not are inside of the procedures, as given
    above.
    T := skew(T)
    T := split(T)

    return T
end function

ตัวอย่างโค้ด pyhton

def Insertion(root,val):
    global null
    if root == null:
        root = AANode(1,null,null,val)
    elif(root.val > val):
        root.left = Insertion(root.left,val)
    elif(root.val < val):
        root.right = Insertion(root.right,val)
    root = Skew(root)
    root = Split(root)
    return root

การลบ[แก้]

ในการลบข้อมูลของต้นไม้เอเอก็คล้ายๆกับการลบข้อมูลขอต้นไม้ทวิภาคอื่นๆ คือสามารถเปลี่ยนการลบโหนดภายใน เป็นการลบโหนดใบได้ โดยการสลับข้อมูลของโหนดมันกับโหนดลูกหลานที่มีค่าใกล้เคียงกับโหนดนั้นมากที่สุด

การรักษาสมดุลของต้นไม้นั้นหลังจากที่ทำการกำจัดโหนดที่ต้องการออกไป ต้องทำการปรับต้นไม้กับโหนดที่มีระดับต่างกับลูกมันอยู่สอง หรือโหนดที่เสียลูกมันไป หลังจากนั้นทำการเอียงและการแบ่งค่าระดับ

ขั้นตอน:

  1. ลดระดับเลยถ้าเป็นไปได้
  2. ทำการเอียงระดับ
  3. ทำการแบ่งระดับ

อย่างไรก็ตามเราต้องเอียงและแบ่งระดับทั้งหมดแทนที่จะเป็นแค่โหนดทำให้โค้ดของเรามีความยุ่งยากมากขึ้น

function delete is
    input: X, the value to delete, and T, the root of the tree from which it should be deleted.
    output: T, balanced, without the value X.
   
    if nil(T) then
        return T
    else if X > value(T) then
        right(T) := delete(X, right(T))
    else if X < value(T) then
        left(T) := delete(X, left(T))
    else
        If we're a leaf, easy, otherwise reduce to leaf case. 
        if leaf(T) then
            return Nil
        else if nil(left(T)) then
            L := successor(T)
            right(T) := delete(value(L), right(T))
            value(T) := value(L)
        else
            L := predecessor(T)
            left(T) := delete(value(L), left(T))
            value(T) := value(L)
        end if
    end if

    Rebalance the tree. Decrease the level of all nodes in this level if
    necessary, and then skew and split all nodes in the new level.
    T := decrease_level(T)
    T := skew(T)
    right(T) := skew(right(T))
    if not nil(right(T))
        right(right(T)) := skew(right(right(T)))
    end if
    T := split(T)
    right(T) := split(right(T))
    return T
end function
function decrease_level is
    input: T, a tree for which we want to remove links that skip levels.
    output: T with its level decreased.

    should_be = min(level(left(T)), level(right(T))) + 1
    if should_be < level(T) then
        level(T) := should_be
        if should_be < level(right(T)) then
            level(right(T)) := should_be
        end if
    end if
    return T
end function

ตัวอย่างโค้ด

def Delete(root,val):
    global null
    if root == null:
        return null
    else:
        if root.val == val:
            if root.left != null and root.right != null:
                heir = root.left
                while heir.right != null:
                    heir = heir.right
                root.val = heir.val
                if(root.left == null):
                    root.left = Delete(null,root.val)
                else:
                    root.left = Delete(root.left,root.val)
            elif root.left == null:
                root = root.right
            else:
                root = root.left
        elif root.val < val:
            root.right = Delete(root.right,val)
        else:
            root.left = Delete(root.left,val)
    should_be = 0
    if (root.left.level < root.right.level):
        should_be = root.left.level + 1
    else:
        should_be = root.right.level + 1
    if should_be < root.level:
        root.level = should_be
        if should_be < root.right.level:
            root.right.level = should_be
    return Skew(Split(root))

ประสิทธิภาพ[แก้]

ประสิทธิภาพของต้นไม้เอเอจะเทียบเท่ากับประสิทธิภาพของต้นไม้สีดำแดง แม้ว่าต้นไม้เอเอจะทำให้การหมุนมากกว่าต้นไม้สีดำแดงเกิดประสิทธิภาพที่คล้ายคลึงกัน ต้นไม้สีแดงดำมีความสม่ำเสมอในการทำงานมากกว่าต้นไม้เอเอแต่ต้นไม้เอเอมีมีเงื่อนไขที่เข้มงวดทำให้เวลาในการค้นหาเร็วขึ้นเล็กน้อย

อ้างอิง[แก้]

  1. "A Disquisition on The Performance Behavior of Binary Search Tree Data Structures (pages 67-75)"