<?php
    #将二叉查找树转换为双向链表,要求不能创建新节点,只能调节节点指针
    
    #解题思路是从树的底层开始,调整每个节点的左右子树,将左子树的最大节点与根节点相连,将又子树的最小节点与根节点相连
    #我们把节点的left当做链表的pre指针,right当做链表的next指针
    #直到所有子树以及根节点转换完成

    #树节点
    class Node {
        public $data = null;
        public $parent = null;
        public $left = null;
        public $right = null;
    }

    #查找树最小节点
    function search_min($root) {
        $cnode = $root;
        while ($cnode->left != null) {
            $cnode = $cnode->left;
        }

        return $cnode;
    }

    #查找树的最打节点
    function search_max($root) {
        $cnode = $root;
        while ($cnode->right != null) {
            $cnode = $cnode->right;
        }

        return $cnode;
    }

    #查找某个节点中序遍历的前趋
    function predecessor($node) {
        #如果该节点存在左子树,则查找其左子树的最大值
        if ($node->left != null) {
            return search_max($left);
        }

        #否则查找其父节点,直到当前节点是其父节点的右孩子
        $p = $node->parent;
        while ($p != null && $node == $p->left) {
            $node = $p;
            $p = $p->parent;
        }

        return $p;
    }

    #查找某个节点中序遍历的后继
    function successor($node) {
        #如果该节点存在右子树,则查找其右子树的最小值
        if ($node->right != null) {
            return search_min($node->right);
        }

        #否则查找其父节点,直到当前节点是其父节点的左孩子
        $p = $node->parent;
        while ($p != null && $node == $p->right) {
            $node = $p;
            $p = $p->parent;
        }

        return $p;
    }

    #插入节点
    function insert_node($root, $node) {
        $cnode = $root;
        $p = $root;
        #查找合适的插入位置
        while ($cnode != null) {
            $p = $cnode;    
            if ($cnode->data > $node->data) {
                $cnode = $cnode->left;
            } else {
                $cnode = $cnode->right;
            }
        }

        if ($p == null) { #如果p为null,说明是空树
            $root = $node;
        } else {
            if ($p->data > $node->data) {
                $p->left = $node;
            } else {
                $p->right = $node;
            }
            $node->parent = $p;    
        }

        return $root;
    }

    #删除结点
    function delete_node($root, $dnode) {
        if ($dnode->left != null || $dnode->right != null) {
            $c = $dnode;
        } else {
            $c = successor($dnode);
        }

        if ($c->left != null) {
            $s = $c->left;
        } else {
            $s = $c->right;
        }

        if ($s != null) {
            $s->parent = $c->parent;
        }

        if ($c->parent == null) { #c是根节点
            $root = $s;
        } else if ($c == $c->parent->left) {
            $c->parent->left = $s; 
        } else {
            $c->parent->right = $s;
        }

        if ($dnode != $c) {
            $dnode->data = $c->data;
        }

        return $root;
    }

    #使用数组建立二叉查找树
    function build_btree($a) {
        $root = new Node();
        $root->data= $a[0];

        for ($i = 1; $i < count($a); $i++) {
            $node = new Node();
            $node->data = $a[$i];
            insert_node($root, $node);
        }

        return $root;
    }

    #二叉树中序遍历
    function inorder_traverse($root) {
        if ($root->left != null) {
            inorder_traverse($root->left);
        }

        echo $root->data . " ";

        if ($root->right != null) {
            inorder_traverse($root->right);
        }
    }

    #链表的遍历
    function linked_list_traverse($head) {
        $node = $head;
        while ($node != null) {
            echo $node->data . " ";
            $node = $node->right;
        }
    }

    #二叉查找树变双向链表
    function change($root) {
        #如果有子节点,就往子节点递归,直到最后一个非叶子节点,将他们的左右子节点连接成链表
        #然后逐层往上递归
        if ($root->left != null) {
            btree_to_doublelist($root->left);
            #这里不用担心调整左右节点以后search_max查找出来的节点会出错,因为虽然调整以后树的结构变了,但是他依然保有二叉树的性质
            #看图1就知道了
            $predecessor = search_max($root->left);
            $predecessor->right = $root;
            $root->left = $predecessor;
        }

        if ($root->right != null) {
            btree_to_doublelist($root->right);
            $successor = search_min($root->right);
            $successor->left = $root;
            $root->right = $successor;
        }
    }

    function btree_to_doublelist($root) {
        #链表头节点就是二叉查找树的最小节点
        $head = search_min($root);
        change($root);
        return $head;
    }

    $a = array(10, 6, 14, 4, 8, 12, 16);
    $root = build_btree($a);
    inorder_traverse($root);
    echo "<br>";
    $link_head = btree_to_doublelist($root);
    linked_list_traverse($link_head);
    echo "<br>";
?>

4 6 8 10 12 14 16 
4 6 8 10 12 14 16

 

posted on 2012-09-26 23:19  ZimZz  阅读(564)  评论(0编辑  收藏  举报