当前位置: 首页 > news >正文

中型企业网站建设/郑州百度公司地址

中型企业网站建设,郑州百度公司地址,wordpress资源分享网,用vultr做网站作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明。谢谢! 树的特征和定义 树(Tree)是元素的集合。我们先以比较直观的方式介绍树。下面的数据结构是一个树: 树有多个节点(node),用…

 

作者: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节点。从图中还可以看到,上面的树总共有4个层次,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)是一种特殊的树。二叉树的每个节点最多只能有2个子节点:

二叉树

由于二叉树的子节点数目确定,所以可以直接采用上图方式在内存中实现。每个节点有一个左子节点(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:



18 
81 
101 
After deletion:


18 
81 
101

 

上述实现中的删除比较复杂。有一种简单的替代操作,称为懒惰删除(lazy deletion)。在懒惰删除时,我们并不真正从二叉搜索树中删除该节点,而是将该节点标记为“已删除”。这样,我们只用找到元素并标记,就可以完成删除元素了。如果有相同的元素重新插入,我们可以将该节点找到,并取消删除标记。

懒惰删除的实现比较简单,可以尝试一下。树所占据的内存空间不会因为删除节点而减小。懒惰节点实际上是用内存空间换取操作的简便性。

 

总结

树, 二叉树, 二叉搜索树

二叉搜索树的删除

懒惰删除

 

欢迎继续阅读“纸上谈兵: 算法与数据结构”系列。

转载于:https://www.cnblogs.com/Alandre/p/3652753.html

http://www.lbrq.cn/news/1055017.html

相关文章:

  • 有没有做网站一次付费/网络营销策划的目的
  • 淘宝上做进出口网站有哪些/谷歌play
  • 网站采集被降权/800元做小程序网站
  • 学做游戏 网站/seo推广有哪些
  • 方城企业网站制作哪家好/百度开户
  • 给网站做备案/百度链接提交收录入口
  • 北京html5网站建设/合肥网站优化排名推广
  • 网站备案成功后怎么办/完整的网页设计代码
  • 网站开发命名规范/网络推广工作内容
  • 网站建设人文类/曹操论坛seo
  • frontpage导入网站/免费域名解析平台
  • esc怎么做网站/杭州seo公司服务
  • 手机做网页的软件有哪些/上海谷歌seo公司
  • 北京建设银行网站首页/永久免费开网店app
  • 温州市住房和城乡建设委员会网站/搜索
  • 网站推广的资源合作推广/东莞seo推广机构帖子
  • 哪个网站可以找设计师做设计师/风云榜小说排行榜
  • 展示营销型网站/盐酸达泊西汀片是治疗什么的药物
  • e特快做单子的网站/西安网站建设公司
  • 网站图片用什么做/seo是什么部位
  • 骏域网站建设专家/seo排名赚app是真的吗
  • 怎么看个人做的付费视频网站/英文网站推广
  • 特级a做爰网站/营销策划方案范文
  • 做网站做小程序推广/百度通用网址
  • 网站的图片怎么做无法下载/网站关键词优化排名技巧
  • 网站存在的缺陷/排名优化怎么做
  • 建设网站企业登录/怎么学做电商然后自己创业
  • 重庆建设网站盘古越/淘宝关键词搜索量查询工具
  • 一个数据库怎么做二个网站/网络建站优化科技
  • 网站怎样做移动端/2022今天刚刚发生地震了
  • LeetCode 面试经典 150_数组/字符串_分发糖果(15_135_C++_困难)(贪心算法)
  • Openlayers基础教程|从前端框架到GIS开发系列课程(19)地图控件和矢量图形绘制
  • No time to train! Training-Free Reference-Based Instance Segmentation之论文阅读
  • 第39周——训练自己的数据集
  • Java集合的遍历方式(全解析)
  • 【2025最新】在 macOS 上构建 Flutter iOS 应用