二叉树概念
树结构是一种非线性存储结构结构,存储的事具有“一对多”关系的数据元素的集合。
树的结点
结点:使用树结构存储的每一个数据元素都被称为“结点”
父结点(双亲结点)、子节点、兄弟结点
树根结点:(“根结点”):每一个非空树都有且只有一个被称为根结点。
叶子结点:如果结点没有任何子节点,那么此结点称为叶子结点。
子树、空树:如果集合本身为空,那么构成的树被称为空树,空树中没有结点
结点的度和层次
对于一个结点,拥有的子树数(结点有多少分支)称为结点的度(Degree)
结点的层次
从一颗树的树根开始,树根所在层为第一层,根的孩子结点所在的层为第二层,依次类推。
有序数和无序树
如果树中结点的子树从左到右看,谁在左边,谁在右边,是有规定的,这颗树称为有序树,反之称为无序树。
森林
由m(m>0)个互不相交的树组成的集合称为森林。
二叉树存储
二叉树链式存储
/*
Author:new
Time:20190911
Consult:http://data.biancheng.net/view/vip_237.html
*/
#include<stdio.h>
#include<stdlib.h>
#define TElemType int
typedef struct BiTNode{
TElemType data;//数据域
struct BiTNode *lchild,*rchild;//左右孩子指针
struct BiTNode *parent;
}BiTNode;//typedef struct BiTNode{}BiTNode,*BiTree; // BiTree表示 指向BiTNode的地址变量
void CreateBiTree(BiTNode *T){// BiTree *T:指向变量又定义一个指向变量,why?? T 为指向 BiTree的地址,*T即为BiTree
//根结点
//T = (BiTNode *)malloc(sizeof(BiTNode));//*T 表示指针变量 BiTree
T->data =1;
//左子树
T->lchild = (BiTNode *)malloc(sizeof(BiTNode));
T->lchild->data = 2;
//右子树
T->rchild = (BiTNode *)malloc(sizeof(BiTNode));
T->rchild->data = 3;
//右子树的左结点
T->rchild->lchild = NULL;
//右子树的右节点
T->rchild->rchild =NULL;
//
T->lchild->lchild = (BiTNode *)malloc(sizeof(BiTNode));
T->lchild->lchild->data = 4;
T->lchild->rchild = NULL;
//
T->lchild->lchild->lchild = NULL;
T->lchild->lchild->rchild = NULL;
}
int main(){
// BiTree Tree;
BiTNode *Tree;//为分配内存,故无效,错误类型:SIGSEGV(Segment fault)意味着指针所对应的地址是无效地址,没有物理内存对应该地址。
Tree = (BiTNode *)malloc(sizeof(BiTNode));
CreateBiTree(Tree);
printf("%d",Tree->lchild->lchild->data);
return 0;
}
没啥问题,可以引用哦(备注下出处)
三种遍历方式
- 先访问根结点,在遍历左右子树,称先序遍历
- 遍历左子树,之后访问根结点,然后遍历右子树,成中序遍历
- 遍历完左右子树,再访问根结点,称后序遍历
三种方式唯一的不同是访问结点时机的不同
二叉树遍历(递归)
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
/*关键点:构造结点结构体、初始化二叉树
递归方法访问二叉树还是有点不理解
前序遍历:根左右
中序遍历:左根右
后序遍历:左右根
*/
#define TElemType int
//构造结点的结构体
typedef struct BiTNode{
TElemType data;//数据域
struct BiTNode *lchild,*rchild;//左右孩子指针
}BiTNode;
void CreateTree(BiTNode *);
void disp(BiTNode *);
void PreOrderTraverse();
void InOrderTraverse();
void PostOrderTraverse();
int main(){
BiTNode *Tree;
//分配内存
Tree = (BiTNode *)malloc(sizeof(BiTNode));
//初始化二叉树
CreateTree(Tree);
printf("%d\n",Tree->lchild->lchild->data);
printf("前序遍历\n");
PreOrderTraverse(Tree);
printf("中序遍历\n");
InOrderTraverse(Tree);
printf("后序遍历\n");
PostOrderTraverse(Tree);
return 0;
}
void CreateTree(BiTNode *T){
//根结点
//T = (BiTNode *)malloc(sizeof(BiTNode));//*T 表示指针变量 BiTree
T->data =1;
//左子树
T->lchild = (BiTNode *)malloc(sizeof(BiTNode));
T->lchild->data = 2;
//右子树
T->rchild = (BiTNode *)malloc(sizeof(BiTNode));
T->rchild->data = 3;
//右子树的左结点
T->rchild->lchild = NULL;
//右子树的右节点
T->rchild->rchild =NULL;
//
T->lchild->lchild = (BiTNode *)malloc(sizeof(BiTNode));
T->lchild->lchild->data = 4;
T->lchild->rchild = NULL;
//
T->lchild->lchild->lchild = NULL;
T->lchild->lchild->rchild = NULL;
}
//模拟操作结点元素的函数,输出结点本身的数字
void disp(BiTNode *T){
printf("%d",T->data);
printf("\n");
}
//先序遍历
void PreOrderTraverse(BiTNode *T){
if(T!=NULL){
disp(T);//调用操作结点数据的函数方法
PreOrderTraverse(T->lchild);//访问该结点的左孩子
PreOrderTraverse(T->rchild);//访问该结点的右孩子
}
//如果结点为空,返回上一层
return;
}
//中序遍历
void InOrderTraverse(BiTNode *T){
if(T!=NULL){
InOrderTraverse(T->lchild);//遍历左孩子
disp(T);
InOrderTraverse(T->rchild);//遍历右孩子
}
return;
}
//后序遍历
void PostOrderTraverse(BiTNode *T){
if(T!=NULL){
PostOrderTraverse(T->lchild);//遍历左孩子
PostOrderTraverse(T->rchild);//遍历右孩子
disp(T);
}
return;
}
二叉树层次遍历
/*
Author:new
Time:20190911
Consult:http://data.biancheng.net/view/vip_237.html
*/
#include<stdio.h>
#include<stdlib.h>
#define TElemType int
//初始化队头和队尾指针,开始值为0
int front =0,rear =0;
typedef struct BiTNode{
TElemType data;//数据域
struct BiTNode *lchild,*rchild;//左右孩子指针
struct BiTNode *parent;
}BiTNode;//
//入队函数
void EnQueue(BiTNode **a,BiTNode *node){
a[rear++] = node;
}
//出队函数
BiTNode *DeQueue(BiTNode **a){
return a[front++];
}
//模拟操作结点元素的函数,输出结点本身的数字
void disp(BiTNode *T){
printf("%d",T->data);
printf("\n");
}
void CreateBiTree(BiTNode *T){// BiTree *T:指向变量又定义一个指向变量,why?? T 为指向 BiTree的地址,*T即为BiTree
//根结点
//T = (BiTNode *)malloc(sizeof(BiTNode));//*T 表示指针变量 BiTree
T->data =1;
//左子树
T->lchild = (BiTNode *)malloc(sizeof(BiTNode));
T->lchild->data = 2;
//右子树
T->rchild = (BiTNode *)malloc(sizeof(BiTNode));
T->rchild->data = 3;
//右子树的左结点
T->rchild->lchild = NULL;
//右子树的右节点
T->rchild->rchild =NULL;
//
T->lchild->lchild = (BiTNode *)malloc(sizeof(BiTNode));
T->lchild->lchild->data = 4;
T->lchild->rchild = NULL;
//
T->lchild->lchild->lchild = NULL;
T->lchild->lchild->rchild = NULL;
}
int main(){
// BiTree Tree;
BiTNode *Tree;//为分配内存,故无效,错误类型:SIGSEGV(Segment fault)意味着指针所对应的地址是无效地址,没有物理内存对应该地址。
Tree = (BiTNode *)malloc(sizeof(BiTNode));
CreateBiTree(Tree);
//printf("%d\n",Tree->lchild->lchild->data);
printf("层次遍历\n");
BiTNode *p;
//采用顺序队列,初始化创建队列数组
BiTNode *a[20];
//根结点入队
EnQueue(a,Tree);//将@树结点的地址存入数组
//当队头和队尾相等时,表示队列为空
while(front < rear){
//队头结点出队
p=DeQueue(a);
disp(p);
//将队头结点的左右孩子依次入队
if(p->lchild != NULL){
EnQueue(a,p->lchild);
}
if(p->rchild != NULL){
EnQueue(a,p->rchild);
}
}
return 0;
}
asd
二叉树前序遍历(非递归)
/*
Author:new
Time:20190911
Consult:http://data.biancheng.net/view/vip_237.html
前序遍历:非递归方法,借助顺序栈,
*/
#include<stdio.h>
#include<stdlib.h>
#define TElemType int
int top =-1;//top变量时刻表示栈顶元素所在位置
typedef struct BiTNode{
TElemType data;//数据域
struct BiTNode *lchild,*rchild;//左右孩子指针
struct BiTNode *parent;
}BiTNode;
void CreateBiTree(BiTNode *T){
//根结点
//T = (BiTNode *)malloc(sizeof(BiTNode));//*T 表示指针变量 BiTree
T->data =1;
//左子树
T->lchild = (BiTNode *)malloc(sizeof(BiTNode));
T->lchild->data = 2;
//右子树
T->rchild = (BiTNode *)malloc(sizeof(BiTNode));
T->rchild->data = 3;
//右子树的左结点
T->rchild->lchild = NULL;
//右子树的右节点
T->rchild->rchild =NULL;
//
T->lchild->lchild = (BiTNode *)malloc(sizeof(BiTNode));
T->lchild->lchild->data = 4;
T->lchild->rchild = NULL;
//
T->lchild->lchild->lchild = NULL;
T->lchild->lchild->rchild = NULL;
}
//前序遍历使用的进栈函数
void push(BiTNode **a,BiTNode *elem){
a[++top] = elem;//那二叉树地址存到顺序栈中
}
//出栈函数
void pop(){
if(top == -1){
return;
}
top--;//top为数组下标
}
//模拟操作结点元素的函数,输出结点本身的数字
void disp(BiTNode *T){
printf("%d",T->data);
printf("\n");
}
//拿到栈顶元素
BiTNode *getTop(BiTNode **a){
return a[top];
}
void PreOrderTraverse(BiTNode *T){
BiTNode *a[20];//定义一个顺序栈
BiTNode *p;//临时指针
push(a,T);//根结点进栈,关键点:数组下标top值实现数据进栈和出栈
while(top != -1){
p = getTop(a);//取栈顶元素,@将先前入栈结点取出其地址
pop();//出栈,@实际a数组中数据还在,这是通过top=-1,实现无法再访问顺序栈了
while(p){
disp(p);//调用结点的操作函数
//如果该结点有右孩子,右孩子进栈
if(p->rchild){
push(a,p->rchild);
}
p = p->lchild;//一直指向根结点最后一个左孩子
}
}
}
/*使用链表初始化树, 这里怎么实现前序遍历*/
int main(){
// BiTree Tree;
BiTNode *Tree;//为分配内存,故无效,错误类型:SIGSEGV(Segment fault)意味着指针所对应的地址是无效地址,没有物理内存对应该地址。
Tree = (BiTNode *)malloc(sizeof(BiTNode));
CreateBiTree(Tree);
//printf("%d",Tree->lchild->lchild->data);
printf("前序遍历\n");
PreOrderTraverse(Tree);
return 0;
}
asd
线索二叉树
在遍历的同时,使用二叉树中空闲的内存空间记录某些结点的前趋和后继的位置(不是全部),这样在算法后期需要遍历二叉树时,就可利用保存的结点信息,提高了遍历效率,使用该种方法构建的二叉树称为“线索二叉树”
存储密度:指数据本身所占的存储空间和整个结点结构所占的存储量之比。
规律:在有n个结点的二叉链表中必定存在n+1个空指针域。
线索二叉树实际上就是使用空指针域来存储结点之前前趋和后继关系的一种特殊的二叉树。