本文已参与「新人创作礼」活动,一起开启掘金创作之路。
二叉搜索树
在建树的过程中,需要特别关注一个点:传的root是引用。如果不是传的引用,那么主函数里的root,和insert函数里的root,都是指针,而且指向的地址是一样的,但是这两个指针本身的地址是不一样的。而你每次插入一个x,都是要用到最初的root的,所以这个root一定是要统一的。否则每次的数据都插在一个假的root上。
#include<bits/stdc++.h>
using namespace std;
struct node{
int val;
node *l,*r;
node(){
val = 0;
l = r = NULL;
}
};
vector<int>a,b,c,d,e;
void insert(node * &root,int x){ // 注意,这里传的是引用
if(root == NULL){
root = new node();
root->val = x;
return;
}
if(x<root->val)insert(root->l,x);
else insert(root->r,x);
}
void pre(node * root){
if(root){
b.push_back(root->val);
pre(root->l);
pre(root->r);
}
}
void pre_mirror(node * root){
if(root){
c.push_back(root->val);
pre_mirror(root->r);
pre_mirror(root->l);
}
}
void post(node * root){
if(root){
post(root->l);
post(root->r);
d.push_back(root->val);
}
}
void post_mirror(node * root){
if(root){
post_mirror(root->r);
post_mirror(root->l);
e.push_back(root->val);
}
}
int main(){
int n,x;
node * root = NULL;
scanf("%d",&n);
for(int i = 1;i<=n;++i){
scanf("%d",&x);
a.push_back(x);
insert(root,x);
}
pre(root);
pre_mirror(root);
if(a==b){
printf("YES\n");
post(root);
for(int i = 0;i<d.size()-1;++i){
printf("%d ",d[i]);
}
printf("%d\n",d[d.size()-1]);return 0;
}
if(a==c){
printf("YES\n");
post_mirror(root);
for(int i = 0;i<e.size()-1;++i){
printf("%d ",e[i]);
}
printf("%d\n",e[e.size()-1]);return 0;
}
printf("NO\n");
return 0;
}
二叉树的中序遍历 + 后序(前序)
总结:
- 了解前序遍历,中序遍历,以及后序遍历的概念。
- 已知中序遍历,和随便另一个遍历方式的结果,就可以构建出一棵唯一的二叉树。
- 由前序遍历的特点可知,根节点是在前序遍历区间的左端点;同理,如果是后序遍历+中序遍历,那么根节点就是在后序遍历区间的右端点。由找到的根节点的元素,去和中序遍历区间去匹配,中序遍历区间中,根节点的左区间是该根节点的左子树,根节点的右区间是该根节点的右子树。
- 在建树的过程中,有个很重要的变量num,num的意思是:在中序遍历中找到的根节点到左侧区间还有多少个节点。因为左子树的节点数就决定了后序遍历区间的范围。
- 以及在缩小后序遍历区间的时候,要注意每次要舍掉已经成为的那个根节点的。
#include <bits/stdc++.h>
using namespace std;
int n;
int post_arr[35],mid_arr[35],pre_arr[35];
int ans_arr[35];
int cnt = 0;
struct node{
int val;
node *l,*r;
node(){
val = 0;
l = r = NULL;
}
};
node * create_mid_post(int l1,int r1,int l2,int r2){//中序遍历的区间、后序遍历的区间范围
if(l1>r1||l2>r2)return NULL;
node * root = new node;
root->val = post_arr[r2];
int pos;
for(int i = l1;i<=r1;++i)if(post_arr[r2]==mid_arr[i]){
pos = i;
break;
}
int num = pos - l1;
root->l = create_mid_post(l1,pos-1,l2,l2+num-1);
root->r = create_mid_post(pos+1,r1,l2+num,r2-1); // 后序遍历最后面的那个节点舍去了
return root;
}
node * create_mid_pre(int l1,int r1,int l2,int r2){//中序遍历的区间、前序遍历的区间范围
if(l1>r1||l2>r2)return NULL;
node * root = new node;
root->val = pre_arr[l2];
int pos;
for(int i = l1;i<=r1;++i)if(pre_arr[l2]==mid_arr[i]){
pos = i;
break;
}
int num = pos - l1;
root->l = create_mid_pre(l1,pos-1,l2+1,l2+1+num-1); // 前序遍历最前面的那个节点舍去了
root->r = create_mid_pre(pos+1,r1,l2+1+num,r2);
return root;
}
void solve(node * root){
queue<node*>q;
q.push(root);
while(!q.empty()){
node * p = q.front();
q.pop();
ans_arr[++cnt] = p->val;
if(p->l)q.push(p->l);
if(p->r)q.push(p->r);
}
}
int main(){
scanf("%d",&n);
for(int i = 1;i<=n;++i)scanf("%d",&post_arr[i]);
for(int i = 1;i<=n;++i)scanf("%d",&mid_arr[i]);
node * root = NULL;
root = create_mid_post(1,n,1,n);
solve(root);
for(int i = 1;i<=cnt-1;++i)printf("%d ",ans_arr[i]);
printf("%d\n",ans_arr[cnt]);
return 0;
}
堆
1. 堆中某个节点的值总是不大于或不小于其父节点的值; 分为小顶堆、大顶堆。
2. 堆总是一棵完全二叉树。
#include<bits/stdc++.h>
using namespace std;
vector<int > heap;
int Index[20010] = {0};
void heapify(int i){
if(i == 1) return;
while(i != 1){// 改成大于号就是大顶堆了
if(heap[i] < heap[i / 2]) swap(heap[i], heap[i / 2]);
else break;
i /= 2;
}
}
int main(){
int n,m,key;
scanf("%d %d", &n, &m);
heap.resize(n+5);
for(int i = 1; i <= n; i++){
scanf("%d", &key);
heap[i] = key;
heapify(i);
}
for(int i = 1; i <= n; i++){
Index[heap[i] + 10000] = i;
}
string s;
for(int i = 0; i < m; i++){
int num;
scanf("%d", & num);
cin>>s;
if(s[0] == 'a'){
int num_1;
scanf("%d", & num_1);
getline(cin, s);
if(Index[num + 10000] / 2 == Index[num_1 + 10000] / 2 ) printf("T\n");
else printf("F\n");
}
else {
cin>>s;
if(s[0] == 'a'){
string s_1,s_2;
int num_1;
cin>>s_1>>s_2;
scanf("%d", &num_1);
if(Index[num_1 + 10000] == Index[num + 10000] / 2) printf("T\n");
else printf("F\n");
}
else {
cin>>s;
if(s == "root"){
if(Index[num + 10000] == 1) printf("T\n");
else printf("F\n");
}
else{
int num_1;
cin>>s;
scanf("%d", &num_1);
if(Index[num + 10000] == Index[num_1 + 10000] / 2) printf("T\n");
else printf("F\n");
}
}
}
}
}