深入浅出--二叉树
来源:互联网 发布:盲僧皮肤龙的传人淘宝 编辑:程序博客网 时间:2024/05/26 08:42
二叉树
(题外话:)在数据结构和算法中,数据结构也就是ADT是组织数据的方式,而算法就是解决问题的流程问题;通常我们说数据结构和算法的优化就是两个方面,即空间和时间,尽可能的使空间和时间最小化。基于以上两个原则,才有了不断在原来的经典的算法之上继续改进和创新。
本主今天讲解一下二叉树,二叉树的应用很广泛,尤其是在后面讲解到查找的算法,二叉树是一个效率很高的数据结构,并且在此基础上延伸到B数,B+树,B*树,红黑树等。
二叉树定义
首先说一下什么是树? 树作为一个常用的数据结构,我们可以暂时理解为数据之间的一对多的关系如图所示。
二叉树在图论中是这样定义的:二叉树是一个连通的无环图,并且每一个顶点的度不大于3。有根二叉树还要满足根结点的度不大于2。有了根结点之后,每个顶点定义了唯一的父结点,和最多2个子结点。
可以把二叉树的定义简单得理解为:如存在根,每个节点的度不大于2,每个结点的孩子结点次序不能任意颠倒(递归定义)。
特殊二叉树
1.斜树
所有结点都只有左子树的二叉树叫左斜树,所有结点都只有右子树的二叉树叫右斜树。斜树的每一层都只有一个结点,结点的个数与斜树的深度相同。
2 满二叉树
在一棵二叉树中,如果所有分支结点都存在左子树和右子树,并且所有叶子结点都在同一层上,这样的二叉树称为满二叉树。(上图中所示的二叉树,就是一棵满二叉树)
3 完全二叉树
对一棵具有n个结点的二叉树按层序编号,如果编号为i(1≤i≤n)的结点与同样深度的满二叉树中的编号为i的结点在二叉树中的位置完全相同,则这棵二叉树称为完全二叉树。
二叉树性质
性质1:在二叉树中至多有2^(n-1)个结点(n为树的深度)。可用数学归纳法证明。
性质2:深度为K的二叉树,至多有(2^n ) -1 个结点。
以上两个性质常会在查找树等问题中用到,如求B树的最小深度。
性质3:对任意一个二叉树,如终端结点n0,而度数为2的结点为n2,则有n0=n2+1。
证明:
设二叉树的结点总数为n,度为0的结点即终端结点为n0,度为1的结点为n1,度为2的结点为n2,则有 n = n0 + n1 + n2,从另一方面讲,度为1的结点有一个子结点,度为2的结点有有两个子结点,度为0的结点有0个子结点,则n = 0 * n0 + 1 * n1 + 2* n2 +1 ,这里为什么加1,加1 是由于加上根结点,由上面两个公式可得 n0 = n2+1。
性质4:具有n个结点的完全二叉树的深度为floor(log2n) + 1 。
性质5:如果对一棵有n个结点的完全二叉树(其深度为floor(log2n) + 1)的结点按层序编号,则对任一结点i(1≤i≤n)有:
(1) 如果i = 1,则结点i是二叉树的根,无双亲;如果i > 1,则其双亲PARENT(i)是结点 floor((i)/2)。
(2)如果2i > n,则结点i无左孩子;否则其左孩子LCHILD(i)是结点2i。
(3)如果2i + 1 > n,则结点i无右孩子;否则其右孩子RCHILD(i)是结点2i + 1。
由此性质可知,如果结点的编号为i(假设其左子树、右子树和父结点都存在),则其左子树的编号为2i,右子树的编号为2i +1, 其父节点为i/2。
二叉树逻辑存储结构
二叉树的逻辑结构如图所示,是客观世界的真实反映,反映了在客观世界中数据之间组织的方式。如图所示。
二叉树的物理存储结构
二叉树的物理存储结构即为在二叉树在计算机世界的反映,一般是顺序存储和链式存储。
顺序存储:如图所示
由此可以看出,当二叉树为左斜树,右斜树,会有很多的空间浪费。
链式存储:如图所示
由此可以看出,链式存储虽然能够节约空间,但是在查找效率上回损失时间。因此,有二叉链表拓展到三叉链表,加个指向父节点的指针。提高查找效率,由此可以看出,数据结构和算法总是在空间和时间上寻求平衡,根据具体情况来设计数据结构和算法。
二叉树的操作(c语言实现)
#include "stdio.h"#include "stdlib.h"#include "string.h"typedef char ElemType;typedef int status; //状态码#define ERROR 0#define TRUE 1/*定义二叉树结构*/typedef struct Node{ ElemType data; struct Node *lchild, *rchild; /*左右孩子*/}BTNode, *BTree;BTree pre;/*前序插入*/void PreOrderInsert(BTree *BT){ char temp; scanf("%c", &temp); if(temp =='.')(*BT) = NULL; else { (*BT) = (BTNode *) malloc(sizeof(BTNode)); (*BT)->data = temp; PreOrderInsert(&(*BT)->lchild); PreOrderInsert(&(*BT)->rchild); }}/*前序遍历*/void preOrder(BTree T){ if(T!=NULL){ printf("%c",T->data); preOrder(T->lchild); preOrder(T->rchild); }}/*中序遍历*/void InOrder(BTree T){ if(T!=NULL){ preOrder(T->lchild); printf("%c",T->data); preOrder(T->rchild); }}/*后序遍历*/void LastOrder(BTree T){ if(T!=NULL){ preOrder(T->lchild); preOrder(T->rchild); printf("%c",T->data); }}/*打印树形结构*/void PrintTree(BTree BT, int nLayer){ int i = 0; if(BT == NULL)return ; PrintTree(BT->rchild, nLayer +1); for(i = 0;i<nLayer;i++){ printf(" "); } printf("%c\n",BT->data); PrintTree(BT->lchild,nLayer +1);}/*树的深度*/int Depth(BTree BT){ int left = 0, right = 0; if(BT != NULL){ //自顶向下方法,也可以用从下向顶 left = Depth(BT->lchild) +1; right = Depth(BT->rchild) +1; return left > right ? left : right; } else return 0;}void main(){ BTree T = NULL; printf("请输入前序顺序空结点以.形式代表:\n"); PreOrderInsert(&T); printf("根节点的结构\n"); PrintTree(T,1); printf("树的深度为:%d\n",Depth(T));}
- 深入浅出--二叉树
- 深入浅出二叉树的遍历
- [数据结构]--深入浅出红黑二叉树
- “砖头变玉石”——深入浅出线索二叉树和普通二叉树间的相互转化
- 深入浅出理解[二叉树的构建、先中后序遍历、树的深度、左右子树互换]
- 深入浅出
- 深入浅出
- 深入浅出
- 二叉树、二叉堆
- 二叉树
- 二叉树
- 二叉树
- 二叉树
- 二叉树
- 二叉树
- 二叉树
- 二叉树
- 二叉树
- php操作memcache的单例模式并测试其机制
- jmeter优化, 单例用无sync那种 ,使用nio
- 【android_温故知新】使用 Intent 和 IntentFilter 进行通信
- Android 系统关机流程分析
- HBase 集群环境搭建-基于Hadoop2.2.0
- 深入浅出--二叉树
- strncpy杂谈
- linux硬盘分区和文件系统
- 安卓listview加载来自json的数据
- 自定义控件中结合设计模式
- 如何构建用户画像
- Hbase 笔记
- 【splay】BZOJ 1251 序列终结者
- Android 开机震动在哪调用的,怎样关闭?