赞
踩
二叉树由结点有限的集合组成,或者为空集,或者由一个根结点及两棵不相交的左子树和右子树构成
例如
N个结点的树有多少种不同的形态(设点、边没有标签)
易知
$$
\begin{aligned}
f(1)&=1\
f(2)&=f(1)\cdot f(0)+f(0)\cdot f(1)\
f(3)&=f(2)\cdot f(0)+f(1)\cdot f(1)+f(0)\cdot f(2)\
\cdots\
f(n)&=\sum_{i=0}^{n-1}f(n-i-1)f(i)\quad
\end{aligned}$$
所以 f ( n ) = 1 n + 1 C 2 n n f(n)=\frac{1}{n+1}C_{2n}^n f(n)=n+11C2nn(卡特兰数)
N个结点的树有多少边
除了根结点每个结点都有一条边进入,所以是N-1条边
满二叉树的结点要么度数为0,要么度数为2,没有度数为1的结点
完全二叉树只有最下面两层结点度数可以小于2,最下面一层的结点都在该层最左边、最连续的位置上
特点:
当二叉树的结点出现空指针时,就增加一个特殊结点——空树叶,扩充的二叉树时满二叉树
示例:
性质:
E = I + 2 n E=I+2n E=I+2n,其中n时内部结点的个数
如上图中E = 3+4+4+3+4+4+3+4+4+3+3=39
I = 0+1+2+3+2+3+1+2+3+2=19
template <class T> class BinaryTreeNode { friend class BinaryTree<T>;//声明二叉树为友元类 private: T info;//二叉树结点数据 public: BinaryTreeNode();//缺省的构造 BinaryTreeNode(const T& ele);//给定数据的构造 BinaryTreeNode(const T& ele, BinaryTreeNode<T> *l, BinaryTreeNode<T> *r);//子树构造 T value() const;//返回当前结点数据 BinaryTreeNode<T>* leftchild() const;//返回左子树 BinaryTreeNode<T>* rightchild() const;//返回右子树 void setLeftchild(BinaryTreeNode<T>*);//设置左子树 void setRightchild(BinaryTreeNode<T>*);//设置右子树 void setValue(const T& val);//设置数据域 bool isLeaf() const;//判断是否为叶结点 BinaryTreeNode<T>& operator = (const BinaryTreeNode<T>& Node);//重载赋值操作符 };
template <class T> class BinaryTree { private: BinaryTreeNode<T>* root;//二叉树根结点 public: BinaryTree() { root = NULL; } ~BinaryTree() { DeleteBinaryTree(root); } bool isEmpty() const;//判定是否为空树 BinaryTreeNode<T>* Root()//返回根结点 { return root; } BinaryTreeNode<T>* Parent(BinaryTreeNode<T> *current);//返回父 BinaryTreeNode<T>* LeftSibling(BinaryTreeNode<T> *current);//左兄 BinaryTreeNode<T>* RightSibling(BinaryTreeNode<T> *current);//右兄 void CreateTree(const T& info, BinaryTree<T>& leftTree, BinaryTree<T>& rightTree);//构造树 void PreOrder(BinaryTreeNode<T> *root);//前序遍历 void InOrder(BinaryTreeNode<T> *root);//中序遍历 void PostOrder(BinaryTreeNode<T> *root);//后序遍历 void LevelOrder(BinaryTreeNode<T> *root);//按层次遍历 void DeleteBinaryTree(BinaryTreeNode<T> *root);//删除二叉树 }
按一定层次访问二叉树的过程,每个结点正好被访问一次,实质是把二叉树的结点放入一个线性序列的过程
分为深度优先和广度优先两种
template <class T>
void DepthOrder(BinaryTree<T>* root)
{
if(root != NULL)
{
visit(root); //前序
DepthOrder(root->leftchild());
visit(root); //中序
DepthOrder(root->rightchild());
visit(root); //后序
}
}
周游的时间复杂度O(n),空间复杂度为O(n)
从根结点开始从上至下逐层遍历,同层结点按照从左到右的顺序遍历
各结点随机存储在内存空间,结点之间关系用指针表示,除了本身数据之外每个结点再设置两个指针字段left和right,分别指向左孩子和右孩子,这种结构成为二叉链表表示法
也可以增加一个指向父节点的指针parent,形成三叉链表,这种链表提供了向上访问的能力
按照一定次序,用一组地址连续的存储单元存储二叉树上的各个结点元素,排成的序列需要能够通过结点在序列中的相对位置确定结点间的逻辑关系
结点i的左子女是结点2i+1,右子女是结点2i+2,父结点是 ⌊ ( i − 1 ) / 2 ⌋ \lfloor(i-1)/2\rfloor ⌊(i−1)/2⌋,左兄是结点i-1,右兄是结点i+1
二叉搜索树具有以下性质
从根结点开始检索,如果结点值为k,检索结束,如果k小于结点的值,只需要检索左子树,如果K大于结点的值,只需要检索右子树,一直持续到k被找到或者遇上了一个树叶
基本步骤与搜索类似,先要进行一次失败的查找,再执行插入
对于一个给定的关键码集合从一个空的二叉树一个个插进去
对于待删除结点pointer,删除过程如下
这样会导致二叉树高度失衡,使得效率降低
改进的思想如下
分为最小值堆和最大值堆,最小值堆的序列有以下特性 k i ≤ K 2 i + 1 , k i ≤ K 2 i + 2 k_i\le K_{2i+1},k_i\le K_{2i+2} ki≤K2i+1,ki≤K2i+2
最大值堆的定义类似
堆中的数据局部有序,结点与其子女之间存在大小比较关系,兄弟之间没有限定大小关系
堆是一个可以用数组表示的完全二叉树
先把新结点插入堆的最后位置,然后向上调整,使之成为堆
移出最小值后,将堆中的最后一个位置上的元素移到根结点,再利用向下调整的办法
建堆的时间复杂度是O(n),插入、删除的时间复杂度都是O(logn)
优先队列的主要特点是从一个集合中快速地查找并移出具有最大值或最小值地元素
堆是优先队列地一种自然的实现方法
一个具有n个外部结点的扩充二叉树,每个外部结点ki有一个wi与之对应,成为该外部结点的权,二叉树叶结点带权外部路径长度总和称为带权外部路径长度,具有最小带权外部路径长度的二叉树称为Huffman树
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。