纸上谈兵: 树, 二叉树, 二叉搜索树

  • 时间:
  • 浏览:2
  • 来源:大发pk10_pk10开奖历史_大发pk10开奖历史

作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明。谢谢!

树的价值形式和定义

树(Tree)是元素的集合。亲们儿先以比较直观的最好的办法介绍树。下面的数据价值形式是另另有一一三个白树:

树有多个节点(node),用以储存元素。一点节点之间处在一定的关系,用连线表示,连线称为边(edge)。边的上面节点称为父节点,下端称为子节点。树像是另另有一一三个白不断分叉的树根。

每个节点都前要有多个子节点(children),而该节点是相应子节点的父节点(parent)。比如说,3,5是6的子节点,6是3,5的父节点;1,8,7是3的子节点, 3是1,8,7的父节点。树有另另有一一三个白如此父节点的节点,称为根节点(root),如图中的6。如此子节点的节点称为叶节点(leaf),比如图中的1,8,9,5节点。从图中还都前要看得人,上面的树总共有另另有一一三个白层次,6处在第一层,9处在第四层。树中节点的最大层次被称为角度。也只要说,该树的角度(depth)为4。

只要亲们儿从节点3以前开始英文英语 英语 向下看,而忽略其它主次。如此亲们儿看得人的是另另有一一三个白以节点3为根节点的树:

三角形代表一棵树

再进一步,只要亲们儿定义孤立的另另有一一三个白节点是一棵树话语,原本的树就都前要表示为根节点和子树(subtree)的关系:

上述观察实际上给了亲们儿本身严格的定义树的最好的办法:

1. 树是元素的集合。

2. 该集合都前要为空。这时树中如此元素,亲们儿称树为空树 (empty tree)

3. 只要该集合不为空,如此该集合有另另有一一三个白根节点,以及0个只要多个子树。根节点与它的子树的根节点用另另有一一三个白边(edge)相连。

上面的第三点是以递归的最好的办法来定义树,也只要在定义树的过程中使用了树自身(子树)。只要树的递归价值形式,一点树相关的操作也都前要方便的使用递归实现。亲们儿将在上面看得人。

(上述定义来自"Data Structures and Algorithm Analysis in C, by Mark Allen Weiss"。 我确实有一点不太严格的地方。只要说空树属于树,第三点应该是 “...以及0个和多个非空子树...” )

树的实现

树的示意图只要给出了树的本身内存实现最好的办法: 每个节点储存元素和多个指向子节点的指针。然而,子节点数目是不选者的。另另有一一三个白父节点只要有小量的子节点,而原本父节点只要还都可以另另有一一三个白子节点,而树的增删节点操作会让子节点的数目处在进一步的变化。你你这俩不选者性就只要带来小量的内存相关操作,只要容易造成内存的浪费。

本身经典的实现最好的办法如下:

树的内存实现

拥有同一父节点的另另有一一三个白节点互为兄弟节点(sibling)。上图的实现最好的办法中,每个节点包所含另另有一一三个白指针指向第另另有一一三个白子节点,并有原本指针指向它的下另另有一一三个白兄弟节点。原本,亲们儿就都前要用统一的、选者的价值形式来表示每个节点。

计算机的文件系统是树的价值形式,比如Linux文件管理背景知识中所介绍的。在UNIX的文件系统中,每个文件(文件夹同样是本身文件),都都前要看做是另另有一一三个白节点。非文件夹的文件被储处在叶节点。文件夹所含指向父节点和子节点的指针(在UNIX中,文件夹还所含另另有一一三个白指向自身的指针,这与亲们儿上面见到的树有所区别)。在git中,全部还会你这俩的树状价值形式,用以表达整个文件系统的版本变化 (参考版本管理三国志)。

文件树

二叉搜索树的C实现

二叉树(binary)是本身特殊的树。二叉树的每个节点最多还都可以有另另有一一三个白子节点

二叉树

只要二叉树的子节点数目选者,一点都前要直接采用上图最好的办法在内存中实现。每个节点有另另有一一三个白左子节点(left children)右子节点(right children)。左子节点是左子树的根节点,右子节点是右子树的根节点。

只要亲们儿给二叉树加另另有一一三个白额外的条件,就都前要得到本身被称作二叉搜索树(binary search tree)的特殊二叉树。二叉搜索树要求:每个节点全部还会比它左子树的任意元素小,只要不比它的右子树的任意元素大。

