二叉树

简介: 二叉树三种遍历递归#include "stdafx.h"#include#include#includeusing namespace std;//定义树的基本框架struct TreeNode {...

二叉树三种遍历

递归


#include "stdafx.h"
#include<iostream>
#include<vector>
#include<queue>
using namespace std;

//定义树的基本框架
struct TreeNode {
	int val;
	TreeNode *left;
	TreeNode *right;
	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

//构造二叉树
TreeNode* CreatTree(vector<int>& num) {
	int length = num.size();
	//如果传入容器为空,则跳出函数,无法构建二叉树
	if (length == 0) return nullptr;
	//赋值的索引位置
	int index = 0;
	//构建一个二叉树
	TreeNode *root = new TreeNode(num[index++]);
	//构建二叉树时所用的工具
	TreeNode *p = nullptr;
	queue<TreeNode*>trans;
	trans.push(root);
	//当队列不为空,此时还有数字没插入树中
	while (!trans.empty() && index < length) {
		p = trans.front();
		trans.pop();
		if (index < length && num[index] != -1) {
			TreeNode *LeftNode = new TreeNode(num[index]);
			p->left = LeftNode;
			trans.push(LeftNode);
		}
		index++;
		if (index < length&&num[index] != -1) {
			TreeNode *RightNode = new TreeNode(num[index]);
			p->right = RightNode;
			trans.push(RightNode);
		}
		index++;
	}
	return root;
}

//前序遍历  根左右
void Preorder(TreeNode *root)
{
	//根为空,则跳出函数
	if (!root)
		return;
	//输出根的值
	cout << root->val << "  ";
	//递归获取左子树的值
	Preorder(root->left);
	//递归获取右子树的值
	Preorder(root->right);
}

//中序遍历  左根右
void Midorder(TreeNode *root)
{
	//根为空,则跳出函数
	if (!root)
		return;
	//递归获取左子树的值
	Midorder(root->left);
	cout << root->val << " ";
	Midorder(root->right);
}

//后序遍历  左右根
void Postorder(TreeNode *root)
{
	if (!root)
		return;
	Postorder(root->right);
	Postorder(root->left);
	cout << root->val << "  ";
}

int main()
{
	vector<int> num = { 3,5,1,6,2,0,8,-1,-1,7,4,-1,-1,-1,-1 };
	TreeNode *tree = CreatTree(num);
	//前序遍历
	Preorder(tree);
	//中序遍历
	Midorder(tree);
	//后序遍历
	Postorder(tree);
    return 0;
}




Leetcode  113


题意:每层取一个节点,各节点之间为父子关系。判断是否存在总和等于给定数值sum的路径。

考点:深度优先搜索

// 知识点:创建二叉树;深度遍历

#include "stdafx.h"
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
//定义二叉树
struct TreeNode {
	int val;
	TreeNode *left;
	TreeNode *right;
	//构造函数,初始数据依次为价值,左子节点,右子节点
	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

class Solution {
public:
	//二维数组,存储所有满足sum的路径
	vector<vector<int>> pathSum(TreeNode* root, int sum) {
		//存储所有满足条件的路径
		vector<vector<int>> paths; 
		//存储当前遍历路径
		vector<int> temp;
		help(root, paths, temp, sum);
		//返回二维数组
		return paths;
	}
	//TreeNode* &root  vector<int> temp 这块没用引用,是每条路径都是相互独立的
	//vector<vector<int>> &paths用引用是因为自始至终他就一个
	void help(TreeNode* &root, vector<vector<int>> &paths, vector<int> temp, int sum) {		
		if (root == nullptr)
			//结束函数
			return;
		//将根节点的值传入temp中
		temp.push_back(root->val);
		if (root->left == nullptr && root->right == nullptr && sum == root->val)
			//将符合要求的容器压入path中
			paths.push_back(temp);
		if (root->left != nullptr)
			//递归   用sum - root->val因为sum要抛去该容器内加入了的元素的值
			help(root->left, paths, temp, sum - root->val);
		if (root->right != nullptr)
			//递归 不断深入,到两侧子节点都为空的时候,该点是叶子结点,就是该路径的尽头了
			help(root->right, paths, temp, sum - root->val);
	}
};
// 创建二叉树
TreeNode* CreateTreeByLevel(vector<int> num) {
	//树中总节点个数
	int len = num.size();
	if (len == 0) {
		return nullptr;
	}
	queue<TreeNode*> queue;
	int index = 0;
	// 创建根节点,这里调用了[]的重载函数
	//将整棵树存在这里
	TreeNode *root = new TreeNode(num[index]);
	index++;
	// 入队列,队列在这里就是一个传递的容器,每次循环会排空上次存的值并存入上次存的值的两个子节点
	queue.push(root);
	//空对象,该对象只有一个val,两个指针和一个成员函数
	TreeNode *p = nullptr;
	//如果queue为空,则证明上一次循环并没有压入任何左子节点或右子节点,证明上一次循环中的root是叶子结点
	while (!queue.empty() && index < len) {
		// 第一次进来的时候,存入了*root的那个根节点
		//出队列,存储上次循环中的root节点,并将之前存入的值清空
		p = queue.front();
		queue.pop();
		// 左节点
		if (index < len && num[index] != -1) {
			// (-1代表该节点为空)如果不空创建一个节点,存入num中的值作为左子节点
			TreeNode *leftNode = new TreeNode(num[index]);
			//压入获取的num里的值到root里面,作为左子节点
			p->left = leftNode;
			queue.push(leftNode);
		}
		index++;
		// 右节点
		if (index < len && num[index] != -1) {
			// 如果不空创建一个节点,存入num中的值作为右子节点
			TreeNode *rightNode = new TreeNode(num[index]);
			//压入获取的num里的值root里面,作为右子节点
			p->right = rightNode;
			queue.push(rightNode);
		}
		index++;
	}
	return root;
}

int main()
{
	//创建解决问题的类的对象
	Solution s;
	// -1代表该节点为空  按层传入 根:5   第二层:4,8   第三层:11,-1,13,4 以此类推
	vector<int> num = { 5,4,8,11,-1,13,4,7,2,-1,-1,5,1 };
	//创建二叉树
	TreeNode* root = CreateTreeByLevel(num);
	//输出二叉树中符合要求的路径
	vector<vector<int> > paths = s.pathSum(root, 22);
	//遍历输出结果,每输出完二维数组的一行就输出一个换行符
	for (int i = 0; i < paths.size(); i++) {
		for (int j = 0; j < paths[i].size(); j++) {
			cout << paths[i][j] << " ";
		}
		cout << endl;
	}
	return 0;
}


Leetcode  236


题意:找到给定的两个节点最近的公共祖先。

思路:1、如果一个节点是另一个节点的祖先,则最近的公共祖先就是两个节点中作为祖先的那一个。

