二叉树,结构很简单,只是比单链表复杂了那么一丢丢而已。我们先来看看它们结点上的差异:

/* 单链表的结构 */
struct SingleList{
int element;
struct SingleList *next;
};
/* 二叉树的结构 */
struct BinaryTree{
int element;
struct BinaryTree *left;
struct BinaryTree *right;
};

  根据以上两个结构,我们不难发现,单链表的结点只有一个指向下一结点的指针,而二叉树中有两个。也就是说单链表每个结点只有一个子节点,而二叉树有两个子节点(其中一个可能为NULL)。了解了这一点的区别,我们就知道:基于二叉树的算法比基于单链表的算法差异就是每次遍历一个结点之后,需要遍历两个子节点,而单链表只需要遍历一个子节点。

  这就引出了2种遍历的方法:广度优先遍历(BFS)深度优先遍历(DFS)。

  对于单链表来说,BFS和DFS是一样的,因为每个节点只有一个子节点,每次遍历下一个节点只有一种选择;但是二叉树每个节点有两个子节点,也就是说遍历的顺序既可以遍历它的子节点(无论左节点还是右结点都是DFS),也可以遍历它的兄弟结点。如果是每次先遍历子节点那么就是DFS;每次先遍历兄弟结点,就是BFS。

  DFS采用栈结构,博主这里用的是递归来实现栈,当然大家也可以用stack来实现;BFS采用的是队列queue。

void dfs(BinaryTree *root){
if(NULL == root)
return ;
dfs(root->left);
dfs(root->right);
}
void bfs(BinaryTree *root){
if(NULL == root)
return ;
queue<BinaryTree *> que;
que.push();
while(!que.empty()){
BinaryTree *pNode = que.front();
     que.pop();
if(pNode->left)
que.push(pNode->left);
if(pNode->right)
que.push(pNode->right);
}
}

  关于树的一些算法中,DFS和BFS一般都适用,但是当涉及到根到叶的路径这类问题时,最好还是用DFS来实现。如下所示:

1、给一棵二叉树和一个值Sum,求出所有从根到叶子的值等于Sum的所有路径。

  思路:深度优先搜索(DFS),然后把从跟开始每次访问一个结点就把该结点添加到一个vec的最后位置,并把sum减去当前借点的值后传递给下一个节点,当一个结点的左右孩子都为NULL,并且值等于sum时,就说明该节点是叶子节点,并且从根结点到该节点的路径和为Sum,把vec,添加到res中;每次返回时,需要把vec中的最后一个值删除,因为每个节点有两个子节点,从根节点到左孩子的叶子的路径与到右孩子叶子的路径是不同的,所有每次访问完左孩子或者右孩子需要把孩子的值从vec中删除。

/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
private:
vector<vector<int>> res;
vector<int> vec;
void _pathSum(TreeNode* root, int sum){
if(root == NULL)
return ;
vec.push_back(root->val);
if(root->left == NULL && root->right == NULL && sum == root->val){
res.push_back(vec);
return ;
}
_pathSum(root->left, sum-root->val);
if(root->left)
vec.pop_back();
_pathSum(root->right, sum-root->val);
if(root->right)
vec.pop_back();
}
public:
vector<vector<int>> pathSum(TreeNode* root, int sum) {
if(NULL == root)
return res;
_pathSum(root, sum);
return res;
}
};

2、转化二叉树

把二叉树:

   /   \

 / \   / \
       

转化成

   /   \

 / \   / \
       

  思路:这个既可以用DFS也可以用BFS,也就是遍历每个节点,然后将它们的左右孩子互换即可。这里采用BFS来实现:

/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
if(NULL == root)
return NULL;
queue<TreeNode*> que;
que.push(root);
while(!que.empty()){
TreeNode* pChild = que.front();
que.pop();
TreeNode* pNode = pChild->left;
pChild->left = pChild->right;
pChild->right = pNode;
if(pChild->left)
que.push(pChild->left);
if(pChild->right)
que.push(pChild->right);
}
return root;
}
};

 3、总结

  只要掌握了DFS和BFS的思想,其它关于二叉树的算法基本上都是类似的,必要的时候通过画图来让自己感性认识一下也是极好的。

  关于Leetcode上的题目代码:https://github.com/whc2uestc/onlineJudge/tree/master/leetCode

版权所有,欢迎转载,转载请注明出处。

