จะตรวจสอบได้อย่างไรว่าต้นไม้ไบนารีสมดุลหรือไม่?


114

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

ฉันกำลังคิดบางอย่างจากสิ่งนี้:

public boolean isBalanced(Node root){
    if(root==null){
        return true;  //tree is empty
    }
    else{
        int lh = root.left.height();
        int rh = root.right.height();
        if(lh - rh > 1 || rh - lh > 1){
            return false;
        }
    }
    return true;
}

นี่เป็นการใช้งานที่ดีหรือไม่? หรือฉันขาดอะไรไป?


หากคุณต้องการดูต้นไม้ไบนารี ascii ของ Donal Fellows พร้อมกราฟิก: i.imgur.com/97C27Ek.png
user7643681

1
คำตอบที่ดีช่วยให้ฉันเดินทางเข้าสหรัฐฯ (เรื่องตลก)
Henry

คำตอบ:


165

สะดุดกับคำถามเก่านี้ในขณะที่ค้นหาอย่างอื่น ฉันสังเกตว่าคุณไม่เคยได้รับคำตอบที่สมบูรณ์

วิธีแก้ปัญหานี้คือเริ่มต้นด้วยการเขียนข้อกำหนดสำหรับฟังก์ชันที่คุณพยายามเขียน

ข้อมูลจำเพาะ: ต้นไม้ไบนารีที่มีรูปร่างดีถูกกล่าวว่าเป็น "ความสูง - สมดุล" ถ้า (1) ว่างเปล่าหรือ (2) ลูกทางซ้ายและขวาของมันมีความสูงสมดุลกันและความสูงของต้นไม้ทางซ้ายอยู่ในช่วง 1 ของ ความสูงของต้นไม้ที่เหมาะสม

ตอนนี้คุณมีข้อมูลจำเพาะแล้วรหัสก็เป็นเรื่องเล็กน้อยที่จะเขียน เพียงทำตามข้อกำหนด:

IsHeightBalanced(tree)
    return (tree is empty) or 
           (IsHeightBalanced(tree.left) and
            IsHeightBalanced(tree.right) and
            abs(Height(tree.left) - Height(tree.right)) <= 1)

การแปลเป็นภาษาโปรแกรมที่คุณเลือกควรเป็นเรื่องเล็กน้อย

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

การออกกำลังกายแบบโบนัสพิเศษ : สมมติว่าต้นไม้ไม่สมดุลอย่างมาก เช่นเดียวกับล้านโหนดที่อยู่ลึกลงไปในด้านหนึ่งและอีกสามโหนดที่อยู่ลึกลงไป มีสถานการณ์ที่อัลกอริทึมนี้ทำให้สแตกหรือไม่? คุณสามารถแก้ไขการใช้งานเพื่อไม่ให้สแตกได้แม้จะได้รับต้นไม้ที่ไม่สมดุลอย่างหนาแน่น?

UPDATE : Donal Fellows ชี้ให้เห็นในคำตอบของเขาว่ามีคำจำกัดความที่แตกต่างกันของ 'สมดุล' ที่สามารถเลือกได้ ตัวอย่างเช่นเราอาจกำหนดคำจำกัดความของ "ความสูงที่สมดุล" ให้เข้มงวดขึ้นและกำหนดให้ความยาวเส้นทางไปยังลูกว่างที่ใกล้ที่สุดอยู่ในเส้นทางหนึ่งไปยังลูกที่ว่างเปล่าที่อยู่ไกลที่สุด คำจำกัดความของฉันเข้มงวดน้อยกว่านั้นดังนั้นจึงยอมรับต้นไม้มากขึ้น

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

มันไม่สำคัญจริงๆ จุดสำคัญของอัลกอริธึมการปรับสมดุลต้นไม้คือการทำให้แน่ใจว่าคุณจะไม่จบลงในสถานการณ์ที่คุณมีโหนดนับล้านในด้านหนึ่งและอีกสามโหนดในอีกด้านหนึ่ง คำจำกัดความของ Donal นั้นดีในทางทฤษฎี แต่ในทางปฏิบัติมันเป็นความเจ็บปวดที่เกิดขึ้นกับอัลกอริธึมการปรับสมดุลของต้นไม้ที่ตรงตามระดับความเข้มงวดนั้น การประหยัดประสิทธิภาพมักจะไม่เป็นเหตุให้ต้นทุนการดำเนินการ คุณใช้เวลาส่วนใหญ่ในการจัดเรียงต้นไม้ที่ไม่จำเป็นเพื่อให้ได้ระดับความสมดุลซึ่งในทางปฏิบัติจะสร้างความแตกต่างเพียงเล็กน้อย ใครจะสนใจว่าบางครั้งต้องใช้กิ่งก้านถึงสี่สิบกิ่งเพื่อไปยังใบไม้ที่ไกลที่สุดในต้นไม้ที่มีความสมดุลไม่สมบูรณ์แบบหนึ่งล้านโหนดในทางทฤษฎีจะใช้เวลาเพียงยี่สิบต้นในต้นไม้ที่สมดุลอย่างสมบูรณ์แบบ? ประเด็นคือไม่เคยเอาเงินล้าน การได้รับจากกรณีที่เลวร้ายที่สุดจากล้านไปสู่กรณีที่เลวร้ายที่สุดของสี่สิบมักจะดีพอ คุณไม่จำเป็นต้องไปถึงกรณีที่เหมาะสมที่สุด


19
+1 สำหรับคำตอบที่ถูกต้องเท่านั้นไม่น่าเชื่อว่าจะไม่มีใครตอบคำถามนี้ได้เป็นเวลา 8 เดือน ...
BlueRaja - Danny Pflughoeft

1
ตอบ "แบบฝึกหัด" ด้านล่าง…
Potatoswatter

ตอบแบบฝึกหัดโบนัสด้านล่าง
Brian

คำตอบของ sdk ด้านล่างดูเหมือนจะถูกต้องและทำให้มีการสำรวจต้นไม้เพียง 2 ครั้งดังนั้น O (n) เว้นแต่ว่าฉันจะพลาดอะไรบางอย่างนั่นก็ไม่ได้ช่วยแก้ปัญหาโบนัสแรกของคุณเป็นอย่างน้อย แน่นอนคุณยังสามารถใช้การเขียนโปรแกรมแบบไดนามิกและโซลูชันของคุณเพื่อแคชความสูงระดับกลางได้
Aly

