数据结构-树

二叉树

  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

二叉树的应用:霍夫曼树

参考这里
https://blog.csdn.net/shuangde800/article/details/7341289

主要有两类:

  • 霍夫曼树构造条件判断树,使其比较次数最少
  • 霍夫曼编码
发布了32 篇原创文章 · 获赞 60 · 访问量 10万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章