树和二叉树
标签(空格分隔) : 算法 ACM
1.二叉树数组表示
A:
以根节点、左节点、右节点的顺序将各个节点放入数组,数组中下标为index的节点其左节点的下标为2 * index + 1 ,右节点为 2 * index + 2 ,其父节点的下标为 ( index - 1) / 2 。( 在完美二叉树中不会有空节点,完美二叉树即在一棵树中,只有最后一层从右边开始缺失节点。)
B:
也可以用三个数组表示,第i个结点的左右结点下标存在left[i]和right[i]中,以简单实现二叉树的访问、增加、更改。
2.二叉树遍历
遍历二叉树的所有结点且仅访问一次。按照根节点位置的不同分为前序遍历,中序遍历,后序遍历。
前序遍历:根节点->左子树->右子树(根节点在前面)
中序遍历:左子树->根节点->右子树(根节点在中间)
后序遍历:左子树->右子树->根节点(根节点在后边)
2.1三种遍历的递归实现方式(DFS)
typedef struct node{
int val;
struct node * left;
struct node * rigtht;
}
//前序遍历
void tree_visit(Node * root)
{
if( root == NULL)
return ;
visit(root);
tree_visit(root->left);
tree_visit(root->right);
}
//中序遍历
void tree_visit(Node * root)
{
if( root == NULL)
return ;
tree_visit(root->left);
visit(root);
tree_visit(root->right);
}
//后续遍历
void tree_visit(Node * root)
{
if( root == NULL)
return ;
tree_visit(root->left);
tree_visit(root->right);
visit(root);
}
2.2三种遍历栈实现方式
//非递归使用栈实现
//前序遍历
void tree_visit(Node * root)
{
if(root == NULL)
return ;
stack<Node *> s;
s.push(root);
Node * p;
while(!s.empty())
{
p = s.top();
s.pop();
visit(p);
if(p->right!=NULL)
s.push(p->right);//栈是先进后出,所以前序遍历的right要先放入栈中
if(p->left!=NULL)
s.push(p->lefy);
}
}
//中序遍历
void tree_visit(Node * root)
{
if(root == NULL)
return ;
stack<Node * > s;
Node * p = root;
//以左结点向下搜索,若结点不存在则出栈父节点进行访问,然后用右结点向下搜索,即中序遍历
while(!s.empty() || p != NULL)
{
if( p == NULL)
{
p = s.pop();
s.pop();
visit(p);
p = p->right;
}
else
{
s.push(p);
p = p -> left;
}
}
}
//后序遍历
void tree_visit(Node * root)
{
if( root == NULL)
return ;
stack<Node *> s;
vector<Node *> rs;
Node * p = NULL;
s.push(root);
while(!s.empty())
{
p = s.top()
s.pop();
//从开始把root插入rs,以left和right的顺序放入栈中,left较right后出栈,所以在rs里left在前,right、root在后。(rs向前插入结点,后插入的结点先访问)
rs.insert(rs,begin(),p);
if(p->left!=NULL)
s.push(p->left);
if(p->right!=NULL)
s.push(p->right);
}
for(int i = 0; i < rs.size();i++)
visit(rs[i]);
}
2.3三种遍历方式的转换
//前序加中序转后序
#include<iostream>
#include<cstring>
using namespace std;
char pre[26],mid[26];
void build(int L1,int R1,int L2,int R2)
{
if(L1 > R1||L2 > R2)
return ;
int root = L1 , count = 0;
while(mid[count+L2]!= pre[root]) count ++;//统计左串长度
build(L1+1,L1+count,L2,L2+count-1);//将root的左串构造成树
build(L1+count+1,R1,L2+count+1,R2);//将root的右串构造成树
cout<<pre[root];//左右子树遍历完,遍历root,就是后序
return ;
}
int main()
{
cin>>pre>>mid;
build(0,strlen(pre)-1,0,strlen(mid)-1);
return 0;
}
//测试样例 ABDGKLRVWSXCEHMNFIOTUJPYQZ KGVRWLSXDBAMHNECTOUIFPYJZQ
//输出 KVWRXSLGDBMNHETUOIYPZQJFCA
备注:有的代码可能不能直接运行,存在些许错误,欢迎大家指正。