二叉树相关练习题(C++)

一、二叉树

1、用递归方法实现二叉树的先序、中序、后序遍历

class TreeToSequence
{

public: 
  

     void preOrder(TreeNode*
root,vector<
int>
&pre) {

         if (!root)

             return;

         pre.push_back(root->val);

         preOrder(root->left,pre);

         preOrder(root->right,pre);      

    }

    void inOrder(TreeNode*
root,vector<
int>
&in) {

        if (!root)

            return;

        inOrder(root->left,in);

        in.push_back(root->val);

        inOrder(root->right,in);

    }

    void postOrder(TreeNode*
root,vector<
int>
&post) {

        if (!root)

            return;

        postOrder(root->left,post);

        postOrder(root->right,post);

        post.push_back(root->val);

    }

    vector<vector<int>
> convert(TreeNode* root) {

        vector<vector<int>
> vRecur;

        vector<int>
pre,in,post;

        preOrder(root,pre);

        inOrder(root,in);

        postOrder(root,post);

        

        vRecur.push_back(pre);

        vRecur.push_back(in);

        vRecur.push_back(post);

        return vRecur;

    }

};

2、用非递归方法实现二叉树的先序、中序、后序遍历

class TreeToSequence {

public:

vector<int> preOrder(TreeNode* root) {

vector<int> pre;

stack<TreeNode*> s;

s.push(root);

while (!s.empty()) {

TreeNode* temp = s.top();

pre.push_back(temp->val);

s.pop();

if (temp->right)

s.push(temp->right);

if (temp->left)

s.push(temp->left);

}

return pre;

}

vector<int> inOrder(TreeNode* root) {

vector<int> in;

stack<TreeNode*> s;

TreeNode* temp = root;

while (temp || !s.empty()){

while (temp) {

s.push(temp);

temp = temp->left;

}

temp = s.top();

s.pop();

in.push_back(temp->val);

temp = temp->right;

}

return in;

}

vector<int> postOrder(TreeNode* root) {

vector<int> post;

stack<TreeNode*> s;

TreeNode *temp = root,*previsited = NULL;

while (temp || !s.empty()){

while (temp) {

s.push(temp);

temp = temp->left;

}

temp = s.top();

if (!temp->right || temp->right == previsited) {

post.push_back(temp->val);

s.pop();

previsited = temp;

temp = NULL;

}

else

temp = temp->right;

}

return post;

}

vector<vector<int> > convert(TreeNode* root) {

vector<vector<int> > vNonRecur;

if (!root)

return vNonRecur;

vNonRecur.push_back(preOrder(root));

vNonRecur.push_back(inOrder(root));

vNonRecur.push_back(postOrder(root));

return vNonRecur;

}

};

3、按照层次打印二叉树,且不同层的数据要打印在不同行。可把不同层的数据存在不同的数组中模拟打印过程。

解法:①二叉树的层序遍历要用到队列。队头结点出队则接着将其左右子节点入队。

②不同层打印在不同行就要考虑在合适的节点处换行。定义两个指针curLast和nexLast分别记录正在打印的行的最右结点和下一行的最右结点。nexLast跟踪入队结点,则当打印结点是当前层最右结点curLast时紧接着的入队结点也是下一行的最右结点;若当前打印的结点为curLast则换行,接着将下一行最右结点指针nexLast赋值给curLast。

class TreePrinter {

public:

vector<vector<int> > printTree(TreeNode* root) {

vector<vector<int> > res;

vector<int> temp;

queue<TreeNode*> q;

TreeNode *curLast = root,*nexLast = NULL,*cur;

q.push(root);

while (!q.empty()) {

cur = q.front();

temp.push_back(cur->val);

q.pop();

if (cur->left) {

q.push(cur->left);

nexLast = cur->left;

}

if (cur->right) {

q.push(cur->right);

nexLast = cur->right;

}

if (cur == curLast) {

res.push_back(temp);

temp.clear();

curLast = nexLast;

}

}

return res;

}

};

4、二叉树的先序序列化

解法:用递归先序遍历更简单,遇到空则在字符串str后追加#!,非空则追加‘数值!’。

注意:int型数据要先转换成字符串类型才能追加到字符串末尾,用stringstream可以实现转换。

