web-dev-qa-db-ja.com

バイナリツリーのバランスが取れているかどうかを判断する方法

それらの学年からしばらく経ちました。病院でITスペシャリストとして仕事に就きました。現在、実際のプログラミングを行うために移動しようとしています。私は現在バイナリツリーに取り組んでおり、ツリーの高さのバランスが取れているかどうかを判断する最善の方法は何だろうと考えていました。

私はこれに沿って何かを考えていました:

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;
}

これは良い実装ですか?または私は何かが欠けていますか?

110
user69514

他の何かを探している間にこの古い質問に出くわしました。完全な答えが得られなかったことに気付きました。

この問題を解決する方法は、作成しようとしている関数の仕様を記述することから始めます。

仕様:整形式の二分木は、(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)

それを選択したプログラミング言語に翻訳するのは簡単なはずです。

ボーナスエクササイズ:この単純なコードスケッチは、高さを計算するときにツリーを何度も横断します。もっと効率的にできますか?

スーパーボーナスエクササイズ:ツリーが大規模にアンバランスであると仮定します。同様に、一方の側に100万ノード、もう一方の側に3つのノードがあります。このアルゴリズムがスタックを爆破するシナリオはありますか?大きく不均衡なツリーが与えられた場合でも、スタックを爆破しないように実装を修正できますか?

UPDATE:Donal Fellowsは答えとして、選択できる「バランスのとれた」にはさまざまな定義があると指摘しています。たとえば、「高さバランス」のより厳密な定義を採用し、nearest空の子へのパスの長さがパスの1つ内にあることを要求できます。 farthest空の子へ。私の定義はそれよりも厳密ではないため、より多くの木を認めています。

また、私の定義よりも厳密でない場合があります。バランスのとれたツリーとは、各ブランチの空のツリーへの最大パス長が2、3、または他の定数以下であると言うことができます。または、最大パス長は最小パス長の半分または4分の1などです。

通常、それは本当に重要ではありません。ツリーバランシングアルゴリズムのポイントは、片側に100万個のノードがあり、反対側に3個のノードがある状況で、終了しないようにすることです。 Donalの定義は理論上は問題ありませんが、実際には、そのレベルの厳密さを満たすツリーバランシングアルゴリズムを考えると苦痛になります。パフォーマンスの節約は、通常、実装コストを正当化しません。実際にはほとんど違いのないレベルのバランスを達成するために、不必要なツリーの再配置を行うのに多くの時間を費やします。理論上、完全にバランスの取れたツリーで20だけしか取れない場合に、100万ノードの不完全にバランスの取れたツリーで最も遠い葉に到達するのに40の枝が必要な場合、誰が気にしますか?重要なのは、100万を要することはないということです。通常、100万の最悪のケースから40の最悪のケースに到達するだけで十分です。最適なケースに至るまですべてを進める必要はありません。

161
Eric Lippert

バランスは本当に微妙な特性です。あなたはそれが何であるかを知っていると思うが、間違いを犯すのはとても簡単だ。特に、Eric Lippertの(良い)答えさえもオフです。それは、高さの概念では不十分だからです。ツリーの最小および最大の高さの概念が必要です(最小の高さとは、ルートからリーフまでの最小ステップ数であり、最大値は...ええと、画像が得られます)。そのため、バランスを次のように定義できます。

ブランチの最大の高さがoneブランチの最小の高さ以下であるツリー。

(これは実際には、ブランチ自体のバランスが取れていることを意味します。最大と最小の両方で同じブランチを選択できます。)

このプロパティを確認するために必要なことは、現在の深さを追跡する単純なツリー走査だけです。最初にバックトラックすると、ベースラインの深さがわかります。その後、バックトラックするたびに、新しい深度をベースラインと比較します

  • ベースラインに等しい場合は、そのまま続行します
  • 複数の異なる場合、ツリーはバランスが取れていません
  • 1回限りの場合は、バランスの範囲がわかっているので、その後のすべての深度(バックトラックしようとしているとき)は最初または2番目の値のいずれかでなければなりません。

コード内:

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

OK、少し乱雑ですが、ルートの両側はバランスが取れています:Cは深さ2、ABDEは深さ3です、およびFGHJは深さ4です。左ブランチの高さは2です(ブランチを横断すると高さが減少することに注意してください)。右ブランチの高さは3です。しかし、CFの間には2の高さの差があるため、ツリー全体はnotバランスです。ミニマックス仕様が必要です(ただし、実際のアルゴリズムは、2つの高さしか許可されていないため、それほど複雑ではありません)。

26
Donal Fellows

ボーナス運動応答。シンプルなソリューション。明らかに、実際の実装では、ユーザーが応答に身長を含めることを要求することを避けるために、これまたは何かをラップするかもしれません。

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     
22
Brian

これは、ツリーの最上位のバランスが取れているかどうかのみを判断します。つまり、左端と右端に2つの長い枝があり、中央に何もないツリーを作成できますが、これはtrueを返します。 trueを返す前に、root.leftroot.rightを再帰的にチェックして、内部でバランスが取れているかどうかを確認する必要があります。

21
Jesse Rusak

注文後の解決策は、一度だけツリーをたどります。時間の複雑さは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);
    }
}
19
Jiaji Li

高さのバランスの取れた二分木の定義は次のとおりです。

everyノードの2つのサブツリーの高さが1を超えて異なることのないバイナリツリー。

