二叉树相关/根据前序、中序确定二叉树

树相关概念(参考大话数据结构):

树是一对多的数据结构。
根节点:一个树中只有一个根节点(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;
}

 

  • 6
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
以下是C++实现重建二叉树的代码和解释: ```cpp #include <iostream> #include <vector> #include <unordered_map> using namespace std; struct TreeNode { int val; TreeNode* left; TreeNode* right; TreeNode(int x) : val(x), left(NULL), right(NULL) {} }; class Solution { public: TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) { unordered_map<int, int> inorder_map; for (int i = 0; i < inorder.size(); i++) { inorder_map[inorder[i]] = i; } return buildTreeHelper(preorder, 0, preorder.size() - 1, inorder, 0, inorder.size() - 1, inorder_map); } TreeNode* buildTreeHelper(vector<int>& preorder, int pre_start, int pre_end, vector<int>& inorder, int in_start, int in_end, unordered_map<int, int>& inorder_map) { if (pre_start > pre_end || in_start > in_end) { return NULL; } int root_val = preorder[pre_start]; TreeNode* root = new TreeNode(root_val); int inorder_root_index = inorder_map[root_val]; int left_subtree_size = inorder_root_index - in_start; root->left = buildTreeHelper(preorder, pre_start + 1, pre_start + left_subtree_size, inorder, in_start, inorder_root_index - 1, inorder_map); root->right = buildTreeHelper(preorder, pre_start + left_subtree_size + 1, pre_end, inorder, inorder_root_index + 1, in_end, inorder_map); return root; } }; int main() { vector<int> preorder = {3, 9, 20, 15, 7}; vector<int> inorder = {9, 3, 15, 20, 7}; Solution s; TreeNode* root = s.buildTree(preorder, inorder); return 0; } ``` 解释: 1. 首先定义二叉树的结构体`TreeNode`,包含一个整型变量`val`和两个指向左右子树的指针`left`和`right`。 2. 定义一个`Solution`类,其包含一个`buildTree`函数,用于重建二叉树。该函数接受两个参数,分别是遍历列`preorder`和遍历列`inorder`,返回重建后的二叉树的根节点指针。 3. 在`buildTree`函数,首先创建一个哈希表`inorder_map`,用于存储遍历每个元素的值和下标的对应关系。 4. 调用`buildTreeHelper`函数,传入遍历列、遍历列、遍历列的起始位置和结束位置、遍历列的起始位置和结束位置以及遍历列的哈希表。 5. 在`buildTreeHelper`函数,首先判断遍历列和遍历列是否为空,如果是,则返回`NULL`。 6. 取出遍历列的第一个元素作为根节点的值,创建一个新的`TreeNode`节点。 7. 在遍历查找根节点的值,得到根节点在遍历的下标`inorder_root_index`。 8. 计算左子树的大小`left_subtree_size`,即遍历根节点左边的元素个数。 9. 递归调用`buildTreeHelper`函数,传入遍历列、左子树的遍历列的起始位置和结束位置、遍历列、左子树的遍历列的起始位置和结束位置以及遍历列的哈希表,得到左子树的根节点指针,将其赋值给当节点的左指针。 10. 递归调用`buildTreeHelper`函数,传入遍历列、右子树的遍历列的起始位置和结束位置、遍历列、右子树的遍历列的起始位置和结束位置以及遍历列的哈希表,得到右子树的根节点指针,将其赋值给当节点的右指针。 11. 返回当节点的指针。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值