class TreeToString {

public:

void preSerial(TreeNode* root,string &str) {

if (!root) {

str += "#!";

return;

}

str += int2string(root->val) + ‘!‘;

preSerial(root->left,str);

preSerial(root->right,str);

}

string int2string(int val) {

stringstream ss;

ss << val;

return ss.str();

}

string toString(TreeNode* root) {

string str;

preSerial(root,str);

return str;

}

};

5、二叉树先序反序列化

解法:①先将字符串序列转换成字符数组的形式。②遍历字符数组,遇到不是#的元素,则新建结点,并用剩下的元素构造这个结点的左子树;遇到#则不新建结点,并且当前正在构建的分支结束,用剩下的元素构造当前分支的父节点的右子树。

6、判断二叉树是否为平衡二叉树

平衡二叉树:任何结点的左右子树高度之差都不大于1.

解法:利用二叉树的后序遍历,统计左右子树的高度,同时通过一个全局的bool变量记录遍历过程中是否出现非平衡二叉树,一旦bool被置为false则说明有子树不是平衡二叉树,直接返回,最后返回这个bool变量即可。

class CheckBalance {

public:

int postVisit(TreeNode* root,bool &isBalance ) {

// 若当前结点空,则直接返回0,即当前子树的高度不增加

if (!root)

return 0;

// 若前结点不空,则统计其左子树的高度

int nL = postVisit(root->left,isBalance );

// 如果在遍历当前节点的左子树的过程中出现非平衡二叉树,此时不再遍历右子树,直接返回

if (!isBalance )

return nL;

// 若当前结点不空且左子树是平衡二叉树,则遍历右子树,统计其高度

int nR = postVisit(root->right,isBalance );

// 如果在遍历右子树的过程中出现非AVL,此时不再判断当前结点为根的子树是否是平衡二叉树,直接返回

if (!isBalance )

return nR;

// 如果当前节点的左右子树都是平衡二叉树,则根据左右子树的高度判断当前结点为根的子树是否是平衡二叉树

if (abs(nL-nR) > 1)

isBalance = false;

// 不管当前结点为根的子树是不是平衡二叉树,都应该使子树的高度增加1

return 1+max(nL,nR);

}

bool check(TreeNode* root) {

bool isBalance
= true;

int height = postVisit(root,isBalance );

return isBalance ;

}

};

7、判断二叉树是不是二叉搜索树

解法:二叉树的中序遍历,若得到的遍历序列是递增的则原二叉树是二叉搜索树。

bool checkSearch(TreeNode* root)
{

stack<TreeNode*>
s;

TreeNode *cur = root,*last
=NULL;

while(cur
|| !s.empty()) {

while(cur)
{

s.push(cur);

cur = cur->left;

}

cur = s.top();

if(!last)

last = cur;

if(cur->val
>= last->val) {

s.pop();

cur = cur->right;

last = cur;

}

else

return false;

}

return
true;

}

8、判断二叉树是不是完全二叉树

解法:利用层序遍历。如果当前结点左孩子空右孩子不空,则肯定不是完全二叉树;如果左右孩子都不空,则正常遍历;如果左孩子不空右孩子空,则在完全二叉树中这个左孩子一定是最后一层最右的结点,并且这种情况只可能发生一次,用n来记录这种情况发生的次数,n>1则返回false。

class CheckCompletion
{

public:

    bool
chk(TreeNode* root) {

        queue<TreeNode*>
q;

        q.push(root);

        int n
0;

        while (!q.empty())
{

            TreeNode*
temp = q.front();

            q.pop();

            if (!temp->left
&& temp->right)

                return false;

            if (temp->left
&& temp->right) {

                q.push(temp->left);

                q.push(temp->right);           

            }

            if (temp->left
&& !temp->right) {

                if (temp->left->left
|| temp->left->right)

                    return false;

                n++;

                if (n
1)

                    return false;

                q.push(temp->left);              

            }               

        }

        return true;

    }

};

9、折纸问题

描述:把纸条竖着放在桌上,然后从纸条的下边向上对折,压出折痕后再展开。此时有1条折痕,突起的方向指向纸条的背面,这条折痕叫做“下”折痕 ;突起的方向指向纸条正面的折痕叫做“上”折痕。如果每次都从下边向上边
对折,对折N次。请从上到下计算出所有折痕的方向。

解法:折痕方向的分布其实是一棵满二叉树。根节点是0,所有结点的左右孩子都分别为0,1。0代表“下”折痕,1代表“上”折痕。可以用递归算法来实现。也可以用非递归方式实现。

