数据结构二叉树相关代码总结(供自己复习)

版权声明:本文为博主原创文章,未经博主允许不得转载。 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;}

猜你喜欢

转载自blog.csdn.net/tonglin12138/article/details/88879920