数据结构-树

来源:互联网 发布:30岁开始学编程 编辑:程序博客网 时间:2024/06/04 18:01

二叉树

  1. 每个结点最多有两颗子树,结点的度最大为2
  2. 左子树和右子树是有顺序的,次序不能颠倒
  3. 节点数为n的树 深度至多为n 至少为log2(n+1)向下取整
  4. 对于任何一棵非空的二叉树,如果叶节点个数为n0,度数为2的节点个数为n2,则有: n0 = n2 + 1

存储二叉树结构的方法一般有三种,数组、链表、游标

满二叉树

高度为h的满二叉树拥有刚刚好(2^h+1 )-1个节点

完全二叉树

若二叉树高度为h,除h层外其他所有层节点个数都达到了最大个数。若h层有叶节点,则所有的叶节点从左到右排列。这就是完全二叉树

  1. 具有n的结点的完全二叉树的深度为log2n+1.
  2. 如果有一颗有n个节点的完全二叉树的节点按层次序编号,对任一层的节点i(1<=i<=n)有

    • 如果i=1,则节点是二叉树的根,无双亲,如果i>1,则其双亲节点为[i/2],向下取整
    • 如果2i>n那么节点i没有左孩子,否则其左孩子为2i
    • 如果2i+1>n那么节点没有右孩子,否则右孩子为2i+1

    tips: 编号后,左子节点的编号是父节点编号的两倍

    参考

二叉树的遍历

屏幕快照 2017-12-19 下午6.20.43.png

前序遍历:根—左—右。

  • 递归实现

  • 非递归实现

    思路:每次访问树的左节点,并将节点入栈。如果左节点为空,就取栈顶出栈,访问栈顶节点的右节点,并继续访问入栈访问左节点。代码如下:

void preOrderTraverse(Tree t) {    Stack s;     Tree tmp = t;    while((tmp != NULL) || !isEmpty(&s)) {        while(tmp != NULL) {            Push(&s, tmp);            visit(&tmp);            tmp = tmp->lchild;        }        if(!isEmpty(&s)) {            Pop(&s, &tmp);            tmp = tmp->rchild;        }    }}

中序遍历: 左-根-右

  • 递归实现

  • 非递归实现

    1. 若其左孩子不为空,则将t入栈,并将t的左孩子设置为当前的t
    2. 若其左孩子为空,则取栈顶元素并进行出栈操作,访问该结点。然后将当前的t置为栈顶结点的右孩子
    3. 直到t为空并且栈为空,则遍历结束。
void inOrderTraverse(Tree t) {    Stack s;     Tree tmp = t;    while((tmp != NULL) || !isEmpty(&s)) {        while(tmp != NULL) {            Push(&s, tmp);            tmp = tmp->lchild;        }        if(!isEmpty(&s)) {            Pop(&s, &tmp);            visit(&tmp);            tmp = tmp->rchild;        }    }}

后序遍历: 左-右-根

  • 递归实现

  • 非递归实现

    确保在访问父节点之前左右子节点都已经被访问。当前节点如果没有子节点,或者当前节点的子节点都被访问的时候,可以访问当前节点。否则将当前节点的子节点入栈。

void postOrderTraverse(Tree t) {    Stack s;     Tree cur = NULL;    Tree pre = NULL;    Push(&s, t);    while(!isEmpty(&s) {         Top(&s, &cur);        if((cur->lchild == NULL && cur->rchild == NULL)) ||                (cur->lchild == NULL && pre != NULL && pre == cur->rchild) ||                (cur->rchild == NULL && pre != NULL && pre == cur->lchild)) {                Pop(&s, &cur);                visit(cur);                pre = cur;              } else {                if(cur->lchild) {                    Push(&s, cur->lchild);                }                if(cur->rchild) {                    Push(&s, cur->rchild);                }            }        }    }}

二叉树的创建

  1. 使用访问序列建立二叉树,如 先序:ABDCEGFHI 中序:DBAEGCHFI

    屏幕快照 2017-12-19 下午9.12.37.png

    tips: 如果仅仅知道二叉树的先序遍历和后序遍历,无法确定二叉树

  2. 使用广义表来构造,如:A(B(D), C(E( ,G), F(H,I)))

    屏幕快照 2017-12-19 下午9.12.37.png

线索树

n个结点的二叉树有2n个链域,其中真正有用的是n – 1个,其它n + 1个都是空域。 为了充分利用结点中的空域,使得对某些运算更快,如前驱或后继等运算。

屏幕快照 2017-12-19 下午9.37.08.png

二叉树的应用:霍夫曼编码

参考链接

原创粉丝点击