入门经典_Chap06_例题[二]:二叉树的指针及数组实现

前言

这波题的所有知识点如下:

  • 二叉树的数组实现
  • 二叉树的链表实现
  • 链表实现的动态化静态方法(内存池)
  • 二叉树的四种遍历
  • 由二叉树的两种遍历序列(必含中序序列)
  • 二叉搜索树

题解如下

UVA-679 - Dropping Balls

思路

    有一棵二叉树,最大深度为D,且所有叶子的深度都相同。所有结点从上到下从左到右编号为1, 2, 3,…, 2 D -1。
    在结点1处放一个小球,它会往下落。每个内结点上都有一个开关,初始全部关闭,当每次有小球落到一个开关上时,状态都会改变。当小球到达一个内结点时,如果该结点上的开关关闭,则往左走,否则往右走,直到走到叶子结点。

    如果直接建树的话数组应该存不下,复杂度应该也说不过去,
    但是如果从给出的编号的奇偶性上下手,思路就显而易见了
    当编号I是奇数时,它是往左走的第(I+1)/2个小球;
    当I是偶数时,它是往右走的第I/2个小球。

代码

int D, I;

int main() {
    #ifdef _LOCAL
    IN;
    #endif // _LOCAL

    int t; cin >>t;
    while(t--) {
        cin >> D >> I;
        int ans = 1;
        for(int i = 1; i < D; ++i) {
            if(I&1) I = I/2+1, ans *= 2;
            else I /= 2, ans = ans*2+1;
        }
        cout << ans <<endl;
    }
    scanf("-1");
    return 0;
}

UVA-122 - Trees on the level

思路

    输入一棵二叉树,你的任务是按从上到下、从左到右的顺序输出各个结点的值。每个结点都按照从根结点到它的移动序列给出(L表示左,R表示右)。
    在输入中,每个结点的左括号和右括号之间没有空格,相邻结点之间用一个空格隔开。每棵树的输入用一对空括号“()”结束(这对括号本身不代表一个结点)
    如果从根到某个叶结点的路径上有的结点没有在输入中给出,或者给出超过一次,应当输出-1。

    个人认为此题的难点在于字符串的处理,其实也不难。
    然后就是根据字符串建树,建好树bfs即可。
    这里给出数组和链表两种写法。

代码

    使用数组

string s;
const int root = 1;
int Left[maxn], Right[maxn], cnt;
int val[maxn];

void init() {
    met(val, 0);
    Left[root] = Right[root] = 0;
    cnt = root;
}

int newnode() {
    int u = ++cnt;
    Left[u] = Right[u] = 0;
    return u;
}

bool check() {
    queue<int> q;
    q.push(root);

    while(!q.empty()) {
        int t = q.front();q.pop();
        if(val[t] == 0) return false;
        if(Left[t] != 0) q.push(Left[t]);
        if(Right[t] != 0) q.push(Right[t]);
    }
    return true;
}

void ot() {
    queue<int> q;
    q.push(root);
    bool spc = 0;

    while(!q.empty()) {
        int t = q.front(); q.pop();
        if(spc) cout << " "; if(!spc) spc = 1;
        cout << val[t];
        if(Left[t] != 0) q.push(Left[t]);
        if(Right[t] != 0) q.push(Right[t]);
    }
    cout << endl;
}

int main() {
    #ifdef _LOCAL
    IN;
    #endif // _LOCAL

    init(); bool flag = 1;
    while(cin >> s) {
        if(s == "()") {
            if(check() && flag ) ot();
            else printf("not complete\n");
            flag = 1; init(); continue;
        }

        int pos = s.find(','), a;
        string s1 = s.substr(1,pos-1);
        stringstream ss(s1); ss >> a;
        string s2 = s.substr(pos+1, s.size()-2-pos);
        int len = s2.size();

        int cur = root;
        for(int i = 0; i < len; ++i) {
            if(s2[i] == 'L') {
                if(Left[cur] == 0) Left[cur] = newnode();
                cur = Left[cur];
            }
            else {
                if(Right[cur] == 0) Right[cur] = newnode();
                cur = Right[cur];
            }
        }
        if(val[cur] != 0) flag = 0;
        val[cur] = a;
    }

    return 0;
}

    使用链表

string s;
struct node {
    int val;
    node *Left, *Right;
    node():val(0), Left(NULL), Right(NULL){}
};
node* root;

queue<node* > freeNodes;    //内存池
node Node[maxn];

void init() {
    for(int i = 0; i < maxn; ++i) freeNodes.push(&Node[i]);
}

node* newnode() {
    node* u = freeNodes.front();
    u->val = 0; u->Left = u->Right = NULL;
    freeNodes.pop();
    return u;
}

void Delete(node* u) {
    freeNodes.push(u);
}

