IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> PAT 甲级 树(二) -> 正文阅读

[数据结构与算法]PAT 甲级 树(二)

AVL两道题的思路待补充,红黑树待写!!!

二叉搜索树最后两层节点数量

题目

二叉搜索树 (BST) 递归定义为具有以下属性的二叉树:

若它的左子树不空,则左子树上所有结点的值均小于或等于它的根结点的值
若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值
它的左、右子树也分别为二叉搜索树
将一系列数字按顺序插入到一个空的二叉搜索树中,然后,请你计算结果树的最低两层的结点个数。

输入格式
第一行包含整数 N,表示插入数字序列包含的数字个数。

第二行包含 N 个整数,表示插入数字序列。

输出格式
以如下格式,在一行中,输出结果树的最后两层的结点数:

n1 + n2 = n
n1 是最底层结点数量,n2 是倒数第二层结点数量,n 是它们的和。

数据范围
1≤N≤1000,
?1000≤ 插入数字 ≤1000。

输入样例:
9
25 30 42 16 20 20 35 -5 28
输出样例:
2 + 4 = 6

思想

1、如何根据序列插入二叉搜索树中

void insert(int& u, int w)
{
    if (!u)
    {
        u = ++ idx;
        v[u] = w;
    }
    else if (w <= v[u]) insert(l[u], w);
    else insert(r[u], w);
}

2、如何记录每一层的节点数量
(1)y总的做法——dfs ,记录深度

void dfs(int u, int depth)
{
    if (!u) return;
    cnt[depth] ++ ;
    max_depth = max(max_depth, depth);
    dfs(l[u], depth + 1);
    dfs(r[u], depth + 1);
}

(2) 我的做法——层序遍历

    queue<PII> q;
    q.push({0, 1});
    int cnt[N], max_level = 0;
    while(q.size()){
        int top = q.front().first;
        int level = q.front().second;
        q.pop();
        cnt[level] ++;
        max_level = max(level, max_level);
        if(l[top] != -1) {
            q.push({l[top], level + 1});
        }
        if(r[top] != -1) {
            q.push({r[top], level + 1});
        }
    }

自己的代码

#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
const int N = 1e3 + 10;
int tr[N], l[N], r[N], a[N];
int idx = 0;
typedef pair<int, int> PII;
void insert(int u, int k){
    if(k <= tr[u]) {
        if(l[u] != -1)
            insert(l[u], k);
        else{
            l[u] = ++idx;
            tr[idx] = k;
        }
    }
    else{
        if(r[u] != -1)
            insert(r[u], k);
        else{
            r[u] = ++idx;
            tr[idx] = k;
        }
    }
}
int main(){
    int n, i;
    cin>>n;
    memset(l, -1, sizeof l);
    memset(r, -1, sizeof r);
    int root = 0;
    for(i = 0; i < n; i ++){
        cin>>a[i];
        if(!i) tr[root] = a[i];
        else insert(root, a[i]);
    }
    
    //层序遍历
    queue<PII> q;
    q.push({0, 1});
    int cnt[N], max_level = 0;
    while(q.size()){
        int top = q.front().first;
        int level = q.front().second;
        q.pop();
        cnt[level] ++;
        max_level = max(level, max_level);
        if(l[top] != -1) {
            q.push({l[top], level + 1});
        }
        if(r[top] != -1) {
            q.push({r[top], level + 1});
        }
    }
    printf("%d + %d = %d", cnt[max_level], cnt[max_level - 1], cnt[max_level] + cnt[max_level - 1]);
}

y总的代码

#include <iostream>

using namespace std;

const int N = 1010;

int n;
int l[N], r[N], v[N], idx;
int cnt[N], max_depth;

void insert(int& u, int w)
{
    if (!u)
    {
        u = ++ idx;
        v[u] = w;
    }
    else if (w <= v[u]) insert(l[u], w);
    else insert(r[u], w);
}

void dfs(int u, int depth)
{
    if (!u) return;
    cnt[depth] ++ ;
    max_depth = max(max_depth, depth);
    dfs(l[u], depth + 1);
    dfs(r[u], depth + 1);
}

