5.1 树

一、树

  • 树是用来按照层次关系组织一系列数据项的方式
  • 有根树
    • 树是特殊的图T = (V, E), 节点数|V| = n, 边数|E| = e
    • 指定任一节点r ∈ V作为根后, T即称作有根树(rooted tree)
    • 任何一组有根树,可以通过引入一个节点r和一组边的情况将它们连成一颗新的有根树,这个新的有根树的根就是r
    • 对于新的有根树T,Ti称作以ri为根的子树(subtree rooted at ri), 记作Ti = subtree(ri)
  • 有序树
    • ri称作r的孩子(child), ri之间互称为兄弟(sibling)
    • r为其父亲(parent), d = degree®为r的(出)度(degree)
    • 可归纳证明: e = 所有节点的度数之和 = n - 1 = O(n)
    • 故在衡量相关复杂度时,可以n作为参照
    • 若指定Ti作为T的第i棵子树,ri作为r的第i个孩子,则称T作为有序树(ordered tree)
  • 路径 + 环路
    • V中的k + 1个节点,通过E中的k条边依次相联,构成一条路径(path),亦称通路
    • 路径长度:边数 = k
    • 环路(cycle / loop): vk = v0
  • 连通加无环
    • 节点之间均有路径,称作连通图(connected)
    • 不含环路,称作无环图(acyclic)
    • 树是无环连通图,极小连通图,极大无环图
    • 故,任一节点v与根之间存在唯一路径
    • 只要指定了根节点,每一个节点都将有一个唯一的指标,就是该节点到根节点的路径长度。可以根据该指标划分等价类。
  • 深度 + 层次
    • 不致歧义时,路径、节点和子树可相互指代。path(v) ~ v ~ subtree(v)
    • v的深度:depth(v) = |path(v)|
    • path(v)上的节点,均为v的祖先(ancestor),v是它们的后代(descendent)
    • 其中,除自身以外,是真(proper)祖先/后代
    • 半线性结构:v的祖先若存在则必然是唯一的,v的后继若存在则未必是唯一的
    • 根节点是所有节点的公共祖先,深度为0
    • 没有后代的节点称作叶子(leaf)
    • 所有叶子深度中的最大者称作树/根的高度height(v) = height(subtree(v))
    • 特别的,空树的高度取作-1
    • depth(v) + height(v) <= height(T)
      树的结构示意

二、树的表示

  • 接口
    树结构提供的接口
  • 父亲表示法
    • 观察:除根外,任一节点有且仅有一个父节点
    • 构思:将节点组织为序列,各节点分别记录,rank-秩,data-本身信息,parent-父节点的秩或位置。
    • 空间性能:O(n)
    • 时间性能:parent(): O(1); root(): O(n)或O(1); firstChild(): O(n);nextSibling(): O(n)
  • 孩子节点表示法
    • 构思:将节点组织为序列,各节点分别记录,rank-秩, data-本身信息, children-孩子列表,记录其所有的孩子节点
  • 父亲孩子表示法
    • 构思:将节点组织为序列,各节点分别记录,rank-秩,data-本身信息,parent-父亲节点,children-孩子列表
    • 缺陷:每一个节点的children引用在规模上有可能相差极其悬殊,每一个小的数据集的长度都恰好是这个节点所对应的出度,而所有这些出度的总和就是整体的边数,等于n - 1.也就是平均而言,所有这些小的数据集的规模,也就是O(1)的样子,而我们这种组织方式,有时候要长达O(n)的一个数据集
  • 长子 + 兄弟表示法
    • 构思:每个节点均设两个引用,每个节点均指向其第一个孩子节点,第一个孩子节点指向其余的孩子节点纵:firstChild(); 横:nextSibling()

