晴神の模拟 | 疯狂的二叉树

1015 | 你们要的中缀表达式树

一开始没注意,以为数值结点值是0 - 9,后来才发现是0 - 10 。= =
但是懒得改太多还是用了char存,printf(“%c”, char(‘9’+1))确认了一下不会和运算符重合= =

  • 第一版
    先中序遍历(注意括号的处理),输出中缀表达式。
    后序遍历,转成后缀表达式,再stack模拟求值。(这个思路昨天的博客刚写到……
#include 
#include 
#include 
#include 
#include 

using namespace std;
struct Node {
    char value;
    int lchild = -1, rchild = -1;
} btree[32];
string suffix_exp;
bool isRoot[32];
int _root = -1;

void in_traverse(int root) {
    if (root != _root && (btree[root].lchild != -1 || btree[root].rchild != -1)) printf("(");
    if (btree[root].lchild != -1) in_traverse(btree[root].lchild);
    btree[root].value == char('0' + 10) ? printf("10") : printf("%c", btree[root].value);
    if (btree[root].rchild != -1) in_traverse(btree[root].rchild);
    if (root != _root && (btree[root].lchild != -1 || btree[root].rchild != -1)) printf(")");
}

void post_traverse(int root) {
    if (btree[root].lchild != -1) post_traverse(btree[root].lchild);
    if (btree[root].rchild != -1) post_traverse(btree[root].rchild);
    suffix_exp += btree[root].value;
}

double calc(const string &str) {
    stack nums;
    int size = str.length(), i = 0;
    while (i < size) {
        if (isdigit(str[i]) || str[i] == char('0' + 10))
            nums.push(str[i] - '0');
        else {
            double n2 = nums.top(), n1;
            nums.pop();
            n1 = nums.top();
            nums.pop();
            switch (str[i]) {
                case '+':
                    nums.push(n1 + n2);
                    break;
                case '-':
                    nums.push(n1 - n2);
                    break;
                case '*':
                    nums.push(n1 * n2);
                    break;
                case '/':
                    nums.push(n1 / n2);
                    break;
            }
        }
        i++;
    }
    return nums.top();
}

int main() {
    int nn;
    string value;
    cin >> nn;
    fill(isRoot, isRoot + nn, true);
    for (int i = 0; i < nn; ++i) {
        cin >> value;
        if (isdigit(value[0])) btree[i].value = char(stoi(value) + '0');
        else btree[i].value = value[0];
    }
    string lc, rc;
    for (int i = 0; i < nn; ++i) {
        cin >> lc >> rc;
        if (lc[0] != '-') isRoot[btree[i].lchild = stoi(lc)] = false;
        if (rc[0] != '-') isRoot[btree[i].rchild = stoi(rc)] = false;
    }
    for (int i = 0; i < nn; ++i) {
        if (isRoot[i]) {
            _root = i;
            break;
        }
    }
    in_traverse(_root);
    post_traverse(_root);
    printf(" %.2lf\n", calc(suffix_exp));
    return 0;
}
  • 第二版
    感觉自己好像绕弯路了 = =,看了晴神的题解,果然= =
    直接在中序遍历时,顺带着求值啊。
  • 表达式树的叶子结点一定是数,非叶子结点一定是运算符。
  • 只含二目运算符的表达式形成的树,一定只有度为2(运算符)和度为0(数)的点。
  • 那么,若为运算符,递归的求这个结点的值;若为叶子,直接返回该结点的值。
#include 
#include 
#include 
#include 

using namespace std;
struct Node {
    char value;
    int lchild = -1, rchild = -1;
} btree[32];
bool isRoot[32];
int _root = -1;

// 有孩子的都是operator结点,双目运算符,必有两个孩子
double in_traverse(int root) {
    double res1, res2, res;
    bool isLeaf = true;
    if (root != _root && (btree[root].lchild != -1 || btree[root].rchild != -1)) printf("(");
    if (btree[root].lchild != -1) {
        isLeaf = false;
        res1 = in_traverse(btree[root].lchild);
    }
    btree[root].value == char('0' + 10) ? printf("10") : printf("%c", btree[root].value);
    if (btree[root].rchild != -1) res2 = in_traverse(btree[root].rchild);
    if (root != _root && (btree[root].lchild != -1 || btree[root].rchild != -1)) printf(")");
    if (!isLeaf)
        switch (btree[root].value) {
            case '+':
                res = res1 + res2;
                break;
            case '-':
                res = res1 - res2;
                break;
            case '*':
                res = res1 * res2;
                break;
            case '/':
                res = res1 / res2;
                break;
        }
    return isLeaf ? btree[root].value - '0' : res;
}

int main() {
    int nn;
    string value;
    cin >> nn;
    fill(isRoot, isRoot + nn, true);
    for (int i = 0; i < nn; ++i) {
        cin >> value;
        if (isdigit(value[0])) btree[i].value = char(stoi(value) + '0');
        else btree[i].value = value[0];
    }
    string lc, rc;
    for (int i = 0; i < nn; ++i) {
        cin >> lc >> rc;
        if (lc[0] != '-') isRoot[btree[i].lchild = stoi(lc)] = false;
        if (rc[0] != '-') isRoot[btree[i].rchild = stoi(rc)] = false;
    }
    for (int i = 0; i < nn; ++i) {
        if (isRoot[i]) {
            _root = i;
            break;
        }
    }
    printf(" %.2lf\n", in_traverse(_root));
    return 0;
}

另外,可以思考一下,怎么由表达式建树

1016 | 二叉树の狂欢

一道巨无霸……

  • 思路
    1. 是AVL tree吗?
      (递归计算子树height)
      不是,输出不平衡结点个数,over; 是,转2。
    2. 是完全二叉树吗?
      (层序遍历⚠️:注意判断条件,顺便给3作准备,用数组存CBT)
      不是,输出满结点的最后一层的层号,over;是,转3。
    3. 将CBT调整为大顶堆,输出swap次数,over。(详见 二叉树|堆 那篇= =
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;
struct Node {
    int key;
    int lchild = -1, rchild = -1, height = 0;
} btree[22];
int nn, root, cnt_not_balance = 0, levels[22] = {0};
bool isRoot[22], isAVL = true;
int max_heap[22];

int updateHeight(int curr) {
    if (btree[curr].lchild == btree[curr].rchild)
        return btree[curr].height = 1; //leaf child == -1
    btree[curr].height = max(updateHeight(btree[curr].lchild), updateHeight(btree[curr].rchild)) + 1;
    int hl = btree[curr].lchild == -1 ? 0 : btree[btree[curr].lchild].height,
            hr = btree[curr].rchild == -1 ? 0 : btree[btree[curr].rchild].height;
    if (abs(hl - hr) > 1) {
        isAVL = false;
        cnt_not_balance++;
    }
    return btree[curr].height;
}

int max_full_level(int rt) { //if not CBT, return max full level
    bool isFull = true;
    int index = 0;
    queue mq;
    levels[rt] = 1;
    mq.push(rt);
    while (!mq.empty()) {
        int temp = mq.front();
        mq.pop();
        max_heap[index++] = btree[temp].key;
        if (!isFull && (btree[temp].lchild != -1 && btree[temp].rchild != -1))
            return levels[temp];
        if (btree[temp].lchild == -1 && btree[temp].rchild != -1)
            return levels[temp];
        else {
            if (btree[temp].lchild == -1 || btree[temp].rchild == -1)
                isFull = false;
            if (btree[temp].lchild != -1) {
                levels[btree[temp].lchild] = levels[temp] + 1;
                mq.push(btree[temp].lchild);
            }
            if (btree[temp].rchild != -1) {
                levels[btree[temp].rchild] = levels[temp] + 1;
                mq.push(btree[temp].rchild);
            }
        }
    }
    return -1;
}

void downAdjust(int curr, int &cnt) {
    while (2 * curr + 1 < nn) {
        int li = 2 * curr + 1, ri = 2 * curr + 2;
        if (ri >= nn && max_heap[li] > max_heap[curr]) {
            swap(max_heap[li], max_heap[curr]);
            cnt++;
            curr = li;
        } else {
            if (max(max_heap[li], max_heap[ri]) < max_heap[curr]) break;
            if (max_heap[li] > max_heap[ri]) {
                swap(max_heap[li], max_heap[curr]);
                curr = li;
            } else {
                swap(max_heap[ri], max_heap[curr]);
                curr = ri;
            }
            cnt++;
        }
    }
}

int adjustHeap() { //heap index 0 - nn-1  not-leaf: 0  -  nn/2-1
    int cnt_swap = 0;
    for (int i = nn / 2 - 1; i >= 0; --i) {
        downAdjust(i, cnt_swap);
    }
    return cnt_swap;
}

int main() {
    scanf("%d", &nn);
    for (int i = 1; i <= nn; ++i) {
        scanf("%d", &btree[i].key);
        isRoot[i] = true;
    }
    string kv;
    for (int i = 1; i <= nn; ++i) {
        cin >> kv;
        if (kv[0] != '-') isRoot[btree[i].lchild = stoi(kv)] = false;
        cin >> kv;
        if (kv[0] != '-') isRoot[btree[i].rchild = stoi(kv)] = false;
    }
    for (int i = 1; i <= nn; ++i) {
        if (isRoot[i]) {
            root = i;
            break;
        }
    }
    updateHeight(root);
    if (isAVL) {
        int mlevel = max_full_level(root);
        if (mlevel == -1) {
            puts("OHHHHH HEAP!!!");
            printf("%d\n", adjustHeap());
        } else {
            puts("NOT COMPLETE TREE!!!");
            printf("%d\n", mlevel);
        }
    } else {
        puts("NOT AVL TREE!!!");
        printf("%d\n", cnt_not_balance);
    }
    return 0;
}

你可能感兴趣的:(晴神の模拟 | 疯狂的二叉树)