递归解法:

class FoldPaper
{

public:

    vector<string>
foldPaper(
int n)
{

        vector<string>
ret;

        foldPrint("down",
ret, n);

        return ret;

    }

    void foldPrint(string
fold, vector<string>& ret, 
int remain){

        if (remain
== 
0)

            return;

        foldPrint("down",
ret, remain - 
1);

        ret.push_back(fold);

        foldPrint("up",
ret, remain - 
1);

    }

};

非递归解法:

class FoldPaper
{

public: 
  

    vector<string>
foldPaper(
int n)
{

        string
sLeft[] = {
"down","down","up"};

        string
sRight[] = {
"down","up","up"};

        vector<string>
lS(sLeft,sLeft+
3);

        vector<string>
rS(sRight,sRight+
3); 
      

        vector<string>
last,odd,even = lS;

        odd.push_back("down");
      
        

        if (n
== 
1)

            return odd;

        }

        if (n
== 
2)
{

            return even;

        } 
      

        int i;

        if (n%2== 1)
{

            i
3;

            last
= odd;

        } 
          

        else {

            i
4;

            last
= even;

        } 
          

        vector<string>
res;

        vector<string>::iterator
iter;

        for (;i
<= n;) {

            iter
= last.begin();
           

            while (iter
< last.end()) {

                res.insert(res.end(),lS.begin(),lS.end());

                res.push_back(*iter);

                res.insert(res.end(),rS.begin(),rS.end());

                if (iter
< last.end()-
1)

                    res.push_back(*(iter+1));

                iter
= iter+
2;

            } 
          

            last.swap(res);

            res.clear();

            i
= i+
2;

        }

        return last; 
      

    }

};

10、一棵二叉树原本是搜索二叉树,但是其中有两个节点调换了位置,使得这棵二叉树不再是搜索二叉树,请找到这两个错误节点并返回他们的值。小的值在前。

解法:二叉树的中序遍历可以检查出树是不是搜索树。用last指针跟踪上一个遍历的结点就可以比较遍历过程中是否出现降序。若调换了两个结点则最多会出现两次降序,若只有第一次,则降序的两个结点就是调换的结点,若有两次降序则第一次较大的结点和第二次较小的结点是调换的两个结点。

class FindErrorNode {

public:

vector<int> findError(TreeNode* root) {

stack<TreeNode*> s;

vector<int> res;

TreeNode *cur = root,*last =NULL;

while(cur || !s.empty()) {

while (cur) {

s.push(cur);

cur = cur->left;

}

cur = s.top();

s.pop();

if(last && cur->val < last->val) {

if (res.empty()) {

res.push_back(cur->val);

res.push_back(last->val);

}

else {

res.erase(res.begin());

res.insert(res.begin(),cur->val);

break;

}

}

last = cur;

cur = cur->right;

}

return res;

}

};

11、对于给定的一棵二叉树,求整棵树上节点间的最大距离。

最大距离的定义:从一个节点走到(可以向上走可以向下走)另一个节点需要经过的结点数(包括这两个结点)。

解法:一棵树的节点间最大距离只可能是一下三种情况。①左子树中的最大距离;②右子树中的最大距离;③左子树中距离根节点最远的结点和右子树中距离根节点最远的结点之间的距离。

采用二叉树的后序递归遍历可是实现。在递归的每一层都求得以当前结点为根节点的树中的最大距离和这棵树中距离根节点最远的结点距离根节点的距离。

classLongestDistance
{

public: 
  

    vector<int>
postVisit(TreeNode* root) {

        vector<int>
resL,resR,res;

        if (!root)
{ // 如果当前节点为空,则以它为根节点的树中最大距离和最远距离都为0

            res.push_back(0);

            res.push_back(0);

            return res;

        } 
 

// 若不空则先后处理左右子树,返回左右子树的最大距离和最远距离          

        resL
= postVisit(root->left);

        resR
= postVisit(root->right);

// 计算以当前结点为根节点的树的最大距离和最远距离       

        int max1
= resL[
0],max2;

        if (resR[0]
> max1)

            max1
= resR[
0];

        if (resL[1]+resR[1]+1>
max1)

            max1
= resL[
1]+resR[1]+1;

        max2
= resL[
1]>resR[1]?resL[1]+1:resR[1]+1;

        res.push_back(max1);

        res.push_back(max2);

        return res;

    }

    

    int findLongest(TreeNode*
root) {

        vector<int>
max = postVisit(root);

        return max[0];

    }

};

