二叉树
二叉树的顺序存储
按满二叉树的结点层次编号,依次存放二叉树中的数据元素。
若有空节点则不能连续存储,空出位置!
二叉树顺序存储缺点
最坏情况:右单支树,深度为k的且只有k个结点的单支树需要长度为2k-1的一维数组。
特点:结点间蕴含在其存储位置中浪费空间,适合存满二叉树和完全二叉树。
二叉树的链式存储
二叉链表
typedef struct BiNode {
TElemType data;
struct BiNode* lchild, * rchild;//左右孩子指针
}BiNode,*BiTree;
三叉链表
再增加一个parent指针域指向双亲结点
typedef struct TriTNode {
TElemType data;
struct TriTNode* child, * parent, * rchild;
}TriTNode,*TriTree;
遍历二叉树
- 遍历定义 :顺着某一条搜索路径巡访二叉树中的结点,使得每个结点均被访问一次,而且仅被访问一次。
- 遍历目的 :得到树中所有结点的一个线性排列。
- 遍历用途 :它是树结构插入、删除、修改、查找和排序运算的前提,是二叉树一切运算的基础和核心。
遍历方法
假设: L :遍历左子树 D :访问根节点 R :遍历右子树
规定先左后右:
DLR ——先序遍历
LDR ——中序遍历
LRD ——后序遍历
先序遍历 | 中序遍历 | 后序遍历 |
---|---|---|
1.访问根结点 2.先序遍历左子树 3.先序遍历右子树 | 1.中序遍历左子树 2.访问根结点 3.中序遍历右子树 | 1.后序遍历左子树 2.后序遍历右子树 3.访问根节点 |
这里是二叉树的遍历方法,当初学二级公共基础知识(前面十分)的题就不会,点我点我!!!
复制一颗二叉树
Status Copy(BiTree T, BiTree& NewT)
{
if (T == NULL)
{
NewT = NULL;
return OK;
}
else
{
NewT = (BiTNode*)malloc(sizeof(BiTree));
NewT->data = T->data;
Copy(T->lchild, NewT->lchild);
Copy(T->rchild, NewT->rchild);
return OK;
}
}//Copy
计算二叉树的深度
int Depth(BiTree T)
{
int m = 1;
int n = 1;
if (T == NULL)
return 0;
else
{
m = Depth(T->lchild);
n = Depth(T->lchild);
if (m > n)
return (m + 1);
else
return (n + 1);
}
}//Depth
计算二叉树的结点个数
int NodeCount(BiTree T)
{
if (T == NULL)
return 0;
else
return NodeCount(T->lchild) + NodeCount(T->rchild) + 1;
}//NodeCount
计算二叉树的叶子结点
int LeafCount(BiTree T)
{
if (T == NULL)
return 0;
if (T->lchild == NULL && T->rchild == NULL)
return 1;
else
return LeafCount(T->lchild) + LeafCount(T->lchild);
}//LeafCount
完整代码
#pragma warning(disable:4996)
#include<stdio.h>
#include<stdlib.h>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
//Status是函数的类型,其值是函数结果状态代码
typedef int Status;
typedef char TElemType;
typedef struct BiNode {
TElemType data;
struct BiNode* lchild, * rchild;//左右孩子指针
}BiTNode, * BiTree;
Status CreateBiTree(BiTree& T);
//按先序次序输入二叉树中结点的值(一个字符),@字符表示空树
//构造二叉链表表示的二叉树T
Status Copy(BiTree T, BiTree& NewT);
//复制一颗二叉树
int Depth(BiTree T);
//计算二叉树的深度
int NodeCount(BiTree T);
//计算二叉树的结点
Status CreateBiTree(BiTree& T)
{
char ch;
scanf("%c", &ch);
if (ch == '@')
T = NULL;
else
{
T = ((BiTNode*)malloc(sizeof(BiTNode)));
if (!(T = (BiTNode*)malloc(sizeof(BiTNode))))
exit(OVERFLOW);
T->data = ch;
CreateBiTree(T->lchild);//构造左子树
CreateBiTree(T->rchild);//构造右子树
}
return OK;
}//CreateBiTree
Status Copy(BiTree T, BiTree& NewT)
{
if (T == NULL)
{
NewT = NULL;
return OK;
}
else
{
NewT = (BiTNode*)malloc(sizeof(BiTree));
NewT->data = T->data;
Copy(T->lchild, NewT->lchild);
Copy(T->rchild, NewT->rchild);
return OK;
}
}//Copy
int Depth(BiTree T)
{
int m = 1;
int n = 1;
if (T == NULL)
return 0;
else
{
m = Depth(T->lchild);
n = Depth(T->lchild);
if (m > n)
return (m + 1);
else
return (n + 1);
}
}//Depth
int NodeCount(BiTree T)
{
if (T == NULL)
return 0;
else
return NodeCount(T->lchild) + NodeCount(T->rchild) + 1;
}//NodeCount
int LeafCount(BiTree T)
{
if (T == NULL)
return 0;
if (T->lchild == NULL && T->rchild == NULL)
return 1;
else
return LeafCount(T->lchild) + LeafCount(T->lchild);
}//LeafCount
int main()
{
BiTree(T);
CreateBiTree(T);
printf("二叉树深度为:%d\n", Depth(T));
printf("结点个数为:%d\n", NodeCount(T));
printf("叶子结点个数为:%d", LeafCount(T));
return 0;
}
线索二叉树(Threaded Binary Tree)
当用二叉链表作为二叉树的存储结构时,可以很方便地找到某个结点的左右孩子;但一般情况下,无法直接找到该结点在某种遍历序列中的前驱和后继结点。
提出问题
如何寻找特定遍历序列中二叉树结点的前驱和后继
探讨空指针数
具有n个结点的二叉链表中,一共有2n个指针域;因为n个节点中有n-1个孩子,即2n个指针域中,有n-1个用来指示结点的左右孩子,其余n+1个指针域为空。
解决方案
如果某个结点的左孩子为空,则将空的左孩子指针域改为指向其前驱;如果某结点的右孩子为空,则将空的右孩子指针域改为指向其后继。为了区分lchild和rchild到底是指向孩子的指针,还是指向前驱或者后继的指针,对二叉链表中每个结点增设两个标志域Itag和rtag,并约定: