树相关概念(参考大话数据结构):
树是一对多的数据结构。
根节点:一个树中只有一个根节点(root)。
子树:节点的子树数量是指与它相邻的(而不是节点下面所有的)下一层有几个节点。
度:节点拥有的子树数量称为节点的度(Degree)。树的度是指树内所有节点度的最大值。
度为0的节点称为叶节点或终端节点。度不为0的节点称为非终端节点或分支节点。
深度:是指树的高度,有几层。
将树中节点的各子树看成从左到右是有次序的,不能互换的,称该树为有序树,否则为无序树。
森林是m(m>=0)棵互不相交的树的集合。对于树中每个节点而言,其子树的集合即为森林。
二叉树相关:
特点:
1.每个节点最多有两个子树,所以二叉树中不存在度大于2的节点。
2.二叉树是有序树,左子树和右子树顺序不能颠倒。
3.二叉树中某节点只有一棵子树时,也要区分是左子树还是右子树。
特殊二叉树:
斜树:所有节点都只有左(右)子树的称为左(右)斜树。斜树跟线性表结构一样。
满二叉树:所有分支节点都存在左右子树,并且所有叶节点都在同一层。
完全二叉树:将满二叉树的最后一层最后一个节点从右到左连续删除任意个节点(必须包含最后一个节点,必须从右到左,必须连续)得到的树就是完全二叉树(这个定义是自己写的,这样写了觉得好理解多了)。
二叉树性质:
1.终端节点(叶节点)数量为a,度为2的节点数量为b,则a=b+1(可使用满二叉树推导,满二叉树的最后一层叶节点的数量-1=不包含最后一层的树的所有节点和)
二叉树存储结构:
1.可以使用二叉链表(包含左子指针和右子指针)或三叉链表(多个父指针)的方式表示
二叉树遍历:
定义:从根节点出发,按照某种次序依次访问二叉树中所有节点,使得每个节点被访问一次且仅被访问一次。
前序遍历(preorder Travelsal VLR):先访问根节点,然后前序遍历左子树,再前序遍历右子树。
中序遍历(inorder Travelsal LDR):从根节点开始(不是先访问根节点),中序遍历根节点的左子树,然后访问根节点,最后中序遍历右子树。
后序遍历(postorder Travelsal LDR):从左到右先叶节点后节点的方式遍历访问左右子树,最后访问根节点。
层序遍历:从树的第一层根节点开始,从上而下逐层遍历,同一层中,按从左到右的顺序遍历。
这里的前、中、后指的是访问根节点的顺序,前指最先访问根节点,中是指中间访问根节点、后是指最后访问根节点,可以对比前中后三种遍历代码对应理解。
下图分别为前序、中序、后序、层序。
推导遍历结果:
1.已知前序遍历和中序遍历,可以确定唯一二叉树。
2.已知后序遍历和中序遍历,可以确定唯一二叉树。
3.已知前序和后序,不能确定二叉树。
前序和中序推导树,推导流程如下:
1.首先确定根节点(前序的第一个字母,后序的最后一个字母),根据根节点可将中序分割成左子树和右子树。
2.将左子树和右子树看成新的树,重复第一步,递归求解树。
比如前序是ABCDEF,中序是CBAEDF,A是根节点,CB是A的左子树,EDF是A的右子树。
对左子树CB进行重新分析。前序是BC,中序是CB,说明B是左子树的根节点,C是B的子节点。中序是CB,C为B的左子节点。
对右子树EDF进行重新分析。前序是DEF,中序是EDF,说明D是右子树的根节点,EF是D的子节点。继续分析即可。
后序和中序推导树,推导流程如下:
1.后序的最后一个节点是根节点,根据根节点在中序中的位置可以将树划分为左右子树。
2.得到左右子树的后序和中序,可以找到左右子树的根节点,继续递归分析即可。
比如中序是CBAEDF,后序是CBEFDA
根节点为后序的最后一个节点A,左子树的中序是CB,左子树的后序是CB,右子树的中序是EDF,右子树的后序是EFD。
左子树的根节点是B,继续分析即可。
前序、中序、后序遍历及基于前序、中序创建树,基于后序、中序创建树的C代码如下:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<signal.h> //signal()
#include<string.h>
#include<sys/stat.h>
#include<time.h>
#include<stdarg.h>
#if 1
#define INFO_DEBUG "%d lines in "__FILE__", complie time is "__TIME__" "__DATE__" \n",__LINE__
#define ADI_RUN_ERROR 1
#define ADI_NULL_POINTER -1
#define ADI_OK 0
#define ADI_PRINT printf("[%s][%d]:",__FUNCTION__,__LINE__);printf
#define ADI_ASSERT(c,prt,ret) if(c) {printf(prt);return ret;}
#endif
#define SUCCESS 0
#define NULL_POINTER 1
#define eleType char
int strLength(char *str)
{
int length = 0;
while('\0' != str[length])
{
length++;
}
return length;
}
/*
二叉树相关
*/
typedef struct BitNode{
eleType ele;
struct BitNode *left,*right;
}BitNode;
/*只创建一个根节点,要指定根节点的值,并将左右指针都设为NULL*/
BitNode *initBitTree(eleType elem)
{
BitNode *root = malloc(sizeof(BitNode));
if(NULL==root) {printf("NULL");return root;}
root->ele = elem;
root->right = NULL;
root->left = NULL;
return root;
}
/*
指定插入的位置:有两种方式,1是指定插入的节点对应的值及左右位置,或者指定插入节点的节点号及左右位置
这里实现指定插入的值及左右位置。
参数意义:
bitTree:要插入的二叉树
parent:父节点值
child:子节点值
pos;插入父节点的左还是右, =0,左;=1,右
*/
int insertBitTree(BitNode *bitTree,eleType parent,eleType child,int pos)
{
}
/*二叉树前序遍历算法,使用递归实现*/
void preorderBitTree(BitNode *bitTree)
{
if(NULL == bitTree)
{
return;
}
printf("%c",bitTree->ele);
preorderBitTree(bitTree->left);
preorderBitTree(bitTree->right);
}
/*二叉树中序遍历算法,使用递归实现*/
void inorderBitTree(BitNode *bitTree)
{
if(NULL == bitTree)
{
return;
}
inorderBitTree(bitTree->left);
printf("%c",bitTree->ele);
inorderBitTree(bitTree->right);
}
/*二叉树后序遍历算法,使用递归实现*/
void postorderBitTree(BitNode *bitTree)
{
if(NULL == bitTree)
{
//ADI_PRINT("NULL pointer\n");
return;
}
postorderBitTree(bitTree->left);
postorderBitTree(bitTree->right);
printf("%c",bitTree->ele);
}
/*根据前序和中序创建树
root:待创建树的根节点
pre:前序
mid:中序
size:树的size
这里涉及二级指针的使用及C语言运算符优先级相关
*/
int treeFromPreMid(BitNode **root,char *pre,char *mid,int size)
{
/*0 == size_length意味着上一次的i=0,即pre[0]=mid[0](树中只有一个节点),递归结束*/
if(0 == size)
{
return SUCCESS;
}
ADI_PRINT("size=%d\n",size);
(*root) = (BitNode *)malloc(sizeof(BitNode));
(*root)->ele = pre[0];
/*找到根节点元素在中序中的位置i*/
int i=0;
while(mid[i] != pre[0])
{i++;}
treeFromPreMid(&(*root)->left,&pre[1],mid,i);//左子树递归求解,C语言运算符优先级:()等于->大于&,所以先*root,接着->,再&
treeFromPreMid(&(*root)->right,&pre[i+1],&mid[i+1],size-i-1);//右子树递归求解
}
/*根据中序,后序求树*/
int treeFromPostMid(BitNode **root, char *post, char *mid,int size)
{
if(0 == size)
{
return SUCCESS;
}
ADI_PRINT("size=%d\n",size);
*root = (BitNode *)malloc(sizeof(BitNode));
(*root)->ele = post[size-1];
int i=0;
while(post[size-1] != mid[i])
{i++;}
treeFromPostMid(&(*root)->left,post,mid,i);
treeFromPostMid(&(*root)->right,&post[i],&mid[i+1],size-i-1);
}
int main()
{
char *pre = "ABCDEF";
char *mid = "CBAEDF";
char *post = "CBEFDA";
BitNode *ROOT = NULL;
treeFromPreMid(&ROOT,pre,mid,strLength(pre));
postorderBitTree(ROOT);
printf("\n");
treeFromPostMid(&ROOT,post,mid,strLength(pre));
preorderBitTree(ROOT);
return SUCCESS;
}