(只要亲们儿假设树中如此重复的元素,如此上述要求都前要写成:每个节点比它左子树的任意节点大,只要比它右子树的任意节点小)

二叉搜索树,注意树中元素的大小

二叉搜索树都前要方便的实现搜索算法。在搜索元素x的以前,亲们儿都前要将x和根节点比较:

1. 只要x等于根节点,如此找到x,停止搜索 (终止条件)

2. 只要x小于根节点,如此搜索左子树

3. 只要x大于根节点,如此搜索右子树

二叉搜索树所前要进行的操作次数最多与树的角度相等。n个节点的二叉搜索树的角度最多为n,离米 为log(n)。

下面是用C语言实现的二叉搜索树,并有搜索插入删除寻找最大最小节点的操作。每个节点中存有另另有一一三个白指针,另另有一一三个白指向父节点,另另有一一三个白指向左子节点,另另有一一三个白指向右子节点。

(原本的实现是为了方便。节点都前要只保存有指向左右子节点的另另有一一三个白指针,并实现上述操作。)

删除节点相对比较错综复杂。删除节点后,有时前要进行一定的调整,以恢复二叉搜索树的性质(每个节点全部还会比它左子树的任意元素小,只要不比它的右子树的任意元素大)。

  • 叶节点都前要直接删除。
  • 删除非叶节点时,比如下图中的节点8,亲们儿都前要删除左子树中最大的元素(只要右树中最大的元素),用删除的节点来补充元素8产生的空缺。但该元素只要也全部还会叶节点,一点它所产生的空缺前要一点元素补充…… 直到最后删除另另有一一三个白叶节点。上述过程都前要递归实现。

删除节点

删除节点后的二叉搜索树

/* By Vamei */
/* binary search tree */
#include <stdio.h>
#include <stdlib.h>

typedef struct node *position;
typedef int ElementTP;

struct node {
    position parent;
    ElementTP element;
    position lchild;
    position rchild;
};

/* pointer => root node of the tree */
typedef struct node *TREE;

void print_sorted_tree(TREE);
position find_min(TREE);
position find_max(TREE);
position find_value(TREE, ElementTP);
position insert_value(TREE, ElementTP);
ElementTP delete_node(position);

static int is_root(position);
static int is_leaf(position);
static ElementTP delete_leaf(position);
static void insert_node_to_nonempty_tree(TREE, position);

void main(void) 
{
    TREE tr;
    position np;
    ElementTP element;
    tr = NULL;
    tr = insert_value(tr, 18);
    tr = insert_value(tr, 5);
    tr = insert_value(tr, 2); 
    tr = insert_value(tr, 8);
    tr = insert_value(tr, 81);
    tr = insert_value(tr, 101);
    printf("Original:\n");
    print_sorted_tree(tr);

    np = find_value(tr, 8);
    if(np != NULL) {
        delete_node(np);
        printf("After deletion:\n");
        print_sorted_tree(tr);
    }
}


/* 
 * print values of the tree in sorted order
 */
void print_sorted_tree(TREE tr)
{
    if (tr == NULL) return;
    print_sorted_tree(tr->lchild);
    printf("%d \n", tr->element);
    print_sorted_tree(tr->rchild);
}

/*
 * search for minimum value
 * traverse lchild
 */
position find_min(TREE tr)
{
    position np;
    np = tr;
    if (np == NULL) return NULL;
    while(np->lchild != NULL) {
        np = np->lchild;
    }
    return np;
}

/*
 * search for maximum value
 * traverse rchild
 */
position find_max(TREE tr)
{
    position np;
    np = tr;
    if (np == NULL) return NULL;
    while(np->rchild != NULL) {
        np = np->rchild;
    }
    return np;
}

/*
 * search for value
 *
 */
position find_value(TREE tr, ElementTP value) 
{
    if (tr == NULL) return NULL; 

    if (tr->element == value) {
        return tr;
    }
    else if (value < tr->element) {
        return find_value(tr->lchild, value);
    }
    else {
        return find_value(tr->rchild, value);
    }
}

/* 
 * delete node np 
 */
ElementTP delete_node(position np) 
{
    position replace;
    ElementTP element;
    if (is_leaf(np)) {
        return delete_leaf(np);
    }   
    else {
        /* if a node is not a leaf, then we need to find a replacement */
        replace = (np->lchild != NULL) ? find_max(np->lchild) : find_min(np->rchild);
        element = np->element;
        np->element = delete_node(replace);
        return element;
    }
}