          2、如果root的左子树p和右子树q都存在,则root肯定是最近祖先。

#include "stdafx.h"
#include<iostream>
#include<vector>
#include<queue>
using namespace std;

//定义树的基本框架
struct TreeNode {
	int val;
	TreeNode *left;
	TreeNode *right;
	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}	
};

//构造二叉树
TreeNode* CreatTree(vector<int>& num) {
	int length = num.size();
	//如果传入容器为空,则跳出函数,无法构建二叉树
	if (length == 0) return nullptr;
	//赋值的索引位置
	int index = 0;
	//构建一个二叉树
	TreeNode *root = new TreeNode(num[index++]);
	//构建二叉树时所用的工具
	TreeNode *p = nullptr;
	
	queue<TreeNode*>trans;
	trans.push(root);
	//当队列不为空,此时还有数字没插入树中
	while (!trans.empty() && index < length) {
		p = trans.front();
		trans.pop();
		if (index < length && num[index] != -1) {
			TreeNode *LeftNode = new TreeNode(num[index]);			
			p->left = LeftNode;
			trans.push(LeftNode);
		}
		index++;
		if (index < length&&num[index] != -1) {
			TreeNode *RightNode = new TreeNode(num[index]);			
			p->right = RightNode;
			trans.push(RightNode);
		}
		index++;
	}
	return root;
}

//递归找到结果
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
	if (root == nullptr || root == p || root == q) return root;
	//如果pq都在root的左子树,那么就需要递归root的左子树,右子树同理
	TreeNode* left = lowestCommonAncestor(root->left, p, q);
	TreeNode* right = lowestCommonAncestor(root->right, p, q);
	//如果root的左子树存在p,右子树存在q,那么root肯定就是最近祖先
	if (left && right) {
		return root;
	}else {
		return left == nullptr ? right : left;
	}
}

int main()
{
	vector<int> num = { 3,5,1,6,2,0,8,-1,-1,7,4,-1,-1,-1,-1 }; 
	int first_num = 0, second_num = 0;
	cin >> first_num;
	cin >> second_num;
	TreeNode *tree = CreatTree(num);
	//不会调用这个函数。。。卡住了。。。。。。。。。。
	lowestCommonAncestor(root, first_num, second_num);
    return 0;
}



leetcode  114


题意:二叉树按前序遍历生成一棵没有左子树的二叉树。