bool check() {
    queue<node> q;
    q.push(*root);

    while(!q.empty()) {
        node t = q.front();q.pop();
        if(t.val == 0) return false;
        if(t.Left != NULL) q.push(*t.Left);
        if(t.Right != NULL) q.push(*t.Right);
    }
    return true;
}

void ot() {
    queue<node> q;
    q.push(*root);
    bool spc = 0;

    while(!q.empty()) {
        node t = q.front(); q.pop();
        if(spc) cout << " "; if(!spc) spc = 1;
        cout << t.val;
        if(t.Left != NULL) q.push(*t.Left);
        if(t.Right != NULL) q.push(*t.Right);
    }
    cout << endl;
}

int main() {
    #ifdef _LOCAL
    IN;
    #endif // _LOCAL

    init();
    root = newnode(); bool flag = 1;
    while(cin >> s) {
        if(s == "()") {
            if(check() && flag ) ot();
            else printf("not complete\n");
            flag = 1; root = newnode(); continue;
        }

        int pos = s.find(','), a;
        string s1 = s.substr(1,pos-1);
        stringstream ss(s1); ss >> a;
        string s2 = s.substr(pos+1, s.size()-2-pos);
        int len = s2.size();

        node *cur = root;
        for(int i = 0; i < len; ++i) {
            if(s2[i] == 'L') {
                if(cur->Left == NULL) cur->Left = newnode();
                cur = cur->Left;
            }
            else {
                if(cur->Right == NULL) cur->Right = newnode();
                cur = cur->Right;
            }
        }
        if(cur->val != 0) flag = 0;
        cur->val = a;
    }
    Delete(root);

    return 0;
}

UVA-548 - Tree

思路

    给一棵点带权(权值各不相同,都是小于10000的正整数)的二叉树的中序和后序遍历,找一个叶子使得它到根的路径上的权和最小。如果有多解,该叶子本身的权应尽量小。输入中每两行表示一棵树,其中第一行为中序遍历,第二行为后序遍历。

    由中序和后序建树即可。建好树题目就水的不行了。

代码


int in[maxn], po[maxn], a, ans, ax;
int Left[maxn], Right[maxn], root;

int build(int L1, int R1, int L2, int R2) {
    //if(L1 == R1) ans = min(ans, in[L1]);
    if(L1 > R1) return 0;
    int rt = po[R2];
    int p = L1;
    while(in[p] != rt) ++p;
    Left[rt] = build(L1, p-1, L2, L2 + p-L1 -1);
    Right[rt] = build(p+1,R1, L2 + p-L1, R2-1);
    return rt;
}

void dfs(int x, int val) {
    if(Left[x] == 0 && Right[x] == 0) {
        if(ans > val) ans = val, ax = x;
        else if(ans == val && x < ax) ans = val, ax = x;
        return;
    }

    if(Left[x] > 0) dfs(Left[x], val +Left[x]);
    if(Right[x] > 0) dfs(Right[x], val + Right[x]);
}

int main() {
    #ifdef _LOCAL
    IN;
    #endif // _LOCAL

    string s;
    while(getline(cin, s)) {
        met(Left, 0); met(Right, 0);
        stringstream ss(s);
        int idx = 0, idy = 0;
        while(ss >> a) in[++idx] = a;
        getline(cin, s);
        stringstream sss(s);
        while(sss >> a) po[++idy] = a;

        root = build(1, idx, 1, idy);
        ans = INF, ax = INF;
        dfs(root, root);
        cout << ax <<endl;
    }

    return 0;
}

UVA-839 - Not so Mobile

思路

    这两题和二叉树本身并无太深的联系,主要是递归输入,有一种二叉树的思想在里面。

代码

const int root = 1;
int Left[maxn], Right[maxn], cnt;
int W[maxn], D[maxn];
bool flag = 1;

void init() {
    met(Left, 0); met(Right, 0);
    Left[root] = Right[root] = 0;
    cnt = root;
    flag = 1;
}

int newnode() {
    int u = ++cnt;
    Left[u] = Right[u] = 0;
    return u;
}

int read(int rt) {
    int a, b, c, d;
    scanf("%d%d%d%d", &a, &b, &c, &d);
    if(Left[rt] == 0) Left[rt] = newnode();
    if(Right[rt] == 0) Right[rt] = newnode();
    D[Left[rt]] = b, D[Right[rt]] = d;
    if(a == 0) a = read(Left[rt]);
    if(c == 0) c = read(Right[rt]);
    W[Left[rt]] = a, W[Right[rt]] = c;
    W[rt] = a + c;
    if(a*b != c*d) flag = 0;

    return W[rt];
}