/* 
 * insert a value into the tree
 * return root address of the tree
 */
position insert_value(TREE tr, ElementTP value) {
    position np;
    /* prepare the node */
    np = (position) malloc(sizeof(struct node));
    np->element = value;
    np->parent  = NULL;
    np->lchild  = NULL;
    np->rchild  = NULL;
 
    if (tr == NULL) tr = np;
    else {
        insert_node_to_nonempty_tree(tr, np);
    }
    return tr;
}


//=============================================

/*
 * np is root?
 */
static int is_root(position np)
{
    return (np->parent == NULL);
}

/*
 * np is leaf?
 */
static int is_leaf(position np)
{
    return (np->lchild == NULL && np->rchild == NULL);
}

/* 
 * if an element is a leaf, 
 * then it could be removed with no side effect.
 */
static ElementTP delete_leaf(position np)
{
    ElementTP element;
    position parent;
    element = np->element;
    parent  = np->parent;
    if(!is_root(np)) {
        if (parent->lchild == np) {
            parent->lchild = NULL;
        }
        else {
            parent->rchild = NULL;
        }
    }
    free(np);
    return element;
}

/*
 * insert a node to a non-empty tree
 * called by insert_value()
 */
static void insert_node_to_nonempty_tree(TREE tr, position np)
{
    /* insert the node */
    if(np->element <= tr->element) {
        if (tr->lchild == NULL) {
            /* then tr->lchild is the proper place */
            tr->lchild = np;
            np->parent = tr;
            return;
        }
        else {
            insert_node_to_nonempty_tree(tr->lchild, np);
        }
    }
    else if(np->element > tr->element) {
        if (tr->rchild == NULL) {
            tr->rchild = np;
            np->parent = tr;
            return;
        }
        else {
            insert_node_to_nonempty_tree(tr->rchild, np);
        }
    }
}

运行结果:

Original:

2

5

8

18

81

101

After deletion:

2

5

18

81

101

上述实现中的删除比较错综复杂。有本身简单的替代操作,称为懒惰删除(lazy deletion)。在懒惰删除时,亲们儿暂且真正从二叉搜索树中删除该节点,只要将该节点标记为“已删除”。原本,亲们儿只用找到元素并标记,就都前要完成删除元素了。只要有相同的元素重新插入,亲们儿都前要将该节点找到,并撤消 删除标记。

懒惰删除的实现比较简单,都前要尝试一下。树所处在的内存空间不想只要删除节点而减小。懒惰节点实际上是用内存空间换取操作的简便性。

总结

树, 二叉树, 二叉搜索树

二叉搜索树的删除

懒惰删除

欢迎继续阅读“纸上谈兵: 算法与数据价值形式”系列。

猜你喜欢

《剑网3》雪河套时装好看吗?雪河套时装预览

《《剑网3》雪河套时装好看吗?雪河套时装预览》文章由于归档,不再展示相关内容,编辑建议你查看最新于此相关的内容:《剑网3》八款满载故事的全新挂件铭刻升级路上的感动《剑网3》全新

2020-01-23

蔡突提育兒政策 張善政轟抄襲

【大公報訊】據中通社報道:中國國民黨2020年台灣大選候選人韓國瑜陣營,25日由副手、「國政」顧問團總召張善政正式表态「0到6歲幫忙養」育兒政策。由於蔡英文日前也喊出「0到6歲

2020-01-23

一周跌14%,比特币期货再迎新低

IT之家6月16日消息 去年,比特币的价格一度飙涨到历史最高峰,接近2万美元,圆了不少人的造富梦。但现在,比特币玩家应该感受到了“韭菜”的痛苦。据证券时报报道称,CME比特币期

2020-01-23

SKT才是真太子队!JAG战队踢掉网线两次 韩国人玩黑幕都这么6吗

斗玩小编 来源:斗玩网 2018-03-1611:13:00

2020-01-22

辐射4开场动画怎么跳过 开场动画跳过方法

更新时间:2017-06-2307:19:22来源:斗蟹游戏编辑:斗蟹或者 玩家在玩辐射4的已经我真是开场动画很烦,如果跳过,接下来小编就为其他同学 带来辐射4开场动画为

2020-01-22