三、二叉树

  • 定义:节点度数不超过2的树称作二叉树
  • 同一节点的孩子和子树,均以左、右区分,隐含了树的有序性,左在前右在后。
  • 基数:深度为k的节点,至多为2^k个
  • 在含n个节点、高度为h的二叉树中h < n < 2^(h+1)
    • n = h + 1时,退化为一条单链
    • n = 2^(h+1) - 1时,即所谓的满二叉树(full binary tree)
    • 二叉树的宽度长宽非常快,是指数型的;二叉树的高度长宽非常慢,是对数型的
  • 真二叉树:每个节点的出度都是偶数,或者是0,或者是2,但是不能是1。如果节点出度为1,就在缺失的那一侧同样引入一个孩子节点,使之为2。在实际的算法中,这种添加完全是假想,不需要真的添加孩子节点,但可使算法的实现更加简洁。
  • 如何通过二叉树描述一般意义的树
    • 二叉树是多叉树的特例,但在有根且有序时,其描述能力却足以覆盖后者
    • 转化方法:长子-兄弟表示法

四、二叉树的实现

  • BinNode模板类
#define BinNodePosi(T) BinNode<T>* //节点位置
template <typename T> struct BinNode{
	BinNodePosi(T) parent, lChild, rChild;//父亲、孩子
	T data; int height; int size(); //高度、子树规模
	BinNodePosi(T) insertAsLC(T const &);//作为左孩子插入节点
	BinNodePosi(T) insertAsRC(T const &);//作为右孩子插入节点
	BinNodePosi(T) succ();//(中序遍历意义下)当前节点的直接后续
	template <typename VST> void travLevel( VST &);//子树层次遍历
	template <typename VST> void travPre(VST &);//子树先序遍历
	template <typename VST> void travIn(VST &);//子树中序遍历
	template <typename VST> void travPost(VST&);//子树后序遍历
}
  • BinNode接口实现
template <typename T> BinNodePosi(T) BinNode<T>::insertAsLC(T const &e)
{return lChild = new BinNode(e, this);}//O(1)

template <typename T> BinNodePosi(T) BinNode<T>::insertAsRC(T const &e)
{return rChild = new BinNode(e, this);}//O(1)

template<typename T>
int BinNode<T>::size(){//后代总数,亦即以其为根的子树的规模
	int s = 1;//计入本身
	if(lChild) s += lChild->size();//递归计入左子树规模
	if(rChild) s += rChild->size();//递归计入右子树规模
	return s;
}//O(n = |size|)
  • BinTree 模板类
template <typename T> class BinTree{
protected:
	int _size;//规模
	BinNodePosi(T) _root;//根节点
	virtual int updateHeight(BinNodePosi(T) x);//更新节点x的高度
	void updateHeightAbove(BinNodePosi(T) x);//更新x及祖先的高度
public:
	int size() const {return _size;}//规模
	bool emoty() const {return !_root;}//判空
	BinNodePosi(T) root() const {return _root;}//树根
	/*...子树接入、删除和分离接口... */
	/*...遍历接口... */
}
  • 高度更新
#define stature(p) ((p) ? (p)->height : -1)//节点高度——约定空树高度为-1

template <typename T> //更新节点x高度,具体规则因树不同而异
	int BinTree<T>::updateHeight(BinNodePosi(T) x){
		return x->height = 1 + max(stature(x->lChild), stature(x->rChild));
}//此处采用常规二叉树规则,O(1)

template <typename T>//更新v及其历代祖先的高度
void BinTree<T>::updateHeightAbove(BinNodePosi(T) x){
	while(x)//可优化:一旦高度未变,即可终止
		{updateHeight(x); x = x->parent;}
}//O(n = depth)
  • 节点插入
template<typename T> BinNodePosi(T)
BinTree<T>::insertAsRC( BinNodePosi(T) x, T const & e){//insertAsLC()对称
	_size++; x->insertAsRC(e);//x祖先的高度可能增加,其余节点必然不变
	uodateHeightAbove(x);
	return x->rChild;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值