int main()
{
    cin >> n;

    int root = 0;
    for (int i = 0; i < n; i ++ )
    {
        int w;
        cin >> w;
        insert(root, w);
    }

    dfs(root, 0);

    int n1 = cnt[max_depth], n2 = cnt[max_depth - 1];
    printf("%d + %d = %d\n", n1, n2, n1 + n2);

    return 0;
}

作者:yxc
链接:https://www.acwing.com/activity/content/code/content/283562/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

前序和后序遍历

题目

假设一个二叉树上所有结点的权值都互不相同。

我们可以通过后序遍历和中序遍历来确定唯一二叉树。

也可以通过前序遍历和中序遍历来确定唯一二叉树。

但是,如果只通过前序遍历和后序遍历,则有可能无法确定唯一二叉树。

现在,给定一组前序遍历和后序遍历,请你输出对应二叉树的中序遍历。

如果树不是唯一的,则输出任意一种可能树的中序遍历即可。

输入格式
第一行包含整数 N,表示结点数量。

第二行给出前序遍历序列。

第三行给出后序遍历序列。

一行中的数字都用空格隔开。

输出格式
首先第一行,如果树唯一,则输出 Yes,如果不唯一,则输出 No。

然后在第二行,输出树的中序遍历。

注意,如果树不唯一,则输出任意一种可能的情况均可。

数据范围
1≤N≤30
输入样例1:
7
1 2 3 4 6 7 5
2 6 7 4 5 3 1
输出样例1:
Yes
2 1 6 4 7 3 5
输入样例2:
4
1 2 3 4
2 4 3 1
输出样例2:
No
2 1 3 4

思想

关键:找到不同遍历之间的特点!

// 先序遍历是根左右,后序遍历是左右根,我们没法判断左子树在哪里结束,于是我们通过枚举的方式,去递归遍历
// 枚举左子树在不同位置结束的时候的方案数,如果方案数 > 1,说明不唯一
// 同时在过程中,由于每次遍历左右子树,于是我们可以借此求得中序遍历。

自己的代码

//  先序遍历是根左右,后序遍历是左右根,我们没法判断左子树在哪里结束,于是我们通过枚举的方式,去递归遍历
// 枚举左子树在不同位置结束的时候的方案数,如果方案数 > 1,说明不唯一
// 同时在过程中,由于每次遍历左右子树,于是我们可以借此求得中序遍历。

#include<iostream>
using namespace std;
const int N = 40;
int pre[N], post[N];
int dfs(int l1, int r1, int l2, int r2, string& in){
    //l1是pre, l2是post
    if(l1 > r1) return 1;//注意这里是return 1
    if(pre[l1] != post[r2]) return 0;
    
    int cnt = 0;
    for (int i = l1; i <= r1; i ++ ){//按理来说,i应该是从l1 + 1开始的,但是如果改成l1 + 1,就会报错
        string lin, rin;
        int lcnt = dfs(l1 + 1, i, l2, l2 + i - l1 - 1, lin);
        int rcnt = dfs(i + 1, r1, l2 + i - l1 , r2 - 1, rin);
        if(lcnt && rcnt){
            cnt += lcnt * rcnt;
            in = lin + to_string(pre[l1]) + ' ' + rin;
            if(cnt > 1) break;
        }
    }
    return cnt;
}
int main(){
    int n, i;
    cin>>n;
    for(i = 0; i < n; i ++) cin>>pre[i];
    for(i = 0; i < n; i ++) cin>>post[i];
    
    string in;
    int cnt = dfs(0, n - 1, 0, n - 1, in);

    if (cnt > 1) puts("No");
    else puts("Yes");
    
    in.pop_back();//会多一个空格,所以要pop_back
    cout << in << endl;
}

y总的代码

#include <iostream>

using namespace std;

const int N = 40;

int n;
int pre[N], post[N];

