c++(排序二叉树)
前面我们讲过双向链表的数据结构。每一个循环节点有两个指针,一个指向前面一个节点,一个指向后继节点,这样所有的节点像一颗颗珍珠一样被一根线穿在了一起。然而今天我们讨论的数据结构却有一点不同,它有三个节点。它是这样定义的:
typedef struct _TREE_NODE
{
int data;
struct _TREE_NODE* parent;
struct _TREE_NODE* left_child;
struct _TREE_NODE* right_child;
}TREE_NODE;
根据上面的数据结构,我们看到每一个数据节点都有三个指针,分别是:指向父母的指针,指向左孩子的指针,指向右孩子的指针。每一个节点都是通过指针相互连接的。相连指针的关系都是父子关系。那么排序二叉树又是什么意思呢?其实很简单,只要在二叉树的基本定义上增加两个基本条件就可以了:(1)所有左子树的节点数值都小于此节点的数值;(2)所有右节点的数值都大于此节点的数值。
既然看到了节点的定义,那么我们并可以得到,只要按照一定的顺序遍历,可以把二叉树中的节点按照某一个顺序打印出来。那么,节点的创建、查找、遍历是怎么进行的呢,二叉树的高度应该怎么计算呢?我们一一道来。
1)创建二叉树节点
TREE_NODE* create_tree_node(int data)
{
TREE_NODE* pTreeNode = NULL;
pTreeNode = (TREE_NODE*)malloc(sizeof(TREE_NODE));
assert(NULL != pTreeNode); memset(pTreeNode, 0, sizeof(TREE_NODE));
pTreeNode->data = data;
return pTreeNode;
}
分析:我们看到,二叉树节点的创建和我们看到的链表节点、堆栈节点创建没有什么本质的区别。首先需要为节点创建内存,然后对内存进行初始化处理。最后将输入参数data输入到tree_node当中即可。
2)数据的查找
TREE_NODE* find_data_in_tree_node(const TREE_NODE* pTreeNode, int data)
{
if(NULL == pTreeNode)
return NULL; if(data == pTreeNode->data)
return (TREE_NODE*)pTreeNode;
else if(data < pTreeNode->data)
return find_data_in_tree_node(pTreeNode->left_child, data);
else
return find_data_in_tree_node(pTreeNode->right_child, data);
}
分析:我们的查找是按照递归迭代进行的。因为整个二叉树是一个排序二叉树,所以我们的数据只需要和每一个节点依次比较就可以了,如果数值比节点数据小,那么向左继续遍历;反之向右继续遍历。如果遍历下去遇到了NULL指针,只能说明当前的数据在二叉树中还不存在。
3)数据统计
int count_node_number_in_tree(const TREE_NODE* pTreeNode)
{
if(NULL == pTreeNode)
return 0; return 1 + count_node_number_in_tree(pTreeNode->left_child)
+ count_node_number_in_tree(pTreeNode->right_child);
}
分析:和上面查找数据一样,统计的工作也比较简单。如果是节点指针,那么直接返回0即可,否则就需要分别统计左节点树的节点个数、右节点树的节点个数,这样所有的节点总数加起来就可以了。
4)按照从小到大的顺序打印节点的数据
void print_all_node_data(const TREE_NODE* pTreeNode)
{
if(pTreeNode){
print_all_node_data(pTreeNode->left_child);
printf("%d\n", pTreeNode->data);
print_all_node_data(pTreeNode->right_child);
}
}
分析:因为二叉树本身的特殊性,按顺序打印二叉树的函数本身也比较简单。首先打印左子树的节点,然后打印本节点的数值,最后打印右子树节点的数值,这样所有节点的数值就都可以打印出来了。
5)统计树的高度
int calculate_height_of_tree(const TREE_NODE* pTreeNode)
{
int left, right;
if(NULL == pTreeNode)
return 0; left = calculate_height_of_tree(pTreeNode->left_child);
right = calculate_height_of_tree(pTreeNode->right_child);
return (left > right) ? (left + 1) : (right + 1);
}
分析:树的高度其实是指所有叶子节点中,从根节点到叶子节点的最大高度可以达到多少。当然,程序中表示得已经很明白了,如果节点为空,那么很遗憾,节点的高度为0;反之如果左子树的高度大于右子树的高度,那么整个二叉树的节点高度就是左子树的高度加上1;如果右子树的高度大于左子树的高度,那么整个二叉树的高度就是右子树的高度加上1。计算树的高度在我们设计平衡二叉树的时候非常有用,特别是测试的时候,希望大家多多理解,熟练掌握。
总结:
1)二叉树是所有树的基础,后续的平衡二叉树、线性二叉树、红黑树、复合二叉树、b树、b+树都以此为基础,希望大家好好学习;
2)二叉树很多的操作是和堆栈紧密联系在一起的,如果大家暂时理解不了递归,可以用循环或者堆栈代替;
3)实践出真知,大家可以自己对排序二叉树的代码多多练习。不瞒大家说,我个人写平衡二叉树不下20多遍,即使这样也不能保证每次都正确;即使这样,我每次写代码的都有不同的感觉。
c++(排序二叉树)的更多相关文章
- C++11 智能指针unique_ptr使用 -- 以排序二叉树为例
用智能指针可以简化内存管理.以树为例,如果用普通指针,通常是在插入新节点时用new,在析构函数中调用delete:但有了unique_ptr类型的智能指针,就不需要在析构函数中delete了,因为当u ...
- 记忆化搜索 codevs 2241 排序二叉树
codevs 2241 排序二叉树 ★ 输入文件:bstree.in 输出文件:bstree.out 简单对比时间限制:1 s 内存限制:128 MB [问题描述] 一个边长为n的正三 ...
- 数据结构与算法系列研究五——树、二叉树、三叉树、平衡排序二叉树AVL
树.二叉树.三叉树.平衡排序二叉树AVL 一.树的定义 树是计算机算法最重要的非线性结构.树中每个数据元素至多有一个直接前驱,但可以有多个直接后继.树是一种以分支关系定义的层次结构. a.树是n ...
- c++(排序二叉树线索化)
前面我们谈到了排序二叉树,还没有熟悉的同学可以看一下这个,二叉树基本操作.二叉树插入.二叉树删除1.删除2.删除3.但是排序二叉树也不是没有缺点,比如说,如果我们想在排序二叉树中删除一段数据的节点怎么 ...
- c++(排序二叉树删除)
相比较节点的添加,平衡二叉树的删除要复杂一些.因为在删除的过程中,你要考虑到不同的情况,针对每一种不同的情况,你要有针对性的反应和调整.所以在代码编写的过程中,我们可以一边写代码,一边写测试用例.编写 ...
- JavaScript实现排序二叉树的相关算法
1.创建排序二叉树的构造函数 /** * 创建排序二叉树的构造函数 * @param valArr 排序二叉树中节点的值 * @constructor */ function BinaryTree(v ...
- Java编程的逻辑 (42) - 排序二叉树
本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...
- (原创)像极了爱情的详解排序二叉树,一秒get
排序二叉树(建立.查找.删除) 二叉树我们已经非常熟悉了,但是除了寻常的储存数据.遍历结构,我们还能用二叉树做什么呢? 我们都知道不同的遍历方式会对相同的树中产生不同的序列结果,排序二叉树就是利用二叉 ...
- 并查集&线段树&树状数组&排序二叉树
超级无敌巨牛逼并查集(带权并查集)https://vjudge.net/problem/UVALive-4487 带删点的加权并查集 https://vjudge.net/problem/UVA-11 ...
随机推荐
- ArcGIS API for JavaScript 4.2学习笔记[10] 2D添加指北针widget、视图保存、视图padding(第二章完结)
这几个例子是第二章除了入门之外比较简单的几个,就做个合集,把最核心的代码(第二参数)和 引用放上来即可,不作多解释. 2D地图添加指北针widget 2D地图一般修正方向为正北方就需要这个widget ...
- Locust no-web 模式与参数详解
读前参考:<性能测试工具Locust > 熟悉 Apache ab 工具的同学都知道,它是没有界面的,通过命令行执行. Locust 同样也提供的命令行运行,好处就是更节省客户端资源. 命 ...
- iOS学习—— UINavigationController的返回按钮与侧滑返回手势的研究
侧滑返回手势是从iOS7开始增加的一个返回操作,经历了两年时间估计iPhone用户大部分都已经忽略了屏幕左上角那个碍眼的back按钮了.之前在网上搜过有关侧滑手势的技术博客,发现大多比较散乱,甚至有很 ...
- Ubuntu安装微信
1.系统是Ubuntu 16.04 64位系统,在网上先去下载electronic-wechat-Linux https://github.com/geeeeeeeeek/electr ...
- IOC的总结
今天趁着空闲总结一下自己IOC的一些理解,希望可以帮助到有需要的人,请大牛们多多指教. (一)IOC IOC就是控制反转,给程序解耦等等,有很多博客都对它做了一些很好的讲解.在这里我也不说太多文字,直 ...
- unittest单元测试框架详解
unittest单元测试框架不仅可以适用于单元测试,还可以适用WEB自动化测试用例的开发与执行,该测试框架可组织执行测试用例,并且提供了丰富的断言方法,判断测试用例是否通过,最终生成测试结果.今天笔者 ...
- 初学Python之 布尔类型
与运算:只有两个布尔值都为 True 时,计算结果才为 True. True and True # ==> True True and False # ==> False False an ...
- nmon进行性能分析
在压测的时候,搭配nmon,可以很好的记录机器cpu情况,内存情况 下载 需要下载nmon和nmon analyser,到各自的官网下载. nmon可以根据自己的操作系统版本下载二进制文件,免去安装. ...
- 我的Python学习笔记(二):浅拷贝和深拷贝
在Python中,对象赋值,拷贝(浅拷贝和深拷贝)之间是有差异的,我们通过下列代码来介绍其区别 一.对象赋值 对象赋值不会复制对象,它只会复制一个对象引用,不会开辟新的内存空间 如下例所示,将test ...
- 北漂的IT人
北京的互联网人,是工作日完全没有个人生活的一类人,也是整个北漂大队伍中,下班时间最晚的那一波人,如果赶上周末还要加班,那毫不夸张地说,你的整个人生都在互联网上奋斗着. 虽说十点上班让多少行内外的人羡慕 ...