ในทางทฤษฎีฉันจะต้องอยู่เคียงข้างกับคำจำกัดความของ Donal Fellows
Dhruv Gairola

27

ความสมดุลเป็นคุณสมบัติที่ละเอียดอ่อนอย่างแท้จริง คุณคิดว่าคุณรู้ว่ามันคืออะไร แต่มันง่ายมากที่จะทำผิด โดยเฉพาะอย่างยิ่งแม้แต่คำตอบ (ที่ดี) ของ Eric Lippert ก็ยังปิดอยู่ นั่นเป็นเพราะความคิดเรื่องความสูงไม่เพียงพอ คุณต้องมีแนวคิดเรื่องความสูงต่ำสุดและสูงสุดของต้นไม้ (โดยที่ความสูงต่ำสุดคือจำนวนขั้นต่ำสุดจากรากถึงใบไม้และสูงสุดคือ ... ดีคุณจะได้ภาพ) ด้วยเหตุนี้เราสามารถกำหนดสมดุลให้เป็น:

ต้นไม้ที่ความสูงสูงสุดของกิ่งใด ๆ ไม่เกินหนึ่งความสูงต่ำสุดของกิ่งใด ๆ

(อันนี้หมายความว่ากิ่งก้านมีความสมดุลในตัวเองคุณสามารถเลือกสาขาเดียวกันได้ทั้งสูงสุดและต่ำสุด)

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

  • ถ้ามันเท่ากับค่าพื้นฐานคุณก็ทำต่อไป
  • ถ้ามันแตกต่างกันมากกว่า 1 ต้นแสดงว่าต้นไม้นั้นไม่สมดุล
  • ถ้าเป็นหนึ่ง off ตอนนี้คุณจะทราบช่วงของความสมดุลแล้วและความลึกที่ตามมาทั้งหมด (เมื่อคุณกำลังจะย้อนรอย) ต้องเป็นค่าแรกหรือค่าที่สอง

ในรหัส:

class Tree {
    Tree left, right;
    static interface Observer {
        public void before();
        public void after();
        public boolean end();
    }
    static boolean traverse(Tree t, Observer o) {
        if (t == null) {
            return o.end();
        } else {
            o.before();
            try {
                if (traverse(left, o))
                    return traverse(right, o);
                return false;
            } finally {
                o.after();
            }
        }
    }
    boolean balanced() {
        final Integer[] heights = new Integer[2];
        return traverse(this, new Observer() {
            int h;
            public void before() { h++; }
            public void after() { h--; }
            public boolean end() {
                if (heights[0] == null) {
                    heights[0] = h;
                } else if (Math.abs(heights[0] - h) > 1) {
                    return false;
                } else if (heights[0] != h) {
                    if (heights[1] == null) {
                        heights[1] = h;
                    } else if (heights[1] != h) {
                        return false;
                    }
                }
                return true;
            }
        });
    }
}

ฉันคิดว่าคุณสามารถทำได้โดยไม่ต้องใช้รูปแบบ Observer แต่ฉันคิดว่ามันง่ายกว่าที่จะหาเหตุผลด้วยวิธีนี้


[แก้ไข]: ทำไมคุณไม่สามารถวัดความสูงของแต่ละด้านได้ พิจารณาต้นไม้นี้:

        /\
       /  \
      /    \
     /      \_____
    /\      /     \_
   /  \    /      / \
  /\   C  /\     /   \
 /  \    /  \   /\   /\
A    B  D    E F  G H  J

ตกลงบิตยุ่ง แต่แต่ละด้านของรากจะมีความสมดุล: Cเป็นความลึก 2 A, B, D, Eมีความลึก 3, F, G, H, Jมีความลึก 4. ความสูงของสาขาซ้ายเป็น 2 (จำความสูงลดลงในขณะที่คุณขวาง สาขา) ความสูงของกิ่งที่เหมาะสมคือ 3 แต่ต้นไม้โดยรวมไม่สมดุลเนื่องจากมีความสูง 2 ระหว่างCและต่างFกัน คุณต้องมีข้อกำหนดขั้นต่ำ (แม้ว่าอัลกอริทึมจริงอาจมีความซับซ้อนน้อยกว่าเนื่องจากควรมีความสูงที่อนุญาตเพียงสองความสูงเท่านั้น)


อ่าจุดดี คุณสามารถมีต้นไม้ซึ่งก็คือ h (LL) = 4, h (LR) = 3, h (RL) = 3, h (RR) = 2 ดังนั้น h (L) = 4 และ h (R) = 3 ดังนั้นจึงดูสมดุลกับอัลกอริทึมก่อนหน้านี้ แต่ด้วยความลึกสูงสุด / นาทีที่ 4/2 จึงไม่สมดุล นี่อาจจะเข้าท่ากว่าด้วยภาพ
ทิม

1
นั่นคือสิ่งที่ฉันเพิ่งเพิ่ม (ด้วยกราฟิค ASCII ที่น่ากลัวที่สุดในโลก)
Donal Fellows

@DonalFellows: คุณพูดถึงความสูงของกิ่งด้านซ้ายคือ 2 แต่กิ่งด้านซ้ายมี 4 โหนดรวมทั้งรากและใบ A ความสูงจะเป็น 3 ในกรณีนี้ถูกต้อง
พายุสมอง

22

สิ่งนี้จะพิจารณาว่าระดับบนสุดของต้นไม้สมดุลหรือไม่ นั่นคือคุณสามารถมีต้นไม้ที่มีกิ่งก้านยาวสองกิ่งห่างจากซ้ายสุดและขวาสุดโดยไม่มีอะไรอยู่ตรงกลางและสิ่งนี้จะกลับมาเป็นจริง คุณต้องตรวจสอบซ้ำroot.leftและroot.rightดูว่ามีความสมดุลภายในหรือไม่ก่อนที่จะคืนค่าจริง


อย่างไรก็ตามหากรหัสมีวิธีความสูงสูงสุดและต่ำสุดหากมีความสมดุลทั่วโลกก็จะมีความสมดุลในท้องถิ่นเช่นกัน
อารีย์

22

การตอบสนองการออกกำลังกายโบนัส วิธีง่ายๆ เห็นได้ชัดว่าในการนำไปใช้งานจริงอาจมีการปิดกั้นสิ่งนี้หรือบางสิ่งบางอย่างเพื่อหลีกเลี่ยงการกำหนดให้ผู้ใช้รวมความสูงไว้ในการตอบสนอง