int dfs(int l1, int r1, int l2, int r2, string& in)
{
    if (l1 > r1) return 1;
    if (pre[l1] != post[r2]) return 0;

    int cnt = 0;
    for (int i = l1; i <= r1; i ++ )  // 枚举左子树包含的节点数量
    {
        string lin, rin;
        int lcnt = dfs(l1 + 1, i, l2, l2 + i - l1 - 1, lin);
        int rcnt = dfs(i + 1, r1, l2 + i - l1 - 1 + 1, r2 - 1, rin);

        if (lcnt && rcnt)
        {
            in = lin + to_string(pre[l1]) + ' ' + rin;
            cnt += lcnt * rcnt;
            if (cnt > 1) break;
        }
    }

    return cnt;
}

int main()
{
    cin >> n;
    for (int i = 0; i < n; i ++ ) cin >> pre[i];
    for (int i = 0; i < n; i ++ ) cin >> post[i];

    string in;    
    int cnt = dfs(0, n - 1, 0, n - 1, in);

    if (cnt > 1) puts("No");
    else puts("Yes");

    in.pop_back();
    cout << in << endl;

    return 0;
}

作者:yxc
链接:https://www.acwing.com/activity/content/code/content/283585/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

Z字形遍历二叉树

题目

假设一个二叉树上各结点的权值互不相同。

我们就可以通过其后序遍历和中序遍历来确定唯一二叉树。

请你输出该二叉树的 Z 字形遍历序列----也就是说,从根结点开始,逐层遍历,第一层从右到左遍历,第二层从左到右遍历,第三层从右到左遍历,以此类推。

例如,下图所示二叉树,其 Z 字形遍历序列应该为:1 11 5 8 17 12 20 15。

337cbfb0-a7b2-4500-9664-318e9ffc870e.jpg

输入格式
第一行包含整数 N,表示二叉树结点数量。

第二行包含 N 个整数,表示二叉树的中序遍历序列。

第三行包含 N 个整数,表示二叉树的后序遍历序列。

输出格式
输出二叉树的 Z 字形遍历序列。

数据范围
1≤N≤30
输入样例:
8
12 11 20 17 1 15 8 5
12 20 17 11 15 8 5 1
输出样例:
1 11 5 8 17 12 20 15

思想

1、给定二叉树中序遍历和后序遍历,重建二叉树

int build(int il, int ir, int pl, int pr)
{
    int root = post[pr];
    int k = pos[root];

    if (il < k) l[root] = build(il, k - 1, pl, pl + k - 1 - il);
    if (k < ir) r[root] = build(k + 1, ir, pl + k - 1 - il + 1, pr - 1);

    return root;
}

2、Z字形层序遍历
只有在偶数层时翻转即可

reverse函数的使用,第二个形参是最后一位的下一个位置

void bfs(int root)
{
    int hh = 0, tt = 0;
    q[0] = root;

    int step = 0;
    while (hh <= tt)
    {
        int head = hh, tail = tt;
        while (hh <= tail)
        {
            int t = q[hh ++ ];
            if (l.count(t)) q[ ++ tt] = l[t];
            if (r.count(t)) q[ ++ tt] = r[t];
        }

        if ( ++ step % 2) reverse(q + head, q + tail + 1);
    }
}


自己的代码

//y总的
//y总的思路,将奇数层的翻转即可
#include <iostream>
#include <algorithm>
#include <unordered_map>

using namespace std;

using namespace std;

const int N = 40;

int n;
unordered_map<int, int> l, r, pos;
int in[N], post[N];
int q[N];

