c++数据结构–树与二叉树详解

  • Post author:
  • Post category:其他




树的定义

树(tree)是n(n>=0)个结点的有限集,它或为空树(n=0);或为非空树,对于非空树T:

(1)有且仅有一个称之为根的结点;

(2)除根以外的其余结点可分为m(m>0)个互不相交的有限集T1,T2,…,Tm,其中每一个集合本身又是一棵树,并且称为根的子树。

树的示例

树的结构定义是一个递归的定义,即在树的定义中又用到树的定义,它道出了树的固有特性。

下面介绍一些树形结构中的基本术语。



树的基本术语

  • **结点:**树中的一个独立单元,包含一个数据元素及若干指向其子树的分支,如上图中的R、A、B、C等;
  • **结点的度:**结点拥有的子树数称为结点的度。如上图R的度为3,A的度2,B的度为0,C的度为1;
  • **树的度:**树的度是树内各结点度的最大值。上图的树的度为3;
  • **叶子:**度为零的结点称为叶子或终端结点。上图中结点D、E、B、G、H、K都是树的叶子;
  • **非终端结点/分支节点:**度不为0的节点;
  • **双亲和孩子:**结点的子树称为该节点的孩子,相应地,该结点称为孩子的双亲。例如上图中A为D、E的双亲,D、E为A的孩子;
  • **兄弟:**同一个双亲的孩子之间互称兄弟。例如上图中D与E互为兄弟;
  • **祖先:**从根到该结点所经路上的所有结点。例如上图中H的祖先为R、C、F;
  • **子孙:**以某结点为根的子树中的任一结点都称为该结点的子孙。如C的子孙有F、G、H、K;
  • **节点的层次:**从根开始定义起,根为第1层,根的子节点为第2层,以此类推。树中任一结点的层次等于其双亲结点的层次加1;
  • **堂兄弟节点:**双亲在同一层的节点互为堂兄弟。如D和F;
  • **树的高度或深度:**树中节点的最大层次。如上图为4;
  • **森林:**由m(m>=0)棵互不相交的树的集合称为森林;



二叉树的定义

二叉树是n个结点所构成的集合,它或为空树(n=0);或为非空树,对于非空树T:

(1)有且仅有一个称之为根的结点;

(2)除根以外的其余结点可分为2个互不相交的有限集T1和T2,分别称为T的左子树和右子树,且T1和T2本身又都是二叉树。

二叉树与树一样具有递归性质,二叉树与树的区别主要有以下几点:

(1)二叉树每个结点至多只有两棵子树(即二叉树中不纯在度大于2的结点);

(2)二叉树的子树有左右之分,其次序不能任意颠倒。

在这里插入图片描述

上文提到的所有关于树的术语都适用于二叉树。



满二叉树与完全二叉树

满二叉树与完全二叉树是二叉树的两种特殊形态。


  • 满二叉树

定义:满二叉树是深度为k且含有 2的k次方 – 1 个结点的二叉树。

在这里插入图片描述

满二叉树的特点是:每一层上的结点数都是最大结点数,即每一层i的结点数都具有最大值 2的(i-1) 个。

可以对满二叉树的结点进行连续编号,约定编号从根结点起,自上而下,自左至右。由此可引出完全二叉树的定义。


  • 完全二叉树

定义:如果二叉树中除去最后一层节点为满二叉树,且最后一层的结点依次从左到右分布,则此二叉树被称为完全二叉树。

(或深度为k的,有n个结点的二叉树,且其每个结点都与深度为k的满二叉树中编号从1至n的结点一一对应)

在这里插入图片描述

完全二叉树的特点是:

(1)叶子结点只可能在层次最大的两层上出现;

(2)对任一结点,若其右分支下的子孙的最大层次为l,则其左分支下的子孙的最大层数必为l或l+1。



三种遍历方式

前序遍历(前根遍历):根——>左——>右

中序遍历(中根遍历):左——>根——>右

后序遍历(后根遍历):左——>右——>根

层序遍历:按照层次遍历

通过前(或后)序遍历和中序遍历的结果我们可以完全确定一个二叉树

而通过前序遍历和后序遍历的结果我们不一定能够确定一个二叉树

(这里不再证明)



