二叉树的常识基础看法(咋说呢,转载我自己的文章,就挺离谱的)
二叉树的自我理解
这是我自己的简单理解 对于什么是二叉树。我的个人看法说就是它其实就是先是一个利用递归的方式结构体然后再结构体里面放有数据,放指针,而对应的指针地址本身也是一个结构体就这样,一个无限套娃的形式产生了,有人就会说那不就停不下来了嘛,这样你可以给一个if判断输入,假如你不要了就直接停了它
if(' '==c)//判断传进去数据是否为空或则为空格
{
*T=NULL;//如果为空,则变成空指针没有后来的指向
}
树的定义
树(Tree)是n(n>=0)个结点的有限集。当n=0时成为空树,在任意一棵非空树中: 有且仅有一个特定的称为根(Root)的结点; 当n>1时,其余结点可分为m(m>0)个互不相交的有限集T1、T2、...、Tm,其中每一个集合本身又是一棵树,并且称为根的子树(SubTree)。
(注意:
对于二叉树的度的计算:非考试人员可以不用记,上网查就好了。
一棵二叉树T,如果其终端结点数为n0,度为2的结点数为n2,则n0=n2+1 这个推导,首先我们再假设度为1的结点数为n1,则二叉树T的结点总数n=n0+n1+n2 ,连接数等于总结点数n-1且等于n1+2*n2 于是n-1=n1+2*n2 所以n0+n1+n2-1=n1+n2+n2 则n0=n2+1。)
二叉树的种类
类型:斜二叉树,一般普通二叉树,满二叉树,完全二叉树。等概念。
直接画图来得更为清晰。
(注意:完全二叉树与满二叉树的区别是,完全二叉树对应的子叶是否有满,而满二叉树是要树的度层(每一层)都要是满的。满二叉树属于完全二叉树。)
二叉树存储与链接的理解和使用
结构的基本认识
知道了二叉树是什么东西后就要知道它的内在的存储方式与更好的使用方法。
知道我们在学习数据结构时,最开始接触的就是顺序存储结构和链式存储结构,但在树中它有点特殊,就是它确实可以用顺序存储结构和链式存储结构,但是为了更好的提高效率,它不当当需要的当个指向而是多个指向,就好像是双向链表与循环链表的结合。
链式链接方式
1.双亲表示法,言外之意就是以双亲作为索引的关键词的一种存储方式。就是按上图的从最开始的结点就行链接直接从头开始。
(*T)->lchild
2.孩子表示法,就是从下面的子叶开始索引到它上层的树从下往上。
T->lchild=T;//并将这个树里的嵌套地左指针指向它地本身
3.双亲孩子表示法就是上面的结合一起来,子叶可以指向树,树也可以指向子叶。这也是现在常用的用法
(注意:在使用这些方法时不可避免地会开辟较多地空间,但是却不可避免,于是就有了一个,来都来了地想法,开辟都开辟了那就利用空间来提高效率,可以不需要从头开始遍历,这样大大地提高效率。)
一个最为常用的线索二叉树遍历代码讲解
一点C语言的必备小知识
将数据类型进行重定义-方便一次性改变数据类型,线索存储标志位,Link(0):表示指向左右孩子的指针,Thread(1):表示指向前驱后续的线索,PointerTag只能在枚举的所定的范围内选取,假如对于枚举中特殊的用法还未链接的小伙伴可以看这个链接https://blog.csdn.net/weixin_46399138/article/details/106753889?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162228878416780262529110%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=162228878416780262529110&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_v2~rank_v29-1-106753889.pc_search_result_cache&utm_term=%E6%9E%9A%E4%B8%BE%E7%B1%BB%E5%9E%8Benum%E7%94%A8%E6%B3%95&spm=1018.2226.3001.4187
还有这个链接http://blog.sina.com.cn/s/blog_17de396f70102y7d3.htmlhttp://blog.sina.com.cn/s/blog_17de396f70102y7d3.html这样就能对齐有个清晰的认识。
之后便能理解这串代码。
#include<stdio.h>
#include<stdlib.h>
typedef char ElemType;
typedef enum{Link,Thread}PointerTag;
解析讲解
定义树的结点,结构指针作用相当于用来递归进行使用
PointerTag ltag,rtag只能在枚举的所定的范围内选取
BiThrNode,*BiThrTree不只是指树而且还可以在对用结点进行指针对应地址标志。
typedef struct BiThrNode
{
char data;
struct BiThrNode *lchild,*rchild;
PointerTag ltag,rtag;
}BiThrNode,*BiThrTree;
BiThrTree pre;全局变量,始终指向刚刚访问过的结点
//全局变量,始终指向刚刚访问过的结点
BiThrTree pre;
//创建一颗二叉树,约定用户遵照前序遍历的方式输入数据,这个使中序遍历的,传入的参数是树的指针也可以说是数的地址 char c/定义要存在树里面得到数据if(' '==c)//判断传进去数据是否为空或则为空格,如果为空,则变成空指针没有后来的指向,如果输入的部位空的话就进行数据的存储和指针的指向,malloc/创造出对应的树的空间,(*T)->data=c将数据存储进去其中T->data 这个是this指针地指向就是相当于x=x(是指后面地x是改过地)(*T)->ltag=Link开始确定该地址指向可以有左右孩子,CreateBiTree(&(*T)->lchild)
void CreateBiTree(BiThrTree *T)
{
char c;
scanf("%c",&c);
if(' '==c)
{
*T=NULL;
}
else
{
*T=(BiThrNode *)malloc(sizeof(BiThrNode));
(*T)->data=c;
(*T)->ltag=Link;
(*T)->rtag=Link;
CreateBiTree(&(*T)->lchild);
CreateBiTree(&(*T)->rchild);
}
}
嵌套中的嵌套,就是将下一个左右孩子的地址拿出来再次创造出新的空间。
中序遍历线索化,开始进行中序遍历,if(T)条件//如果T存在部位null空,则就可以进行遍历,先不断地往下找进行遍历,直到对应结点或树地下一个孩子也就是子叶为空时停止,if(!T->lchild)//就如一直遍历到最后空指针时,T->ltag=Thread;//在该这个树进行表值他是有数据的。
void InThreading(BiThrTree T)
{
if(T)
{
InThreading(T->lchild);
if(!T->lchild)
{
T->ltag=Thread;
T->lchild=T;
}
pre=T;
Inthreading(T->rchild);
}
}
有序地开始遍历,将最开始树,头结点和后面地树结点进行传入。
void InOrderThreading(BiThrTree *p,BiThrTree T)
{
*p=(BiThrTree)malloc(sizeof(BiThrNode));
(*p)->ltag=Link;
(*p)->rtag=Thread;
(*p)->rchild=*p;
if(!T)
{
(*p)->lchild=T;
pre=*p;
InThreading(T);
pre->rchild=*p;
pre->rtag=Thread;
(*p)->rchild=pre;
}
}
读取在树中存储的数据
void visit(char c)
{
printf("%c",c);
}
中序遍历二叉树,非递归,订单开始将树中存储的信息并不断的读出来,定义一个临时的点树进行暂存像temp那样当中间媒介那样,(p!=T)//加如它存储的不是下面哪一个的上面的树依旧是最后一颗树的子叶指向它树的本身的结点就进行下面。
void InOrderTraverse(BiThrTree T)
{
BiThrTree p;
p=T->lchild;
while(p!=T)
{
while(p->ltag==Link)
{
p=p->lchild;
}
visit(p->data);
while(p->rtag==Thread&&p->rchild!=T)
{
p=p->rchild;
visit(p->data);
}
p=p->rchild;
}
}
剩下就没什么了就是简单的实现和使用。
int main()
{
BiThrTree P,T=NULL;//最开始就行NULL定义最初话进行
CreateBiTree(&T);//开始创造用户需要的树开始
InOrderThreading(&P,T);//将头结点和头树开始遍历查找
printf("中序遍历输出结果为:");
InOrderTraverse(p);//输入查按照的值
printf("\n");
return 0;
}
基础二叉树实例
直接上代码
#include<stdio.h>
#include<stdlib.h>
typedef char ElemType;//将变量进行重定义-方便一次性改变数据类型
typedef struct BiTNode//定义树的结点
{
char data;
struct BiTNode *lchild,*rchild;//定义结构指针作用相当于用来递归进行使用
}BiTNode,*BiTree;//不只是指树而且还可以在对用结点进行指针对应地址标志
void CreateBiTree(BiTree *T)//创造二叉树,这个使中序遍历的,传入的参数是树的指针也可以说是数的地址
{
char c;//定义要存在树里面得到数据
scanf("%c",&c);//输入数据
if(' '==c)//判断传进去数据是否为空或则为空格
{
*T=NULL;//如果为空,则变成空指针没有后来的指向
}
else//如果输入的不为空的话就进行数据的存储和指针的指向
{
*T=(BiTNode *)malloc(sizeof(BiTNode));//创造出对应的树的空间
(*T)->data=c;//将数据存储进去其中T->data 这个是this指针地指向就是相当于x=x(是指后面地x是改过地)
CreateBiTree(&(*T)->lchild);//嵌套中的嵌套,就是将下一个左右孩子的地址拿出来再次创造出新的空间
CreateBiTree(&(*T)->rchild);//如果没有或则是输入为空则停止不再输入,和创造
}
}
void visit(char c,int level)//读取在树中存储的数据
{
printf("%c位于第%d层",c,level);//打印数据
printf("\n");
}
void PreOrderTraverse(BiTree T,int level)//前序遍历
{
if(T)
{
visit(T->data,level);
PreOrderTraverse(T->lchild,level+1);
PreOrderTraverse(T->rchild,level+1);
}
}
int main()
{
int level =1;
BiTree T=NULL;//最开始就行NULL定义最初话进行
CreateBiTree(&T);//开始创造用户需要的树开始
PreOrderTraverse(T,level);//将头结点和头树开始遍历查找
return 0;
}
使用效果:
(注:输入空格则以为空结点,为空指针指向。)
特殊二叉树
赫夫曼树
是一种最优二叉树选择。通过计算WPL来确定它的效率。现今使用在文件传输与文件压缩的功能中。WPL=树的度乘于该层中的权值(可以理解为结点里存的数据值)。
当树的WPL越小则效率越高,所以在我们在对于值得使用和判定的时候需要考虑的位置和链接。
红黑树
和上面所将的二叉树没有任何差别,只是他会在结点里,在存储数据时也标记该结点为红或黑。