陈越《数据结构》第三讲 树(上)
来源:互联网 发布:微信打开淘宝 编辑:程序博客网 时间:2024/06/07 08:33
3.1 树与树的表示
3.1.1 引子:查找
分层次组织在管理上具有更高的效率!
查找
1. 定义:
根据某个给定 关键字K ,从 集合R 中找出关键字与K 相同的记录。
2.分类:
- 静态查找:集合中 记录是固定 的;
- 动态查找: 集合中 记录是动态变化的。
3.静态查找的方法
方法1: 顺序查找(时间复杂度为
O(n) );
//在数组的头部,建立哨兵 和标记指针 ,可减少判断的分支。
方法2:二分查找(时间复杂度
O(logN) )。
数据必须从小到大排列!
问:
在二分查找中,我们是取mid等于left和right的中间值,即用等分的方法进行查找。
那为什么一定要等分呐?能不能进行“黄金分割”?也就是mid=left+0.618(right-left),当然mid要取整数。如果这样查找,时间复杂性是多少?也许你还可以编程做个试验,比较一下二分法和“黄金分割”法的执行效率。
答:
二分法每次能有100%的概率能只剩50%的数据,每次剩下的期望为50%,即每次除以2。所以时间复杂度是:
而黄金分割的话每次都有
3.1.2 树
- 定义:
n(n≥0) 个结点构成的有限集合。
- 当
n=0 时,称为 空树 ;- 树中有一个称为“ 根(Root ) ”的特殊结点, 用 r 表示;
- 其余结点可分为m(m>0) 个 互不相交的 有限集,其中每个集合本身又是一棵树,称为原来树的“ 子树 (SubTree )”。
2.
- 子树是 不相交 的 ;
- 除了根结点外, 每个结点有且仅有一个父结点 ;
- 一棵N 个结点的树有N-1 条边 。
3.
树是保证节点联通的最小的一种联通方式!
- 结点的度(Degree ): 结点的 子树个数;
树的度 :树的所有结点中最大的度数;- 叶结点 (Leaf): 度为0 的结点;
- 父结点 (Parent ):有子树的结点是其子树的根结点的父结点;
- 子结点 (Child ):若A 结点是B 结点的父结点,则称B 结点是A 结点的子结点;子结点也称 孩子结点 ;
- 兄弟结点 (Sibling ):具有同一父结点的各结点彼此是兄弟结点;
路径和路径长度 :从结点n1 到nk 的 路径 为一个结点序列n1,n2,…,nk,ni是ni+1 的父结点。路径所包含边的个数为 路径的长度 ;- 祖先结点(Ancestor) :沿 树根到某一结点路径 上的所有结点都是这个结点的祖先结点;
- 子孙结点(Descendant) :某一结点的 子树中的所有结点 是这个结点的子孙;
结点的层次 (Level):规定 根结点在1 层 ,其它任一结点的层数是其父结点的层数加1;树的深度 (Depth) :树中所有结点中的 最大层次 是这棵树的深 度。
4.
儿子-兄弟表示法
所需的总空间为3N (N为节点数)。
问:
树的集合称为森林。是否也可以使用“儿子-兄弟”表示法存储森林?如何实现?
答:
可以,不同树的根节点看成是这棵树的入口,各个树之间可以看做是兄弟节点。
3.2 二叉树及存储结构
3.2.1 二叉树
二叉树的定义 定义:一个有穷的结点集合。
- 这个集合 可以为空;
- 若不为空,则它是由 根结点 和称为其 左子树
TL 和 右子树TR 的两个不相交的二叉树组成。
特殊二叉树 二叉树的性质 - 一个二叉树第
i 层的最大结点数为:2i−1 ,i≥1 。 深度 为k 的二叉树有最大结点总数为:2k−1 ,k≥1 。- 对
任何非空二叉树T ,若n0 表示叶结点的个数、n2 是度为2 的非叶结点个数,那么两者满足关系n0=n2+1 。
- 一个二叉树第
问:
讨论3.3:
在二叉树中,我们知道叶结点总数与有两个儿子的结点总数之间的关系是:
那么类似关系是否可以推广到
答:
4.
- 遍历又分为:
先序、中序、后序和层次遍历 。
3.2.2 二叉树的存储结构
顺序存储(主要针对
完全二叉树 );链式存储
在此处再次说一说 :
typedef struct PloyNode *Polynomial;//这句有什么用呢?
typedef struct PolyNode{//这两个typedef有什么联系吗?
int coef;
int expon;
Polynomial link;//这里是定义了一个相当于next后继指针吗?
}
如果按这样定义好了之后,如何定义一个这样的链表?
网上有一个经典的解释 :
1.typedef struct PloyNode *Polynomial;
这句是说:定义了一个结构体变量的指针,以后你可以直接用Polynomial来代表struct PolyNode *这个数据.
2.typedef struct PolyNode{
int coef;
int expon;
Polynomial link; }
这个也是一个定义,定义了一个结构体变量,简化了结构体变量的定义。你可以用PolyNode来代表整个结构体变量。再来说一下他们之间的联系: 第一个是定义的一个简化的指针变量:struct PolyNode * ; 第二个定义了一个简化的结构体变量PolyNode来代替:typedef struct PolyNode;
综上是否可理解为:指针变量Polynomial具有结构体PolyNode的结构,即L=(Polynomial)malloc(sizeof(PolyNode))这样就生成一个新的PloyNode结点。
3.3 二叉树的遍历
1.运用递归函数进行遍历
先序遍历
中序遍历
后序遍历
总结:
- 三种遍历算法的遍历路径是一样的,只是访问各节点的时机不同。
2.非递归遍历(使用
问:
讨论3.4 如何用堆栈实现后序遍历的非递归程序?
我们前面看到,借助堆栈可以实现前序遍历、中序遍历的非递归程序,而且两者的程序结构几乎一样。
答:
不行,不能用前面同样的结构进行对比处理。
可以利用两个堆栈和一个指针进行处理。
3.层序遍历(使用
问:
将层序遍历中的队列改为堆栈:
如果将层序遍历中的队列改为堆栈,是否也是一种树的遍历?可以应用这种方法改造出一种前序、中序、后序的非递归遍历吗?
答:
就是把数据
把数据都
4.二叉树的应用
例1:输出二叉树中的 叶子结点。
例2. 求二叉树的高度
例3. 由 任意两种 遍历序列确定二叉树,对么?(
其中一个必须是中序遍历。 )
3.4 小白专场:树的同构
程序:
//author: Paul-Huang//data: 18/6/2017#include<stdio.h>#include <stdlib.h>#include<process.h>//引入头文件#define MaxTree 10#define Null -1 #define ElementType char #define Tree int//建立动态链表struct TreeNode{ ElementType node; Tree Left; Tree Right;}Tree1[MaxTree],Tree2[MaxTree];Tree BuildTree(struct TreeNode T[]);int Isomprphic(Tree root1, Tree root2);int main(){ Tree R1, R2; R1 = BuildTree(Tree1); R2 = BuildTree(Tree2); if (Isomprphic(R1, R2)){ printf("Yes\n"); } else{ printf("No\n"); } system("pause");//暂停往下执行 按下任意键继续 return 1;}Tree BuildTree(struct TreeNode T[]){ Tree check[MaxTree], Root = Null; //root = Null 空树则返回Null char cl, cr; int i,N; scanf("%d\n",&N); if (N) { for ( i = 0; i < N; i++) check[i] = 0; //输入数值,并建立链表 for (i = 0; i < N; i++) { scanf("%c %c %c\n", &T[i].node, &cl, &cr); if (cl != '-'){ T[i].Left = cl - '0'; check[T[i].Left] = 1; } else{ T[i].Left = Null; } if (cr != '-'){ T[i].Right = cr - '0'; check[T[i].Right] = 1; } else{ T[i].Right = Null; } } //查找二叉树的根 for (i = 0; i < N; i++) if (!check[i]) break; Root = i; } return Root;}int Isomprphic(Tree root1, Tree root2){ if ((root1 == Null) && (root2 == Null))/* both empty */ return 1; if (((root1 == Null) && (root2 != Null)) || ((root1 != Null) && (root2 == Null))) return 0;/* one of them is empty */ if (Tree1[root1].node != Tree2[root2].node) return 0; /* roots are different */ if ((Tree1[root1].Left == Null) && (Tree2[root2].Left == Null)) /* both have no left subtree */ return Isomprphic(Tree1[root1].Right,Tree2[root2].Right); if ((Tree1[root1].Right == Null) && (Tree2[root2].Right == Null)) /* both have no right subtree */ return Isomprphic(Tree1[root1].Left, Tree2[root2].Left); if ((Tree1[root1].Left != Null) && (Tree2[root2].Left != Null) && ((Tree1[Tree1[root1].Left].node) == (Tree2[Tree2[root2].Left].node))) /* no need to swap the left and the right */ return (Isomprphic(Tree1[root1].Left, Tree2[root2].Left)&& Isomprphic(Tree1[root1].Right,Tree2[root2].Right)); else/* need to swap the left and the right */ return (Isomprphic(Tree1[root1].Left, Tree2[root2].Right) && Isomprphic(Tree1[root1].Right, Tree2[root2].Left));}
#include<stdio.h>#include<iostream>#define MaxTree 10#define ElementType int#define Tree int #define Null -1struct TreeNode{ ElementType Element; Tree left; Tree right;}T[MaxTree];Tree BulidTree(struct TreeNode T[]);void FindLeave(Tree R);int main(){ Tree R; R = BulidTree(T); FindLeave(R); //system("pause");//暂停往下执行 按下任意键继续 return 0;}Tree BulidTree(struct TreeNode T[]){ int i,N; char cl,cr; Tree check[MaxTree],Root = Null; scanf("%d\n",&N); for(i=0;i<N;i++)check[i] = 0; if(N) { for(i=0;i<N;i++) { T[i].Element = i; scanf("\n%c %c",&cl,&cr); if(cl != '-') { T[i].left = cl - '0'; check[T[i].left] = 1; } else T[i].left = Null; if(cr !='-') { T[i].right = cr - '0'; check[T[i].right] = 1; } else T[i].right = Null; } for(i=0;i<N;i++) if(!check[i])break; Root = i; } return Root;}void FindLeave(Tree R){ int leaves = 0; int queue[MaxTree]; int front = 0,rear = 0; queue[rear++] = R; while(rear - front) { if((T[queue[front]].left != -1)) queue[rear++] = T[queue[front]].left; //左边如果不为空,加入队列 if((T[queue[front]].right != -1)) queue[rear++] = T[queue[front]].right; //右边如果不为空,加入队列 if((T[queue[front]].left == -1)&& (T[queue[front]].right == -1)) { if(leaves) printf(" "); printf("%d",queue[front]); ++leaves; } //左右两边为空,则是叶子节点,输出 front++; }}
- 陈越《数据结构》第三讲 树(上)
- 数据结构——第三讲、树(上)(1)
- 数据结构——第三讲、树(上)(2)
- 数据结构——第三讲、树(上)(3)
- 陈越《数据结构》第六讲 图(上)
- 数据结构(陈越)PAT练习题 第三周:树(上)
- 陈越《数据结构》第四讲 树(中)
- 陈越《数据结构》第五讲 树(下)
- 【数据结构第三周】树知识点整理(上)
- 第三讲 面向对象(上)
- 孙鑫java无难事视频 日志 ---第三讲(上)
- 第三十一讲 : DataSet和DataAdapter(上)
- 暑假集训 二叉树 大话数据结构上讲的
- 数据结构——第六讲、图(上)(1)
- 数据结构——第六讲、图(上)(2)
- springboot系列(第三讲)
- 数据结构 第三讲--参数的值传递与引用传递
- 陈越《数据结构》第一讲 基本概念
- 121. Best Time to Buy and Sell Stock
- 第三方网站新浪微博登录
- OpenCV中直方图反向投影算法详解与实现
- 论F12的使用,通过前端Bug下载Abook网站 不可下载的文件
- C#基础之自定义类型
- 陈越《数据结构》第三讲 树(上)
- scrapy爬虫框架入门实例
- 欢迎使用CSDN-markdown编辑器
- Java实现-不同的二叉查找树1
- c基础编程能力实训报告——货物管理系统
- Kinect+OpenNI学习笔记(不需要骨骼跟踪的人体手部分割)
- Spring Security之自定义数据库表
- zookeeper基础知识
- 【算法】最短路径-弗洛伊德(Floyd-Warshall)