二叉树创建存储
前序遍历创建存储
先定义树节点的结构体
struct BinaryTree {
char val;
BinaryTree* Left;
BinaryTree* Right;
BinaryTree(char c) {
val = c;
Left = NULL;
Right = NULL;
}
};
然后用前序遍历的方式递归创建二叉树
这里flag作为空结点的标志
char flag;
BinaryTree* Creat_Tree(){
char c;
cin >> c;
if (c == flag) return NULL;
else {
BinaryTree* root = new BinaryTree(c);
root->Left=Creat_Tree();
root->Right=Creat_Tree();
return root;
}
}
在创建的时候根据要求更改细节部分
若最后的结束标志都不再输入,则要利用while(cin>>)
BinaryTree* Creat_Tree() {
char c;
int k = 0;
while (cin >> c && k == 0) {
k = 1;
if (c == flag) return NULL;
else {
BinaryTree* root = new BinaryTree(c);
root->Left = Creat_Tree();
root->Right = Creat_Tree();
return root;
}
}
}
创建如图的二叉树:
完整代码
#include<iostream>
using namespace std;
struct BinaryTree {
char val;
BinaryTree* Left;
BinaryTree* Right;
BinaryTree(char c) {
val = c;
Left = NULL;
Right = NULL;
}
};
//前序遍历打印二叉树
void preOderTraverse(BinaryTree* root) {
cout << root->val << " ";
if (root->Left) preOderTraverse(root->Left);
if (root->Right) preOderTraverse(root->Right);
}
//前序遍历创建二叉树
char flag;
BinaryTree* Creat_Tree(){
char c;
cin >> c;
if (c == flag) return NULL;
else {
BinaryTree* root = new BinaryTree(c);
root->Left=Creat_Tree();
root->Right=Creat_Tree();
return root;
}
}
//末尾结束符不给出的情况下创建
/*
BinaryTree* Creat_Tree() {
char c;
int k = 0;
while (cin >> c && k == 0) {
k = 1;
if (c == flag) return NULL;
else {
BinaryTree* root = new BinaryTree(c);
root->Left = Creat_Tree();
root->Right = Creat_Tree();
return root;
}
}
}
*/
int main()
{
cin >> flag;
BinaryTree* root = NULL;
root=Creat_Tree();
if (root == NULL) cout << "这是一个空树";
else
preOderTraverse(root);
return 0;
}
输入:
#
a b f # e # # c # d # #
输出:
a b f e c d
层次遍历创建存储
定义二叉树的结构体
struct BinaryTree {
char val;
BinaryTree* Left;
BinaryTree* Right;
BinaryTree(char c) {
val = c;
Left = NULL;
Right = NULL;
}
};
先对第一个输入的结点值判断,如果是结束符则直接返回NULL,如果不是,则将根节点创建出来并加入队列
当队列不空时候,每次从队列中取出队头,先对其左孩子判断是否创建该结点再对右孩子判断,创建一个就加入
char flag;
BinaryTree* Creat_Tree() {
queue<BinaryTree*>q;
BinaryTree* root=NULL;
char c;
cin>>c;
if(c==flag) return root;
root=new BinaryTree(c);
q.push(root);
while(!q.empty()){
BinaryTree* p=q.front();
q.pop();
if(!(cin>>c)) return root;
if(c==flag) p->Left=NULL;
else {
p->Left=new BinaryTree(c);
q.push(p->Left);
}
if(!(cin>>c)) return root;
if(c==flag) p->Right=NULL;
else{
p->Right=new BinaryTree(c);
q.push(p->Right);
}
}
return root;
}
创建如图的二叉树:
完整代码
#include<iostream>
using namespace std;
#include<queue>
struct BinaryTree {
char val;
BinaryTree* Left;
BinaryTree* Right;
BinaryTree(char c) {
val = c;
Left = NULL;
Right = NULL;
}
};
char flag;
BinaryTree* Creat_Tree() {
queue<BinaryTree*>q;
BinaryTree* root=NULL;
char c;
cin>>c;
if(c==flag) return root;
root=new BinaryTree(c);
q.push(root);
while(!q.empty()){
BinaryTree* p=q.front();
q.pop();
if(!(cin>>c)) return root;
if(c==flag) p->Left=NULL;
else {
p->Left=new BinaryTree(c);
q.push(p->Left);
}
if(!(cin>>c)) return root;
if(c==flag) p->Right=NULL;
else{
p->Right=new BinaryTree(c);
q.push(p->Right);
}
}
return root;
}
//层次遍历打印输出
void Traverse(BinaryTree* root) {
queue<BinaryTree*>q;
if (root == NULL) return;
q.push(root);
while (q.size()) {
int len=q.size();
for (int i = 0; i < len; i++) {
BinaryTree* p = q.front();
q.pop();
cout << p->val << " ";
if (p->Left) q.push(p->Left);
if (p->Right)q.push(p->Right);
}
}
}
int main()
{
cin >> flag;
BinaryTree* root=NULL;
root=Creat_Tree();
if(root==NULL) cout<<"pop";
Traverse(root);
return 0;
}
输入:
#
a b c f # # d # e
输出:
a b c f d e
二叉树遍历
递归
前序、中序、后序遍历
对于一棵二叉树,在遍历该树的过程中,每个点会经过三次,而对第几次访问操作则划分了是前序、中序还是后序遍历,操作的点视为对根节点操作,若是在第一次经过时操作,则是前序遍历(根左右);经过第二次时操作,则是中序遍历(左根右);经过第三次时操作,则是后序遍历(左右根)。
对每个点这样重复操作就是递归的思想。
前序
void preOder(BinaryTree* root)
{
//操作
//cout<<root->val<<" ";
preOder(root->left);
preOder(root->right);
}
中序
void preOder(BinaryTree* root)
{
preOder(root->left);
//操作
//cout<<root->val<<" ";
preOder(root->right);
}
后序
void preOder(BinaryTree* root)
{
preOder(root->left);
preOder(root->right);
//操作
//cout<<root->val<<" ";
}
非递归
前序、中序、后续遍历都要借助栈,而层次遍历是借助队列
前序遍历
先对根节点操作,然后先将右孩子判断入栈,再对左孩子判断入栈,这样才能在从栈中取出时先取出对应的左孩子
vector<char> preOderTraverse(BinaryTree* root) {
vector<char>v;
stack<BinaryTree*>s;
if (root == NULL) return v;
s.push(root);
while (s.size()) {
BinaryTree* p = s.top();
s.pop();
v.push_back(p->val);
if (p->Right) s.push(p->Right);
if (p->Left) s.push(p->Left);
}
return v;
}
遍历的结果存储在v中
中序遍历
中序遍历比较特殊,因为它需要保存父亲节点,因此在每次向左寻找节点过程中将经过的节点都存入栈中,当向左找到空节点时就从栈中取出存储在栈顶的节点,也就是空节点的父亲节点,然后将父亲节点加入vector容器v中,再让当前节点变为其右节点
vector<char> inorderTraverse(BinaryTree* root) {
vector<int> v;
stack<BinaryTree*> s;
if (root == NULL) return v;
BinaryTree* p = root;
while (p || s.size()) {
if (p) {
s.push(p);
p = p->left;
}
else {
p = s.top();
s.pop();
v.push_back(p->val);
p = p->right;
}
}
return v;
}
后序遍历
后序遍历的顺序是左右根,前序遍历的顺序是根左右,前序遍历倒过来是右左根,而影响左右顺序的是加入栈的顺序,那么就可以在顺序上做文章,将前序遍历的左右入栈顺序更改,让左孩子先入栈,右孩子后入栈,最后将得到的顺序倒过来就得到了后序遍历的结果
vector<char> preOderTraverse(BinaryTree* root) {
vector<char>v;
stack<BinaryTree*>s;
if (root == NULL) return v;
s.push(root);
while (s.size()) {
BinaryTree* p = s.top();
s.pop();
v.push_back(p->val);
if (p->Left) s.push(p->Left);
if (p->Right) s.push(p->Right);
}
reverse(v.begin(), v.end());
return v;
}
层次遍历
先对根节点判断,空直接返回
不空则将根节点入队列
当队列不空时,将队列中的元素依次取出,输出并判断左右孩子是否存在,若存在则将孩子加入队列(有一层一层处理的感觉)
void Traverse(BinaryTree* root) {
queue<BinaryTree*>q;
if (root == NULL) return;
q.push(root);
while (q.size()) {
int len=q.size();
for (int i = 0; i < len; i++) {
BinaryTree* p = q.front();
q.pop();
cout << p->val << " ";
if (p->Left) q.push(p->Left);
if (p->Right)q.push(p->Right);
}
}
}
对称二叉树的判断
二叉树对称不仅要局部左右孩子对称,整体也要对称
比如下面这样的就是对称的:
下面这样的就是不对称的:
理解了定义后,下面我们来看看如何用编程去判断一棵二叉树是否是对称的:
递归解法:
定义的函数是一个有两个参数的函数,传入左孩子和右孩子
首先判断传入的参数左右孩子是否对称{
…一个为空一个不空不对称
…都不空但是值不同不对称
}
然后再判断内外层是否对称{
…内层:左孩子的右孩子与右孩子的左孩子的值不同不对称
…外层:左孩子的左孩子与右孩子的右孩子的值不同不对称
}
二叉树结构体:
struct TreeNode {
int val;
TreeNode* Left;
TreeNode* Right;
TreeNode(int val) {
this->val = val;
Left = NULL;
Right = NULL;
}
TreeNode() {
val = 0;
Left = NULL;
Right = NULL;
}
};
递归写法:
bool is_Symmetric(TreeNode* left,TreeNode* right) {
if (left == NULL && right) return false;
else if (left && right == NULL) return false;
else if (left == NULL && right == NULL) return true;
else if (left->val && right->val) return false;
bool intrue = is_Symmetric(left->Right, right->Left);
bool outtrue = is_Symmetric(left->Left, right->Right);
if (intrue && outtrue) return true;
else return false;
}
非递归解法:
非递归定义的函数含有一个参数root,root为空则整个树是个空树,直接返回true
不空则借助队列(或者栈)操作,将root的左孩子和右孩子依次入队
当队列不空时,从队列中依次取出两个元素,用leftnode和rightnode依次接收,判断是否满足对称条件,不满足直接返回false,满足说明两个元素都不空,将他们按内外层对称的逻辑入队,leftnode的右孩子和rightnode的左孩子依次入队,leftnode的左孩子和rightnode的右孩子依次入队
非递归写法:
bool is_Symmertic(TreeNode* root) {
queue<TreeNode*>q;
if (root == NULL) return true;
q.push(root->Left);
q.push(root->Right);
while (q.size()) {
TreeNode* leftnode = q.front();
q.pop();
TreeNode* rightnode = q.front();
q.pop();
if (!leftnode && !rightnode) continue;
if (!leftnode || !rightnode || leftnode->val != rightnode->val) return false;
q.push(leftnode->Right);
q.push(rightnode->Left);
q.push(leftnode->Left);
q.push(rightnode->Right);
}
return true;
}
持续更新中~~~