<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html><head><meta http-equiv="Cont

本文涉及的产品
转发路由器TR,750小时连接 100GB跨地域
简介:     参考文献: 《数据结构(C语言版)》  严蔚敏 吴伟民 编著     开发平台:Ubuntu11.04    编译器:gcc version4.5.2 (Ubuntu/Linaro 4.5.2-8ubuntu4)     树(Tree)是n(n≥0)个结点的有限集。

    参考文献: 《数据结构(C语言版)》  严蔚敏 吴伟民 编著

 

    开发平台:Ubuntu11.04

    编译器:gcc version4.5.2 (Ubuntu/Linaro 4.5.2-8ubuntu4)

 

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

    结点拥有的子树数称为结点的度(Degree)。度为0的结点称为叶子(Leaf)或终端结点。度不为0的结点称为非终端结点或分支结点。

    树的度是树内各结点的度的最大值。

    结点的子树的根称为该结点的孩子(Child),相应地,该结点称为孩子的双亲(Parent)。

    结点的层次(Level)是从根结点开始计算起,根为第一层,根的孩子为第二层,依次类推。树中结点的最大层次称为树的深度(Depth)或高度。

    如果将树中结点的各子树看成从左至右是有次序的(即不能互换),则称该树为有序树,否则称为无序树。

    1、二叉树

    二叉树(Binary Tree)的特点是每个结点至多具有两棵子树(即在二叉树中不存在度大于2的结点),并且子树之间有左右之分。

    二叉树的性质:

    (1)、在二叉树的第i层上至多有2i-1个结点(i≥1)。

    (2)、深度为k的二叉树至多有2k-1个结点(k≥1)。

    (3)、对任何一棵二叉树,如果其终端结点数为n0,度为2的结点数为n2,则n0=n2+1。

    一棵深度为k且有2k-1个结点的二叉树称为满二叉树。

    可以对满二叉树的结点进行连续编号,约定编号从根结点起,自上而下,自左至右,则由此可引出完全二叉树的定义。深度为k且有n个结点的二叉树,当且仅当其每一个结点都与深度为k的满二叉树中编号从1到n的结点一一对应时,称之为完全二叉树。

 

    (4)、具有n个结点的完全二叉树的深度为不大于log2n的最大整数加1。

    (5)、如果对一棵有n个结点的完全二叉树的结点按层序编号(从第1层到最后一层,每层从左到右),则对任一结点i(1≤i≤n),有

    a、如果i=1,则结点i是二叉树的根,无双亲;如果i>1,则其双亲是结点x(其中x是不大于i/2的最大整数)。

    b、如果2i>n,则结点i无左孩子(结点i为叶子结点);否则其左孩子是结点2i。

    c、如果2i+1>n,则结点i无右孩子;否则其右孩子是结点2i+1。

    二叉树的链式存储:

    链式二叉树中的每个结点至少需要包含三个域,数据域和左、右指针域。

 

    二叉树的遍历:

    假如以L、D、R分别表示遍历左子树、访问根结点和遍历右子树,则可有DLR、DRL、LRD、LDR、RLD、RDL这六种遍历二叉树的方案。若限定先左后右,则只有三种方案,分别称之为先(根)序遍历、中(根)序遍历和后(根)序遍历,它们以访问根结点的次序来区分。

    2、二叉查找树

    二叉查找树(BinarySearch Tree,也叫二叉搜索树,或称二叉排序树Binary Sort Tree)或者是一棵空树,或者是具有下列性质的二叉树:

    (1)、若它的左子树不为空,则左子树上所有结点的值均小于它的根结点的值;

    (2)、若它的右子树不为空,则右子树上所有结点的值均大于它的根结点的值;

    (3)、它的左、右子树也分别为二叉查找树。

    3、二叉查找树的基本运算 

/*  bst - binary search/sort tree 
 * by Richard Tang <tanglinux@gmail.com>  */#include <stdio.h>#include <stdlib.h>
