线索二叉树JS

线索二叉树

当用二叉链表来存储二叉树时,每次只能找到左右孩子的信息,不能直接找到其前驱和后继结点的信息。线索二叉树就解决了这个问题。

结点结构图:
LChild Ltag Data Rtag RChild

A.如果有左孩子,则LChild继续指向左孩子,否则,指向该结点的前驱结点。
B.如果有右孩子,则RChild继续指向右孩子,否则,指向该结点的后继结点。
Ltag 用来标记是 左孩子(Ltag = 0)还是 前驱结点 (Ltag = 1)
Rtag 用来标记是 右孩子(Rtag = 0) 还是 后继结点 (Rtag = 1)

线索链表:上面的结点结构组成的二叉树的存储结构
线索:在这种存储结构中,指向前驱和后继结点的指针
线索化:对二叉树以某种次序进行遍历并且加上线索的过程
线索二叉树:线索化的二叉树
线索二叉树JS_第1张图片
说明:画线索二叉树时,实线表示指针,指向其左、右孩子;虚线表示线索,指向其直接前驱或直接后继。

线索二叉树的遍历

var LINK = 0;
var THREAD = 1;

function BinaryThreadTree_inOrder(data, leftChild, rightChild) {
    this.data = data;
    this.leftChild = leftChild || null;
    this.rightChild = rightChild || null;
    // 左右标记
    this.leftTag = this.rightTag = undefined;
}
BinaryThreadTree_inOrder.prototype = {
    constructor: BinaryThreadTree_inOrder,
    // 中序线索二叉树的遍历
    inOrderTraverse_thread: function (visit) {
        var p = this.leftChild;

        while (p != this) {
            while (p.leftTag === LINK) p = p.leftChild;

            if (visit(p.data) === false) return;

            while (p.rightTag == THREAD && p.rightChild != this) {
                p = p.rightChild;
                visit(p.data);
            }
            p = p.rightChild;
        }
    },
    // 中序线索化
    inOrderThreading: function () {
        return inOrderThreading(this);
    },
    // 在当前结点插入子树x,p代表当前结点
    insertSubTree: function (xTree) {
        var s, q;
        // x作为p的左子树
        if (this.leftTag === THREAD) {
            s = this.leftChild; // s为p的前驱
            this.leftTag = LINK;
            this.leftChild = xTree;
            q = xTree;

            while (q.leftChild && q.leftTag === LINK) q = q.leftChild;
            // 找到子树中的最左结点,并修改其前驱指向s
            q.leftChild = s;
            xTree.rightTag = THREAD;
            // x的后继指向p
            xTree.rightChild = this;
        }
        // x作为p的右子树
        else if (this.rightTag === THREAD) {
            // s为p的后继
            s = this.rightChild;
            this.rightTag = LINK;
            this.rightChild = xTree;
            q = xTree;

            while (q.leftChild && q.leftTag === LINK) q = q.leftChild;
            // 找到子树中的最左结点,并修改其前驱指向p
            q.leftChild = this;
            xTree.rightTag = THREAD;
            // x的后继指向p的后继
            xTree.rightChild = s;
        }
        // x作为p的左子树,p的左子树作为x的右子树
        else {
            s = this.leftChild;
            var t = s;

            while (t.leftChild && t.leftTag === LINK) t = t.leftChild;
            // 找到p的左子树的最左结点t和前驱u
            var u = t.leftChild;
            this.leftChild = xTree;
            xTree.rightTag = LINK;
            // x作为p的左子树,p的左子树作为x的右子树
            xTree.rightChild = s;
            t.leftChild = xTree;
            q = xTree;

            while (q.leftChild && q.leftTag === LINK) q = q.leftChild;
            // 找到子树中的最左结点,并修改其前驱指向u
            q.leftChild = u;
        }
    }
};

// 二叉树中序线索化
function inOrderThreading(tree) {
    var threadTree = new BinaryThreadTree();
    threadTree.leftTag = LINK;
    threadTree.rightTag = THREAD;
    // 右指针回指
    threadTree.rightChild = threadTree;

    var pre;
    // 若二叉树为空,左指针回指
    if (!tree) threadTree.leftChild = threadTree;
    else {
        threadTree.leftChild = tree;
        pre = threadTree;
        inThreading(tree);  // 中序遍历进行中序线索化
        // 最后一个结点线索化
        pre.rightChild = threadTree;
        pre.rightTag = THREAD;
        threadTree.rightChild = pre;
    }

    return threadTree;

    function inThreading(p) {
        if (!p) return;

        inThreading(p.leftChild);   // 左子树线索化
        // 前驱线索
        if (!p.leftChild) {
            p.leftTag = THREAD;
            p.leftChild = pre;
        }
        // 后继线索
        if (!pre.rightChild) {
            pre.rightTag = THREAD;
            pre.rightChild = p;
        }
        pre = p;
        inThreading(p.rightChild);  // 右子树线索化
    }
}

参考:
线索二叉树
javascript实现数据结构:线索二叉树

你可能感兴趣的:(数据结构)