int build(int il, int ir, int pl, int pr)
{
    int root = post[pr];
    int k = pos[root];

    if (il < k) l[root] = build(il, k - 1, pl, pl + k - 1 - il);
    if (k < ir) r[root] = build(k + 1, ir, pl + k - 1 - il + 1, pr - 1);

    return root;
}
//这里记录了如何写出层序遍历每一层的写法,q即为层序遍历结果
void bfs(int root){
    int hh = 0, tt = 0;
    q[0] = root;
    int step = 0;
    while(hh <= tt){
        int head = hh, tail = tt;
        while(hh <= tail){//只遍历到上一层添加到的tt处
            int t = q[hh ++];
            if (l.count(t)) q[ ++ tt] = l[t];
            if (r.count(t)) q[ ++ tt] = r[t];
        }
        if(++ step % 2 == 1) reverse(q + head, q + tail + 1);
    }
}
int main()
{
    cin >> n;
    for (int i = 0; i < n; i ++ )
    {
        cin >> in[i];
        pos[in[i]] = i;
    }
    for (int i = 0; i < n; i ++ ) cin >> post[i];

    int root = build(0, n - 1, 0, n - 1);

    bfs(root);

    cout << q[0];
    for (int i = 1; i < n; i ++ ) cout << ' ' << q[i];
    cout << endl;

    return 0;
}




//自己的代码
/*#include <iostream>
#include <cstring>
#include <queue>
#include <stack>
using namespace std;
const int N = 1e4 + 10;
int post[N], in[N], r[N], l[N], pos[N];
typedef pair<int, int> PII;
int build(int l1, int r1, int l2, int r2){
    if(l1 > r1) return false;
    int root = post[r2];
    int k = pos[root];
    
    if(l1 < k) l[root] = build(l1, k - 1, l2, l2 + k - 1- l1);
    if(k < r1) r[root] = build(k + 1, r1, l2 + k - l1, r2 - 1);
    
    return root;
}
int main(){
    int n;
    cin>>n;
    for (int i = 0; i < n; i ++ )
    {
        cin >> in[i];
        pos[in[i]] = i;
    }
    for(int i = 0; i < n; i ++) cin>>post[i];
    memset(l, -1, sizeof l);
    memset(r, -1, sizeof r);
    
    int root = build(0, n - 1, 0, n - 1);
    
    queue<PII> q;
    q.push({root, 1});
    //cout<<root;
    int before_level = 1;
    string str;
    queue<PII> a;
    while(q.size()){
        int top = q.front().first;
        int level = q.front().second;
        if(before_level != level){
            if(level % 2 ==  1){
                //reverse(q);
                a = q;
                stack<PII> s;
                while(a.size()){
                    s.push(a.front());
                    a.pop();
                }
                while(s.size()){
                    a.push(s.top());
                    s.pop();
                }
            }
        }
        if(level > 2 && level % 2 == 1){
            str += to_string(a.front().first) + " ";
            a.pop();
        }
        else str += to_string(top) + " ";
        //cout<<top<<endl;
        q.pop();
        before_level = level;
        if(l[top] != -1)
            q.push({l[top], level + 1});
        if(r[top] != -1)
            q.push({r[top], level + 1});
    }
    str.pop_back();
    cout<<str<<endl;
}*/

y总的代码

#include <iostream>
#include <algorithm>
#include <unordered_map>

using namespace std;

using namespace std;

const int N = 40;

int n;
unordered_map<int, int> l, r, pos;
int in[N], post[N];
int q[N];

int build(int il, int ir, int pl, int pr)
{
    int root = post[pr];
    int k = pos[root];

    if (il < k) l[root] = build(il, k - 1, pl, pl + k - 1 - il);
    if (k < ir) r[root] = build(k + 1, ir, pl + k - 1 - il + 1, pr - 1);

    return root;
}

void bfs(int root)
{
    int hh = 0, tt = 0;
    q[0] = root;

    int step = 0;
    while (hh <= tt)
    {
        int head = hh, tail = tt;
        while (hh <= tail)
        {
            int t = q[hh ++ ];
            if (l.count(t)) q[ ++ tt] = l[t];
            if (r.count(t)) q[ ++ tt] = r[t];
        }

        if ( ++ step % 2) reverse(q + head, q + tail + 1);
    }
}

int main()
{
    cin >> n;
    for (int i = 0; i < n; i ++ )
    {
        cin >> in[i];
        pos[in[i]] = i;
    }
    for (int i = 0; i < n; i ++ ) cin >> post[i];

    int root = build(0, n - 1, 0, n - 1);

    bfs(root);

    cout << q[0];
    for (int i = 1; i < n; i ++ ) cout << ' ' << q[i];
    cout << endl;

    return 0;
}

