Unity教程合集程序员unity3D技术分享

四. 树

2016-11-18  本文已影响0人  陈码工

note:
先理解思想, 再理解代码;
如下只是最基本和核心的;


树的定义

Tree是n个结点的有限集合, 非空树遵循:
(1) 有且仅有一个特定的称为根的结点;
(2) 当n>1时, 其余结点可分为m个互不相交的有限集合T1, T2, ..., Tm, 其中每个集合本身又是一棵树, 并且称为根的子树(SubTree).

树的各个名词

二叉树

二叉树的特性

证明: 利用总数和, 出入相等的关系来证明.
和等式: 二叉树中, N = n0 + n1 + n2, 不存在任何其他度(因为二叉树最大的度就是2);
出入等式: N-1(入) = n1+2*n2;
和等式代入出入等式, 则n0 = n2+1;

二叉树的存储结构

顺序存储(顺序表)

/*顺序表存储树*/
//其中parent是也可以去掉的属性;
typedef struct TreeNode{
    ElemType data;
    int lchild, rchild, parent;
}

typedef struct BinaryTree{
    TreeNode[] tree;
    int root;
}

链式存储(链表) 比较推荐

/*三叉链表*/
//如果去掉parent, 那么就是二叉链表;
typedef struct TreeNode {
    ElemType data;
    struct TreeNode *lchild, *rchild, *parent;
}

typedef struct BinaryTree{
    TreeNode *root;
}

二叉树的遍历

深度优先

1. 先序

定义: 上左右

/*先序遍历*/
void Traverse( TreeNode T[], index ) {
if (index!=-1) 
    visit(Tree[index]); 
    Traverse( T, Tree[index].lchild]);
    Traverse( T, Tree[index].rchild);  
}

2. 中序

定义: 左上右

/*中序遍历*/
void Traverse( TreeNode T[], index ) {
if (index!=-1) 
    Traverse( T, Tree[index].lchild]);
    visit(Tree[index]);
    Traverse( T, Tree[index].rchild);  
}
/*中序不递归*/
void Traverse(BiTree T, visit) {
    Stack s = new Stack();
    while (T!=null || s.isEmpty==false) {
        s.push(T); 
        T=T.left;
    } else {
        T = s.pop();
        visit(T);
        T = T.right;
    }
}

3. 后序

定义: 左右上

/*后序遍历*/
void Traverse( TreeNode T[], index ) {
if (index!=-1) 
    Traverse( T, Tree[index].lchild]);
    visit(Tree[index]);
    Traverse( T, Tree[index].rchild);  
}

广度优先

void Traverse( TreeNode T[SIZE], index) {
      for i = index ~ SIZE
          visit T[i];
}

二叉树的线索化

对于链表表示的二叉树, 我们希望能获得每个节点在遍历顺序中的前驱和后继节点, 这就是二叉树的线索化问题.

typdef struct TreeNode{
    ElemType data;
    struct TreeNode *lchild, *rchild;
    pointerTag LTag, RTag;
}

普通的树和森林

普通树的存储结构

1. 父亲表示法

typedef struct {
    ElemType data;
    int parent;
}TreeNode;

/*整棵树*/
typdef struct {
    TreeNode nodes[MAX_TREE_SIZE];
    int r, n;   //root的index和节点数目n; 
}Tree;

2. 孩子表示法

/*孩子位置链表的结点*/
typedef struct {
    int childIndex;
    struct ChildInfo *next; 
}ChildInfo ,*ChildList;
/*树中的结点*/
typedef struct {
    ElemType data;
    ChildList childs;
} TreeNode;
/*整棵树*/
typdef struct {
    TreeNode nodes[MAX_TREE_SIZE];
    int r, n;   //root的index和节点数目n; 
}Tree;

3. 孩子兄弟表示法

/*Node*/
typedef struct {
    ElemType data;
    int firstChild, nextSibling;
} TreeNode;
/*整棵树Tree*/
typdef struct {
    TreeNode nodes[MAX_TREE_SIZE];
    int r, n;   //root的index和节点数目n; 
} Tree;

树和森林与二叉树之间的转化

1. 普通树和二叉树的相互转化(基本要求)

使用孩子兄弟法: 定义二叉树T的左子节点T->lchild是first-child, 这个左子节点的右子节点T->lchild->rchild是它的next-sibling, 而这个左子节点的左子节点则是它自己的first-child, 如此递归定义, 从而实现普通的树结构转化成二叉树;
note: 转化成的二叉树的根节点肯定没有右子节点!

2. 普通森林转化成二叉树(基本要求)

note: 这次, 跟上面不同, 二叉树的根节点有右子节点, 而且是代表森林中不同的树的根节点;

普通树和森林的遍历

1. 普通树的遍历

先根遍历普通树:
先访问根结点, 然后遍历子树
==> 如果转化为二叉树的话, 映射为先序; //画图容易看出;

后根遍历普通树:
先遍历子树, 然后才访问根结点
==> 如果转化为二叉树的话, 映射为中序; //画图容易看出;

2. 森林的遍历

哈夫曼编码(Huffman coding)

node BuildHuffmanTree(C[]) {
n = C.length;
Q is a Minimum Priority built from C;
for ( i = 1~n-1)  //到第n-1次的操作后, Q中应该只有一个元素
    node z is a new node;
    z.lchild = x = Q.extractMin();
    z.rchild = y = Q.extractMin();
    z.weight = x.weight+y.weight;
    Q.insert(z);
return Q.extractMin();  //return the root of the tree;
}

Encode(C, root) {
for (i = 1~C.length) {
    j = i;
    if (C[j].parent != null) {
         if (C is C.parent.lchild) {C[i].code = 0 + C[i].code}
         if (C is C.parent.rchild) {C[i].code = 1 + C[i].code}
    }
    j = C[j].parent;
}
}
上一篇 下一篇

猜你喜欢

热点阅读