Data Structure Review Five: tree and binary tree

Definition tree and binary tree

The definition of the tree

Tree is a finite set of n nodes, n = 0 when empty tree, the tree has for a non-empty:

1, there is only one node is called the root;

2, the remaining nodes other than the root node can be divided into m disjoint finite sets T1, T2, ..., Tm, wherein each set is itself a tree, and the subtree rooted become.

The basic term of the tree

1, the node : a separate unit in the tree, comprising a plurality of data elements, and its subtree branch point;

2, of the nodes : the number of knot points have subtree;

3, of the trees : the maximum value of the nodes in the tree;

4, leaf : degree nodes (terminal node) of 0;

5, the non-terminal node : node degree is not (branch node) is 0;

6: parents and children : root of the subtree node is called a child of the node, accordingly, be a child of the parent node;

7, brothers : between a parent with a child called each other brother;

8, ancestors : the node from the root to all nodes on the branch is;

9, descendants : a node in the subtree rooted at a node become any descendants of the node;

10, level : starting from the root, root for the first layer, the hierarchical tree nodes at any level equal to its parent node plus one;

11, cousins : parent node in the same layer as each other cousins;

12, the depth of the tree : the maximum depth of the tree or hierarchy called the height of the tree node;

13, ordered and unordered tree Tree : If each of the sub-tree nodes as the order is from left to right (i.e., not interchangeable), the tree is called ordered tree, otherwise known as non- order tree. In the root of the left subtree ordered tree is called the first child, the rightmost called second child;

14, the forest : m is a collection of disjoint trees tree; tree for each node, which subtree is the set of forest.

The definition of a binary tree

Binary tree is a set composed of n nodes, n = 0 when empty tree for tree T has a non-empty:

1, there is only one node is called the root;

2, the remaining nodes other than the root node can be divided into two disjoint finite sets T1, T2, are called the left subtree of T and right subtree, and T1 and T2 are, in turn, the binary tree;

Binary Tree

The nature of binary tree

1, the i-th layer in the binary tree has at most 2^{i-1}nodes (i> = 1);

2, a binary tree of depth k at most 2^{k}-1nodes (k> = 1);

3, any binary tree T, if it is the terminal number of nodes n0, the number of nodes of degree 2 is n2, then n0 = n2 + 1;

Simple Prove: n = n0 + n1 + n2 (each sum node degree) and n = n1 + 2 * n2 + 1 (a root of the subtree and processing), to obtain simultaneous n0 = n2 + 1;

4, a complete binary tree has a depth of n nodes is \left \lfloor log_{2} n\right \rfloor+1;

5, if the node of the n nodes and a complete binary tree by a sequence number, then for any node, there are:

(1) if i = 1, i is the root node of the binary tree, no parents; if i> 1, it is the parent node \left \lfloor i/2\right \rfloor;

(2) If 2i is greater than n, the node i no left child, otherwise it is left child node 2i;

(3) If 2i + 1> n, then no right child node i, otherwise it is the right child node 2i + 1;

Full Binary : depth k and containing 2^{k}-1binary tree of nodes;

Complete binary tree : the depth k, there are n nodes in the binary tree, if and only if each of which nodes are associated with a full binary tree of depth k correspond numbered from 1 to n nodes, called complete binary tree;

Binary storage structure

Two types of storage: sequential storage, the storage chain;

When stored in order to complete binary tree, simply by starting from the root to the storage sequence; for a general binary tree, which shall control and the node on the binary tree, it is stored in the corresponding location in the one-dimensional array, the absence of labeled node 0;

Chain store:

