• PHP 将二叉查找树转换为双向链表,要求不能创建新节点,只能调节节点指针


    <?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

     

  • 相关阅读:
    C#8.0——异步流(AsyncStream)
    递归,循环,尾递归
    C#7.2——编写安全高效的C#代码
    Ocelot中文文档-Route
    Ocelot中文文档-Configuration
    Ocelot中文文档-Not Supported
    Ocelot中文文档-Getting Started
    .NET 单元测试的利剑——模拟框架Moq(简述篇)
    输入五个数字,按从大到小的顺序输出
    函数和方法的区别
  • 原文地址:https://www.cnblogs.com/zemliu/p/2704881.html
Copyright © 2020-2023  润新知