作者:yxc
链接:https://www.acwing.com/activity/content/code/content/283592/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

后序遍历

题目

假设二叉树上各结点的权值互不相同且都为正整数。

给定二叉树的前序遍历和中序遍历,请你输出二叉树的后序遍历的第一个数字。

输入格式
第一行包含整数 N,表示二叉树结点总数。

第二行给出二叉树的前序遍历序列。

第三行给出二叉树的中序遍历序列。

输出格式
输出二叉树的后序遍历的第一个数字。

数据范围
1≤N≤50000
输入样例:
7
1 2 3 4 5 6 7
2 3 1 5 4 7 6
输出样例:
3

思想

自己的代码

//这题要用哈希表来存,不能用遍历来找root的下标,会超时
//其他题,也可能用哈希表存l,和r, 因为不知道节点的值多大,有可能很大
#include<iostream>
#include <unordered_map>
using namespace std;
unordered_map<int,int> pos;
int post = 0;
const int N = 1e5 + 10;
int pre[N], in[N];
void build(int pl, int pr, int il, int ir){
    int root = pre[pl];
    int k = pos[root];
    if(il < k) build(pl + 1, pl + + 1 + k - 1 - il, il, k - 1);
    if(k < ir) build(pl + 1 + k - 1 - il + 1, pr, k + 1, ir);
    
    if(!post) post = root;//第一个return的就是它
}
int main(){
    int n;
    cin>>n;
    for (int i = 0; i < n; i ++ ) cin >> pre[i];
    for (int i = 0; i < n; i ++ )
    {
        cin >> in[i];
        pos[in[i]] = i;
    }
    build(0, n - 1, 0, n - 1);
    cout<<post<<endl;
}

y总的代码

#include <iostream>
#include <unordered_map>

using namespace std;

const int N = 50010;

int n;
int pre[N], in[N];
unordered_map<int, int> pos;
int post;

void build(int il, int ir, int pl, int pr)
{
    int root = pre[pl];
    int k = pos[root];

    if (il < k) build(il, k - 1, pl + 1, pl + 1 + k - 1 - il);
    if (k < ir) build(k + 1, ir, pl + 1 + k - 1 - il + 1, pr);

    if (!post) post = root;
}

int main()
{
    cin >> n;

    for (int i = 0; i < n; i ++ ) cin >> pre[i];
    for (int i = 0; i < n; i ++ )
    {
        cin >> in[i];
        pos[in[i]] = i;
    }

    build(0, n - 1, 0, n - 1);

    cout << post << endl;
    return 0;
}

作者:yxc
链接:https://www.acwing.com/activity/content/code/content/283601/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

AVL树的根

题目

AVL树是一种自平衡二叉搜索树。

在AVL树中,任何节点的两个子树的高度最多相差 1 个。

如果某个时间,某节点的两个子树之间的高度差超过 1,则将通过树旋转进行重新平衡以恢复此属性。

图 1?4 说明了旋转规则。

31.jpg 32.jpg
33.jpg 34.jpg

现在,给定插入序列,请你求出 AVL 树的根是多少。

输入格式
第一行包含整数 N,表示总插入值数量。

第二行包含 N 个不同的整数,表示每个插入值。

输出格式
输出得到的 AVL 树的根是多少。

数据范围
1≤N≤20
输入样例1:
5
88 70 61 96 120
输出样例1:
70
输入样例2:
7
88 70 61 96 120 90 65
输出样例2:
88

思想

待补充!!!!

自己的代码

#include<iostream>
using namespace std;
const int N = 100;
int l[N], r[N], h[N], v[N];
int idx = 0;
void update(int u){
    h[u] = max(h[l[u]], h[r[u]]) + 1;
}
void R(int &u){
    int p = l[u];
    l[u] = r[p];
    r[p] = u;
    update(u),update(p);//更新高度
    u = p;//要用引用更新根
}
void L(int &u){
    int p = r[u];
    r[u] = l[p];
    l[p] = u;
    update(u),update(p);
    u = p;
}
int get_balance(int u){
    
    return h[l[u]] - h[r[u]];
}