考点:二叉树前序遍历

思路:还是要用递归了。


//前序遍历树,把值压入链表
#include "stdafx.h"
#include<iostream>
#include<queue>
using namespace std;

//定义树的基本框架
struct TreeNode {
	int val;
	TreeNode *left;
	TreeNode *right;
	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

//构造二叉树
TreeNode* CreatTree(vector<int> num) {
	int length = num.size();
	//如果传入容器为空,则跳出函数,无法构建二叉树
	if (length == 0) return nullptr;
	//赋值的索引位置
	int index = 0;
	//构建一个二叉树
	TreeNode *root = new TreeNode(num[index++]);
	//构建二叉树时所用的工具
	TreeNode *p = nullptr;
	queue<TreeNode*>trans;
	trans.push(root);
	//当队列不为空,此时还有数字没插入树中
	while (!trans.empty() && index < length) {
		p = trans.front();
		trans.pop();
		if (index < length && num[index] != -1) {
			TreeNode *LeftNode = new TreeNode(num[index]);
			p->left = LeftNode;
			trans.push(LeftNode);
		}
		index++;
		if (index < length&&num[index] != -1) {
			TreeNode *RightNode = new TreeNode(num[index]);
			p->right = RightNode;
			trans.push(RightNode);
		}
		index++;
	}
	return root;
}

TreeNode* Preorder(TreeNode *root)
{
	queue<TreeNode *>s;
	//根为空,则跳出函数
	if (!root)
		return;
	helper(s, root);
	TreeNode *head = root;
	s.pop();
	//将会去的内容依次放入新的树中
	while (s.size() > 0) {
		head->right = s.front();
		head->left = nullptr;
		head = head->right;
		s.pop();
	}
	return head;
}
//前序遍历思想
void helper(std::queue<TreeNode*>& s, TreeNode* root) {
	if (root == nullptr) {
		return;
	}
	s.push(root);
	helper(s, root->left);
	helper(s, root->right);
}

int main()
{
	vector<int> num = { 1,2,5,3,4,-1,6 };
	TreeNode *tree = CreatTree(num);	
	TreeNode * answer=Preorder(tree);
    return 0;
}

找到一个别的解题思路,没看懂,先记录一下

原文链接:http://blog.csdn.net/zjajgyy/article/details/77478333

class Solution {
public:
    void flatten(TreeNode *root) {
        TreeNode*now = root;
        while (now)
        {
            if(now->left)
            {
                //Find current node's prenode that links to current node's right subtree
                TreeNode* pre = now->left;
                while(pre->right)
                {
                    pre = pre->right;
                }
                pre->right = now->right;
                //Use current node's left subtree to replace its right subtree(original right 
                //subtree is already linked by current node's prenode
                now->right = now->left;
                now->left = NULL;
            }
            now = now->right;
        }
    }
};


LeetCode 199




题意:依次输出按层遍历最右侧的子节点的值。

考点:层序遍历,深度优先搜索

思路:层序遍历:每层最后入队的那个值就是要输出的值; 深度优先遍历:反向遍历,右子树优先搜索(这个方法感觉效率不高)。

层序遍历的主要思路就是先把根节点存入,然后输出,输出的同时把根节点的左右孩子存入,再把左孩子输出,同样输出的同时把左孩子的孩子在存入,直到遍历完成,例如:
       a
   b       c
d   e   f   g   

先把a存入,然后输出a,输出a的同时把b c存入,然后再输出b,输出b的同时存入d e,继续输出c,然后存入f g,直到全部输出

二叉树层序遍历代码如下(学习了一种新的二叉树的赋值方法):

#include "stdafx.h"
#include<iostream>
#include<vector>
#include<queue>
using namespace std;

//定义树的基本框架
struct TreeNode {
	int val;
	TreeNode *left;
	TreeNode *right;
	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

void answer(TreeNode* arr[])
{
	queue<TreeNode*> rel; //定义一个队列,数据类型是二叉树指针,不要仅是int!!不然无法遍历
	rel.push(arr[0]);
	while (!rel.empty())
	{
		TreeNode* front = rel.front();
		cout << front->val << endl;
		//删除最前面的节点
		rel.pop(); 
		//判断最前面的左节点是否为空,不是则放入队列
		if (front->left != nullptr) 
			rel.push(front->left);
		//判断最前面的右节点是否为空,不是则放入队列
		if (front->right != nullptr)
			rel.push(front->right);
	}
}

int main()
{	
	//构建二叉树
	TreeNode* s_arr[6];
	s_arr[0] = new TreeNode(0);
	s_arr[1] = new TreeNode(1);
	s_arr[2] = new TreeNode(2);
	s_arr[3] = new TreeNode(3);
	s_arr[4] = new TreeNode(4);
	s_arr[5] = new TreeNode(5);
	s_arr[0]->left = s_arr[1];  //   0
	s_arr[0]->right = s_arr[2]; //  1  2
	s_arr[1]->left = s_arr[3];  // 3     5
	s_arr[3]->left = s_arr[4];  //4
	s_arr[2]->right = s_arr[5]; //所以层序遍历的结果为:0 1 2 3 5 4
	
	answer(s_arr);

    return 0;
}


广度优先解法


自己写了一个按层遍历的,似乎不太完美。

/*
deque的一些操作
c.size();         //返回当前的元素数量
c.empty();       //判断大小是否为零。等同于c.size() == 0,但可能更快
c.max_size();    //可容纳元素的最大数量
c.at(idx) ;       //返回索引为idx所标示的元素。如果idx越界,抛出out_of_range
c[idx] ;         //返回索引idx所标示的元素。不进行范围检查
c.front() ;       //返回第一个元素,不检查元素是否存在
c.back();        //返回最后一个元素
c.begin();       //返回一个随机迭代器,指向第一个元素
c.end();         //返回一个随机迭代器,指向最后元素的下一位置
*/
#include "stdafx.h"
#include<iostream>
#include<vector>
#include<queue>
#include<deque>
#include<math.h>
using namespace std;

//定义树的基本框架
struct TreeNode {
	int val;
	TreeNode *left;
	TreeNode *right;
	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

vector<int> answer(TreeNode* arr[])
{
	//定义一个队列,数据类型是二叉树指针,不要仅是int,不然无法遍历
	queue<TreeNode*> rel; 
	deque<TreeNode*> answer1;	
	vector<int> answer2;
	rel.push(arr[0]);
	while (!rel.empty())
	{
		TreeNode* front = rel.front();
		//cout << front->val << endl;
		answer1.push_back(rel.front());
		//删除最前面的节点
		rel.pop(); 
		//判断最前面的左节点是否为空,不是则放入队列
		if (front->left != nullptr) 
			rel.push(front->left);
		//判断最前面的右节点是否为空,不是则放入队列
		if (front->right != nullptr)
			rel.push(front->right);
	}	
	//answer1.size()返回值类型是size_t
	int flag = answer1.size();
	int ceng = 0;
	while (flag) {
		if (flag / 2 >= 2) {
			ceng++;
			flag = flag / 2;
		}
		else {
			break;
		}
	}
	//树有这些层
	ceng += 2;
	for (int i = answer1.size()-1; i >0;) {
		if (ceng > 0) {
			if (answer1[i]->val != -1 && pow(2, ceng)-2 >= i && pow(2, ceng-1)-1 <= i) {
				answer2.push_back(answer1[i]->val);
				i = pow(2, ceng-1)-2;
				ceng--;
			}
			else {
				i--;
			}
		}
		else {
			break;
		}
	}
	answer2.push_back(answer1[0]->val);	
	return answer2;
}

int main()
{	
	//构建二叉树
	TreeNode* s_arr[7];
	s_arr[0] = new TreeNode(1);
	s_arr[1] = new TreeNode(2);
	s_arr[2] = new TreeNode(3);
	s_arr[3] = new TreeNode(-1);
	s_arr[4] = new TreeNode(5);
	s_arr[5] = new TreeNode(-1);
	s_arr[6] = new TreeNode(4);
	
	s_arr[0]->left = s_arr[1];  //        1
	s_arr[0]->right = s_arr[2]; //     2     3
	s_arr[1]->left = s_arr[3];  //  -1   5  -1  4
	s_arr[1]->right = s_arr[4];
	s_arr[2]->left = s_arr[5];
	s_arr[2]->right = s_arr[6];	
	
	answer(s_arr);

    return 0;
}


网上收集了一个广度优先的解法,很不错

http://blog.csdn.net/liuchuo/article/details/51990665

/*
deque的一些操作
c.size();         //返回当前的元素数量
c.empty();       //判断大小是否为零。等同于c.size() == 0,但可能更快
c.max_size();    //可容纳元素的最大数量
c.at(idx) ;       //返回索引为idx所标示的元素。如果idx越界,抛出out_of_range
c[idx] ;         //返回索引idx所标示的元素。不进行范围检查
c.front() ;       //返回第一个元素,不检查元素是否存在
c.back();        //返回最后一个元素
c.begin();       //返回一个随机迭代器,指向第一个元素
c.end();         //返回一个随机迭代器,指向最后元素的下一位置
*/
#include "stdafx.h"
#include<iostream>
#include<vector>
#include<queue>
#include<deque>
#include<math.h>
using namespace std;

//定义树的基本框架
struct TreeNode {
	int val;
	TreeNode *left;
	TreeNode *right;
	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

//构造二叉树
TreeNode* CreatTree(vector<int> num) {
	int length = num.size();
	//如果传入容器为空,则跳出函数,无法构建二叉树
	if (length == 0) return nullptr;
	//赋值的索引位置
	int index = 0;
	//构建一个二叉树
	TreeNode *root = new TreeNode(num[index++]);
	//构建二叉树时所用的工具
	TreeNode *p = nullptr;
	queue<TreeNode*>trans;
	trans.push(root);
	//当队列不为空,此时还有数字没插入树中
	while (!trans.empty() && index < length) {
		p = trans.front();
		trans.pop();
		if (index < length && num[index] != -1) {
			TreeNode *LeftNode = new TreeNode(num[index]);
			p->left = LeftNode;
			trans.push(LeftNode);
		}
		index++;
		if (index < length&&num[index] != -1) {
			TreeNode *RightNode = new TreeNode(num[index]);
			p->right = RightNode;
			trans.push(RightNode);
		}
		index++;
	}
	return root;
}

//按层遍历
vector<int> rightSideView(TreeNode* root) {
	vector<int> v;
	queue<TreeNode*> q;
	if (root == NULL)
		return v;
	q.push(root);
	TreeNode* h=nullptr;
	while (!q.empty()) {
		//整棵树压入时,size值为1,将根的两个子树压入之后,size值为2
		int size = q.size();
		while (size--) {
			h = q.front();
			q.pop();
			//子树非空,则压入队列 
			if (h->left != NULL)
				q.push(h->left);
			if (h->right != NULL)
				q.push(h->right);
		}
		v.push_back(h->val);
	}
	return v;
}

int main()
{		
	vector<int> num = { 1,2,3,-1,5,-1,4 };
	TreeNode *tree = CreatTree(num);
	vector<int> answer=rightSideView(tree);
    return 0;
}


深度优先的解法


#include "stdafx.h"
#include<iostream>
#include<vector>
#include<queue>
using namespace std;

struct TreeNode {
	int val;
	TreeNode* left;
	TreeNode * right;
	TreeNode(int x):val(x),left(nullptr),right(nullptr){ }
};

//构造二叉树
TreeNode* CreatTree(vector<int>num)
{
	int len = num.size();
	if (len == 0) return nullptr;

	int index = 0;
	TreeNode* root = new TreeNode(num[index++]);
	TreeNode* p = nullptr;
	queue<TreeNode*> queue;
	queue.push(root);
	while (!queue.empty()&&index<len) {
		p=queue.front();
		queue.pop();
		if (index < len && num[index] != -1) {
			TreeNode* LeftNode = new TreeNode(num[index]);
			p = LeftNode;
			queue.push(LeftNode);
		}index++;
		if (index < len && num[index] != -1) {
			TreeNode* RightNode = new TreeNode(num[index]);
			p = RightNode;
			queue.push(RightNode);
		}index++;
	}
}

//深度优先遍历
vector<int> rightSideView(TreeNode* root) {
	vector<int> rlt;
	dfs(root, 1, rlt);
	return rlt;
}

void dfs(TreeNode* root, int step, vector<int>& vec)
{
	if (!root) return;
	if (vec.size()<step) vec.push_back(root->val);
	dfs(root->right, step + 1, vec);
	dfs(root->left, step + 1, vec);
}

int main()
{
	vector<int>num = { 1,2,3,-1,5,-1,4 };
	TreeNode* answer = CreatTree(num);
	rightSideView(answer);
	dfs(answer, 1, num);
    return 0;
}



未完待续。。。。。。。。。。。。。



相关文章
|
6月前
|
存储 C++
二叉树
二叉树“【5月更文挑战第22天】”
33 3
二叉树(详解)下
二叉树(详解)
60 0
|
6月前
|
算法 网络协议 NoSQL
认识二叉树(详细介绍)
认识二叉树(详细介绍)
|
11月前
|
存储
浅谈二叉树
浅谈二叉树
49 1
|
6月前
|
存储 Java C++
二叉树的实现(上)
二叉树的实现
68 0
|
存储
二叉树讲解
二叉树讲解
74 0
|
存储
二叉树的相关列题!!
二叉树的相关列题!!
77 0
|
存储
【二叉树】(一)
【二叉树】(一)
47 0