二叉树的构造
void createTree(TreeNode* &root)//构造时候尤其要注意,放进去引用,因为修改的是指针本身不是指针所指内容
{
int val;
cin >> val;
if (val)
{
root = new TreeNode(val);
createTree(root->left);
createTree(root->right);
}
else
{
return;
}
return;
}
该情况为“先序”的思路来构造的
void createTree2(TreeNode*& root)
{
int a;
cin >> a;
if (a)
root = new TreeNode(a);
else
return;
queue<TreeNode*> que;
que.push(root);
while (!que.empty())
{
TreeNode* p = que.front();
que.pop();
cin >> a;
if (a)
{
p->left = new TreeNode(a);
que.push(p->left);
}
cin >> a;
if (a)
{
p->right = new TreeNode(a);
que.push(p->right);
}
}
return;
}//层次create
该情况是以层次遍历的思想,利用队列来进行构造
深度优先遍历分为递归法和迭代法,递归法较为简单,下面是中序遍历的递归函数
void midOrderTree(TreeNode* root)//中序遍历
{
if (root == NULL)
return;
midOrderTree(root->left);
cout << root->val << ' ';
midOrderTree(root->right);
return;
}
迭代法也有两类,一类是单纯针对每一种顺序遍历来改变思路求解,无通用性。
void pre(TreeNode* root)
{
stack<TreeNode*> st;
if(root!=NULL)
st.push(root);
TreeNode* p = NULL;
while (!st.empty())
{
p = st.top();
st.pop();
cout << p->val << ' ';
if(p->right)
st.push(p->right);
if(p->left)
st.push(p->left);
}
return;
}
该情况利用了堆栈,先序遍历时,先把树根入栈,每弹出一个元素指针,就要再进去0~2个元素,注意顺序是先右后左放,才能先左后右出
void mid(TreeNode* root)//把根左边的全放进去,出来时候把右边的左线也放进去
{
stack<TreeNode*> st;
TreeNode* p = root;
while (p != NULL || !st.empty())//难点之处,利用p的有无,把这次迭代放新东西和处理top()分开
{
if (p != NULL)
{
st.push(p);
p = p->left;
}
else
{
p = st.top();
st.pop();
cout << p->val << ' ';
p = p->right;
}
}
}
中序的思路稍微复杂一点点,while语句的部分,需要借助p来区分开本次迭达的操作是入栈还是处理栈顶元素
void end(TreeNode* root)//针对先序修改输出顺序,中左右->中右左->左右中
{
vector<int> re;
stack<TreeNode*> st;
if (root != NULL)
st.push(root);
while (!st.empty())
{
TreeNode* p = st.top();
st.pop();
re.push_back(p->val);
if(p->left != NULL)
st.push(p->left);
if(p->right != NULL)
st.push(p->right);
}
for (int i = re.size()-1; i>=0; i--)
{
cout << re[i] << ' ';
}
return;
}
后序的处理思路借助于先序的思路,仅改变先序的输出顺序即可
迭代法除了上述三个算法,还有一种比较通用的算法,该通用解法思路需要刻意记一下
//上面的三种思路清晰,但是不够通用统一,还用一种比较通用的迭代思路,以中序为例
void midOrder(TreeNode* root)
{
TreeNode* p = root;
stack<TreeNode*> st;
if (p != NULL)
st.push(p);
while (!st.empty())
{
p = st.top();
if (p != NULL)
{
st.pop();
if (p->right != NULL)
st.push(p->right);
st.push(p);
st.push(NULL);
if (p->left != NULL)
st.push(p->left);
}
else
{
st.pop();
p = st.top();
st.pop();
cout << p->val << ' ';
}
}
}
这种思路参照于迭代法的中序遍历,同样是通过一个元素是否为空来判定本次迭代是出栈还是入栈处理,把那些已经遍历访问过(访问完又回来是因为需要处理好其左右子节点,按顺序重新放进来),但还未被处理掉的元素之前压入NULL元素,待下次遍历之时再彻底出栈不再回来
层次遍历
//层序遍历,用到的是队列,出一个,进0~2个
void levelOrder(TreeNode* root)
{
queue<TreeNode*> que;
if (root != NULL)
que.push(root);
while (!que.empty())
{
TreeNode* p = que.front();
que.pop();
cout << p->val << ' ';
if (p->left != NULL)
que.push(p->left);
if (p->right != NULL)
que.push(p->right);
}
return;
}
};
和深度遍历非递归法最大不同之处在于用到的是队列,思路较为简单
详细代码如下
#include<iostream>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
struct TreeNode {//节点
int val;
TreeNode *left;
TreeNode *right;
TreeNode() : val(0), left(nullptr), right(nullptr) {}
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};
class tree
{
public:
tree()
{}
void createTree(TreeNode* &root)//构造时候尤其要注意,放进去引用,因为修改的是指针本身不是指针所指内容
{
int val;
cin >> val;
if (val)
{
root = new TreeNode(val);
createTree(root->left);
createTree(root->right);
}
else
{
return;
}
return;
}
void createTree2(TreeNode*& root)
{
int a;
cin >> a;
if (a)
root = new TreeNode(a);
else
return;
queue<TreeNode*> que;
que.push(root);
while (!que.empty())
{
TreeNode* p = que.front();
que.pop();
cin >> a;
if (a)
{
p->left = new TreeNode(a);
que.push(p->left);
}
cin >> a;
if (a)
{
p->right = new TreeNode(a);
que.push(p->right);
}
}
return;
}//层次create
//深度优先遍历
void preOrderTree(TreeNode* root)//先序遍历
{
if (root != NULL)
cout << root->val << ' ';
else
return;
preOrderTree(root->left);
preOrderTree(root->right);
return;
}
void midOrderTree(TreeNode* root)//中序遍历
{
if (root == NULL)
return;
midOrderTree(root->left);
cout << root->val << ' ';
midOrderTree(root->right);
return;
}
void endOrderTree(TreeNode* root)//后序遍历
{
if (root == NULL)
return;
endOrderTree(root->left);
endOrderTree(root->right);
cout << root->val << ' ';
}
//迭代法遍历
void pre(TreeNode* root)
{
stack<TreeNode*> st;
if(root!=NULL)
st.push(root);
TreeNode* p = NULL;
while (!st.empty())
{
p = st.top();
st.pop();
cout << p->val << ' ';
if(p->right)
st.push(p->right);
if(p->left)
st.push(p->left);
}
return;
}
void mid(TreeNode* root)//把根左边的全放进去,出来时候把右边的左线也放进去
{
stack<TreeNode*> st;
TreeNode* p = root;
while (p != NULL || !st.empty())//难点之处,利用p的有无,把这次迭代放新东西和处理top()分开
{
if (p != NULL)
{
st.push(p);
p = p->left;
}
else
{
p = st.top();
st.pop();
cout << p->val << ' ';
p = p->right;
}
}
}
void end(TreeNode* root)//针对先序修改输出顺序,中左右->中右左->左右中
{
vector<int> re;
stack<TreeNode*> st;
if (root != NULL)
st.push(root);
while (!st.empty())
{
TreeNode* p = st.top();
st.pop();
re.push_back(p->val);
if(p->left != NULL)
st.push(p->left);
if(p->right != NULL)
st.push(p->right);
}
for (int i = re.size()-1; i>=0; i--)
{
cout << re[i] << ' ';
}
return;
}
//上面的三种思路清晰,但是不够通用统一,还用一种比较通用的迭代思路,以中序为例
void midOrder(TreeNode* root)
{
TreeNode* p = root;
stack<TreeNode*> st;
if (p != NULL)
st.push(p);
while (!st.empty())
{
p = st.top();
if (p != NULL)
{
st.pop();
if (p->right != NULL)
st.push(p->right);
st.push(p);
st.push(NULL);
if (p->left != NULL)
st.push(p->left);
}
else
{
st.pop();
p = st.top();
st.pop();
cout << p->val << ' ';
}
}
}
//层序遍历,用到的是队列,出一个,进0~2个
void levelOrder(TreeNode* root)
{
queue<TreeNode*> que;
if (root != NULL)
que.push(root);
while (!que.empty())
{
TreeNode* p = que.front();
que.pop();
cout << p->val << ' ';
if (p->left != NULL)
que.push(p->left);
if (p->right != NULL)
que.push(p->right);
}
return;
}
};
int main()
{
TreeNode* root = NULL;
tree Tree;
Tree.createTree(root);
//Tree.preOrderTree(root);
//cout << endl;
//Tree.pre(root);
//cout << endl;
//Tree.midOrderTree(root);
//cout << endl;
//Tree.mid(root);
//cout << endl;
//Tree.endOrderTree(root);
//cout << endl;
//Tree.end(root);
//cout << endl;
//
//Tree.midOrder(root);
//cout << endl;
Tree.levelOrder(root);
}