void insert(int &u, int w){
    if(!u){//第一种情况,一开始u==0, 第二种l[u]或r[u]==0,插入到对应位置 
        u = ++ idx;//注意0位置不存任何东西,0位置时用来表示空的
        v[u] = w;
    }
    else if(w < v[u]){
        insert(l[u], w);
        if(get_balance(u) == 2){
            if(get_balance(l[u]) == 1) R(u);
            else L(l[u]), R(u);
        }
    }
    else{
        insert(r[u], w);
        if (get_balance(u) == -2)
        {
            if(get_balance(r[u]) == -1) L(u);//注意这里是-1
            else R(r[u]), L(u);
        }
    }
    update(u);//每次插入都要更新h
}

int main(){
    int n;
    cin>>n;
    int u = 0, i, w;
    for(i = 0; i < n; i ++){
        cin>>w;
        insert(u, w);
    }
    cout<<v[u]<<endl;
    
}

y总的代码

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 30;

int l[N], r[N], v[N], h[N], idx;

void update(int u)
{
    h[u] = max(h[l[u]], h[r[u]]) + 1;
}

void R(int& u)
{
    int p = l[u];
    l[u] = r[p], r[p] = u;
    update(u), update(p);
    u = p;
}

void L(int& u)
{
    int p = r[u];
    r[u] = l[p], l[p] = u;
    update(u), update(p);
    u = p;
}

int get_balance(int u)
{
    return h[l[u]] - h[r[u]];
}

void insert(int& u, int w)
{
    if (!u) u = ++ idx, v[u] = w;
    else if (w < v[u])
    {
        insert(l[u], w);
        if (get_balance(u) == 2)
        {
            if (get_balance(l[u]) == 1) R(u);
            else L(l[u]), R(u);
        }
    }
    else
    {
        insert(r[u], w);
        if (get_balance(u) == -2)
        {
            if (get_balance(r[u]) == -1) L(u);
            else R(r[u]), L(u);
        }
    }

    update(u);
}

int main()
{
    int n, root = 0;
    cin >> n;

    while (n -- )
    {
        int w;
        cin >> w;
        insert(root, w);
    }

    cout << v[root] << endl;

    return 0;
}

作者:yxc
链接:https://www.acwing.com/activity/content/code/content/283632/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

判断完全AVL树

题目

AVL树是一种自平衡二叉搜索树。

在AVL树中,任何节点的两个子树的高度最多相差 1 个。

如果某个时间,某节点的两个子树之间的高度差超过 1,则将通过树旋转进行重新平衡以恢复此属性。

图 1?4 说明了旋转规则。

1.jpg 2.jpg
3.jpg 4.jpg

现在,给定插入序列,请你输出得到的AVL树的层序遍历,并判断它是否是完全二叉树。

输入格式
第一行包含整数 N,表示插入序列中元素个数。

第二行包含 N 个不同的整数表示插入序列。

输出格式
第一行输出得到的AVL树的层序遍历序列。

第二行,如果该AVL树是完全二叉树,则输出 YES,否则输出 NO。

数据范围
1≤N≤20
输入样例1:
5
88 70 61 63 65
输出样例1:
70 63 88 61 65
YES
输入样例2:
8
88 70 61 96 120 90 65 68
输出样例2:
88 65 96 61 70 90 120 68
NO
难度:中等
时/空限制:0.4s / 64MB
总通过数:374
总尝试数:634
来源:PAT甲级真题1123
算法标签

代码

#include <iostream>

using namespace std;

const int N = 30;

int n;
int l[N], r[N], v[N], h[N], idx;
int q[N], pos[N];

void update(int u)
{
    h[u] = max(h[l[u]], h[r[u]]) + 1;
}