IsHeightBalanced(tree, out height)
    if (tree is empty)
        height = 0
        return true
    balance = IsHeightBalanced(tree.left, heightleft) and IsHeightBalanced(tree.right, heightright)
    height = max(heightleft, heightright)+1
    return balance and abs(heightleft - heightright) <= 1     

หากต้นไม้มีความสูงมากกว่าสองสามร้อยชั้นคุณจะได้รับข้อยกเว้น stackoverflow คุณทำได้อย่างมีประสิทธิภาพ แต่ไม่สามารถจัดการกับชุดข้อมูลขนาดกลางหรือขนาดใหญ่ได้
Eric Leschinski

นี่คือรหัสเทียมที่คุณเพิ่งสร้างขึ้นมาหรือเป็นภาษาจริง? (ฉันหมายถึงout heightสัญกรณ์ตัวแปร ")
kap

@kap: นี่คือ pseudocode แต่ไวยากรณ์ออกมาจาก C # โดยทั่วไปหมายความว่าพารามิเตอร์เดินทางจากฟังก์ชันที่เรียกไปยังผู้เรียก (ซึ่งตรงข้ามกับพารามิเตอร์มาตรฐานซึ่งเดินทางจากผู้เรียกไปยังฟังก์ชันที่เรียกว่าหรือพารามิเตอร์การอ้างอิงซึ่งเดินทางจากตัวเรียกไปยังฟังก์ชันที่เรียกว่าและย้อนกลับ) สิ่งนี้ช่วยให้ฟังก์ชันส่งคืนค่ามากกว่าหนึ่งค่าได้อย่างมีประสิทธิภาพ
Brian

20

โพสต์คำสั่งซื้อข้ามต้นไม้เพียงครั้งเดียว ความซับซ้อนของเวลาคือ O (n) ช่องว่างคือ O (1) ดีกว่าโซลูชันจากบนลงล่าง ฉันให้การใช้งานเวอร์ชัน java แก่คุณ

public static <T> boolean isBalanced(TreeNode<T> root){
    return checkBalance(root) != -1;
}

private static <T> int checkBalance(TreeNode<T> node){
    if(node == null) return 0;
    int left = checkBalance(node.getLeft());

    if(left == -1) return -1;

    int right = checkBalance(node.getRight());

    if(right == -1) return -1;

    if(Math.abs(left - right) > 1){
        return -1;
    }else{
        return 1 + Math.max(left, right);
    }
}

4
ทางออกที่ดี แต่ความซับซ้อนของพื้นที่ควรเป็น O (H) โดยที่ H คือความสูงของต้นไม้ เนื่องจากการจัดสรรสแต็กสำหรับการเรียกซ้ำ
legrass

อะไรleft == -1หมายถึง? เมื่อไหร่ที่จะเป็นเช่นนั้น? เราถือว่าการเรียกแบบเรียกซ้ำเป็นนัยว่าleft == -1เป็นจริงหรือไม่หากต้นไม้ย่อยทั้งหมดของลูกทางซ้ายไม่สมดุล?
Aspen

left == 1หมายความว่าทรีย่อยด้านซ้ายไม่สมดุลจากนั้นต้นไม้ทั้งต้นจะไม่สมดุล เราไม่ต้องตรวจสอบแผนผังย่อยที่ถูกต้องอีกต่อไปและสามารถส่งคืน-1ได้
ตั้งแต่

ความซับซ้อนของเวลาคือ O (n) เนื่องจากคุณต้องผ่านองค์ประกอบทั้งหมด และถ้าคุณมีโหนด x และจะใช้เวลา y ในการตรวจสอบยอดเงิน หากคุณมีโหนด 2x จะใช้เวลาตรวจสอบยอดคงเหลือ 2 ปี นั่นคือเสียงทั้งหมดใช่มั้ย?
แจ็ค

คำอธิบายที่ดีพร้อมการวาดอยู่ที่นี่: algorithms.tutorialhorizon.com/…
Shir

15

คำจำกัดความของต้นไม้ไบนารีที่สมดุลความสูงคือ:

ต้นไม้ไบนารีซึ่งความสูงของต้นไม้ย่อยทั้งสองของทุกโหนดไม่เคยแตกต่างกันเกิน 1

ดังนั้นต้นไม้ไบนารีที่ว่างเปล่าจะมีความสูงสมดุลเสมอ
ต้นไม้ไบนารีที่ไม่ว่างเปล่าจะมีความสมดุลสูงหาก:

  1. แผนผังย่อยด้านซ้ายมีความสูงสมดุล
  2. แผนผังย่อยที่เหมาะสมคือความสูงที่สมดุล
  3. ความแตกต่างระหว่างความสูงของทรีย่อยด้านซ้ายและด้านขวาไม่เกิน 1

พิจารณาต้นไม้:

    A
     \ 
      B
     / \
    C   D

ตามที่เห็นทรีย่อยด้านซ้ายAมีความสมดุลสูง (เนื่องจากว่างเปล่า) และทรีย่อยด้านขวาก็เช่นกัน แต่ก็ยังคงต้นไม้จะไม่สูงสมดุลตามเงื่อนไข 3 ไม่เป็นไปตามความสูงของต้นไม้ย่อยซ้ายเป็นและความสูงของต้นไม้ย่อยที่ถูกต้องคือ02

ต้นไม้ต่อไปนี้มีความสูงไม่สมดุลแม้ว่าความสูงของต้นไม้ย่อยด้านซ้ายและด้านขวาจะเท่ากัน รหัสที่มีอยู่ของคุณจะกลับมาเป็นจริง

       A
     /  \ 
    B    C
   /      \
  D        G
 /          \
E            H

ดังนั้นคำว่าeveryใน def จึงสำคัญมาก

สิ่งนี้จะได้ผล:

int height(treeNodePtr root) {
        return (!root) ? 0: 1 + MAX(height(root->left),height(root->right));
}

bool isHeightBalanced(treeNodePtr root) {
        return (root == NULL) ||
                (isHeightBalanced(root->left) &&
                isHeightBalanced(root->right) &&
                abs(height(root->left) - height(root->right)) <=1);
}

ลิงค์ Ideone


ดังนั้นคำตอบนี้ช่วยฉันได้มาก อย่างไรก็ตามฉันพบว่า [MIT intro to algorithms course] ฟรีดูเหมือนว่าจะขัดแย้งกับเงื่อนไขที่ 3 หน้า 4 แสดงต้นไม้ RB ที่ความสูงของกิ่งด้านซ้ายคือ 2 และสาขาด้านขวาคือ 4 คุณช่วยชี้แจงให้ฉันทราบได้ไหม บางทีฉันอาจไม่เข้าใจคำจำกัดความของแผนผังย่อย [1]: ocw.mit.edu/courses/electrical-engineering-and-computer-science/…
i8abug

ความแตกต่างน่าจะมาจากคำจำกัดความนี้ในบันทึกย่อของหลักสูตร เส้นทางที่เรียบง่ายทั้งหมดจากโหนดใด ๆ x ไปยังลีฟลีฟมีจำนวนโหนดสีดำเท่ากัน = black-height (x)
i8abug

เพื่อติดตามผลฉันพบคำจำกัดความที่เปลี่ยนจุด (3) ในคำตอบของคุณที่ว่า "ใบไม้ทุกใบอยู่ห่างจากรากไม่เกินระยะที่กำหนด" ดูเหมือนว่าจะตอบสนองทั้งสองกรณี นี่คือลิงค์จากเครื่องเรียนแบบสุ่ม
i8abug

8

หากต้นไม้ไบนารีมีความสมดุลหรือไม่สามารถตรวจสอบได้โดยการส่งผ่านคำสั่งระดับ:

private boolean isLeaf(TreeNode root) {
    if (root.left == null && root.right == null)
        return true;
    return false;
}

private boolean isBalanced(TreeNode root) {
    if (root == null)
        return true;
    Vector<TreeNode> queue = new Vector<TreeNode>();
    int level = 1, minLevel = Integer.MAX_VALUE, maxLevel = Integer.MIN_VALUE;
    queue.add(root);
    while (!queue.isEmpty()) {
        int elementCount = queue.size();
        while (elementCount > 0) {
            TreeNode node = queue.remove(0);
            if (isLeaf(node)) {
                if (minLevel > level)
                    minLevel = level;
                if (maxLevel < level)
                    maxLevel = level;
            } else {
                if (node.left != null)
                    queue.add(node.left);
                if (node.right != null)
                    queue.add(node.right);
            }
            elementCount--;
        }
        if (abs(maxLevel - minLevel) > 1) {
            return false;
        }
        level++;
    }

    return true;
}

1
คำตอบที่ยอดเยี่ยม ฉันคิดว่ามันเป็นไปตามข้อกำหนดทั้งหมดที่ Eric โพสต์เกี่ยวกับโบนัสและ Super-Bonus เป็นการทำซ้ำ (โดยใช้คิว) และไม่เรียกซ้ำดังนั้น call-stack จะไม่ล้นและเราย้ายปัญหาหน่วยความจำทั้งหมดไปที่ฮีป ไม่จำเป็นต้องเดินลัดเลาะไปตามต้นไม้ทั้งหมด มันเลื่อนไปทีละระดับดังนั้นหากต้นไม้ไม่สมดุลอย่างสิ้นเชิงไปที่ 1 ด้านต้นไม้จะพบว่ามันเร็ว ๆ นี้จริงๆ (เร็วที่สุดเร็วกว่าอัลกอริทึมแบบวนซ้ำส่วนใหญ่แม้ว่าคุณจะสามารถใช้อัลกอริธึมการวนซ้ำตามลำดับหลังการสั่งซื้อซึ่งจะพบระดับสุดท้าย ไม่สมดุลเร็วกว่า แต่จะแย่ลงในระดับแรก) +1 :-)
David Refaeli

