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

来源:互联网 发布:javabean连接数据库 编辑:程序博客网 时间:2024/05/17 08:22

前言

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

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

题解如下

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 4void 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;}