二叉树ADT(含实现

#define Status int
#define MAXSIZE 100
//二叉树的链表存储形式
typedef string TElemType;
typedef struct BiNode
{
    TElemType data;                      //结点数据域
    struct BiNode* lchild, * rchild; //左右孩子指针
} BiTNode, * BiTree;
Status InitBiTree(BiTree& T,string str)//构造空二叉树T( 先序序列)
{
    //按先序次序输入二叉树中结点的值(一个字符),创建二叉链表表示的二叉树T
    string ch;
    cin >> ch;
    if (ch == str)
        T = NULL; //递归结束,建空树
    else
    {
        T = new BiTNode;
        T->data = ch;            //生成根结点
        InitBiTree(T->lchild,str); //递归创建左子树
        InitBiTree(T->rchild,str); //递归创建右子树
    }
    return 1;
}
Status ClearNode(BiTNode *T)//清除叶子
{
    delete T;
    return 1;
}
Status ClearBiTree(BiTree &T)//将二叉树清为空树(差根结点
{
    if (T->lchild != NULL&& T->rchild != NULL)
    {
        if (T->lchild != NULL)
            ClearBiTree(T->lchild);
        if (T->rchild != NULL)
            ClearBiTree(T->rchild);
    }
    else
        ClearNode(T);
    return 1;
}
Status DestroyBiTree(BiTree &T)//销毁二叉树(需上面那个递归函数
{
    ClearBiTree(T);
    ClearNode(T);
    T = NULL;
    return 1;
}
bool BiTreeEmpty(BiTree T)//若T为空二叉树,返回1
{
    if (T!=NULL)
        return 0;
    else
        return 1;
}
int BiTreeDepth(BiTree T)//返回二叉树深度
{
    int m, n;
    if (T == NULL)
        return 0; //如果是空树,深度为0,递归结束
    else
    {
        m = BiTreeDepth(T->lchild); //递归计算左子树的深度记为m
        n = BiTreeDepth(T->rchild); //递归计算右子树的深度记为n
        if (m > n)
            return (m + 1); //二叉树的深度为m 与n的较大者加1
        else
            return (n + 1);
    }
}
BiTNode *ROOT(BiTree& T)//返回根结点
{
    BiTNode *p = T;
    return p;
}
BiTNode *Value(BiTree T, TElemType e)//返回值为e的结点
{
    BiTree Q[MAXSIZE];
    int front = 0, rear = 0;
    BiTree p;
    if (T)
    {
        Q[rear] = T;
        rear++;
        while (front != rear)/*队列不空*/
        {
            p = Q[front];/*出队*/
            front = (front + 1) % MAXSIZE;
            if (p->data == e)/*如果找到*/
                return p;
            if (p->lchild)/*左树入队*/
            {
                Q[rear] = p->lchild;
                rear = (rear + 1) % MAXSIZE;
            }
            if (p->rchild)/*右树入队*/
            {
                Q[rear] = p->rchild;
                rear = (rear + 1) % MAXSIZE;
            }
        }
    }
    return NULL;
}
void Assign(BiTree T, TElemType e, TElemType value)//结点e赋值为value
{
    BiTNode *p= Value(T, e);
    p->data = value;
    return;
}
BiTNode *arent(BiTree T, TElemType e)//返回双亲,否则返回空
{
    BiTNode* p;
    if (T->lchild != NULL)
        if (T->lchild->data == e)
            return T;
    if (T->rchild != NULL)
        if (T->rchild->data == e)
            return T;
    if (T->lchild != NULL)
    {
        p = arent(T->lchild, e);
        if(p!=NULL)
            return arent(T->lchild, e);
    }
    if (T->rchild != NULL)
    {
        p = arent(T->rchild, e);
        if (p!=NULL)
            return arent(T->rchild, e);
    }
    return NULL;
}
BiTNode *LeftChild(BiTree T, TElemType e)//返回左孩子,否则返回空
{
    BiTNode* p = Value(T, e);
    return p->lchild;
}
BiTNode *RightChild(BiTree T, TElemType e)//返回右孩子,否则返回空
{
    BiTNode* p = Value(T, e);
    return p->rchild;
}
void PreOrderTraverse(BiTree T)//先序遍历
{
    if (T == NULL) { return; }
    cout << T->data << ",";// 当前节点
    PreOrderTraverse(T->lchild);
    PreOrderTraverse(T->rchild);    
}
void InOrderTraverse(BiTree T)//中序遍历
{
    if (T == NULL) { return; }
    InOrderTraverse(T->lchild);
    cout << T->data << ",";// 当前节点
    InOrderTraverse(T->rchild);    
}
void PostOrderTraverse(BiTree T)//后序遍历
{
    if (T == NULL) {return;}
    PostOrderTraverse(T->lchild);
    PostOrderTraverse(T->rchild);
    cout << T->data << ",";// 当前节点
}



其它知识点

剩下的还有一些关于森林转换二叉树、哈夫曼树和哈夫曼编码的知识点,但是我已经肝到神志不清😵了。。。下次一定,下次一定好吧🕊🕊🕊



版权声明:本文为qq_60462402原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。