したがって、空のバイナリツリーは常に高さのバランスが取れています。
次の場合、空でない二分木は高さのバランスが取れています:

  1. 左のサブツリーは高さのバランスが取れています。
  2. 右のサブツリーは高さのバランスが取れています。
  3. 左右のサブツリーの高さの差は1以下です。

ツリーを考えてみましょう:

    A
     \ 
      B
     / \
    C   D

見てわかるように、Aの左側のサブツリーは(空であるため)高さのバランスが取れており、右側のサブツリーも同様です。ただし、左のサブツリーの高さが0で、右のサブツリーの高さが2であるため、条件3が満たされないため、ツリーの高さのバランスが取れていません。

また、左と右のサブツリーの高さが等しい場合でも、次のツリーは高さのバランスが取れていません。既存のコードはtrueを返します。

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

したがって、def内のWordeveryは非常に重要です。

これは動作します:

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 Link

15
codaddict

バイナリツリーがバランスされているかどうかは、レベル順走査によってチェックできます。

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;
}
7
lucky

これは実際よりもずっと複雑になっています。

アルゴリズムは次のとおりです。

  1. A =最高レベルのノードの深さ
  2. B =最下位レベルのノードの深さ

  3. Abs(A-B)<= 1の場合、ツリーはバランスが取れています

7
Mike

バランスの意味は、手元の構造に少し依存します。たとえば、Bツリーのノードはルートから一定の深さを超えることはできません。または、その点で、ルートから一定の深さにすべてのデータが存在しますが、葉から葉への分布が不均衡になる場合があります-しかし、1つのノードは不均一です。スキップリストは、バランスの点でまったく考えがありません。代わりに、まともなパフォーマンスを達成する確率に依存しています。フィボナッチツリーは意図的にバランスが崩れ、場合によってはより長い更新と引き換えにリバランスを延期して優れた漸近的なパフォーマンスを実現します。 AVLツリーと赤黒ツリーはメタデータを各ノードに付加して、深度バランス不変を達成します。

これらの構造およびその他のすべては、ほとんどの一般的なプログラミングシステムの標準ライブラリに存在します(python、RAGE!を除く)。 1つまたは2つの実装はプログラミングの優れた実践ですが、市販のコレクションで満たす必要のない特殊なパフォーマンスの問題がない限り、生産のために独自にロールするのに時間を有効に使用することはおそらくありません。

注1:サブツリーの高さは一度だけ計算されます。

注2:左のサブツリーのバランスが崩れている場合、100万個の要素を含む可能性のある右のサブツリーの計算はスキップされます。

// 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;
}
4
Arun
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));
}
3
sdk

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);
            }
        }
    }
}
3
sbp

バランシングは通常、各方向の最長パスの長さに依存します。上記のアルゴリズムはあなたのためにそうするつもりはありません。

何を実装しようとしていますか?周囲には自己分散ツリーがあります(AVL /赤黒)。実際、Javaツリーはバランスが取れています。

3
Uri

これがあなたのjobの場合、私は提案します:

  1. 車輪を再発明しない および
  2. COTSを使用/購入 ビットをいじる代わりに。
  3. ビジネス上の問題を解決するための時間/エネルギーを節約します。
3
Steven A. Lowe
#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;
}
2
Frank Raaj

RE:BFSを使用してレベル順のトラバーサルを行う@luckyのソリューション。

ツリーをトラバースし、ノードがリーフである最小レベルを記述するvars min/max-levelへの参照を保持します。

@luckyソリューションには修正が必要だと思います。 @codaddictが示唆するように、ノードがリーフかどうかをチェックするのではなく、左または右の子がnull(両方ではない)であるかどうかをチェックする必要があります。そうでない場合、アルゴリズムはこれを有効な平衡ツリーと見なします。

     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)スペースで動作する最初の質問で提供されるすべての規定を満たす必要があります。メモリオーバーフローは、再帰呼び出しスタックを爆破するのではなく、ヒープに向けられます。

または、最初にツリーをトラバースして、各ルートサブツリーの最大高さを繰り返し計算します。次に、別の反復実行で、各ルートの左右のサブツリーのキャッシュされた高さが複数回異なることがないかどうかを確認します。これは、O(n)時間とO(n)スペースでも実行されますが、スタックオーバーフローが発生しないように繰り返し実行されます。

1
vikasnair

これは、一般的な深さ優先走査に基づいたバージョンです。他の正解よりも速く、言及されたすべての「課題」を処理する必要があります。スタイルをおologiesびしますが、私はJavaを本当に知りません。

Maxとminの両方が設定されており、差が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
Potatoswatter
/* 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
Intuiter

さて、左右の高さを決定する方法が必要です。左右のバランスが取れている場合。

そして、私はただreturn height(node->left) == height(node->right);

height関数の作成については、以下をお読みください: nderstanding recursion

1
tpdi

どんな木について話しているのですか? 自己バランス があります。バランスを維持するためにツリーの順序を変更する必要があるかどうかを判断するアルゴリズムを確認してください。

1
lothar

空のツリーは高さのバランスが取れています。空でないバイナリツリー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
Saqlain

エリックのボーナスエクササイズのために試したことがあります。再帰的なループを解き、バランスが取れていないサブツリーを見つけたらすぐに戻ります。

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
Sudharsanan

特に大きなツリーでパフォーマンスを向上させるには、各ノードの高さを保存して、スペースとパフォーマンスのトレードオフを実現します。

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;

}
0
Maher Rezeq
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
always
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
Pranay