数与二叉树
树形结构:类似家谱,行政区划分
根
子树
结点的度:结点拥有的非空子树的数目
向下有多少分支,度就是几
叶子结点:结点的度为0,就是该结点后面没有直接相连的结点了
树的度:树中所有结点的度中的最大值
子结点,父结点:结点向下的直接分支就是子结点,直接相连的上一级就是父结点
结点的层次:根结点的层次为1,其子结点的层次为2,以此类推
树的深度:树中结点存在的最大层次
有序树和无序树:树中各结点的子树看成自左向右有序的称为有序树
判断很简单:就是子树能不能左右互换位置,不能换就是有序树
二叉树:二叉树是每个结点最多有两个子树的树结构
二叉树是有序树,结点的子树:根的左子树,根的右子树
满二叉树:满二叉树是完全二叉树的一个特例
完全二叉树
二叉树:非线性数据结构,元素间一对多,链式存储,链表
BinTree:二叉树
定义结点数据类型:每个结点包含一个数据域和两个指针域
struct BinTreeNode //BinTree二叉树 Node结点
{
char data;
struct BinTreeNode *Leftchild,*RightChild;
};
左孩子指针LeftChild | 数据域 | 右孩子指针RightChild |
定义一个二叉树,就是定义一个空树,也就是定义一个空指针:
BinTreeNode* Root; //定义根结点指针
root=NULL; //null指针和未初始化的指针不同。
//未初始化的指针可能包含任何值,而包含NULL的指针则不会内存中的任何地址
新建一个结点
BinTreeNode *p=new BinTreeNode; //使用C++中new方法
p->data='A'; //给数据域赋值
P->LeftChild=NULL; //左子树为空
p->RightChild=NULL; //右子树为空
这里涉及到C++到new方法,我们后面会讲这个
建立二叉树
建立结点ABC,指针pqr分别指向ABC
p->RightChild=q; //左孩子指针指向B
p->RightChild=r; //右孩子指针指向C
new方法
首先看一段常见代码
void func()
{
int a=100; //a的内存是由编译器自动分配的
int* p=&a; //p存储了a的地址
}
函数结束运行时,编译器会自动释放a的内存
接下来我们可以用new这个关键字动态申请内存
void func()
{
int *p=new int; //动态申请了一个int大小的内存
delete p;
}
//用new请求的内存,我们需要用delate手动删除内存
//delete 释放的是p指向的内存,并不会删除p本身
//删除之后,该指针还可以指向别的地方,如下:
void func()
{
int a=100;
int* p=new int;
delete p;
p=&a;
}
//new还可以用来请求多个元素组成的数组
void func()
{
int* p=new int[100];
delete[] p; //[]中不需要填写具体的个数
}
完全二叉树编号:每个结点从上到下,每一层从左到右,1~n进行编号,注意,这个并不是遍历的顺序编号
完全二叉树的顺序存储,可以直接按照编号存储
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
A | B | C | D | E | F | G |
如果不是完全二叉树,可以增加虚结点,补全为一个完全二叉树,虚结点也需要存储,虚结点由#表示
根据数组中存储的完全二叉树,生成一个链式结构的二叉树(可能存在虚结点#)
算法:
下标为1的元素为根结点
依次处理数组元素,下标i是偶数的元素,是[i/2结]点的左孩子;下标i是奇数的元素,是[i/2]结点的右孩子,遇到虚元素就跳过
结点i和父结点[i/2]相连接:指针,结点[i/2]的指针为p,结点[i]的指针为q.
p->LeftChild=q;
//或者下面,根据情况选择
p->RightChild=q;