二叉树专题
Complete Binary Search Tree (30)
Link
这道题相当于是已知完全二叉排序树的中序遍历,要输出其层序遍历。做法很巧妙,根本不用建树。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <string>
#include <string.h>
#include <vector>
#include <cmath>
#include <unordered_set>
using namespace std;
int n,cur;
int a[1010],b[1010];
void levelTraverse(int r){
if(r<=n){
levelTraverse(r<<1);
b[r]=a[++cur];
levelTraverse((r<<1)+1);
}
}
int main() {
scanf("%d",&n);
for(int i=1;i<=n;++i)
scanf("%d",&a[i]);
sort(a+1,a+1+n);
levelTraverse(1);
for(int i=1;i<n;++i)
printf("%d ",b[i]);
printf("%d\n",b[n]);
return 0;
}
我在官方OJ上做的时候, 想出了一种很巧妙的非递归解法:
Link
思路是: 假设完全二叉树从根节点开始层次遍历的所有节点依次编号为 1~n, 那么我先用栈存储下中序遍历这棵树的编号顺序, 也就是代码中 cnt 的遍历顺序. 由于中序遍历得到的一定是原数组 a 的增序排列, 因此将中序遍历的编号顺序与增序排列的值一次关联, 最后将编号顺序从小到大排序——也就得到了层次遍历的顺序. 一次输出与其关联的值即可.
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <string>
#include <string.h>
#include <vector>
#include <stack>
using namespace std;
int n;
int a[1010];
stack<int>st;
struct node{
int index,val;
bool operator<(node x)const{
return index<x.index;
}
}b[1010];
int main() {
scanf("%d",&n);
for(int i=1;i<=n;++i)
scanf("%d",&a[i]);
sort(a+1,a+1+n);
int cnt=1,num=1;
st.push(cnt);
while(!st.empty()){
cnt=st.top();
if((cnt<<1)<=n)
st.push(cnt<<1);
else{
st.pop();
b[num]={cnt,a[num]};
num++;
while(!st.empty()){
cnt=st.top();
st.pop();
b[num]={cnt,a[num]};
num++;
if((cnt<<1)+1<=n){
st.push((cnt<<1)+1);
break;
}
}
}
}
sort(b+1,b+1+n);
for(int i=1;i<n;++i)
printf("%d ",b[i].val);
printf("%d\n",b[n].val);
return 0;
}
Root of AVL Tree (25)
Link
AVL模板题
借用网上的图在此解释一下4种旋转的情形:(左右图都是不平衡的AVL)
先左旋后右旋指的是先左旋左子树,后右旋根节点。实际上左子树是平衡的,但是左孩子(左子树的根节点)满足两边高度之差等于1,这就导致了根节点不平衡。如果左孩子的右子树高度比左子树高度大1,那么就要先左旋以左孩子为根节点的左子树(这就会让新的左孩子的左子树高度比右子树高度大1);如果左孩子的左子树高度比右子树高度大1,那么就不必进行任何操作。也就是说,这种情况下首先要让长度的不平衡集中到左孩子的左边,最后将根节点右旋即可。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <string>
#include <string.h>
#include <vector>
#include <cmath>
using namespace std;
struct node{
int val;
struct node *left,*right;
};
//return root
//左旋的情况:根节点所在的树不平衡
node *rotateLeft(node *root){
node *t=root->right;
root->right=t->left;
t->left=root;
return t;
}
node *rotateRight(node *root){
node *t=root->left;
root->left=t->right;
t->right=root;
return t;
}
//先左旋后右旋的情况:先左旋左子树,后右旋根节点
//左子树平衡,但左子树的两边高度差是1,导致了根节点不平衡
node *rotateLeftRight(node *root){
//先在左子树上完成左旋
root->left=rotateLeft(root->left);
//后右旋根节点
return rotateRight(root);
}
node *rotateRightLeft(node *root){
root->right=rotateRight(root->right);
return rotateLeft(root);
}
int getHeight(node *root){
if(root==NULL) return 0;
return max(getHeight(root->left),getHeight(root->right))+1;
}
node *insert(node *root,int val){
if(root==NULL){
root=new node();
root->val=val;
root->left=root->right=NULL;
}else if(val<root->val){
root->left=insert(root->left,val);
if(getHeight(root->left)-getHeight(root->right)==2)
root=val<root->left->val?rotateRight(root):rotateLeftRight(root);
}else{
root->right=insert(root->right,val);
if(getHeight(root->right)-getHeight(root->left)==2)
root=val<root->right->val?rotateRightLeft(root):rotateLeft(root);
}
return root;
}
int main() {
int n,val;
scanf("%d",&n);
node *root=NULL;
for(int i=1;i<=n;++i){
scanf("%d",&val);
root=insert(root,val);
}
printf("%d\n",root->val);
return 0;
}
Is It a Binary Search Tree (25)
Link
根据BST的前序遍历输出其后序遍历。不用建树。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <string>
#include <string.h>
#include <vector>
using namespace std;
int n;
int a[1010];
bool isMirror=false;
bool isBST=true;
vector<int>ans;
void build(int l,int r){
if(!isBST||l>r) return;
int root=a[l];
if(isMirror){
int i=l+1;
for(;i<=r;++i){
if(a[i]<a[l])
break;
}
for(int j=i;j<=r;++j){
if(a[j]>=a[l]){
isBST=false;
break;
}
}
build(l+1,i-1);
build(i,r);
}else{
int i=l+1;
for(;i<=r;++i){
if(a[i]>=a[l])
break;
}
for(int j=i;j<=r;++j){
if(a[j]<a[l]){
isBST=false;
break;
}
}
build(l+1,i-1);
build(i,r);
}
ans.push_back(root);
}
int main() {
scanf("%d",&n);
for(int i=1;i<=n;++i)
scanf("%d",&a[i]);
if(n==1){
printf("YES\n%d",a[0]);
return 0;
}
if(n>1&&a[2]>=a[1]) isMirror=true;
build(1,n);
if(!isBST) printf("NO\n");
else{
printf("YES\n");
printf("%d",ans[0]);
for(int i=1;i<ans.size();++i)
printf(" %d",ans[i]);
}
return 0;
}
第二次在官方OJ上做时提交的代码:
Link
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <string>
#include <string.h>
#include <vector>
using namespace std;
int n;
int a[1010];
bool flag=true;
vector<int>ans;
void Traverse(int l,int r){
if(l>r||r>n) return;
int i=l+1;
for(;i<=r;++i)
if(a[i]>=a[l])
break;
for(int j=i+1;j<=r;++j)
if(a[j]<a[l]){
flag=false;
break;
}
Traverse(l+1,i-1);
Traverse(i,r);
ans.push_back(a[l]);
}
void MirrorTraverse(int l,int r){
if(l>r||r>n) return;
int i=l+1;
for(;i<=r;++i)
if(a[i]<a[l])
break;
for(int j=i+1;j<=r;++j)
if(a[j]>=a[l]){
flag=false;
break;
}
MirrorTraverse(l+1,i-1);
MirrorTraverse(i,r);
ans.push_back(a[l]);
}
int main() {
scanf("%d",&n);
for(int i=1;i<=n;++i)
scanf("%d",&a[i]);
if(n==1){
printf("YES\n%d\n",a[1]);
return 0;
}
if(a[2]<a[1]){
Traverse(1,n);
}else{
MirrorTraverse(1,n);
}
if(!flag) printf("NO\n");
else{
printf("YES\n");
for(int i=0;i<n-1;++i)
printf("%d ",ans[i]);
printf("%d\n",ans[n-1]);
}
return 0;
}
1086 Tree Traversals Again
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <string>
#include <string.h>
#include <vector>
#include <stack>
using namespace std;
int n,num;
char op[5];
vector<int>pre,in,post;
stack<int>st;
void Traverse(int l1,int r1,int l2,int r2){
if(l1>r1||l2>r2) return;
int root=pre[l1],pos=0;
for(int i=l2;i<=r2;++i)
if(in[i]==root){
pos=i;
break;
}
Traverse(l1+1,l1+pos-l2,l2,pos-1);
Traverse(l1+pos-l2+1,r1,pos+1,r2);
post.push_back(root);
}
int main() {
scanf("%d",&n);
for(int i=1;i<=(n<<1);++i){
scanf("%s",op);
if(op[1]=='u'){
scanf("%d",&num);
pre.push_back(num);
st.push(num);
}else{
in.push_back(st.top());
st.pop();
}
}
Traverse(0,n-1,0,n-1);
for(int i=0;i<n-1;++i)
printf("%d ",post[i]);
printf("%d\n",post[n-1]);
return 0;
}