关于Leetcode上二叉树的算法总结的更多相关文章

  1. LeetCode:二叉树的后序遍历【145】

    LeetCode:二叉树的后序遍历[145] 题目描述 给定一个二叉树,返回它的 后序 遍历. 示例: 输入: [1,null,2,3] 1 \ 2 / 3 输出: [3,2,1] 进阶: 递归算法很 ...

  2. LeetCode:二叉树的层次遍历||【107】

    LeetCode:二叉树的层次遍历||[107] 题目描述 给定一个二叉树,返回其节点值自底向上的层次遍历. (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历) 例如:给定二叉树 [3,9,2 ...

  3. LeetCode:二叉树剪枝【814】

    LeetCode:二叉树剪枝[814] 题目描述 给定二叉树根结点 root ,此外树的每个结点的值要么是 0,要么是 1. 返回移除了所有不包含 1 的子树的原二叉树. ( 节点 X 的子树为 X ...

  4. Leetcode 297.二叉树的序列化和反序列化

    二叉树地序列化和反序列化 序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得到原数据. ...

  5. 别再埋头刷LeetCode之:北美算法面试的题目分类,按类型和规律刷题,事半功倍

    算法面试过程中,题目类型多,数量大.大家都不可避免的会在LeetCode上进行训练.但问题是,题目杂,而且已经超过1300道题. 全部刷完且掌握,不是一件容易的事情.那我们应该怎么办呢?找规律,总结才 ...

  6. Java实现 LeetCode 297 二叉树的序列化与反序列化

    297. 二叉树的序列化与反序列化 序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得 ...

  7. LeetCode解题记录(贪心算法)(二)

    1. 前言 由于后面还有很多题型要写,贪心算法目前可能就到此为止了,上一篇博客的地址为 LeetCode解题记录(贪心算法)(一) 下面正式开始我们的刷题之旅 2. 贪心 763. 划分字母区间(中等 ...

  8. 利用Mahout实现在Hadoop上运行K-Means算法

    利用Mahout实现在Hadoop上运行K-Means算法 一.介绍Mahout Mahout是Apache下的开源机器学习软件包,目前实现的机器学习算法主要包含有协同过滤/推荐引擎,聚类和分类三个部 ...

  9. 关于LeetCode上链表题目的一些trick

    最近在刷leetcode上关于链表的一些高频题,在写代码的过程中总结了链表的一些解题技巧和常见题型. 结点的删除 指定链表中的某个结点,将其从链表中删除. 由于在链表中删除某个结点需要找到该结点的前一 ...

随机推荐

  1. PhantomJS快速入门

    本文简要介绍了PhantomJS的相关基础知识点,主要包括PhantomJS的介绍.下载与安装.HelloWorld程序.核心模块介绍等.由于鄙人才疏学浅,难免有疏漏之处,欢迎指正交流. 1.Phan ...

  2. 最简单的轮播广告(原生JS)

    改变每个图片的opacity属性:来自学友刘斌 素材图片: <!DOCTYPE html> <html lang="en"> <head> &l ...

  3. IP查询接口地址

    腾讯的: http://fw.qq.com/ipaddress直接返回本机的IP地址对应的地区 新浪的:http://counter.sina.com.cn/ip?ip=IP地址返回Js数据,感觉不是 ...

  4. MongoDB,客户端工具备份数据库

    本篇介绍下如何利用客户端工具来进行远程服务器的数据备份到本地. 以客户端工具MongoVUE为例来进行讲解: 1.首先要连接本地服务器以及远程服务器数据库 2.在本地服务器(127.0.0.1)中,右 ...

  5. 教你写能被舒服舒服又舒服地调用的iOS库

    目录 前言 脑洞开一开 分析 整容 结语 前言 2014年过的那么快,过年又那么块,2015年又是飞快地节奏,真尼玛感觉上帝是不是无聊使用了变速外挂开启了加速模式~到现在博主都无法接受已经上班的事实… ...

  6. 属性(@property)、@synthesize

    先前我们学的实例变量是这样的 { int _age; int _height; int age; } 后来学属性 @property int age; 看到@property 会自动编译生成某个成员变 ...

  7. JavaScript学习01 语言简介、基本使用和变量声明

    JavaScript语言简介.基本使用和变量声明 JavaScript是网景(Netscape)公司开发的一种基于客户端浏览器.面向对象.事件驱动式的网页脚本语言. JavaScript的前身叫Liv ...

  8. Android时区及语言代码

    1. 设置默认时区   PRODUCT_PROPERTY_OVERRIDES += \         persist.sys.timezone=Asia/Shanghai\ 注:搜索“persist ...

  9. 转大写字母-(ASCII表)

    #include<stdio.h> /* 转大写,ASCII表.大写与小写相差32 */ char upper(char c) { if(c>='a'&&c<= ...

  10. 深入.net(类及方法)

    .net 的命名规则: 帕斯卡命名法 ----- 多个单词说明,且直接连接,并首字母大写(类名.方法名.属性名....) 骆驼命名法---------多个单词说明,且直接连接,并首字母大写,第一个字母 ...