二叉树
二叉树是一种重要的数据结构,与数组、向量、链表都是一种顺序容器,它们提供了按位置访问数据的手段。但是有一个缺点,它们都是按照位置来确定数据,想要通过值来获取数据,只能通过遍历的方式。而二叉树在很大程度上解决了这个缺点,二叉树是按值来保存元素,也按值来访问元素。
二叉树由一个个节点组成,一个节点最多只能有两个子节点,从根节点开始左右扩散,分左子节点和右子节点,向下一直分支。
许多实际问题抽象出来的数据结构往往是二叉树的形式,即使是一般的树也能简单地转换为二叉树,而且二叉树的存储结构及其算法都较为简单,因此二叉树显得特别重要。二叉树是递归定义的。
(1)完全二叉树——若设二叉树的高度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第h层有叶子节点,并且叶子结点都是从左到右依次排布,这就是完全二叉树。
(2)满二叉树——除了叶结点外每一个结点都有左右子叶且叶子结点都处在最底层的二叉树。
(3)平衡二叉树——平衡二叉树又被称为AVL树(区别于AVL算法),它是一棵二叉排序树,且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
二叉树的基本性质
(1) 在非空二叉树中,第i层的结点总数不超过 , i>=1;
(2) 深度为h的二叉树最多有 个结点(h>=1),最少有h个结点;
(3) 对于任意一棵二叉树,如果其叶结点数为N0,而度数为2的结点总数为N2,则N0=N2+1;
(4) 具有n个结点的完全二叉树的深度为
(5)有N个结点的完全二叉树各结点如果用顺序方式存储,则结点之间有如下关系:
若I为结点编号则 如果I>1,则其父结点的编号为I/2;
如果2*I<=N,则其左儿子(即左子树的根结点)的编号为2*I;若2*I>N,则无左儿子;
如果2*I+1<=N,则其右儿子的结点编号为2*I+1;若2*I+1>N,则无右儿子。
(6)给定N个节点,能构成h(N)种不同的二叉树。
h(N)为卡特兰数的第N项。h(n)=C(2*n,n)/(n+1)。
(7)设有i个枝点,I为所有枝点的道路长度总和,J为叶的道路长度总和J=I+2i
二叉树的遍历
对于二叉树来讲最主要、最基本的运算是遍历。
从二叉树的递归定义可知,一棵非空的二叉树由根结点及左、右子树这三个基本部分组成。因此,在任一给定结点上,可以按某种次序执行三个操作:
(1)访问结点本身(N),
(2)遍历该结点的左子树(L),
(3)遍历该结点的右子树(R)。
遍历方法普遍有以下几种:
先序遍历(NLR)、中序遍历(LNR),后序遍历(LRN)和层次遍历。
遍历节点顺序:
先序遍历(NLR):根、左子树、右子树
中序遍历(LNR):左子树、根、右子树
后序遍历(LRN):左子树、右子树、根
层次遍历:按照从上到下、从左到右的次序进行遍历
二叉树的代码的实现
1 <?php 2 class Node{ 3 public $value; 4 public $left; 5 public $right; 6 } 7 //先序遍历 根节点 ---> 左子树 ---> 右子树 8 function preorder($root){ 9 $stack=array(); 10 array_push($stack,$root); 11 while(!empty($stack)){ 12 $center_node=array_pop($stack); 13 echo $center_node->value.' ';//先输出根节点 14 if($center_node->right!=null){ 15 array_push($stack,$center_node->right);//压入左子树 16 } 17 if($center_node->left!=null){ 18 array_push($stack,$center_node->left); 19 } 20 } 21 } 22 //中序遍历,左子树---> 根节点 ---> 右子树 23 function inorder($root){ 24 $stack = array(); 25 $center_node = $root; 26 while (!empty($stack) || $center_node != null) { 27 while ($center_node != null) { 28 array_push($stack, $center_node); 29 $center_node = $center_node->left; 30 } 31 32 $center_node = array_pop($stack); 33 echo $center_node->value . " "; 34 35 $center_node = $center_node->right; 36 } 37 } 38 //后序遍历,左子树 ---> 右子树 ---> 根节点 39 function tailorder($root){ 40 $stack=array(); 41 $outstack=array(); 42 array_push($stack,$root); 43 while(!empty($stack)){ 44 $center_node=array_pop($stack); 45 array_push($outstack,$center_node);//最先压入根节点,最后输出 46 if($center_node->left!=null){ 47 array_push($stack,$center_node->left); 48 } 49 if($center_node->right!=null){ 50 array_push($stack,$center_node->right); 51 } 52 } 53 54 while(!empty($outstack)){ 55 $center_node=array_pop($outstack); 56 echo $center_node->value.' '; 57 } 58 59 } 60 $a=new Node(); 61 $b=new Node(); 62 $c=new Node(); 63 $d=new Node(); 64 $e=new Node(); 65 $f=new Node(); 66 $a->value='A'; 67 $b->value='B'; 68 $c->value='C'; 69 $d->value='D'; 70 $e->value='E'; 71 $f->value='F'; 72 $a->left=$b; 73 $a->right=$c; 74 $b->left=$d; 75 $c->left=$e; 76 $c->right=$f; 77 preorder($a);//A B D C E F 78 echo '<hr/>'; 79 inorder($a);//D B A E C F 80 echo '<hr/>'; 81 tailorder($a);//D B E F C A
二叉树的用途
(有待更新)