void R(int& u)
{
    int p = l[u];
    l[u] = r[p], r[p] = u;
    update(u), update(p);
    u = p;
}

void L(int& u)
{
    int p = r[u];
    r[u] = l[p], l[p] = u;
    update(u), update(p);
    u = p;
}

int get_balance(int u)
{
    return h[l[u]] - h[r[u]];
}

void insert(int& u, int w)
{
    if (!u) u = ++ idx, v[u] = w;
    else if (w < v[u])
    {
        insert(l[u], w);
        if (get_balance(u) == 2)
        {
            if (get_balance(l[u]) == 1) R(u);
            else L(l[u]), R(u);
        }
    }
    else
    {
        insert(r[u], w);
        if (get_balance(u) == -2)
        {
            if (get_balance(r[u]) == -1) L(u);
            else R(r[u]), L(u);
        }
    }

    update(u);
}

bool bfs(int root)
{
    int hh = 0, tt = 0;
    q[0] = root;
    pos[root] = 1;

    bool res = true;
    while (hh <= tt)
    {
        int t = q[hh ++ ];
        if (pos[t] > n) res = false;

        if (l[t]) q[ ++ tt] = l[t], pos[l[t]] = pos[t] * 2;
        if (r[t]) q[ ++ tt] = r[t], pos[r[t]] = pos[t] * 2 + 1;
    }

    return res;
}

int main()
{
    int root = 0;
    cin >> n;
    for (int i = 0; i < n; i ++ )
    {
        int w;
        cin >> w;
        insert(root, w);
    }

    bool res = bfs(root);

    cout << v[q[0]];
    for (int i = 1; i < n; i ++ ) cout << ' ' << v[q[i]];
    cout << endl;

    if (res) puts("YES");
    else puts("NO");

    return 0;
}

作者:yxc
链接:https://www.acwing.com/activity/content/code/content/283649/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

判断红黑树

待补充!!!

题目

思想

代码

等重路径

题目

给定一个非空的树,树根为 R。

树中每个节点 Ti 的权重为 Wi。

从 R 到 L 的路径权重定义为从根节点 R 到任何叶节点 L 的路径中包含的所有节点的权重之和。

现在给定一个加权树以及一个给定权重数字,请你找出树中所有的权重等于该数字的路径(必须从根节点到叶节点)。

例如,我们考虑下图的树,对于每个节点,上方的数字是节点 ID,它是两位数字,而下方的数字是该节点的权重。

假设给定数为 24,则存在 4 个具有相同给定权重的不同路径:{10 5 2 7},{10 4 10},{10 3 3 6 2},{10 3 3 6 2}, 已经在图中用红色标出。

在这里插入图片描述

输入格式
第一行包含三个整数 N,M,S,分别表示树的总节点数量,非叶子节点数量,给定权重数字。

第二行包含 N 个整数 Wi,表示每个节点的权重。

接下来 M 行,每行的格式为:

ID K ID[1] ID[2] … ID[K]
ID 是一个两位数字,表示一个非叶子结点编号,K 是一个整数,表示它的子结点数,接下来的 K 个 ID[i] 也是两位数字,表示一个子结点的编号。

出于方便考虑,根节点固定为 00,且树中所有节点的编号为 00~N?1。

输出格式
以单调递减的顺序输出所有权重为S的路径。

每个路径占一行,从根节点到叶节点按顺序输出每个节点的权重。

注意:我们称 A 序列 {A1,A2,…,An} 大于 B 序列 {B1,B2,…,Bm},当且仅当存在一个整数 k,1≤k<min(n,m),对于所有 1≤i≤k,Ai=Bi 成立,并且 Ak+1>Bk+1。

数据范围
1≤N≤100,
0≤M<N,
0<S<230,
0<Wi<1000
输入样例:
20 9 24
10 2 4 3 5 10 2 18 9 7 2 2 1 3 12 1 8 6 2 2
00 4 01 02 03 04
02 1 05
04 2 06 07
03 3 11 12 13
06 1 09
07 2 08 10
16 1 15
13 3 14 16 17
17 2 18 19
输出样例:
10 5 2 7
10 4 10
10 3 3 6 2
10 3 3 6 2
难度:中等
时/空限制:0.4s / 64MB
总通过数:504
总尝试数:801
来源:PAT甲级真题1053
算法标签