12、寻找一颗二叉树中节点数最多的搜索树的根节点

解法一:只有两种情况。①当前结点的左子树的最大搜索树以当前结点的左孩子为根节点,右子树的最大搜索树以右孩子为根节点,且左子树的最大值小于根节点,右子树的最小值大于根节点,则当前结点就是以其为根节点的子树的最大搜索树,结点个数为左右子树中最大搜索树结点个数之和加1,最大值为右子树的最大值,最小值为左子树的最小值;②第①种情况不满足,则左右子树中结点数最多的最大搜索树为当前的最大搜索树,存在四种情况,如下代码所示。

classMaxSubtree
{

public:

    typedef
struct {

        vector<int>
num;

        TreeNode*
rMax;

    }
Dataset;

    Dataset
postVisit(TreeNode* root) {

        Dataset
datal,datar,data;

        if(!root)
{

            data.num.insert(data.num.begin(),3,0);

            data.rMax
= NULL;

            returndata;

        } 
     

        datal
= postVisit(root->left);

        datar
= postVisit(root->right);

        

        if(root->left
&& root->right) {

            if(datal.rMax
== root->left &&

                datar.rMax
== root->right &&

                datal.num[2]
< root->val &&

                datar.num[1]
> root->val) {

            

                data.rMax
= root;               

                data.num.push_back(datal.num[0]+datar.num[0]+1);

                data.num.push_back(datal.num[1]<datar.num[1]?datal.num[1]:datar.num[1]);

                data.num.push_back(datal.num[2]<datar.num[2]?datar.num[2]:datal.num[2]);

            }

            else{

                if(datal.num[0]>datar.num[0])

                    data
= datal;

                elseif(datal.num[0]<datar.num[0])

                    data
= datar;

                else

                    data
= datal.rMax->val > datar.rMax->val?datal:datar;                               

            }

        } 
          

        elseif(!root->left
&& !root->right) {

            data.rMax
= root;

            data.num.push_back(datal.num[0]+datar.num[0]+1);

            data.num.push_back(root->val);

            data.num.push_back(root->val);

        }

        elseif(!root->left)
{

            if(datar.num[1]
> root->val && datar.rMax == root->right) {

                data.rMax
= root;

                data.num.push_back(datal.num[0]+datar.num[0]+1);

                data.num.push_back(root->val);

                data.num.push_back(datar.num[2]);

            }               

            else

                data
= datar;

        }

        else{

            if(datal.num[2]
< root->val && datal.rMax == root->left) {

                data.rMax
= root;

                data.num.push_back(datal.num[0]+datar.num[0]+1);

                data.num.push_back(datal.num[1]);

                data.num.push_back(root->val);

            }               

            else

                 data
= datal;

        }

       returndata;

    }

    

    TreeNode*
getMax(TreeNode* root) {

        Dataset
resData = postVisit(root);

        returnresData.rMax;

    }

};

解法2:

classMaxSubtree
{

public:

    bool
chk[
550];

    voidget(TreeNode*
rt,
int*mn,int*mx,int*sz,TreeNode
*&ret,
int&msz){

        intv
= rt->val;

        mn[v]
10101010;
mx[v] = 
0;

        chk[v]
false;

        intlsz
0,rsz
0,lmx
0,rmx
0,lmn
10101010,rmn
10101010;

        bool
cl = 
true,cr
true;

        if(rt->left)
get(rt->left,mn,mx,sz,ret,msz),lsz = sz[rt->left->val],lmn = mn[rt->left->val],lmx = mx[rt->left->val],cl = chk[rt->left->val];

        if(rt->right)
get(rt->right,mn,mx,sz,ret,msz),rsz = sz[rt->right->val],rmn = mn[rt->right->val],rmx = mx[rt->right->val],cr = chk[rt->right->val];

        if(lsz
!= -
1&&
rsz != -
1){

            if(cl
&& cr && lmx < v && v < rmn){

                inttmp
= lsz + rsz + 
1;

                chk[v]
true;

                if(tmp
> msz || (tmp == msz && ret->val < v)){

                    ret
= rt; msz = tmp;

                }

            }

            sz[v]
= lsz + rsz + 
1;

            mx[v]
= max(v,lmx);

            mn[v]
= min(v,lmn);

        }

    }

    TreeNode*
getMax(TreeNode* root) {

        TreeNode*
ret = NULL;

        intmn[550],mx[550],sz[550],msz
0;

        get(root,mn,mx,sz,ret,msz);

        returnret;

    }

};