7

สิ่งนี้ถูกทำให้ซับซ้อนกว่าที่เป็นจริง

อัลกอริทึมมีดังนี้:

  1. ให้ A = ความลึกของโหนดระดับสูงสุด
  2. ให้ B = ความลึกของโหนดระดับต่ำสุด

  3. ถ้า abs (AB) <= 1 แสดงว่าต้นไม้นั้นสมดุล


ง่ายและตรง!
Wasim Thabraze

3
ปัญหาสองประการมันไม่ได้มีประสิทธิภาพเท่าที่ควรคุณกำลังทำสองครั้งผ่านต้นไม้ทั้งหมด และสำหรับต้นไม้ที่มีโหนดหนึ่งโหนดไปทางซ้ายและอีกหลายพันไปทางขวาคุณจะก้าวผ่านสิ่งทั้งหมดโดยไม่จำเป็นเมื่อคุณสามารถหยุดได้หลังจากการตรวจสอบ 3 ครั้ง
Eric Leschinski

5

ความสมดุลนั้นขึ้นอยู่กับโครงสร้างในมือเล็กน้อย ตัวอย่างเช่น B-Tree ไม่สามารถมีโหนดมากกว่าความลึกที่แน่นอนจากรากหรือน้อยกว่าสำหรับสสารนั้นข้อมูลทั้งหมดอยู่ที่ระดับความลึกคงที่จากราก แต่อาจไม่สมดุลหากการกระจายของใบไม้ไปยังใบไม้ - แต่หนึ่งโหนดไม่สม่ำเสมอ การข้ามรายการไม่มีความคิดเกี่ยวกับความสมดุลเลยโดยอาศัยความน่าจะเป็นเพื่อให้ได้ประสิทธิภาพที่เหมาะสมแทน ต้นไม้ฟีโบนักชีขาดความสมดุลโดยเจตนาเลื่อนการปรับสมดุลใหม่เพื่อให้ได้ประสิทธิภาพที่เหนือกว่าโดยแลกกับการอัปเดตที่นานขึ้นในบางครั้ง ต้นไม้ AVL และ Red-Black แนบข้อมูลเมตากับแต่ละโหนดเพื่อให้ได้ค่าคงที่สมดุลเชิงลึก

โครงสร้างเหล่านี้และอื่น ๆ ทั้งหมดมีอยู่ในไลบรารีมาตรฐานของระบบการเขียนโปรแกรมทั่วไปส่วนใหญ่ (ยกเว้น python, RAGE!) การใช้หนึ่งหรือสองอย่างเป็นแนวทางปฏิบัติที่ดีในการเขียนโปรแกรม แต่อาจไม่ใช่การใช้เวลาที่ดีในการผลิตของคุณเองสำหรับการผลิตเว้นแต่ว่าปัญหาของคุณจะมีประสิทธิภาพที่แปลกประหลาดซึ่งไม่จำเป็นต้องเป็นที่พอใจกับคอลเลคชันที่ไม่ได้วางจำหน่าย


