@blog.justoneplanet.info

日々勉強

二分木と二分探索木

意思の疎通が上手くいかなかったりするので、ちゃんと区別したい。で記事にした。゜(´□`。)°゜

■二分木(binary tree)

各ノードの子要素が2以下で通常は左と右と呼ばれる。

var BT = function(value){
    var self = this;
    self._left  = null;
    self._right = null;
    self.value = value;
    self.appendChild = function(child, location){
        if(location === 'left' && self._left === null){
            self._left = child;
            return true;
        }
        else if(location === 'right' && self._right === null){
            self._right = child;
            return true;
        }
        else{
            return false;
        }
    }
}

// test code
var root  = new BT(5);
var leaf1 = new BT(7);
var leaf2 = new BT(2);
var leaf3 = new BT(10);
var leaf4 = new BT(6);
var leaf5 = new BT(1);
var leaf6 = new BT(8);

root.appendChild(leaf1, 'left');
root.appendChild(leaf2, 'right');

leaf1.appendChild(leaf3, 'left');
leaf1.appendChild(leaf4, 'right');
leaf2.appendChild(leaf5, 'left');
leaf2.appendChild(leaf6, 'right');

console.log(root);
console.log(JSON.stringify(root));

■二分探索木(binary search tree)

二分木の一種だが要素の大小に『left < parent < right』という順序が成立する。

var BST = function(value){
    var self = this;
    self._left  = null;
    self._right = null;
    self.value = value;
    self.appendChild = function(child){
        if(child.value < self.value){
            if(self._left){
                self._left.appendChild(child);
            }
            else{
                self._left = child;
            }
        }
        else{
            if(self._right){
                self._right.appendChild(child);
            }
            else{
                self._right = child;
            }
        }
    }
}

// test code
var root  = new BST(5);
var leaf1 = new BST(7);
var leaf2 = new BST(2);
var leaf3 = new BST(10);
var leaf4 = new BST(6);
var leaf5 = new BST(1);
var leaf6 = new BST(8);

root.appendChild(leaf1);
root.appendChild(leaf2);
root.appendChild(leaf3);
root.appendChild(leaf4);
root.appendChild(leaf5);
root.appendChild(leaf6);

console.log(root);
console.log(JSON.stringify(root));

つまり要素の大小関係に基づいて位置が決まるのがbinary search treeであって、binary treeではないよね。ちなみに以前はめんどいから配列で実装した。配列で実現することも可能だが、木が平衡でない場合に無駄な空きができてしまう。

■文献

まぁ、色々読んだほうが早いかもしれん。

Binary tree

Binary trees are commonly used to implement binary search trees and binary heaps.

Binary search tree

In computer science, a binary search tree (BST) or ordered binary tree is a node-based binary tree data structure which has the following properties:[1]

  • The left subtree of a node contains only nodes with keys less than the node’s key.
  • The right subtree of a node contains only nodes with keys greater than the node’s key.
  • Both the left and right subtrees must also be binary search trees.

アルゴリズムクイックリファレンス(p143)

二分探索木Tは、順序特性を持つ、すなわちキーによって識別される節点の有限集合となる。節点集合は空でなければ、根節点(root node)nrを含む。節点nは、2つの二分探索木TlとTrとを持ち、節点nのキーをkとしたら、Tlのすべてのキーが≦kで、Trのすべてのキーが≧kであるという性質を保持する。この性質は、二分探索木の性質(binary-search-tree property)と呼ばれる(Cormen et al., 2001)。

■canvas

つーかさ、console.logで確認するのめんどいよね!そういうわけでcanvasで表示させます。

var BST = function(value){
    var self = this;
    self._left  = null;
    self._right = null;
    self.value = value;
    
    /**
     * appendChild
     * @param {Object} child
     */
    self.appendChild = function(child){
        if(child.value < self.value){
            if(self._left){
                self._left.appendChild(child);
            }
            else{
                self._left = child;
            }
        }
        else{
            if(self._right){
                self._right.appendChild(child);
            }
            else{
                self._right = child;
            }
        }
    }
    
    /**
     * draw
     * @param {Object} context
     * @param {int} left
     * @param {int} top
     * @param {int} center
     * @param {int} depth
     */
    self.draw = function(context, left, top, center, depth){
        if(self._left !== null){
            var cl = left - (center / Math.pow(2, depth + 1));
            var ct = top + 50
            context.fillStyle = 'black';
            context.beginPath();
            context.moveTo(left, top);
            context.lineTo(cl, ct);
            context.stroke();
            var lp = self._left.draw(context, cl, ct, center, depth + 1);
        }
        if(self._right !== null){
            var cl = left + (center / Math.pow(2, depth + 1));
            var ct = top + 50
            context.fillStyle = 'black';
            context.beginPath();
            context.moveTo(left, top);
            context.lineTo(cl, ct);
            context.stroke();
            var lp = self._right.draw(context, cl, ct, center, depth + 1);
        }
        context.fillStyle = 'red';
        context.beginPath();
        context.arc(left, top, 10, 0, Math.PI * 2, false);
        context.fill();
        
        context.font = "15px Arial bold";
        context.textAlign = "center";
        context.textBaseline = "middle";
        context.fillStyle = 'white';
        context.fillText(self.value, left, top, 30);
        return {"left" : left, "top" : top};
    }
}

// test code
var root  = new BST(5);
root.appendChild(new BST(7));
root.appendChild(new BST(2));
root.appendChild(new BST(10));
root.appendChild(new BST(6));
root.appendChild(new BST(1));
root.appendChild(new BST(8));
root.appendChild(new BST(12));
root.appendChild(new BST(11));
root.appendChild(new BST(9));
root.appendChild(new BST(4));
root.draw(document.getElementById("canvas").getContext('2d'), 200, 50, 200, 0);

おや、まぁ、なんと素敵なことでしょう!(o゚▽゚)♡

コメントはまだありません»

No comments yet.

RSS feed for comments on this post.TrackBack URL

Leave a comment