时间: 2024-10-20 08:25:09

二叉树相关练习题(C++)的相关文章

tr命令的使用及相关练习题

tr命令相关选项: tr-转换或删除字符 常用选项: -c:取字符集的补集 -d:删除匹配的指定字符集中的字符 -s:把连续重复的字符以单独一个字符表示 -t:先删除第一字符集较第二字符集多出的字符 \\:反斜杠 \a:响铃 \b:退格 \n:换行 \r:回车 [:alnum:] :所有的字母和数字                                                 [:alpha:] :所有的字母                                   

LeetCode:二叉树相关应用

LeetCode:二叉树相关应用 基础知识 617.归并两个二叉树 题目 Given two binary trees and imagine that when you put one of them to cover the other, some nodes of the two trees are overlapped while the others are not. You need to merge them into a new binary tree. The merge ru

acwing 70-72 剑指OFFER 二叉树相关

地址 https://www.acwing.com/problem/content/66/ https://www.acwing.com/problem/content/67/ https://www.acwing.com/problem/content/submission/68/ 三道题都是二叉树相关 使用递归遍历即可解决 70. 二叉搜索树的第k个结点 给定一棵二叉搜索树,请找出其中的第k小的结点. 你可以假设树和k都存在,并且1≤k≤树的总结点数. 输入 输入:root = [2, 1,

二叉树相关

/* _递归的精髓在二叉树的各种问题上体现的淋漓尽致!!! */ #include<stdio.h> #include<iostream> #include <stack> #include<vector> #include <assert.h> using namespace std; typedef struct node //二叉树结点的结构体表示形式 { int data; node *left,*right; }BTree; //---

C++实现二叉树相关操作

测试环境:windows 7 vs2010 主要实现二叉树的初始化递归和非递归遍历,层次遍历,获取叶子节点的个数,获取树的高度以及镜像树,部分代码也参考了互联网上的相关资料. 源程序: BinaryTreeNode.h #ifndef _BINARY_NODE #define _BINARY_NODE #include<iostream> using namespace std; template<class ItemType> struct BinaryTreeNode { It

二叉树相关知识总结(三)

前两篇日志主要研究了二叉树的相关基本知识,以及二叉树的最基本的实现 今天我们主要研究下,二叉查找树的相关主要特点,以及Java实现. 一.概念 二叉排序树或者是一棵空树,或者是具有下列性质的二叉树: (1)若左子树不空,则左子树上所有结点的值均小于或等于它的根结点的值: (2)若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值: 换句话说:中根遍历是有序的. (3)左.右子树也分别为二叉排序树: 思考:重复的值怎么处理?是否存在值一样的节点? 初始化一颗二叉排序树根节点的选取问题 p

二叉树相关基础知识总结

一:树的概念 树是一种数据结构,它是由n(n>=1)个有限结点组成一个具有层次关系的集合.把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的.它具有以下的特点: 1:每个结点有零个或多个子结点: 2:没有父结点的结点称为根结点: 3:每一个非根结点有且只有一个父结点: 4:除了根结点外,每个子结点可以分为多个不相交的子树 二:树相关术语 节点的度:一个节点含有的子树的个数称为该节点的度: 叶节点或终端节点:度为0的节点称为叶节点: 非终端节点或分支节点:度不为0的节点:

二叉树相关题目总结

1. 简要介绍   关于二叉树问题,由于其本身固有的递归属性,通常我们可以用递归算法来解决.(<编程之美>,P253) 总结的题目主要以leetcode题目为主. 2. 测试用例 空树,只有节点的二叉树,只有左子树/右子树的二叉树,既有左子树右有右子树的二叉树. 3. 二叉树的遍历 遍历简介: 二叉树的遍历 分层遍历:二叉树分层遍历 前序遍历:[LeetCode] Binary Tree Preorder Traversal 中序遍历:[LeetCode] Binary Tree Inorde

[原创]二叉树相关笔试题代码

1 //二叉树问题集: 2 //20140822 3 4 #include <iostream> 5 #include <cstdio> 6 #include <cstdlib> 7 #include <queue> 8 #include <stack> 9 #include <list> 10 using namespace std; 11 12 13 typedef int ElementType; 14 typedef stru