typedef struct BiTNode{
    char data;
    struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;

Binary tree traversal

Based on the sequence preorder traversal can be divided into preorder , preorder and postorder traversals three kinds of traversal method

Preorder traversal operates as follows:

If the binary tree is empty, empty, otherwise:

1, access the root node;

2, preorder left subtree;

3, preorder right subtree;

Other so on;

Preorder:

Preorder recursive algorithm :

void PreOrderTraverse(BiTree T){
    if(T){
        cout<<T->data;
        PreOrderTraverse(T->lchild);
        PreOrderTraverse(T->rchild);
    }
    return;
} 

Preorder

In order traversal recursive algorithm :

void InOrderTraverse(BiTree T){
    if(T){
        PreOrderTraverse(T->lchild);
        cout<<T->data;
        PreOrderTraverse(T->rchild);
    }
    return;
} 

Postorder

Postorder recursive algorithm :

void PostOrderTraverse(BiTree T){
    if(T){
        PreOrderTraverse(T->lchild);
        PreOrderTraverse(T->rchild);
        cout<<T->data;
    }
    return;
} 

Application Binary Tree Traversal

Build binary list (to preorder for example)

Algorithm steps:

1, the scanning sequence of characters, characters read CH;

2, if ch is a '/' character, indicating that the binary tree is empty tree, that is, T is NULL, otherwise execute the following operations:

(1) applying a T junction point in space;

(2) assigned to the ch T-> data;

(3) create a recursive left subtree of T;

(4) recursively create the right subtree of T;

On the code:

void CreateTree(BiTree &T){//建树
    char elem;
    cin>>elem;
    if(elem=='/') T=NULL;
    else{
        T=new BiTNode;
        T->data=elem;
        CreateTree(T->lchild);
        CreateTree(T->rchild);
    }
    return;
}

There copying binary tree, binary tree computing algorithms such as depth, thinking about the same, not much to say.

Threaded binary

Threaded binary tree based on a certain rule nodes are arranged in a binary tree in linear sequence, the first sequence to obtain a sequence of nodes in a binary tree, and the subsequent sequence sequence sequence.

Changing the binary tree node structure, and increase ltag RTag two flag fields, ltag is 0, lchild pointing to the left child node, ltag is 1, lchild point node precursor; RTag time 0, rchild junction point of the right child, RTag is 1, rchild directed to the subsequent node;

Trees and Forests

Common tree storage structure:

1, parents notation

A set of contiguous node tree stored in the storage unit, each node in addition to the data field Data, also attached to a parent domain to indicate the position of its parent node;

In this memory structure, easy to find the root node of the tree, and parents, but the need to traverse the entire structure of a child node when evaluated

2, children notation

Since each node in the tree may have more subtrees, multiple available list, each pointer field points to the root of a subtree

Combined with the child and parents notation as shown below:

3, children brothers notation

In binary tree lists as storage structure, linked list node point to two chain domain of a child node of the first node, and a next sibling node, and a domain named firstchild domain nextsibling

FIG storage results are as follows:

Forest and binary conversion

1, converted into a binary tree forest

If F = {T1, T2, ..., Tm} forest, the following rules can be converted into a binary tree B = (root, LB, RB)

(1) If F is empty, i.e., m = 0, then B is empty tree;

(2) If F is not empty, i.e., m = 0, the root is the root B of forest tree root of the ROOT (T1);! LB B left subtree is the subtree root node in the forest T1 F1 = {T11, T12, ..., T1m} converted from the binary tree; RB from the right subtree of the forest F '= {T2, T3, ..., Tm} converted from the binary tree;

2, converted into a binary tree forest

If B = (root, LB, RB) is a binary tree, the following rules can be converted into F = {T1, T2, ..., Tm}:

(1) If B is empty, then F is empty;

(2) If B is not empty, then the ROOT F root tree T1 is the first (T1) B is the root of the binary tree root; T1 subtree root node in the forest F1 is converted by the left subtree of B into an LB forest; F. T1 in addition to the rest of a forest of trees F '' = {T2, T3, ..., Tm} converted from a right subtree of RB B together.

Traversing the tree and forest

1, the tree traversal

In the above an example in FIG.

First Traversal : RADEBCFGHK

后根遍历:D E A B G H K F C R

2、森林的遍历

先序遍历森林(非空):

(1)访问森林中第一棵树的根结点

(2)先序遍历第一棵树的根结点的子树森林

(3)先序遍历除去第一棵树之后剩余的树构成的森林

中序遍历森林(非空):

(1)中序遍历森林中第一棵树的根结点的子树森林

(2)访问第一棵树的根结点

(3)中序遍历除去第一棵树之后剩余的树构成的森林

哈夫曼树及其应用

哈夫曼树又称最优树,是一种带权路径长度最短的树。

结点的带权路径长度:从该结点到树根之间的路径长度与节点上权的乘积;

树的带权路径长度:树中所有叶子节点的带全路径长度之和。

构造过程:

1、根据给定的n个权值{w1,w2,…,wn},构造n棵只有根结点的二叉树,这n棵二叉树构成一个森林F;

2、在森林中选区两棵根结点的权值最小的树作为左右子树构造一棵新的二叉树,且置新的二叉树的根结点的权值为左右子树上根结点的权值之和;

3、在森林F中删除这两棵树,同时将新得到的二叉树加入F中;

4、重复(2)和(3),直到F只含一棵树为止,这棵树便是哈夫曼树。

哈夫曼树存储结构:

typedef struct HTNode{
    int weight;
    int lchild,rchild,parent;
}HTNode,*HTree;

构造哈夫曼树算法:

1、初始化:首先动态申请2n个单元;然后循环2n-1次,从1号单元开始,依次将1至2n-1所有单元中的双亲、左孩子、右孩子的下表都初始化为0;最后再循环n次,输入前n个单元中叶子节点的权值;

2、创建树:循环n-1次,通过n-1次的选择、删除与合并来创建哈夫曼树。选择是从当前森林中选择双亲为0且权值最小的两个数根节点s1和s2,删除是将s1和s2的双亲改为非0;合并就是将s1和s2的权值和作为一个新结点的权值依次存入到数组的第n+1之后的单元中,同时记录着个新结点左孩子的下标为s1,右孩子的下标为s2。

void CreateHMT(HTree &HT,int n){
    int m=2*n-1;
    HT=new HTNode[m+1];
    for(int i=1;i<=m;++i){
        HT[i].lchild=HT[i].rchild=HT[i].parent=0;
    }
    for(int i=1;i<=n;i++){
        cin>>HT[i].weight;
    }
    for(int i=n+1;i<=m;++i){
        int s1,s2;
        SelectMin(HT,i,s1,s2);
        HT[s1].parent=HT[s2].parent=i;
        HT[i].weight=HT[s1].weight+HT[s2].weight;
        HT[i].lchild=s1;HT[i].rchild=s2;
    }
    return;
}

哈夫曼编码

前缀编码:如果一个编码方案中人一个编码都不是其他任何编码的前缀,则称编码是前缀码;

哈夫曼编码:对一棵具有n个叶子的哈夫曼树,若对树中的每个做分支赋予0,右分支赋予1,则从根到每个叶子的路径上,各分支的赋值分别构成一个二进制串,该二进制串就称为哈夫曼编码

哈夫曼编码是最优前缀编码

哈夫曼编码存储表示:

typedef char **HuffmanCode; 

算法步骤:

1、分配n个字符编码的编码表空间HC,长度为n-1;分配临时存储每个字符编码的动态数组空间cd,cd[n-1]置为’\0‘;

2、逐个求解n个字符的编码,循环n次,执行以下操作:

(1)设置变量start用于记录编码在cd中存放的位置,start初始时指向最后,即编码结束符位置n-1;

(2)设置变量c用于记录从叶子结点向上回溯至根结点所经过的结点下标,c初始时为当前待编码字符的下标i,f用于记录双亲结点的下标;

(3)从叶子节点向上回溯至根结点,求得字符i的编码,当f没有到达根结点时,循环执行以下操作:

回溯依次start向前指一个位置,即--start;

若结点c是f的左孩子,则生成编码0,否则生成编码1,保存在cd[start]中;

继续向上回溯,改变c和f的值。

(4)根据数组cd的字符串长度为第i个字符编码分配空间HC[i],然后将数组cd中的编码复制到HC[i]中;

3、释放临时空间cd。

代码实现;

void CreatHFC(HTree HT,HFMCode &hc,int n){
    hc=new char*[n+1];//开n+1个1维数组空间
    char* cd=new char[n];//临时数组
    cd[n-1]='\0';
    for(int i=1;i<=n;++i){
        int start=n-1;  
        int c=i;
        int f=HT[i].parent;
        while(f!=0){
            start--;
            if(HT[f].lchild==c)
            cd[start]='0';
            else cd[start]='1';
            c=f;
            f=HT[f].parent;
        }
        hc[i]=new char[n-start];
        strcpy(hc[i],&cd[start]);
    }
    delete cd;
    return;
}

附上一条龙完整代码:

#include<bits/stdc++.h>
using namespace std;
typedef struct HTNode{
    char name;
    int weight;
    int lchild,rchild,parent;
}HTNode,*HTree;
typedef char** HFMCode;
void SelectMin(HTree HT,int n,int &s1,int &s2){
    s1=s2=0;
    int i;
    for(i=0;i<n;++i){//先将s1,s2赋上值,
        if(HT[i].parent==0){//从未被选过的元素,即双亲为0的元素中挑选
            if(s1==0){
                s1=i;
            }
            else {
                s2=i;
                break;//不要忘了!!此时s1、s2都已赋值成功,直接跳出
            }
        }
    }
    if(HT[s1].weight>HT[s2].weight){//把s1作为较小的元素
        int t=s1;
        s1=s2;
        s2=t;
    }
    for(;i<n;++i){          //接着开始比较
        if(HT[i].parent==0){
            if(HT[i].weight<HT[s1].weight){
                s2=s1;
                s1=i;
            }
            else if(HT[i].weight<HT[s2].weight){
                s2=i;
            }
        }
    }
    return;
}
void CreateHMT(HTree &HT,int n){
    int m=2*n-1;
    HT=new HTNode[m+1];
    for(int i=1;i<=m;++i){
        HT[i].lchild=HT[i].rchild=HT[i].parent=0;
    }
    cout<<"请输入各个元素字母及权重:\n";
    for(int i=1;i<=n;i++){
        cin>>HT[i].name>>HT[i].weight;
    }
    for(int i=n+1;i<=m;++i){
        int s1,s2;
        SelectMin(HT,i,s1,s2);
        HT[s1].parent=HT[s2].parent=i;
        HT[i].weight=HT[s1].weight+HT[s2].weight;
        HT[i].lchild=s1;HT[i].rchild=s2;
    }
    return;
}
void CreatHFC(HTree HT,HFMCode &hc,int n){
    hc=new char*[n+1];//开n+1个1维数组空间
    char* cd=new char[n];//临时数组
    cd[n-1]='\0';
    for(int i=1;i<=n;++i){
        int start=n-1;  
        int c=i;
        int f=HT[i].parent;
        while(f!=0){
            start--;
            if(HT[f].lchild==c)
            cd[start]='0';
            else cd[start]='1';
            c=f;
            f=HT[f].parent;
        }
        hc[i]=new char[n-start];
        strcpy(hc[i],&cd[start]);
    }
    delete cd;
    return;
}
void Print(HTree HT,HFMCode HC,int n){
    for(int i=1;i<=n;++i){
        cout<<HT[i].name<<":"<<HC[i]<<endl;
    }
    return;
}
int main(){
    HTree HT;
    int n;
    cout<<"请输入元素个数:";
    cin>>n;
    CreateHMT(HT,n);
    HFMCode HC;
    CreatHFC(HT,HC,n);
    Print(HT,HC,n);
    return 0;
}

测试样例:

————————————————————————————————————————————————————————

Source: http://data.biancheng.net/view/30.html

https://www.cnblogs.com/ciyeer/p/9045746.html

https://blog.csdn.net/qq_25775935/article/details/88647758

Note: This article All content is derived from the "data structure (C language Second Edition)" (Yan Wei Min teacher a)

Released six original articles · won praise 0 · Views 123

Guess you like

Origin blog.csdn.net/Roy_F_M/article/details/103839968