typedef int data_type;
typedef struct bst_node {
    data_type data;
    struct bst_node *lchild, *rchild;
}bst_t, *bst_p;

    (1)、插入

    在二叉查找树中插入新结点,要保证插入新结点后仍能满足二叉查找树的性质。例子中的插入过程如下:

    a、若二叉查找树root为空,则使新结点为根;

    b、若二叉查找树root不为空,则通过search_bst_for_insert函数寻找插入点并返回它的地址(若新结点中的关键字已经存在,则返回空指针);

    c、若新结点的关键字小于插入点的关键字,则将新结点插入到插入点的左子树中,大于则插入到插入点的右子树中。 

static bst_p search_bst_for_insert(bst_p *root, data_type key)
{
    bst_p s, p = *root;

    while (p) {
    s = p;

    if (p->data == key)
        return NULL;

    p = (key < p->data) ? p->lchild : p->rchild;
    }

    return s;
}

void insert_bst_node(bst_p *root, data_type data)
{
    bst_p s, p;

    s = malloc(sizeof(struct bst_node));
    if (!s)
    perror("Allocate dynamic memory");

    s -> data = data;
    s -> lchild = s -> rchild = NULL;

    if (*root == NULL)
    *root = s;
    else {
    p = search_bst_for_insert(root, data);
    if (p == NULL) {
        fprintf(stderr, "The %d already exists.\n", data);
        free(s);
        return;
    }

    if (data < p->data)
        p->lchild = s;
    else
        p->rchild = s;
    }
}

    (2)、遍历 

static int print(data_type data)
{
    printf("%d ", data);

    return 1;
}

int pre_order_traverse(bst_p root, int (*visit)(data_type data)) 
{
    if (root) {
    if (visit(root->data))
        if (pre_order_traverse(root->lchild, visit))
            if (pre_order_traverse(root->rchild, visit))
                return 1;
    return 0;
    }
    else
    return 1;
}

int post_order_traverse(bst_p root, int (*visit)(data_type data))
{
    if (root) {
    if (post_order_traverse(root->lchild, visit))
        if (visit(root->data))
        if (post_order_traverse(root->rchild, visit))
            return 1;
    return 0;
    }
    else
    return 1;
}

    中序遍历二叉查找树可得到一个关键字的有序序列。

    (3)、删除

    删除某个结点后依然要保持二叉查找树的特性。例子中的删除过程如下:

    a、若删除点是叶子结点,则设置其双亲结点的指针为空。

    b、若删除点只有左子树,或只有右子树,则设置其双亲结点的指针指向左子树或右子树。

    c、若删除点的左右子树均不为空,则:

    1)、查询删除点的右子树的左子树是否为空,若为空,则把删除点的左子树设为删除点的右子树的左子树。

 

    2)、若不为空,则继续查询左子树,直到找到最底层的左子树为止。

 

void delete_bst_node(bst_p *root, data_type data)
{
    bst_p p = *root, parent, s;

    if (!p) {
    fprintf(stderr, "Not found %d.\n", data);
    return;
    }

    if (p->data == data) {
    /* It's a leaf node */
    if (!p->rchild && !p->lchild) {
        *root = NULL;
        free(p);
    }
    /* the right child is NULL */
    else if (!p->rchild) {
        *root = p->lchild;
        free(p);
    }
    /* the left child is NULL */
    else if (!p->lchild) {
        *root = p->rchild;
        free(p);
    }
    /* the node has both children */
    else {
        s = p->rchild;
        /* the s without left child */
        if (!s->lchild)
        s->lchild = p->lchild;
        /* the s have left child */
        else {
        /* find the smallest node in the left subtree of s */
        while (s->lchild) {
            /* record the parent node of s */
            parent = s;
            s = s->lchild;
        }
        parent->lchild = s->rchild;
        s->lchild = p->lchild;
        s->rchild = p->rchild;
        }
        *root = s;
        free(p);
    }
    } 
    else if (data > p->data) {
    delete_bst_node(&(p->rchild), data);
    } 
    else if (data < p->data) {
    delete_bst_node(&(p->lchild), data);
    }
}

    4、二叉查找树的查找分析

    同样的关键字,以不同的插入顺序,会产生不同形态的二叉查找树。 

