树、链表

1. 树

1.1. 树(Tree)是n(n>=0)个结点的有限集。n=0时成为空树。

在任意有一颗非空树中:

  • 有且仅有一个特定的结点被称为根的结点(结点都应包括两个部分:一个是需要用的实际数据data;另一个就是存储下一个结点地址的指针,即数据域和指针域。)
  • 除根结点之外的其余数据元素被分为m(m≥0)个互不相交的集合T1,T2,……Tm-1,其中每一个集合Ti(1<=i<=m)本身也是一棵树,被称作原树的子树。(m>0时子树个数没有限制,但它们一定是互不相交的)

                                                          

 

1.2. 结点拥有的子树数目称为结点的度。

 某一结点的子树的根节点为该结点的孩子结点,该结点称为孩子结点的双亲结点。

上图中  结点A为结点B 结点C的双亲结点,B C为A的孩子结点,同一个双亲结点的孩子结点之间称为兄弟结点

没有孩子的结点(也就是度为0的结点)称为叶子(Leaf)或终端结点

至少有一个孩子的结点称为分支(Branch)或非终端结点。

 

1.3. 从根开始,根为第一层,根的孩子为第二层,依此类推

 树中结点的最大层次数称为树的深度或高度。

2. 二叉树

二叉查找树  根结点的值大于左子树的任一结点的值,小于其 右子树任一结点的值

2.1. 二叉树:每个结点至多拥有两颗子树(即二叉树中不存在度大于2的结点),并且二叉树的子树有左右之分,顺序不能颠倒

2.2. 二叉树性质

  • 在二叉树的第 i 层上最多有 2^(i-1)个结点。 (i>=1) 
  • 二叉树中如果深度为K,那么二叉树最多有2^(k) - 1个结点。(k>=1)
  • n0 = n2 +1  n0表示度数为0的结点数,n2表示度数为2的结点数
  • 完全二叉树中,具有n个结点的二叉树的深度为 [log2n]+1 ,其中[log2n]向下取整。

对二叉树进行编号,二叉树中任意一个编号为 i 的结点有如下特性:

  1. 若 i = 1,则该结点是二叉树的根,无双亲,否则编号为[ i / 2]的结点为其双亲结点;
  2. 若 2i > n,则该结点无左孩子,否则编号为 2i 的结点为其左孩子结点;
  3. 若 2i +1 > n,则该结点无有孩子结点,否则,编号为 2i + 1 的结点为其有孩子结点;

2.3. 完美二叉树(Perfect Binary Tree)

一个深度为k(k >= -1) 且有 2^(k+1) -1 个结点的二叉树称为完美二叉树。(满二叉树)

2.4. 完全二叉树 (Complete Binary Tree) 

完全二叉树从根结点到倒数第二层满足完美二叉树,最后一层可以不完全填充,其叶子结点都靠左对齐。

右图中如果将编号11(k)结点从编号6(F)的左儿子位置移动到编号5(E)的右儿子位置,则变成一棵完全二叉树。

        

 2.5. 完满二叉树

所有非叶子结点的度都是2 (只要有孩子结点,就必然有两个孩子结点)

2.6. 完美二叉树、完全二叉树、完满二叉树等价关系

  • 完美二叉树一定是完全二叉树,但完全二叉树不一定是完美二叉树;
  • 完美二叉树一定是完满二叉树,但完满二叉树不一定是完美二叉树;
  • 完全二叉树可能是完美二叉树,完满二叉树也可能是完全二叉树;
  • 既是完全二叉树又是完满二叉树也不一定是完美二叉树;

2.7. 斜树

斜树:所有的结点都只有左子树的二叉树叫左斜树。所有结点都是只有右子树的二叉树叫右斜树。这两者统称为斜树。

2.8. 二叉树遍历

已知中序遍历和后序遍历,可确定一棵二叉树。后序遍历最后一个结点为树的根结点

已知前序遍历和后序遍历序列,不可以唯一确定一棵二叉树。

先序遍历,从二叉树的根节点出发,第一次到达结点时就输出数据。按照从左到右的方向访问。

从根结点出发,则第一次到达结点A,故输出A;
继续向左访问,第一次访问结点B,故输出B;
按照同样规则,输出D,输出H;
当到达叶子结点H,返回到D,此时已经是第二次到达D,故不在输出D,进而向D右子树访问,D右子树不为空,则访问至I,第一次到达I,则输出I;
I为叶子结点,则返回到D,D左右子树已经访问完毕,则返回到B,进而到B右子树,第一次到达E,故输出E;
向E左子树,故输出J;
按照同样的访问规则,继续输出C、F、G;

遍历结果为:A B D H I E J C F G

/*二叉树的前序遍历递归算法*/
public void PreOrderTraverse(BiTree T)
{
    if(T==NULL)
    return;
     print("结点:" + T->data);  /*显示结点数据
    PreOrderTraverse(T->lchild);    /*再先序遍历左子树*/
    PreOrderTraverse(T->rchild);    /*最后先序遍历右子树*/
}

中序遍历(先输出左孩子结点):从二叉树根结点出发,当第二次(判断其左孩子是否存在,不存在则输出,存在则继续向下进行这一步)到达结点时就输出结点数据,按照先向左(子树)再向右(子树)的方向访问。

从根结点出发,则第一次到达结点A,不输出A,继续向左访问,第一次访问结点B,不输出B;继续到达D,H;
到达H,H左子树为空,则返回到H,此时第二次访问H,故输出H;
H右子树为空,则返回至D,此时第二次到达D,故输出D;
由D返回至B,第二次到达B,故输出B;
按照同样规则继续访问,输出J、E、A、F、C、G;

遍历结果为:H D I B J E A F C G

/*二叉树的中序遍历递归算法*/
public void InOrderTraverse(BiTree T)
{
    if(T==NULL)
    return;
    InOrderTraverse(T->lchild); /*中序遍历左子树*/
    print("结点:" + T->data);  /*显示结点数据
    InOrderTraverse(T->rchild); /*最后中序遍历右子树*/
}

后序遍历:从二叉树根结点出发,当第三次(判断其右孩子结点是否存在)到达结点时输出结点数据,按照先向左(子树)再向右(子树)的方向访问。

从根结点出发,则第一次到达结点A,不输出A,继续向左访问,第一次访问结点B,不输出B;继续到达D,H;
到达H,H左子树为空,则返回到H,此时第二次访问H,不输出H;
H右子树为空,则返回至H,此时第三次到达H,故输出H;
由H返回至D,第二次到达D,不输出D;
继续访问至I,I左右子树均为空,故第三次访问I时,输出I;
返回至D,此时第三次到达D,故输出D;
按照同样规则继续访问,输出J、E、B、F、G、C,A;

遍历结果为:H I D J E B F G C A

/*二叉树的后序遍历递归算法*/
public void PostOrderTraverse(BiTree T)
{
    if(T==NULL)
    return;
    PostOrderTraverse(T->lchild);   /*先后序遍历左子树*/
    PostOrderTraverse(T->rchild);   /*再后续遍历右子树*/
    print("结点:" + T->data);  /*显示结点数据
}

2. 二叉链表

链表结构存储二叉树,这种链表称为二叉链表

# 定义结点代码
typedef struct BiTNode{
    TElemType data;//数据
    struct BiTNode *lchild, *rchild;//左右孩子指针
} BiTNode, *BiTree;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值