4

หมายเหตุ 1: ความสูงของแผนผังย่อยใด ๆ จะคำนวณเพียงครั้งเดียว

หมายเหตุ 2: หากแผนผังย่อยด้านซ้ายไม่สมดุลการคำนวณของแผนผังย่อยด้านขวาซึ่งอาจมีองค์ประกอบเป็นล้านองค์ประกอบจะถูกข้ามไป

// return height of tree rooted at "tn" if, and only if, it is a balanced subtree
// else return -1
int maxHeight( TreeNode const * tn ) {
    if( tn ) {
        int const lh = maxHeight( tn->left );
        if( lh == -1 ) return -1;
        int const rh = maxHeight( tn->right );
        if( rh == -1 ) return -1;
        if( abs( lh - rh ) > 1 ) return -1;
        return 1 + max( lh, rh );
    }
    return 0;
}

bool isBalanced( TreeNode const * root ) {
    // Unless the maxHeight is -1, the subtree under "root" is balanced
    return maxHeight( root ) != -1;
}

3

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

คุณกำลังพยายามทำอะไรอยู่? มีต้นไม้ปรับสมดุลได้เองโดยรอบ (AVL / แดง - ดำ) ในความเป็นจริงต้นชวามีความสมดุล



3
public boolean isBalanced(TreeNode root)
{
    return (maxDepth(root) - minDepth(root) <= 1);
}

public int maxDepth(TreeNode root)
{
    if (root == null) return 0;

    return 1 + max(maxDepth(root.left), maxDepth(root.right));
}

public int minDepth (TreeNode root)
{
    if (root == null) return 0;

    return 1 + min(minDepth(root.left), minDepth(root.right));
}

ฉันคิดว่าวิธีนี้ไม่ถูกต้องหากคุณส่งต้นไม้ที่มีโหนดเดียวเช่นรูทมันจะกลับมาเป็น maxDepth 1(เหมือนกันสำหรับ minDepth) ความลึกที่ถูกต้องควรจะ0เป็นรากของต้นไม้มี0ความลึกเสมอ
Cratylus

3

นี่คือโซลูชันที่ผ่านการทดสอบแล้วที่สมบูรณ์ใน C # (ขออภัยฉันไม่ใช่ java dev) (เพียงคัดลอกวางในแอปคอนโซล) ฉันรู้ว่าคำจำกัดความของความสมดุลนั้นแตกต่างกันไปดังนั้นทุกคนอาจไม่ชอบผลการทดสอบของฉัน แต่โปรดดูวิธีการตรวจสอบความลึก / ความสูงที่แตกต่างกันเล็กน้อยในการวนซ้ำแบบวนซ้ำและออกจากการไม่ตรงกันครั้งแรกโดยไม่บันทึกความสูง / ระดับ / ความลึกของโหนดในแต่ละโหนด (เฉพาะการรักษาไว้ในการเรียกใช้ฟังก์ชัน)

using System;
using System.Linq;
using System.Text;

namespace BalancedTree
{
    class Program
    {
        public static void Main()
        {
            //Value Gathering
            Console.WriteLine(RunTreeTests(new[] { 0 }));
            Console.WriteLine(RunTreeTests(new int[] { }));

            Console.WriteLine(RunTreeTests(new[] { 0, 1, 2, 3, 4, -1, -4, -3, -2 }));
            Console.WriteLine(RunTreeTests(null));
            Console.WriteLine(RunTreeTests(new[] { 10, 8, 12, 8, 4, 14, 8, 10 }));
            Console.WriteLine(RunTreeTests(new int[] { 20, 10, 30, 5, 15, 25, 35, 3, 8, 12, 17, 22, 27, 32, 37 }));

            Console.ReadKey();
        }

        static string RunTreeTests(int[] scores)
        {
            if (scores == null || scores.Count() == 0)
            {
                return null;
            }

            var tree = new BinarySearchTree();

            foreach (var score in scores)
            {
                tree.InsertScore(score);
            }

            Console.WriteLine(tree.IsBalanced());

            var sb = tree.GetBreadthWardsTraversedNodes();

            return sb.ToString(0, sb.Length - 1);
        }
    }

    public class Node
    {
        public int Value { get; set; }
        public int Count { get; set; }
        public Node RightChild { get; set; }
        public Node LeftChild { get; set; }
        public Node(int value)
        {
            Value = value;
            Count = 1;
        }

        public override string ToString()
        {
            return Value + ":" + Count;
        }

        public bool IsLeafNode()
        {
            return LeftChild == null && RightChild == null;
        }

        public void AddValue(int value)
        {
            if (value == Value)
            {
                Count++;
            }
            else
            {
                if (value > Value)
                {
                    if (RightChild == null)
                    {
                        RightChild = new Node(value);
                    }
                    else
                    {
                        RightChild.AddValue(value);
                    }
                }
                else
                {
                    if (LeftChild == null)
                    {
                        LeftChild = new Node(value);
                    }
                    else
                    {
                        LeftChild.AddValue(value);
                    }
                }
            }
        }
    }

    public class BinarySearchTree
    {
        public Node Root { get; set; }

        public void InsertScore(int score)
        {
            if (Root == null)
            {
                Root = new Node(score);
            }
            else
            {
                Root.AddValue(score);
            }
        }

        private static int _heightCheck;
        public bool IsBalanced()
        {
            _heightCheck = 0;
            var height = 0;
            if (Root == null) return true;
            var result = CheckHeight(Root, ref height);
            height--;
            return (result && height == 0);
        }

        private static bool CheckHeight(Node node, ref int height)
        {
            height++;
            if (node.LeftChild == null)
            {
                if (node.RightChild != null) return false;
                if (_heightCheck != 0) return _heightCheck == height;
                _heightCheck = height;
                return true;
            }
            if (node.RightChild == null)
            {
                return false;
            }

            var leftCheck = CheckHeight(node.LeftChild, ref height);
            if (!leftCheck) return false;
            height--;
            var rightCheck = CheckHeight(node.RightChild, ref height);
            if (!rightCheck) return false;
            height--;
            return true;
        }


        public StringBuilder GetBreadthWardsTraversedNodes()
        {
            if (Root == null) return null;
            var traversQueue = new StringBuilder();
            traversQueue.Append(Root + ",");
            if (Root.IsLeafNode()) return traversQueue;
            TraversBreadthWards(traversQueue, Root);
            return traversQueue;
        }

