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