二叉搜索树

137 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

二叉搜索树

题目详情 - L2-004 这是二叉搜索树吗? (25 分) (pintia.cn)

在建树的过程中,需要特别关注一个点:传的root是引用。如果不是传的引用,那么主函数里的root,和insert函数里的root,都是指针,而且指向的地址是一样的,但是这两个指针本身的地址是不一样的。而你每次插入一个x,都是要用到最初的root的,所以这个root一定是要统一的。否则每次的数据都插在一个假的root上。

image.png

#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;
}

二叉树的中序遍历 + 后序(前序)

题目详情 - L2-006 树的遍历 (25 分) (pintia.cn)

总结:

  • 了解前序遍历,中序遍历,以及后序遍历的概念。
  • 已知中序遍历,和随便另一个遍历方式的结果,就可以构建出一棵唯一的二叉树。
  • 由前序遍历的特点可知,根节点是在前序遍历区间的左端点;同理,如果是后序遍历+中序遍历,那么根节点就是在后序遍历区间的右端点。由找到的根节点的元素,去和中序遍历区间去匹配,中序遍历区间中,根节点的左区间是该根节点的左子树,根节点的右区间是该根节点的右子树。
  • 在建树的过程中,有个很重要的变量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. 堆总是一棵完全二叉树

题目详情 - L2-012 关于堆的判断 (25 分) (pintia.cn)

#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");
                }
            }
        }
    }
}