        private static void TraversBreadthWards(StringBuilder sb, Node node)
        {
            if (node == null) return;
            sb.Append(node.LeftChild + ",");
            sb.Append(node.RightChild + ",");
            if (node.LeftChild != null && !node.LeftChild.IsLeafNode())
            {
                TraversBreadthWards(sb, node.LeftChild);
            }
            if (node.RightChild != null && !node.RightChild.IsLeafNode())
            {
                TraversBreadthWards(sb, node.RightChild);
            }
        }
    }
}

ฉันไม่เข้าใจว่ามีคนโหวตลบคำตอบนี้ภายใน 2 นาทีหลังจากโพสต์คำตอบได้อย่างไร ?? การโหวตเชิงลบนั้นใช้ได้ แต่คุณช่วยอธิบายว่ามีอะไรผิดปกติกับโซลูชันนี้ได้ไหม
sbp

2
#include <iostream>
#include <deque>
#include <queue>

struct node
{
    int data;
    node *left;
    node *right;
};

bool isBalanced(node *root)
{
    if ( !root)
    {
        return true;
    }

    std::queue<node *> q1;
    std::queue<int>  q2;
    int level = 0, last_level = -1, node_count = 0;

    q1.push(root);
    q2.push(level);

    while ( !q1.empty() )
    {
        node *current = q1.front();
        level = q2.front();

        q1.pop();
        q2.pop();

        if ( level )
        {
            ++node_count;
        }

                if ( current->left )
                {
                        q1.push(current->left);
                        q2.push(level + 1);
                }

                if ( current->right )
                {
                        q1.push(current->right);
                        q2.push(level + 1);
                }

        if ( level != last_level )
        {
            std::cout << "Check: " << (node_count ? node_count - 1 : 1) << ", Level: " << level << ", Old level: " << last_level << std::endl;
            if ( level && (node_count - 1) != (1 << (level-1)) )
            {
                return false;
            }

            last_level = q2.front();
            if ( level ) node_count = 1;
        }
    }

    return true;
}

int main()
{
    node tree[15];

    tree[0].left  = &tree[1];
    tree[0].right = &tree[2];
    tree[1].left  = &tree[3];
    tree[1].right = &tree[4];
    tree[2].left  = &tree[5];
    tree[2].right = &tree[6];
    tree[3].left  = &tree[7];
    tree[3].right = &tree[8];
    tree[4].left  = &tree[9];   // NULL;
    tree[4].right = &tree[10];  // NULL;
    tree[5].left  = &tree[11];  // NULL;
    tree[5].right = &tree[12];  // NULL;
    tree[6].left  = &tree[13];
    tree[6].right = &tree[14];
    tree[7].left  = &tree[11];
    tree[7].right = &tree[12];
    tree[8].left  = NULL;
    tree[8].right = &tree[10];
    tree[9].left  = NULL;
    tree[9].right = &tree[10];
    tree[10].left = NULL;
    tree[10].right= NULL;
    tree[11].left = NULL;
    tree[11].right= NULL;
    tree[12].left = NULL;
    tree[12].right= NULL;
    tree[13].left = NULL;
    tree[13].right= NULL;
    tree[14].left = NULL;
    tree[14].right= NULL;

    std::cout << "Result: " << isBalanced(tree) << std::endl;

    return 0;
}

คุณอาจต้องการเพิ่มความคิดเห็น
jgauffin

2

RE: @ lucky's solution โดยใช้ BFS เพื่อทำการ traversal ตามลำดับระดับ

เราสำรวจต้นไม้และเก็บข้อมูลอ้างอิงไปยัง vars min / max-level ซึ่งอธิบายระดับต่ำสุดที่โหนดเป็นใบไม้

ฉันเชื่อว่าโซลูชัน @lucky ต้องมีการปรับเปลี่ยน ตามที่แนะนำโดย @codaddict แทนที่จะตรวจสอบว่าโหนดเป็นใบไม้หรือไม่เราต้องตรวจสอบว่าลูกทางซ้ายหรือขวาเป็นโมฆะ (ไม่ใช่ทั้งคู่) มิฉะนั้นอัลกอริทึมจะพิจารณาว่านี่เป็นโครงสร้างสมดุลที่ถูกต้อง:

     1
    / \
   2   4
    \   \
     3   1

ใน Python:

def is_bal(root):
    if root is None:
        return True

    import queue

    Q = queue.Queue()
    Q.put(root)

    level = 0
    min_level, max_level = sys.maxsize, sys.minsize

    while not Q.empty():
        level_size = Q.qsize()

        for i in range(level_size):
            node = Q.get()

            if not node.left or node.right:
                min_level, max_level = min(min_level, level), max(max_level, level)

            if node.left:
                Q.put(node.left)
            if node.right:
                Q.put(node.right)

        level += 1

        if abs(max_level - min_level) > 1:
            return False

    return True

วิธีการแก้ปัญหานี้ควรเป็นไปตามข้อกำหนดทั้งหมดที่ให้ไว้ในคำถามเริ่มต้นทำงานในเวลา O (n) และช่องว่าง O (n) หน่วยความจำล้นจะถูกส่งไปยังฮีปแทนที่จะเป่า call-stack แบบเรียกซ้ำ

หรืออีกวิธีหนึ่งคือในขั้นต้นเราสามารถสำรวจต้นไม้เพื่อคำนวณ + แคชความสูงสูงสุดสำหรับทรีย่อยแต่ละรากซ้ำ ๆ จากนั้นในการรันซ้ำอีกรอบตรวจสอบว่าความสูงแคชของทรีย่อยซ้ายและขวาสำหรับแต่ละรูทไม่เคยแตกต่างกันมากกว่าหนึ่งรูท สิ่งนี้จะทำงานในเวลา O (n) และช่องว่าง O (n) แต่จะทำซ้ำเพื่อไม่ให้เกิดสแต็กล้น


1

คุณต้องมีวิธีกำหนดความสูงของซ้ายและขวาและถ้าซ้ายและขวาสมดุลกัน

และฉันก็แค่ return height(node->left) == height(node->right);

เกี่ยวกับการเขียนheightฟังก์ชันโปรดอ่าน: การ ทำความเข้าใจการเรียกซ้ำ


