转载出处:http://www.61mon.com/index.php/archives/191/
(1):前序遍历,中序遍历,后序遍历;
(2):层次遍历;
(3):求树的节点数;
(4):求树的叶子数;
(5):求树的深度;
(6):求二叉树第 k 层的节点个数;
(7):判断两棵二叉树是否结构相同;
(8):求二叉树的镜像;
(9):求两个节点的最低公共祖先节点;
(10):求任意两节点距离;
(11):找出二叉树中某个节点的所有祖先节点;
(12):二叉树前序中序推后序;
(13):判断二叉树是不是平衡二叉树;
(14):判断二叉树是不是完全二叉树;
(15):判断是否是二叉查找树的后序遍历结果;
(16):给定一个二叉查找树中的节点,找出在中序遍历下它的后继和前驱;
(17):二分查找树转化为排序的循环双链表;
(18):二叉树路径等于目标值的所有路径。
(19):二叉树的所有路径。
二叉树节点定义如下:
struct BinaryTreeNode
{
int m_nValue;
BinaryTreeNode* m_pLeft;
BinaryTreeNode* m_pRight;
};
(1):前序遍历,中序遍历,后序遍历;
前序遍历:对于当前节点,先输出该节点,然后输出它的左孩子,最后输出它的右孩子。
递归版本:
void PreOrderTraverse(BinaryTreeNode * pRoot)
{
if(pRoot == NULL)
return;
Visit(pRoot);
PreOrderTraverse(pRoot->m_pLeft); // 前序遍历左子树
PreOrderTraverse(pRoot->m_pRight); // 前序遍历右子树
}
非递归版本:
/* 前序遍历非递归版 */
void PreOrderNonRec(Node * node)
{
stack<Node*> S;
Node * p = node;
while (p || !S.empty())
{
while (p)
{
cout << p->data << " "; //先输出当前节点
S.push(p);
p = p->left; //然后输出左孩子
} //while结束意味着左孩子已经全部输出
if (!S.empty())
{
p = S.top()->right; //最后输出右孩子
S.pop();
}
}
}
中序遍历:对于当前节点,先输出它的左孩子,然后输出该节点,最后输出它的右孩子
递归版本:
/* 中序遍历递归版 */
void InOrderRec(Node * node)
{
if (node == nullptr)
return;
InOrderRec(node->left); //先输出左孩子
cout << node->data << " "; //然后输出当前节点
InOrderRec(node->right); //最后输出右孩子
}
非递归版本:
/* 中序遍历非递归版 */
void InOrderNonRec(Node * node)
{
stack<Node*> S;
Node * p = node;
while (p || !S.empty())
{
while (p)
{
S.push(p);
p = p->left;
} //while结束意味着左孩子为空
if (!S.empty())
{
cout << S.top()->data << " "; //左孩子已经全部输出,接着输出当前节点
p = S.top()->right; //左孩子全部输出,当前节点也输出后,最后输出右孩子
S.pop();
}
}
}
后序遍历:对于当前节点,先输出它的左孩子,然后输出它的右孩子,最后输出该节点
递归版本:
/* 后序遍历递归版 */
void PostOrderRec(Node * node)
{
if (node == nullptr)
return;
PostOrderRec(node->left); //先输出左孩子
PostOrderRec(node->right); //然后输出右孩子
cout << node->data << " "; //最后输出当前节点
}
非递归版本:
/* 后序遍历非递归版 */
void PostOrderNonRec(Node * node)
{
Node * pre = nullptr;
Node * cur = node;
stack<Node*> S;
S.push(cur);
while (!S.empty())
{
cur = S.top();
if ((!cur->left && !cur->right) || //第一个输出的必是无左右孩子的叶子节点,只要第一个节点输出,
(pre && (pre == cur->left || pre == cur->right))) //以后的pre就不会是空。此处的判断语句加入一个pre,只是用来
{ //确保可以正确输出第一个节点。
cout << cur->data << " "; //左右孩子都全部输出,再输出当前节点
pre = cur;
S.pop();
}
else
{
if (cur->right)
S.push(cur->right); //先进右孩子,再进左孩子,取出来的才是左孩子
if (cur->left)
S.push(cur->left);
}
}
}
(2):层次遍历;
层次遍历:广度优先算法,分层输出节点,使用队列的先进先出特性保存头节点,把当前层都压入队列后依次出列输出。
void LevelOrder(Node * node)
{
Node * p = node;
queue<Node*> Q; //队列
Q.push(p);
while (!Q.empty())
{
p = Q.front();
cout << p->data << " ";
Q.pop();
if (p->left)
Q.push(p->left); //注意顺序,先进左孩子
if (p->right)
Q.push(p->right);
}
}
最大深度:
(3):求树的节点数;
树的节点数采用递归方式:
int CountNodes(Node * node)
{
if (node == nullptr)
return 0;
return CountNodes(node->left) + CountNodes(node->right) + 1;
}
(4):求树的叶子数;
树的叶子:和树的节点数有所不同,更改递归返回点。
int CountLeaves(Node * node)
{
if (node == nullptr)
return 0;
if (!node->left && !node->right)
return 1;
return CountLeaves(node->left) + CountLeaves(node->right);
}
(5):求树的深度;
树的深度:
采用递归方式:
int GetDepth(BinaryTreeNode * pRoot)
{
if(pRoot == NULL) // 递归出口
return 0;
int depthLeft = GetDepth(pRoot->m_pLeft);
int depthRight = GetDepth(pRoot->m_pRight);
return depthLeft > depthRight ? (depthLeft + 1) : (depthRight + 1);
}
可以采用广度优先的方法计算,输出一层后计数,最后得到的数字即为最大层数。
int GetDepth(TreeNode *root) {
if (!root) {
return 0;
}
int curDep = 0;
queue<TreeNode *>queuelist;
queuelist.push(root);
TreeNode *curNode;
while (!queuelist.empty()) {
int size = queuelist.size();
for (int i = 0; i < size; i++) {
curNode = queuelist.front();
queuelist.pop();
if (curNode->left) {
queuelist.push(curNode->left);
}
if (curNode->right) {
queuelist.push(curNode->right);
}
}
curDep++;
}
return curDep;
}
(6):求二叉树第 k 层的节点个数;
第K层节点个数:递归控制,每次向下一层则K减1,直到到达K层。
int GetKLevel(Node * node, int k)
{
if (node == nullptr)
return 0;
if (k == 1)
return 1;
return GetKLevel(node->left, k - 1) + GetKLevel(node->right, k - 1);
}
非递归方式,采用和树的深度相同的思想:
int GetKLevel(TreeNode *root, int K) {
if (!root) {
return 0;
}
int curDep = 0;
queue<TreeNode *>queuelist;
queuelist.push(root);
TreeNode *curNode;
while (!queuelist.empty()) {
int size = queuelist.size();
if ( k == curDep ) {
return size;
}
for (int i = 0; i < size; i++) {
curNode = queuelist.front();
queuelist.pop();
if (curNode->left) {
queuelist.push(curNode->left);
}
if (curNode->right) {
queuelist.push(curNode->right);
}
}
curDep++;
}
return 0;
}
(7):判断两棵二叉树是否结构相同;
结构相同:不考虑数字是否相同,只考虑左右子树是否一致。递归方法解最简单。
bool StructureCmp(Node * node1, Node * node2)
{
if (node1 == nullptr && node2 == nullptr)
return true;
else if (node1 == nullptr || node2 == nullptr)
return false;
return StructureCmp(node1->left, node2->left) && Str1uctureCmp(node1->right, node2->right);
}
(8):求二叉树的镜像;
镜像:左右翻转。
递归方式:
void Mirror(Node * node)
{
if (node == nullptr)
return;
Node * temp = node->left;
node->left = node->right;
node->right = temp;
Mirror(node->left);
Mirror(node->right);
}
(9):求两个节点的最低公共祖先节点;
最低公共祖先:需要注意两个节点本来就在一个树上的情况,此时最低公共祖先就是其中靠近根节点的那个。
递归方式:
Node * FindLCA(Node * node, Node * target1, Node * target2)
{
if (node == nullptr)
return nullptr;
if (node == target1 || node == target2)
return node;
Node * left = FindLCA(node->left, target1, target2);
Node * right = FindLCA(node->right, target1, target2);
if (left && right) //分别在左右子树
return node;
return left ? left : right; //都在左子树或右子树
}
(10):求任意两节点距离;
任意两节点距离:两节点到最低公共祖先的距离之和。
int FindLevel(Node * node, Node * target)
{
if (node == nullptr)
return -1;
if (node == target)
return 0;
int level = FindLevel(node->left, target); //先在左子树找
if (level == -1)
level = FindLevel(node->right, target); //如果左子树没找到,在右子树找
if (level != -1) //找到了,回溯
return level + 1;
return -1; //如果左右子树都没找到
}
int DistanceNodes(Node * node, Node * target1, Node * target2)
{
Node * lca = FindLCA(node, target1, target2); //找到最低公共祖先节点
int level1 = FindLevel(lca, target1);
int level2 = FindLevel(lca, target2);
return level1 + level2;
}
(11):找出二叉树中某个节点的所有祖先节点;
所有祖先节点:
bool FindAllAncestors(Node * node, Node * target)
{
if (node == nullptr)
return false;
if (node == target)
return true;
if (FindAllAncestors(node->left, target) || FindAllAncestors(node->right, target)) //找到了
{
cout << node->data << " ";
return true; //回溯
}
return false; //如果左右子树都没找到
}
(12):二叉树前序中序推后序;
/* 前序遍历和中序遍历结果以长度为n的数组存储,pos1为前序数组下标,pos2为后序下标 */
int pre_order_arry[n];
int in_order_arry[n];
void PrintPostOrder(int pos1, int pos2, int n)
{
if (n == 1)
{
cout << pre_order_arry[pos1];
return;
}
if (n == 0)
return;
int i = 0;
for (; pre_order_arry[pos1] != in_order_arry[pos2 + i]; i++)
;
PrintPostOrder(pos1 + 1, pos2, i);
PrintPostOrder(pos1 + i + 1, pos2 + i + 1, n - i - 1);
cout << pre_order_arry[pos1];
}
(13):判断二叉树是不是平衡二叉树;
平衡二叉树:一棵高度平衡的二叉树的定义是:一棵二叉树中每个节点的两个子树的深度相差不会超过1。
int getDepth (TreeNode *root) {
if(!root) return 0;
int left = getDepth(root->left);
int right = getDepth(root->right);
return ((left>right)?left:right)+1;
}
bool isBalanced(TreeNode *root) {
// write your code here
if(!root) return true;
int left = getDepth(root->left);
int right = getDepth(root->right);
if((left > right + 1)||(right > left+1)) {
return false;
}
else{
return isBalanced(root->left)&&isBalanced(root->right);
}
}
(14):判断二叉树是不是完全二叉树;
完全二叉树:除最后一层外,每一层上的结点数均达到最大值;在最后一层上只缺少右边的若干结点。
bool IsCBT(Node * node)
{
bool flag = false;
queue<Node*> Q;
Q.push(node);
while (!Q.empty())
{
Node * p = Q.front();
Q.pop();
if (flag)
{
if (p->left || p->right)
return false;
}
else
{
if (p->left && p->right)
{
Q.push(p->left);
Q.push(p->right);
}
else if (p->right) //只有右节点
return false;
else if (p->left) //只有左节点
{
Q.push(p->left);
flag = true;
}
else //没有节点
flag = true;
}
}
return true;
}
flag用来标识是否已经出现了第一个没有右孩子的节点,如果出现了则认为是倒数第二行,然后依次判断倒数第一行的各个节点还有没有孩子。
(15):判断是否是二叉查找树的后序遍历结果;
int array[n]; //长度为n的序列,注意begin和end遵循的是左闭右闭原则
bool IsSequenceOfBST(int begin, int end)
{
if (end - begin <= 0)
return true;
int root_data = array[end]; //数组尾元素为根节点
int i = begin;
for (; array[i] < root_data; i++); //取得左子树
int j = i;
for (; j < end; j++)
if (array[j] < root_data) //此时右子树应该都大于根节点;若存在小于,直接return false
return false;
return IsSequenceOfBST(begin, i - 1) && IsSequenceOfBST(i, end - 1); //左右子树是否都满足
}
(16):给定一个二叉查找树中的节点,找出在中序遍历下它的后继和前驱;
查找后续节点:
如果节点中有指向父亲节点的指针(假如根节点的父节点为 nullptr),则:
(1):如果当前节点有右孩子,则后继节点为这个右孩子的最左孩子;
(2):如果当前节点没有右孩子;
(2.1):当前节点为根节点,返回 nullptr;
(2.2):当前节点只是个普通节点,也就是存在父节点;
(2.2.1):当前节点是父亲节点的左孩子,则父亲节点就是后继节点;
(2.2.2):当前节点是父亲节点的右孩子,沿着父亲节点往上走,直到 n-1 代祖先是 n 代祖先的左孩子,则后继为 n 代祖
先或遍历到根节点也没找到符合的,则当前节点就是中序遍历的最后一个节点,返回 nullptr。
Node * Increment(Node * node)
{
if (node->right)
{
node = node->right;
while (node->left)
node = node->left;
}
else
{
Node * p = node->parent;
while (p && p->right == node)
{
node = p;
p = p->parent;
}
node = p;
}
return node;
}
(17):二分查找树转化为排序的循环双链表;
循环双链表:使用中序遍历的方法输出索引数组,再进行组合可以达目的,时间O(n),空间O(n);
如果限制使用的空间,则需要在遍历的同时构建链表,使用递归方法:
/* 合并两个a,b两个循环双向链表 */
Node * Append(Node * a, Node * b)
{
if (a == nullptr) return b;
if (b == nullptr) return a;
//分别得到两个链表的最后一个元素
Node * a_last = a->left;
Node * b_last = b->left;
//将两个链表头尾相连
a_last->right = b;
b->left = a_last;
a->left = b_last;
b_last->right = a;
return a;
}
/* 递归的解决二叉树转换为双链表 */
Node * TreeToList(Node * node)
{
if (node == nullptr) return nullptr;
//递归解决子树
Node * left_list = TreeToList(node->left);
Node * right_list = TreeToList(node->right);
//把根节点转换为一个节点的双链表。方便后面的链表合并
node->left = node;
node->right = node;
//合并之后即为升序排列
left_list = Append(left_list, node);
left_list = Append(left_list, right_list);
return left_list;
}
(18):二叉树路径等于目标值的所有路径;
路径和:最容易想到的办法就是递归,需要注意传入的参数是引用。
class Solution {
public:
/**
* @param root the root of binary tree
* @param target an integer
* @return all valid paths
*/
void path(vector<vector<int>>&ve, vector<int> v,int val, TreeNode* root){
if(root==NULL)return;
val=val-root->val;
v.push_back(root->val);
if(val==0&&root->left==NULL&&root->right==NULL){
ve.push_back(v);
return;
}
path(ve,v,val,root->left);
path(ve,v,val,root->right);
}
vector<vector<int>> binaryTreePathSum(TreeNode *root, int target) {
// Write your code here
vector<vector<int>> ve;
vector<int>v;
path(ve,v,target,root);
return ve;
}
};
(19):二叉树的所有路径;
vector<string> binaryTreePaths(TreeNode* root) {
// Write your code here
vector<string> res;
if(root==NULL) return res;
binaryTreePathsCore(root,res,to_string(root->val));
return res;
}
void binaryTreePathsCore(TreeNode* root,vector<string> &str,string strpath)
{
if(root->left==NULL&&root->right==NULL)//叶子结点
{
str.push_back(strpath);
return;
}
if(root->left!=NULL)
binaryTreePathsCore(root->left,str,strpath+"->"+to_string(root->left->val));
if(root->right!=NULL)
binaryTreePathsCore(root->right,str,strpath+"->"+to_string(root->right->val));
}