版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/tonglin12138/article/details/88879920
二叉树的建立:
//二叉树的二叉链表结构,也就是二叉树的存储结构,1个数据域,2个指针域(分别指向左右孩子)
typedef struct BiTNode
{
ElemType data;
struct BiTNode *lchild, *rchild;
}BiTNode, *BiTree;
//二叉树的建立,按前序遍历的方式建立二叉树,当然也可以以中序或后序的方式建立二叉树
void CreateBiTree(BiTree *T)
{
ElemType ch;
cin >> ch;
if (ch == '#')
*T = NULL; //保证是叶结点
else
{
*T = (BiTree)malloc(sizeof(BiTNode));
//if (!*T)
//exit(OVERFLOW); //内存分配失败则退出。
(*T)->data = ch;//生成结点
CreateBiTree(&(*T)->lchild);//构造左子树
CreateBiTree(&(*T)->rchild);//构造右子树
}
}
二叉树的遍历
前序遍历:
1 void preOrder1(BinTree *root) //递归前序遍历
2 {
3 if(root!=NULL)
4 {
5 cout<<root->data<<" ";
6 preOrder1(root->lchild);
7 preOrder1(root->rchild);
8 }
9 }
1 void preOrder2(BinTree *root) //非递归前序遍历
2 {
3 stack<BinTree*> s;
4 BinTree *p=root;
5 while(p!=NULL||!s.empty())
6 {
7 while(p!=NULL)
8 {
9 cout<<p->data<<" ";
10 s.push(p);
11 p=p->lchild;
12 }
13 if(!s.empty())
14 {
15 p=s.top();
16 s.pop();
17 p=p->rchild;
18 }
19 }
20 }
中序遍历 :
1 void inOrder1(BinTree *root) //递归中序遍历
2 {
3 if(root!=NULL)
4 {
5 inOrder1(root->lchild);
6 cout<<root->data<<" ";
7 inOrder1(root->rchild);
8 }
9 }
1 void inOrder2(BinTree *root) //非递归中序遍历
2 {
3 stack<BinTree*> s;
4 BinTree *p=root;
5 while(p!=NULL||!s.empty())
6 {
7 while(p!=NULL)
8 {
9 s.push(p);
10 p=p->lchild;
11 }
12 if(!s.empty())
13 {
14 p=s.top();
15 cout<<p->data<<" ";
16 s.pop();
17 p=p->rchild;
18 }
19 }
20 }
后序遍历:
1 void postOrder1(BinTree *root) //递归后序遍历
2 {
3 if(root!=NULL)
4 {
5 postOrder1(root->lchild);
6 postOrder1(root->rchild);
7 cout<<root->data<<" ";
8 }
9 }
要保证根结点在左孩子和右孩子访问之后才能访问,因此对于任一结点P,先将其入栈。
如果P不存在左孩子和右孩子,则可以直接访问它;或者P存 在左孩子或者右孩子,但是其左孩子和右孩子都已被访问过了,则同样可以直接访问该结点。若非上述两种情况,则将P的右孩子和左孩子依次入栈,这样就保证了 每次取栈顶元素的时候,左孩子在右孩子前面被访问,左孩子和右孩子都在根结点前面被访问。
1 void postOrder3(BinTree *root) //非递归后序遍历
2 {
3 stack<BinTree*> s;
4 BinTree *cur; //当前结点
5 BinTree *pre=NULL; //前一次访问的结点
6 s.push(root);
7 while(!s.empty())
8 {
9 cur=s.top();
10 if((cur->lchild==NULL&&cur->rchild==NULL)||
11 (pre!=NULL&&(pre==cur->lchild||pre==cur->rchild)))
12 {
13 cout<<cur->data<<" "; //如果当前结点没有孩子结点或者孩子节点都已被访问过
14 s.pop();
15 pre=cur;
16 }
17 else
18 {
19 if(cur->rchild!=NULL)
20 s.push(cur->rchild);
21 if(cur->lchild!=NULL)
22 s.push(cur->lchild);
23 }
24 }
25 }
层序遍历
void level_order(Bitree *root)
{
if(root==NULL)
return;
Bitree p=root;
queue<Bitree>queue_;
queue.push(p);
while(!queue_.empty())
{
p=queue_.front();
cout<<p->data<<endl;
queue_.pop();
if(p->lchild)
queue_.push(p->lchild);
if(p->rchild)
queue_.push(p->rchild);
}
}
将有序数组转换为二叉搜索树
1 /**
2 * Definition for binary tree
3 * struct TreeNode {
4 * int val;
5 * TreeNode *left;
6 * TreeNode *right;
7 * TreeNode(int x) : val(x), left(NULL), right(NULL) {}
8 * };
9 */
10 class Solution {
11 public:
12 TreeNode *sortedArrayToBST(vector<int> &num) {
13 return sortedArrayToBST(num, 0 , num.size() - 1);
14 }
15 TreeNode *sortedArrayToBST(vector<int> &num, int left, int right) {
16 if (left > right) return NULL;
17 int mid = (left + right) / 2;
18 TreeNode *cur = new TreeNode(num[mid]);
19 cur->left = sortedArrayToBST(num, left, mid - 1);
20 cur->right = sortedArrayToBST(num, mid + 1, right);
21 return cur;
22 }
23 };
判断平衡树
解决思路一:按照前序遍历的路线判断。
1.判断以根结点的树是否为二叉平衡树。求出左右子树的高度,判断它们的高度差是否超过了1。
2.递归判断根的左子树是否为平衡二叉树
3.递归判断根的右子树是否为平衡二叉树
注意:空树也是平衡二叉树
代码实现:
//二叉树的高度(比较左右子树那个高,高的加1既为二叉树的高度)
int BinaryTreeHigh(BTNode* root)
{
if (root == NULL)
{
return 0;
}
int ret1 = BinaryTreeHigh(root->_left);
int ret2 = BinaryTreeHigh(root->_right);
//二叉树的高度为左子树和右子树中高的那个高度加1
return ret1 > ret2 ? ret1 + 1 : ret2 + 1;
}
//判断树是否为平衡二叉树(1:是 0:不是)
int IsBlancedTree_R(BTNode* root)
{
//空树是平衡二叉树
//平衡二叉树是指以当前结点为根的左右子树高度不得超过1
if (root == NULL)
return 1;
//右子树深度
int right = BinaryTreeHigh(root->_left);
//左子树深度
int left = BinaryTreeHigh(root->_right);
int gap = right - left;
//深度超过1不是
if (gap > 1 || gap < -1)
return 0;
//递归判断子树
return IsBlancedTree_R(root->_left) && IsBlancedTree_R(root->_right);
}
对于上边的代码,效率会很低,因为这种方法存在着许多重复的计算。以上图的例子分析,从12开始判断,用BinaryTreeHigh函数求深度时,要遍历35、9,而在判断以35位根的树是否为平衡二叉树时也要遍历9。因此,这种方法存在着许多重复的计算。那么我们怎么能让它们不重复呢?
解决思路二:按照后序遍历的路线判断
1.首先,判断它的左子树是否为平衡二叉树
2.然后在判断它的右子树是否为平衡二叉树
3.判断它们是否为平衡二叉树的同时,记录它们的左右子树的深度
4.最后在判断以这个结点为根的树是否为平衡二叉树
代码实现:
//判断树是否为平衡二叉树(1:是 0:不是)
//优化版本(不用遍历重复的结点)
int IsBlancedTree_op(BTNode* root, int *pdepth)
{
if (root == NULL)
{
*pdepth = 0;
return 1;
}
//按照后序遍历去判断,先判断左右子树,然后记录以当前结点为根树的深度
int left, right;
if (IsBlancedTree_op(root->_left, &left) && IsBlancedTree_op(root->_right, &right))
{
int gap = right - left;
if (gap <= 1 && gap >= -1)
{
*pdepth = left>right ? left + 1 : right + 1;
return 1;
}
}
return 0;
}
根据前序和中序构建一棵树
/************************************************************************/
/* 算法
1、通过先序遍历找到根结点A,再通过A在中序遍历的位置找出左子树,右子树
2、在A的左子树中,找左子树的根结点(在先序中找),转步骤1
3、在A的右子树中,找右子树的根结点(在先序中找),转步骤1 */
/************************************************************************/
//根据先序遍历和中序遍历创建二叉树
BiTNode* createBiTree(char *pre, char *in, int n)
{
int i = 0;
int n1 = 0,n2 = 0;
int m1 = 0,m2 = 0;
BiTNode*node = NULL;
char lpre[N],rpre[N];
char lin[N],rin[N];
if (n == 0)
{
return NULL;
}
node = (BiTNode*)malloc(sizeof(BiTNode));
if (node==NULL)
{
return NULL;
}
memset(node,0,sizeof(BiTNode));
//先序序列的第一个元素必为根结点
node->data = pre[0];
//根据根结点将中序序列分为左子树和右子数
for (i = 0;i<n;i++)
{
if ((i<=n1)&&(in[i]!=pre[0]))
{
lin[n1++] = in[i];
}
else if(in[i]!=pre[0])
{
rin[n2++] = in[i];
}
}
//根据树的先序序列的长度等于中序序列的长度
//且先序遍历是先左子树再后子树,无论先序还是中序 左子树和右子树的长度都是固定的
//主意 从i=1开始 因为先序遍历的第一个是根
for (i = 1;i < n;i++)
{
if (i< (n1+1))//n1代表了左子树的长度
{
lpre[m1++] = pre[i];
}
else
{
rpre[m2++] = pre[i];
}
}
node->lchild = createBiTree(lpre,lin,n1);
node->rchild = createBiTree(rpre,rin,n2);
return node;
}
根据后序和中序构建一棵树
算法如下:
1)先在后序序列中找到根结点,
2)在中序序列中找到根结点位置,(可以将二叉树分为左子树和右子树)
3)用同样的办法构造左子树 。
4)用同样的办法构造右子树。
算法如下:
BinaryTree* Creat_Node(char ch)
{
BinaryTree* root;
root = new BinaryTree;
root->data = ch;
root->lchild = root->rchild = NULL;
return root;
}
BinaryTree* Mid_Post_Create_Pre(char* mid,char*post,int N)
{
if(!mid||!post||N<0){
cout<<"输入出错!"<<endl;
return NULL;
}
int root_index = 0;
for(root_index = 0 ; root_index < N ; root_index++){
if(mid[root_index] == post[N-1]){
break;
}
}
if(root_index == N){
cout<<"中序序列与后序序列不匹配!"<<endl;
return NULL;
}
BinaryTree* root = this->Creat_Node(post[N-1]);
if(root_index > 0){
root->lchild = root->Mid_Post_Create_Pre(mid,post,root_index);
}
if(N-root_index-1 > 0){
root->rchild = root->Mid_Post_Create_Pre(mid+root_index+1,post+root_index,N-root_index-1);
}
return root;
}
已知前序和中序,直接输出后序(不用创建树)
#include <iostream>
#include <fstream>
#include <string>
struct TreeNode
{
struct TreeNode* left;
struct TreeNode* right;
char elem;
};
TreeNode* BinaryTreeFromOrderings(char* inorder, char* preorder, int length)
{
if(length == 0)
{
return NULL;
}
TreeNode* node = new TreeNode;
node->elem = *preorder;
int rootIndex = 0;
for(;rootIndex < length; rootIndex++)
{
if(inorder[rootIndex] == *preorder)
break;
}
node->left = BinaryTreeFromOrderings(inorder, preorder +1, rootIndex);
node->right = BinaryTreeFromOrderings(inorder + rootIndex + 1, preorder + rootIndex + 1, length - (rootIndex + 1));
std::cout<<node->elem<<std::endl;
free(node);
return NULL;
}
int main(int argc, char** argv){
char* pr="GDAFEMHZ";
char* in="ADEFGHMZ"; BinaryTreeFromOrderings(in, pr, 8); printf("\n"); return 0;}