思想

1、dfs去求

void dfs(int u, int s, vector<int> &path)
{
    bool is_leaf = true;
    for (int i = 0; i < n; i ++ )
        if (g[u][i])
        {
            is_leaf = false;
            break;
        }

    if (is_leaf)
    {
        if (s == S) ans.push_back(path);
    }
    else
    {
        for (int i = 0; i < n; i ++ )
            if (g[u][i])
            {
                path.push_back(w[i]);
                dfs(i, s + w[i], path);
                path.pop_back();
            }
    }
}

2、 从大到小排序,价格后面的greater

vector<vector<int>> ans;
sort(ans.begin(), ans.end(), greater<vector<int>>());

自己的代码

//用vector可以实现如上的比较
//用vector<vector<int>> 来存路径
//判断叶子节点——bool数组,我感觉很多方法都可以
//使用dfs可以搜索从根节点到每一个叶子节点的路径
#include<iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 110;
int w[N];
bool g[N][N];
vector<vector<int>> ans;
int n, m, S;
void dfs(int u, int s, vector<int> &path){
    bool is_leaf = true;
    for(int i = 0; i < n; i ++){
        if(g[u][i]){
            is_leaf = false;
            break;
        }
    }
    if(is_leaf){
        if(s == S)
            ans.push_back(path);
        return;
    }
    else{
        for(int i = 0; i < n; i ++){
            if(g[u][i]){
                path.push_back(w[i]);
                dfs(i,s + w[i],path);
                path.pop_back();
            }
        }
    }
    return;
}
int main(){
    cin>>n>>m>>S;
    for(int i = 0; i < n; i ++) cin>>w[i];
    for(int i = 0; i < m; i ++){
        int id, k;
        cin>>id>>k;
        for(int j = 0; j < k; j ++){
            int child;
            cin>>child;
            g[id][child] = true;
        }
    }
    vector<int> path;
    path.push_back(w[0]);
    dfs(0, w[0], path);
    
    sort(ans.begin(), ans.end(), greater<vector<int>>());//这个greater什么意思????
    
    for(auto an : ans){
        cout<<an[0];
        for(int i = 1; i < an.size(); i ++){
            cout<<" "<<an[i];
        }
        cout<<endl;
    }
}

y总的代码

#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>

using namespace std;

const int N = 110;

int n, m, S;
int w[N];
bool g[N][N];
vector<vector<int>> ans;

void dfs(int u, int s, vector<int> &path)
{
    bool is_leaf = true;
    for (int i = 0; i < n; i ++ )
        if (g[u][i])
        {
            is_leaf = false;
            break;
        }

    if (is_leaf)
    {
        if (s == S) ans.push_back(path);
    }
    else
    {
        for (int i = 0; i < n; i ++ )
            if (g[u][i])
            {
                path.push_back(w[i]);
                dfs(i, s + w[i], path);
                path.pop_back();
            }
    }
}

int main()
{
    cin >> n >> m >> S;
    for (int i = 0; i < n; i ++ ) cin >> w[i];

    while (m -- )
    {
        int id, k;
        cin >> id >> k;
        while (k -- )
        {
            int son;
            cin >> son;
            g[id][son] = true;
        }
    }

    vector<int> path({w[0]});
    dfs(0, w[0], path);

    sort(ans.begin(), ans.end(), greater<vector<int>>());

    for (auto p : ans)
    {
        cout << p[0];
        for (int i = 1; i < p.size(); i ++ ) cout << ' ' << p[i];
        cout << endl;
    }

    return 0;
}

作者:yxc
链接:https://www.acwing.com/activity/content/code/content/294234/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-09-09 12:01:51  更:2021-09-09 12:04:39 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 1:52:19-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码