中根线索二叉树
概念辨析
线性表:最基本的线性数据结构,是由0个或多个具有相同类型的节点组成的有序集合;可细分为顺序存储结构和链式存储结构;
- 将数据依次存储在连续的整块物理空间中,这种存储结构称为顺序存储结构,简称顺序表
- 如图 3b) 所示,数据分散的存储在物理空间中,通过一根线保存着它们之间的逻辑关系,这种存储结构称为链式存储结构(简称链表)
链表和顺序表--空间使用情况//插入删除操作//存取数据的操作
顺序表所占用的空间来自申请的数组空间,数组大小是事先确定的,当表中的元素较少时,顺序表中很多空间处于闲置状态,造成了空间的浪费。
链表所占用的空间是需要动态申请的,不存在空间浪费的问题,但是链表需要在每个结点上附加一个或多个指针,从而产生额外开销。
各种操作:对于顺序表,随机存取非常容易,但每插入或者删除若干元素;对于链表,无法实现随机存取,必须要从表头开始遍历链表,直到找到要存取的元素,但链表的插入和删除操作非常简便,只需要修改一个或两个指针值。
单链表:线性表的链式存储结构之一,一个单链表的结点由指针域和数据域构成,指针域是存放该结点后续结点的地址信息;
堆栈和队列:两类操作受限的代表性线性表,堆栈只允许在表的一端进行插入和删除的操作,且这些都是按照后进先出的原则进行的。队列的所有插入操作都在表的一端进行,所以删除(以及存取)都是在表的另一端进行,且这些操作都按照先进先出的原则进行;【存储方式可以是顺序表/链式】
* 多维数组不是线性表
二叉查找树(二叉搜索树,二叉排序树):它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。
二叉平衡树:首先它是 "二叉搜索树",其次,它是平衡的,即它的每一个结点的左子树的高度和右子树的高度差的绝对值(平衡因子)至多为 1。
最优二叉搜索树:对给定的概率集合,期望搜索代价最小的二叉搜索树称为最优二叉搜索树
折半查找二叉判定树:是一颗二叉平衡树,只适用于顺序表,要求线性表必须按关键词有序排序
- 当 n=0 时,折半查找判定树为空;
- 当 n>0 时,折半查找判定树的根结点是有序表中序号为 mid=(n+1)/2 的记录,根结点的左子树是与有序表 r [1] ~ r [mid-1] 相对应的折半查找判定树,根结点的右子树是与 r [mid+1] ~ r [n] 相对应的折半查找判定树。
//折半查找判定树就是一棵最优的二叉搜索树(自然也是平衡二叉树),
BiTree build(int *nums,int low,int high){
if(low <= high){
int mid = (low + high) / 2;
BiTree T = (BiTree)malloc(sizeof(BiTreeNode));
T -> data = nums[mid];
T -> lchild = build(nums,low,mid - 1);
T -> rchild = build(nums,mid + 1,high);
return T;
}else{
return NULL;
}
int BinarySearch(int R[],int n, int K){
//在R中对半查找K,R中关键词递增有序
int s = 1, e = n, mid;
while(s <= e){
mid=(s+e)/2; //若有整型溢出风险,可令mid=s+(e-s)/2
if(K==R[mid]) return mid; //查找成功
else if(K<R[mid]) e=mid-1; //在左半部分查找
else s=mid+1; //K>R[mid],在右半部分查找
}
return -1;
}
AOV网(activity on vertex):顶点表示活动或任务(Activity),有向边表示活动(或任务)间的先后关系。
AOE网(activity on edges):有向边表示活动或任务(Activity) ,用边上的权值表示活动的持续时间,顶点称为事件(Event):表示其入边的任务已完成,出边的任务可开始的状态。
AOV网只描述了活动的约束关系,而AOE网建立在AOV网的基础上,可以分析完成整个工程需要的时间,为缩短工程时间、应加快哪些活动等问题;
数据结构包括数据的逻辑结构、存储结构和其上的操作。
按某种逻辑关系将一批数据元素组织起来,按一定的存储方式将它们存储起来,并在这些数据元素上定义一个操作集合,就得到了一个特定的数据结构。
➢ 线性结构: 结构中有且仅有一个始结点和一个终结点,始结点只有一个后继结点,终结点只有一个前趋结点,每个内结点有且仅有一个前趋结点和一个后继结点。
➢ 非线性结构:结构中的结点可能有0个或多个前趋结点、后继结点。
➢ 层次(树形)结构:根节点没有前驱;除根节点,每个节点有一个前驱,可有多个后继。
➢ 图(网状)结构:每个结点可以有任意多个前驱和后继。
➢ 集合:每个节点都没有前驱和后继。
补充:
顺序存储:存储密度高,存储空间利用率低;
顺序表所占用的空间来自于申请的数组空间,数组大小是事先确定的,当表中的元素 较少时,顺序表中的很多空间处于闲置状态,造成了空间的浪费
链式存储:存储密度小,存储空间利用率高;
链表所占用的空间是根据需要动态申请的,不存在空间浪费问题;
可以将一些零碎的小空间链接起来组成逻辑上连续的空间,因此空间利用率较高;
但链表需要在每个结点上附加一个指针,从而产生额外开销,存储同样大小的内容时,链式存储所用空间比顺序存储所用空间要大,所以存储密度就小些。
前/后缀表达式的计算机求值
- 从右至左扫描表达式(后缀表达式:从左到右)
- 遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(栈顶元素 op 次顶元素),并将结果入栈
- 重复上述过程直到表达式最左端,最后运算得出的值即为表达式的结果
中缀->前/后缀表达式转化步骤:
- 按照运算符的优先级对所有的运算单位加括号
- 将运算符移动到对应括号的前面(前缀表达式)或后面(后缀表达式)
- 去掉括号,得到前缀或后缀表达式
ex:中缀表达式:(a+b)*c+d/(e*f-g)-h
1)加括号
式子变成((((a+b)*c)+(d/((e*f)-g)))-h)
2)移动运算符
对于前缀表达式,变成了-(+( *(+(ab)c) /(d-(*(ef)g)) )h)
对于后缀表达式:变成了( (((ab)+c)* ( d( (ef)*g)-)/ )+ h)-
3)去掉括号
前缀表达式:-+*+abc/d-*efgh
后缀表达式:ab+c*def*g-/+h-
有向图每个点两两相连,有N(N-1)条边,则一定强连通。
连通N个顶点的有向图至少有[ N ]条边;(题意为强连通)
若无向图连通,必定至少有n-1条边;反过来有n-1条边,不一定连通;
若无向图有(n-1)(n-2)+1条边,则必连通;
某树的度:指树中各结点度的最大值。二叉树的结点:0/1/2;
一个结点的度:该结点的出度,即拥有子结点的数量;
n个结点二叉查找树的数量:
【是神奇的Catalan数,跟混合栈总洗数一样】
算法的优劣与算法的正确性、时间复杂性、空间复杂度、可读性、健壮(鲁棒)性有关;与语言、计算机无关;
算法的特性: 有限性、确定性、输入、输出、可行性;
程序是算法的具体实现,可以不满足算法的性质的有限性。
循环链表:把链接结构“循环化”,即把表尾结点的next域存放指向哨位结点的指针,而不是存放空指针NULL,这样的单链表被称为循环链表。判断最后一个结点:while(p->next!=head)
双向链表(Double-Linked List)每个结点有两个指针域,左指针指向其前驱,右指针指向其后继;优点:方便找结点的前驱
*双向循环链表,head的前驱是tail
树的深度:根到结点的路径长度;根结点的深度是0;
树的高度:该结点到叶子结点的最长路径长度;
二叉树:叶子结点的数量:n0;非叶子结点的数量n0-1;
树:边数+1=顶点数;
高度为k的二叉树中至多有2^(k+1) -1 个结点。
第k层至多有2^k层结点;
在n个结点构成的二叉树中,若叶结点个数为n0,度为2的结点个数为n2,则有:n0=n2+1.
具有n (n>0)个结点的完全二叉树的高度是 log2n
高度为k的完全二叉树最少有_2^k__个结点( 高度为k-1的满二叉树再加1个结点)
已知一棵完全二叉树的第n层有k个叶结点,则该完全二叉树的结点个数最少是 2^n+k-1(k为叶结点) ,最多是 2n+2-2k-1 (k 个叶结点在 倒数第二层)