3
คุณต้องการให้ความสูงซ้ายและขวาอยู่ภายใน 1 ไม่จำเป็นต้องเท่ากัน
Alex B

1

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


1

นี่คือเวอร์ชันที่อ้างอิงจากการข้ามผ่านเชิงลึกทั่วไปก่อน ควรเร็วกว่าคำตอบที่ถูกต้องอื่น ๆ และจัดการกับ "ความท้าทาย" ที่กล่าวมาทั้งหมด ขออภัยสำหรับรูปแบบฉันไม่รู้จัก Java จริงๆ

คุณยังสามารถทำให้เร็วขึ้นได้มากโดยการกลับมาก่อนเวลาหากตั้งค่าสูงสุดและต่ำสุดไว้และมีความแตกต่าง> 1

public boolean isBalanced( Node root ) {
    int curDepth = 0, maxLeaf = 0, minLeaf = INT_MAX;
    if ( root == null ) return true;
    while ( root != null ) {
        if ( root.left == null || root.right == null ) {
            maxLeaf = max( maxLeaf, curDepth );
            minLeaf = min( minLeaf, curDepth );
        }
        if ( root.left != null ) {
            curDepth += 1;
            root = root.left;
        } else {
            Node last = root;
            while ( root != null
             && ( root.right == null || root.right == last ) ) {
                curDepth -= 1;
                last = root;
                root = root.parent;
            }
            if ( root != null ) {
                curDepth += 1;
                root = root.right;
            }
        }
    }
    return ( maxLeaf - minLeaf <= 1 );
}

1
เป็นความพยายามที่ดี แต่ไม่ได้ผลอย่างชัดเจน ให้ x เป็นโหนดว่าง ให้โหนดทรีที่ไม่เป็นค่าว่างแสดงเป็น (ค่าทางซ้ายขวา) พิจารณาต้นไม้ (x A (x B x)) "root" ชี้ไปที่โหนด A, B, A, B, A, B ... ตลอดไป อยากลองอีกครั้งไหม คำใบ้: มันง่ายกว่าจริง ๆหากไม่มีคำแนะนำของผู้ปกครอง
Eric Lippert

@ เอริก: อ๊ะแก้ไขแล้ว (ฉันคิดว่า) ฉันกำลังพยายามทำสิ่งนี้โดยไม่มีหน่วยความจำ O (ความลึก) และถ้าโครงสร้างไม่มีตัวชี้หลัก (มักจะทำ) คุณต้องใช้สแต็ก
Potatoswatter

สิ่งที่คุณกำลังบอกฉันคือคุณต้องการใช้หน่วยความจำถาวร O (n) ในตัวชี้หลักเพื่อหลีกเลี่ยงการจัดสรรหน่วยความจำชั่วคราว O (d) โดยที่บันทึก n <= d <= n? ดูเหมือนว่าเศรษฐกิจที่ผิดพลาด
Eric Lippert

น่าเสียดายที่แม้ว่าคุณจะแก้ไขปัญหาเกี่ยวกับการส่งผ่านแล้ว แต่ก็มีปัญหาใหญ่กว่านี้ นี่ไม่ได้ทดสอบว่าต้นไม้มีความสมดุลหรือไม่ แต่เป็นการทดสอบว่าต้นไม้มีใบใกล้เคียงกับระดับเดียวกันหรือไม่ นั่นไม่ใช่คำจำกัดความของ "สมดุล" ที่ฉันให้ไว้ พิจารณาต้นไม้ ((((x D x) C x) B x) A x) รหัสของคุณรายงานว่า "สมดุล" เมื่อเห็นได้ชัดว่าไม่สมดุลสูงสุด อยากลองอีกครั้งไหม
Eric Lippert

@Eric reply 1: ไม่ใช่เศรษฐกิจที่ผิดพลาดหากคุณใช้พอยน์เตอร์หลักสำหรับสิ่งอื่นแล้ว ตอบกลับ 2: แน่ใจทำไมไม่ นี่เป็นวิธีการแก้จุดบกพร่องที่แปลกประหลาด…ฉันไม่ควรจะเขียนข้ามผ่านอะไรแบบสุ่มสี่สุ่มห้าตอนตี 4 …
Potatoswatter

1
/* Returns true if Tree is balanced, i.e. if the difference between the longest path and the shortest path from the root to a leaf node is no more than than 1. This difference can be changed to any arbitrary positive number. */
boolean isBalanced(Node root) {
    if (longestPath(root) - shortestPath(root) > 1)
        return false;
    else
        return true;
}


int longestPath(Node root) {
    if (root == null);
        return 0;
    else {
        int leftPathLength = longestPath(root.left);
        int rightPathLength = longestPath(root.right);
        if (leftPathLength >= rightPathLength)
            return leftPathLength + 1;
        else
            return rightPathLength + 1;
    }
}

int shortestPath(Node root) {
    if (root == null);
        return 0;
    else {
        int leftPathLength = shortestPath(root.left);
        int rightPathLength = shortestPath(root.right);
        if (leftPathLength <= rightPathLength)
            return leftPathLength + 1;
        else
            return rightPathLength + 1;
    }
}

1
คุณควรเพิ่มคำอธิบายในคำตอบและ / หรือความคิดเห็นลงในตัวอย่างโค้ดของคุณ
Brad Campbell

1
class Node {
    int data;
    Node left;
    Node right;

    // assign variable with constructor
    public Node(int data) {
        this.data = data;
    }
}

public class BinaryTree {

    Node root;

    // get max depth
    public static int maxDepth(Node node) {
        if (node == null)
            return 0;

        return 1 + Math.max(maxDepth(node.left), maxDepth(node.right));
    }

    // get min depth
    public static int minDepth(Node node) {
        if (node == null)
            return 0;

        return 1 + Math.min(minDepth(node.left), minDepth(node.right));
    }

    // return max-min<=1 to check if tree balanced
    public boolean isBalanced(Node node) {

        if (Math.abs(maxDepth(node) - minDepth(node)) <= 1)
            return true;

        return false;
    }

    public static void main(String... strings) {
        BinaryTree tree = new BinaryTree();
        tree.root = new Node(1);
        tree.root.left = new Node(2);
        tree.root.right = new Node(3);


        if (tree.isBalanced(tree.root))
            System.out.println("Tree is balanced");
        else
            System.out.println("Tree is not balanced");
    }
}

0

