目录
一、 树
1-1 树的定义
树是由 n(n >= 0) 个结点组成的有限集 [ 具有层次关系 ] ;当 n = 0 时, 称为空树 ;对于任意一棵非空树满足 :
- 有且仅有一个特定的根节点(Root);
- 当 n>1 时,除根结点以外的其余结点可划分为 m(m>0)个互不相交的有限集 T1 , T2……,Tm,其中每个集合本身又是一棵树,并且称为根的子树 。
1-2 树的基本术语
-
双亲 、孩子 、兄弟 、 祖先 、 子孙 …
-
结点的度(Degree) :某个结点所拥有的子树个数 ;
- 度为 0 的结点称为叶子节点(Leaf)。[ 终端结点 ]
- 度不为 0 的结点称为分支节点(Branch)。[非终端结点 ]
-
树的度(Degree) :树的度是该树中所有结点度的最大值。通常将度为 m 的树 称为 m 叉树。
-
层次:根结点的层次为1,其余结点的层次等于该结点的双亲结点的层次加1
-
树的高度:树中结点的最大层次
-
森林:0个或多个不相交的树组成。对森林加上一个根,森林即成为树;删去根,树即成为森林。
1-3 树的性质
- 性质1:树中的结点总数等于所有结点的度(Degree)之和加1。
- 性质2:非空m叉树的第 i 层上最多有 m^(i+1) 个结点 (i>=1)。
- 性质3:深度(高度)为 h 的 m 叉树最多有 (m^h - 1)/(m - 1) 个结点;
二、二叉树
2-1 二叉树的定义
二叉树结构是一种简化的树型结构。是由 n (n >= 0) 个结点组成的有限集合;该集合或者为空,或者是由一个根结点和两颗互不相交的称为左子树和右子树的二叉树组成。[ 有序树 ]
每个结点的度(Degree)只可能是 0 或 1 或 2。
2-2 二叉树的性质
-
满二叉树
- 高度为 h 的二叉树中结点总数为 2^h - 1 。
- 每一层的结点数都达到最大结点数 。
-
完全二叉树
- 若深度为 h 的二叉树,前 h-1 层都是满的
- 并且第 h 层的结点从左至右依次排列
-
二叉排序树
- 树上所有结点的关键字中(左子树的结点 < 根结点 < 右子树的结点 )
-
平衡二叉树
- 树上任一结点的左子树和右子树的深度之差绝对值不超过1
- 性质1: 非空二叉树的第 i 层上至多有 2^(i+1) 个结点;
- 性质2:深度(高度)为 k 的二叉树至多有 2^k - 1个结点;
- 性质3:非空二叉树中的叶子结点数 = 所有度为2的结点数之和 + 1。[ n0 = n2 + 1 ];
- 性质4: 具有n个结点的完全二叉树的深度为⎿log2 n⏌+1。
- 性质5: 对有 n 个结点的完全二叉树编号后,第 i 个结点的编号(1<=i<=n),有:
- 如果i=1,则结点i是二叉树的根,无双亲;如果i>1,则其双亲是结点⎿i/2⏌。
- 如果2i>n,则结点i为叶子结点,无左孩子;否则,其左孩子是结点 2i。
- 如果2i+1>n,则结点i无右孩子;否则,其右孩子是结点 2i+1 。
2-3 二叉树的存储结构
-
顺序存储
-
链式存储 //不适用于单分枝结点较多,高度变化较大的二叉树
//类定义
template <class T>
struct BiNode {
TElemType data; //数据域
BiNode<T> *lchild; // 左孩子的指针
BiNode<T> *rchild; //右孩子指针
};
template <class T>class BiTree {
BiNode<T> *Root; // 根指针
public:
BiTree() { Root = NULL; } // 无参构造函数,构造空树
};
2-4 二叉树的遍历
- 先序遍历(Pre-Order) [ 根左右 ]
template <class T>
void BiTree<T>::PreOrder() {
PreOrder(Root);
}
template <class T>
void BiTree<T>::PreOrder(BiNode<T> *p) {
if(p==NULL)
return; // 若二叉树为空,则遍历结束
cout << p->data; // 访问当前结点
PreOrder(p->lchild); // 先序遍历当前结点的左子树
PreOrder(p->rchild); // 先序遍历当前结点的右子树
}
- 中序遍历 (In-Order)[ 左根右 ]
template <class T>
void BiTree<T>::InOrder(BiNode<T> *p) {
if(p==NULL)
return; // 若二叉树为空,则遍历结束
InOrder(p->lchild); // 中序遍历当前结点的左子树
cout << p->data; // 访问当前结点
InOrder(p->rchild); // 中序遍历当前结点的右子树
}
- 后序遍历 (Post-Order)[ 左右根 ]
template <class T>
void BiTree<T>::PostOrder(BiNode<T> *p) {
if(p==NULL)
return; // 若二叉树为空,则遍历结束
PostOrder(p->lchild); // 后序遍历当前结点的左子树
PostOrder(p->rchild); // 后序遍历当前结点的右子树
cout << p->data; // 访问当前结点
}
- 层序遍历
void BiTree<T>::LevelOrder( ) {
if(Root == NULL) return; // ①若二叉树为空,遍历结束
LinkQueue<BiNode<T> *> Q; // Q为指针队列
Q.EnQueue(Root); // ②将根指针加入指针队列
while( !Q.Empty() ) { // ③若指针队列不空,则循环
BiNode<T> *p = Q.DeQueue(); // ④ 出队列,得到当前指针 p
cout << p->data; // 访问当前结点
// 若 p 有左、右孩子,则左、右孩子地址进队列Q
if(p->lchild)
Q.EnQueue(p->lchild);
if(p->rchild)
Q.EnQueue(p->rchild);
}
}
2-5 二叉树的构造和析构算法
- 由单个遍历序列构造二叉树
// 由带空指针标记的先序序列构造二叉树的算法
BiTree<T>::BiTree(vector<T> &pre) {
int i = 0; // 向量pre的下标变量
Root = CreateByPre(pre, i);
}
BiNode<T> * BiTree<T>::CreateByPre(vector<T> &pre, int &i ) {
T e = pre[i]; i++; // 提取当前数据
if(e == ‘*’ ) return NULL; // 若是特殊数据,返回空指针
BiNode<T> *p = new BiNode<T>; // 创建新结点
p->data = e; p->lchild = CreateByPre(pre, i); // 创建左子树
p->rchild = CreateByPre(pre, i); // 创建右子树
return p;
}
- 由二个遍历序列构造二叉树
//由先序序列和中序序列构造二叉树的算法
BiTree<T>::BiTree(vector<T> &pre,vector<T> &mid) {
n = pre.size();
Root = CreateByPreMid(pre, mid, 0, 0, n);
}
BiNode<T> * BiTree<T>::CreateByPreMid( vector<T> &pre, vector<T> &mid,int ipre, int imid, int n) {
if(n==0) return NULL;
BiNode<T> *p = new BiNode<T>; // 创建新结点(根结点)
p->data = pre[ipre];
for(int i = 0; i < n; i++) // 在中序序列中定位根结点
if(pre[ ipre ] == mid[ imid + i ]) { break; }
// 创建左、右子树
p->lchild = CreateByPreMid(pre, mid, ipre+1, imid, i );
p->rchild = CreateByPreMid(pre, mid, ipre+i+1, imid+i+1, n-i-1);
return p;
}
- 拷贝构造二叉树
BiTree<T>::BiTree(BiTree<T> &tree) {
Root = Copy(tree.Root);
}
BiNode<T> * BiTree<T>::Copy(BiNode<T> *p) {
if(p == NULL) return NULL;
BiNode<T> *newp = new BiNode<T>;
newp->data = p->data;
newp->lchild = Copy(p->lchild); // 复制左子树
newp->rchild = Copy(p->rchild); // 复制右子树
return newp;
}
- 二叉树的析构算法
BiTree<T>::~BiTree() {
Free(Root);
}
void BiTree<T>::Free(BiNode<T> *p) {
if(p == NULL) return;
Free( p->lchild ); // 释放左子树
Free( p->rchild ); // 释放右子树
delete p; // 释放根结点
}
2-6 二叉树的其他算法
- 计算二叉树结点数
int BiTree<T>::Count() {
return Count(Root);
}
int BiTree<T>::Count(BiNode<T> *p) {
if( p == NULL ) { return 0; }
int left = Count( p->lchild );
int right = Count( p->rchild );
return 1 + left + right;
}
- 计算二叉树高度
int BiTree<T>::Height() {
return Height(Root);
}
int BiTree<T>::Height(BiNode<T> *p) {
if( p == NULL ) { return 0; }
int left = Height( p->lchild );
int right = Height( p->rchild );
if(left > right) return left+1;
else return right+1;
}
- 二叉树的查找算法
BiNode<T> * BiTree<T>::Search(T e) {
return Search(Root, e);
}
BiNode<T> * BiTree<T>::Search(BiNode<T> *p, T e) {
if( p == NULL ) { return NULL; }
if( p->data == e) { return p; } // 查找成功
BiNode<T> *q = Search(p->lchild, e);
if(q != NULL) return q; //若在左子树中查找成功,则返回
return Search(p->rchild, e); // 返回在右子树中的查找结果
}
//父结点的查找
BiNode<T> * BiTree<T>::SearchParent(BiNode<T> *child) {
return SearchParent(Root, child);
}
BiNode<T> * BiTree<T>::SearchParent(BiNode<T> *p, BiNode<T> *child) {
if(p == NULL || child == NULL) { return NULL; }
if(p->lchild == child || p->rchild == child) { return p; } // 查找成功
BiNode<T> *q = SearchParent(p->lchild, child);
if(q != NULL) return { q; } // 若在左子树中查找成功,则返回
return SearchParent(p->rchild, child); // 返回在右子树中的查找结果
}
声明:
此篇文章的主体内容均出自数据结构相关书籍,非本人原创,只是在学习的过程中觉得有必要将其写入个人博客之中,且最终目的只是为了方便自己或有需要的人进行查阅。博客中的图片为本人采用相关软件绘制。若需转载本文仍需本人同意。