int main() {
    #ifdef _LOCAL
    IN;
    #endif // _LOCAL

    int t; cin >> t;
    while(t--) {
        init();
        read(root);
        if(flag) printf("YES\n");
        else printf("NO\n");
        if(t) printf("\n");
    }
    return 0;
}

UVA-699 - The Falling Leaves

思路

    同样是考查递归输入的水题。

代码


bool read(int id) {
    int a; scanf("%d", &a);
    if(a == -1) return false;
    read(id-1);
    read(id+1);
    ans[id]+=a;
    return true;
}


int main() {
    #ifdef _LOCAL
    IN;
    #endif // _LOCAL

    int kase = 0;
    met(ans, 0);
    while(read(maxn/2)) {
        aid = maxn/2;
        cnt = 0, cnt2 = 0;
        while(ans[aid]!=0) --aid; ++aid;
        //bfs();

        printf("Case %d:\n", ++kase);
        printf("%d", ans[aid]);
        for(int i = aid+1; ans[i]!=0; ++i) printf(" %d", ans[i]);
        printf("\n\n");
        met(ans, 0);
    }
    return 0;
}

UVA-297 - Quadtrees

思路

    这一题叫做四分树。实际上和二叉树没多大区别。
    注意最大层数为5层。

代码

char s1[maxn], s2[maxn];
int id, deep;

const int root = 1;
int Left[maxn], Right[maxn], Up[maxn], Down[maxn], cnt;
int val[maxn];

void init() {
    Left[root] = Right[root] = Up[root] = Down[root] = 0;
    cnt = root;
    met(val, 0);
}

int newnode() {
    int u = ++cnt;
    Left[u] = Right[u] = Up[u] = Down[u] = 0;
    return u;
}

void build(char s[], int rt, int depth) {
    //deep = max(deep, depth);
    if(s[id] == 'f') {
        if(val[rt] == 0) val[rt] = 1;
        Left[rt] = Right[rt] = Up[rt] = Down[rt] = 0;

    }
    else if(s[id] == 'e') {}
    else {
        if(val[rt] == 1) return;
        if(Left[rt] == 0) Left[rt] = newnode();
        ++id; build(s, Left[rt], depth+1);
        if(Right[rt] == 0) Right[rt] = newnode();
        ++id; build(s, Right[rt], depth+1);
        if(Up[rt] == 0) Up[rt] = newnode();
        ++id; build(s, Up[rt], depth+1);
        if(Down[rt] == 0) Down[rt] = newnode();
        ++id; build(s, Down[rt], depth+1);
    }

}

int solve() {
    int ans = 0;
    queue<int> q, d;
    q.push(root); d.push(0);

    while(!q.empty()) {
        int t = q.front(); q.pop();
        int dp = d.front(); d.pop();
        if(val[t] == 1) ans += pow(4,deep-dp);
        if(Left[t] != 0) q.push(Left[t]), d.push(dp+1);
        if(Right[t] != 0) q.push(Right[t]), d.push(dp+1);
        if(Up[t] != 0) q.push(Up[t]), d.push(dp+1);
        if(Down[t] != 0) q.push(Down[t]), d.push(dp+1);
    }
    return ans;
}

int main() {
    #ifdef _LOCAL
    IN;
    #endif // _LOCAL

    int t; cin >> t;
    while(t--) {
        deep = 5;init();
        scanf("%s%s",s1, s2);
        id = 0; build(s1, root, 0);
        id = 0; build(s2, root, 0);
        //cout << deep <<endl;
        printf("There are %d black pixels.\n", solve());

    }

    return 0;
}

    自己的代码略水,书上的代码好。如下:

#include<cstdio>
#include<cstring>
const int len = 32;
const int maxn = 1024 + 10;
char s[maxn];
int buf[len][len], cnt;
//把字符串s[p..]导出到以(r,c)为左上角,边长为w的缓冲区中
//2 1
//3 4
void draw(const char* s, int& p, int r, int c, int w) {
    char ch = s[p++];
    if(ch == 'p') {
        draw(s, p, r, c+w/2, w/2);      //1
        draw(s, p, r, c , w/2);         //2
        draw(s, p, r+w/2, c , w/2);     //3
        draw(s, p, r+w/2, c+w/2, w/2);  //4
    }
    else if(ch == 'f') {              //画黑像素(白像素不画)
        for(int i = r; i < r+w; i++) for(int j = c; j < c+w; j++)
            if(buf[i][j] == 0) {
                buf[i][j] = 1;
                cnt++;
            }
    }
}

int main( ) {
    int T;
    scanf("%d", &T);
    while(T--) {
        memset(buf, 0, sizeof(buf));
        cnt = 0;
        for(int i = 0; i < 2; i++) {
            scanf("%s", s);
            int p = 0;
            draw(s, p, 0, 0, len);
        }
        printf("There are %d black pixels.\n", cnt);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值