นี่คือสิ่งที่ฉันได้ลองทำแบบฝึกหัดโบนัสของ Eric ฉันพยายามคลายการวนซ้ำของฉันและกลับมาทันทีที่ฉันพบว่าแผนผังย่อยไม่สมดุล

int heightBalanced(node *root){
    int i = 1;
    heightBalancedRecursive(root, &i);
    return i; 
} 

int heightBalancedRecursive(node *root, int *i){

    int lb = 0, rb = 0;

    if(!root || ! *i)  // if node is null or a subtree is not height balanced
           return 0;  

    lb = heightBalancedRecursive(root -> left,i);

    if (!*i)         // subtree is not balanced. Skip traversing the tree anymore
        return 0;

    rb = heightBalancedRecursive(root -> right,i)

    if (abs(lb - rb) > 1)  // not balanced. Make i zero.
        *i = 0;

    return ( lb > rb ? lb +1 : rb + 1); // return the current height of the subtree
}

0
public int height(Node node){
    if(node==null)return 0;
    else{
        int l=height(node.leftChild);
        int r=height(node.rightChild);
       return(l>r?l+1:r+1);

}}
public boolean balanced(Node n){

    int l= height(n.leftChild);
    int r= height(n.rightChild);

    System.out.println(l + " " +r);
    if(Math.abs(l-r)>1)
        return false;
    else 
        return true;
    }

0

ต้นไม้ที่ว่างเปล่ามีความสมดุลสูง ต้นไม้ไบนารีที่ไม่ว่างเปล่า T จะสมดุลถ้า:

1) แผนผังย่อยด้านซ้ายของ T มีความสมดุล

2) แผนผังย่อยด้านขวาของ T มีความสมดุล

3) ความแตกต่างระหว่างความสูงของทรีย่อยด้านซ้ายและทรีย่อยด้านขวาไม่เกิน 1

/* program to check if a tree is height-balanced or not */
#include<stdio.h>
#include<stdlib.h>
#define bool int

/* A binary tree node has data, pointer to left child
   and a pointer to right child */
struct node
{
  int data;
  struct node* left;
  struct node* right;
};

/* The function returns true if root is balanced else false
   The second parameter is to store the height of tree.  
   Initially, we need to pass a pointer to a location with value 
   as 0. We can also write a wrapper over this function */
bool isBalanced(struct node *root, int* height)
{
  /* lh --> Height of left subtree 
     rh --> Height of right subtree */   
  int lh = 0, rh = 0;  

  /* l will be true if left subtree is balanced 
    and r will be true if right subtree is balanced */
  int l = 0, r = 0;

  if(root == NULL)
  {
    *height = 0;
     return 1;
  }

  /* Get the heights of left and right subtrees in lh and rh 
    And store the returned values in l and r */   
  l = isBalanced(root->left, &lh);
  r = isBalanced(root->right,&rh);

  /* Height of current node is max of heights of left and 
     right subtrees plus 1*/   
  *height = (lh > rh? lh: rh) + 1;

  /* If difference between heights of left and right 
     subtrees is more than 2 then this node is not balanced
     so return 0 */
  if((lh - rh >= 2) || (rh - lh >= 2))
    return 0;

  /* If this node is balanced and left and right subtrees 
    are balanced then return true */
  else return l&&r;
}


/* UTILITY FUNCTIONS TO TEST isBalanced() FUNCTION */

/* Helper function that allocates a new node with the
   given data and NULL left and right pointers. */
struct node* newNode(int data)
{
    struct node* node = (struct node*)
                                malloc(sizeof(struct node));
    node->data = data;
    node->left = NULL;
    node->right = NULL;

    return(node);
}

int main()
{
  int height = 0;

  /* Constructed binary tree is
             1
           /   \
         2      3
       /  \    /
     4     5  6
    /
   7
  */   
  struct node *root = newNode(1);  
  root->left = newNode(2);
  root->right = newNode(3);
  root->left->left = newNode(4);
  root->left->right = newNode(5);
  root->right->left = newNode(6);
  root->left->left->left = newNode(7);

  if(isBalanced(root, &height))
    printf("Tree is balanced");
  else
    printf("Tree is not balanced");    

  getchar();
  return 0;
}

ความซับซ้อนของเวลา: O (n)


0

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

class Node {
    Node left;
    Node right;
    int value;
    int height;
}

ตัวอย่างการใช้งานการเพิ่มและการลบเดียวกัน

void addNode(Node root,int v)
{    int height =0;
     while(root != null)
     {
         // Since we are adding new node so the height 
         // will increase by one in each node we will pass by
         root.height += 1;
         height++;
         else if(v > root.value){
            root = root.left();
            }
         else{
         root = root.right();
         }

     }

         height++;
         Node n = new Node(v , height);
         root = n;         
}
int treeMaxHeight(Node root)
{
 return Math.Max(root.left.height,root.right.height);
}

int treeMinHeight(Node root)
{
 return Math.Min(root.left.height,root.right.height);

}

Boolean isNodeBlanced(Node root)
{
   if (treeMaxHeight(root) - treeMinHeight(root) > 2)
       return false;

  return true;
}

Boolean isTreeBlanced (Node root)
{
    if(root == null || isTreeBalanced(root.left) && isTreeBalanced(root.right) && isNodeBlanced(root))
    return true;

  return false;

}

-1
    static boolean isBalanced(Node root) {
    //check in the depth of left and right subtree
    int diff = depth(root.getLeft()) - depth(root.getRight());
    if (diff < 0) {
        diff = diff * -1;
    }
    if (diff > 1) {
        return false;
    }
    //go to child nodes
    else {
        if (root.getLeft() == null && root.getRight() == null) {
            return true;
        } else if (root.getLeft() == null) {
            if (depth(root.getRight()) > 1) {
                return false;
            } else {
                return true;
            }
        } else if (root.getRight() == null) {
            if (depth(root.getLeft()) > 1) {
                return false;
            } else {
                return true;
            }
        } else if (root.getLeft() != null && root.getRight() != null && isBalanced(root.getLeft()) && isBalanced(root.getRight())) {
            return true;
        } else {
            return false;
        }
    }
}

-2

จะไม่ทำงานนี้?

return ( ( Math.abs( size( root.left ) - size( root.right ) ) < 2 );

ต้นไม้ที่ไม่สมดุลจะล้มเหลวเสมอ


4
ต้นไม้ที่สมดุลจำนวนมากก็จะล้มเหลวเช่นกัน
Brian
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.