int main(int argc, char *argv[])
{
    int i, num;
    bst_p root = NULL;

    if (argc < 2) {
    fprintf(stderr, "Usage: %s num\n", argv[0]);
    exit(-1);
    }

    num = atoi(argv[1]);
    data_type arr[num];
    printf("Please enter %d integers:\n", num);
    for (i = 0; i < num; i++) {
    scanf("%d", &arr[i]);
    insert_bst_node(&root, arr[i]);
    }

    printf("\npre order traverse: ");
    pre_order_traverse(root, print);
    printf("\npost order traverse: ");
    post_order_traverse(root, print);
    printf("\n");

    delete_bst_node(&root, 45);

    printf("\npre order traverse: ");
    pre_order_traverse(root, print);
    printf("\npost order traverse: ");
    post_order_traverse(root, print);
    printf("\n");

    return 0;
}

    运行两次,以不同的顺序输入相同的六个关键字:

     

    根据前序遍历的结果可得到两次运行所产生的二叉查找树的形态并不相同,如下图:

 

各种二叉树详细介绍<<—-可以点击这儿!

目录
相关文章
|
Web App开发 前端开发 关系型数据库
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html><head><meta http-equiv="Cont
fuser可用于查询文件、目录、socket端口和文件系统的使用进程 1.查询文件和目录使用者 fuser最基本的用法是查询某个文件或目录被哪个进程使用: # fuser -v .
884 0
|
Web App开发 前端开发
|
Web App开发 前端开发 算法
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html><head><meta http-equiv="Cont
基于大数据的精准营销与应用场景 2015年08月11日 大数据 大数据营销时代来临营销学领域过去半个多世纪的发展让我们见证了从“以产品为中心”到“以客户为中心”的转变。
919 0
|
Web App开发 前端开发 Java
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html><head><meta http-equiv="Cont
 Connection reset by peer的常见原因: 1)服务器的并发连接数超过了其承载量,服务器会将其中一些连接关闭;    如果知道实际连接服务器的并发客户数没有超过服务器的承载量,看下有没有网络流量异常。
862 0
|
Web App开发 存储 前端开发
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html><head><meta http-equiv="Cont
NoSuchObjectException(message:There is no database named cloudera_manager_metastore_canary_test_db_hive_hivemetastore_df61080e04cd7eb36c4336f71b5a8bc4) at org.
1082 0
|
Web App开发 前端开发 数据库
|
Web App开发 前端开发
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html><head><meta http-equiv="Cont
【CRM五策略】           对客户进行分类,不是根据规模,而是根据和你的关系,越细腻越好;           不定期更新客户资料,信息越全面越好;           主动对客户进行关怀,拿出你的诚意和...
640 0
|
Web App开发 前端开发
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html><head><meta http-equiv="Cont
authentification验证 - 是指验证who you are(你是谁), 所以需要用到username和password进行身份验证。
634 0
|
Web App开发 前端开发
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html><head><meta http-equiv="Cont
原文见:http://kafka.apache.org/documentation.html#semantics kafka在生产者和消费者之间的传输是如何保证的,我们可以知道有这么几种可能提供的delivery guarantee: At most once 消息可能会丢,但绝不会重复传输 At least one 消息绝不会丢,但可能会重复传输 Exactly once 每条消息肯定会被传输一次且仅传输一次,很多时候这是用户所想要的。
905 0
|
Web App开发 监控 前端开发
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html><head><meta http-equiv="Cont
Spark Streaming 的一些问题,做选型前关注这些问题可以有效的降低使用风险。 checkpoint checkpoint 是个很好的恢复机制。
939 0