二叉树求第三种遍历序列 Trie

二叉搜索树

二叉搜索树(Binary Search Tree)它或者是一棵空树,或者是具有下列性质的二叉树:它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉搜索树。
二叉搜索树能高效进行如下操作

  • 插入一个数值
  • 查询是否包含某个数值
  • 删除某个数值
比较繁琐的地方是删除结点时, 对于 "需要删除的结点" 而言分3种情况
(所谓提上去是指提到现在需要删除的结点的位置)
1. 没有左儿子,那么就把右儿子提上去
2. 左儿子没有右儿子,把左儿子提上去
3. 以上2种情况都不满足,把左儿子的子孙中最大的结点提上去
struct nd {
    int val;
    nd *lch, *rch;
};

// 插入数值x
nd *insert(nd *p, int x) {
    if (p == NULL) {
        nd *q = new nd;
        q->val = x;
        q->lch = q->rch = NULL;
        return q;
    } else {
        if (x < p->val)
            p->lch = insert(p->lch, x);
        else
            p->rch = insert(p->rch, x);
        return p;
    }
}

// 是否存在数值x
bool find(nd *p, int x) {
    if (p == NULL) return 0;
    else if (x == p->val) return 1;
    else if (x < p->val) return find(p->lch, x);
    else return find(p->rch, x);
}

// 删除数值x, 返回删后链表的头指针
nd *remove(nd *p, int x) {
    if (p == NULL) return NULL;
    else if (x < p->val) p->lch = remove(p->lch, x);
    else if (x > p->val) p->rch = remove(p->rch, x);
    else if (p->lch == NULL){
        nd *q = p->rch;
        delete p;
        return q;
    }
    else if (p->lch->rch == NULL) {
        nd *q = p->lch;
        q->rch = p->rch;
        delete p;
        return q;
    } else {
        nd *q;
        for (q = p->lch; q->rch->rch != NULL; q = q->rch);
        nd *r = q->rch;
        q->rch = r->lch;
        r->lch = p->lch;
        r->rch = p->rch;
        delete p;
        return r;
    }
    return p;
}

Trie树,原理十分简单,看这道题就完事儿了。
这里权当备份个模板:

#include <bits/stdc++.h>
using namespace std;
#define FOR(i,a,b) for(int i=(a);i<=(b);++i)
#define maxN 1000005
char a[maxN];

struct Trie {
  int nxt[26], cnt;
  void init() {
    cnt = 0, memset(nxt, -1, sizeof nxt);
  }
} T[maxN];
int L;

void insert(string s) {
  int p = 0;
  FOR(i, 0, (int)s.size() - 1) {
    int r = s[i] - 'a';
    if (T[p].nxt[r] == -1) {
      T[L].init();
      T[p].nxt[r] = L++;
    }
    p = T[p].nxt[r];
    T[p].cnt++;
  }
}

void query(string s) {
  int p = 0;
  FOR(i, 0, (int)s.size() - 1) {
    int r = s[i] - 'a';
    if (T[p].nxt[r] == -1) {
      cout << 0 << endl;
      return;
    }
    p = T[p].nxt[r];
  }
  cout << T[p].cnt << endl;
}

int main () {
  // freopen("data.in", "r", stdin);
  int n, m;
  cin >> n;
  T[0].init();
  L = 1;
  string s;
  FOR(i, 0, n - 1) cin >> s, insert(s);
  cin >> m;
  while (m--) {
    cin >> s;
    query(s);
  }
  return 0;
}
样例树
        4
     /     \
    1       6
     \     /   \
      3   5     7
     /
   2
前中求后序
#include <iostream>
#include <bits/stdc++.h>
using namespace std;

#define mst(a,b) memset(a,b,sizeof(a))
#define rep(i,a,b) for(int i=(a);i<(b);++i)

const int maxN = 35;
int N, M;
struct node { int v; node *lc, *rc; };
int mid[maxN], pre[maxN];

node* build(int *p, int *m, int len) {
    if (len == 0)
        return nullptr;
    node* prt = new node();
    prt->v = p[0];
    int idx;
    for (idx = 0; idx < len; ++idx)
        if (m[idx] == p[0])
            break;
    int lsz = idx, rsz = len - idx - 1;
    prt->lc = build(p + 1, m, lsz);
    prt->rc = build(p + 1 + lsz, m + idx + 1, rsz);
    return prt;
}
void print_path(node *prt) {
    if (prt == nullptr)
        return;
    print_path(prt->lc);
    print_path(prt->rc);
    printf("%d ", prt->v);
}

int main() {
    freopen("data.in", "r", stdin);
    scanf("%d", &N);
    rep(i, 0, N) scanf("%d", &mid[i]);
    rep(i, 0, N) scanf("%d", &pre[i]);

    node *prt = build(pre, mid, N);
    print_path(prt);
    return 0;
}

输入样例 节点个数+中序+前序:

7
1 2 3 4 5 6 7
4 1 3 2 6 5 7

输出样例:
2 3 1 5 7 6 4

后中求前序
#include <iostream>
#include <bits/stdc++.h>
using namespace std;

#define mst(a,b) memset(a,b,sizeof(a))
#define rep(i,a,b) for(int i=(a);i<(b);++i)
const int maxN = 35;
int N, M;

struct node { node *lch, *rch; int v; };

node* build(int *mid, int *post, int len) {
    if (len == 0)
        return 0;
    int rt_idx;
    for (rt_idx = 0; rt_idx < len; ++rt_idx)
        if (mid[rt_idx] == *(post + len - 1))
            break;

    node *rt = new node;
    rt->v = mid[rt_idx];

    rt->lch = build(mid, post, rt_idx);
    rt->rch = build(mid + rt_idx + 1, post + rt_idx, len - (rt_idx + 1));
    return rt;
}

void print_tree(node *rt) {
    if (rt == nullptr)
        return;
    printf("%d ", rt->v);
    print_tree(rt->lch);
    print_tree(rt->rch);
}

int main() {
    // freopen("data.in", "r", stdin);

    int post[maxN], mid[maxN];
    scanf("%d", &N);
    rep(i, 0, N) scanf("%d", &mid[i]);
    rep(i, 0, N) scanf("%d", &post[i]);

    node* rt = build(mid, post, N);
    print_tree(rt);
    return 0;
}

输入样例 节点个数+中序+后序:

7
1 2 3 4 5 6 7
2 3 1 5 7 6 4

输出样例:
4 1 3 2 6 5 7

还遇到一道题:

知道一颗树的bfs遍历和dfs遍历序列.其中遍历过程选择孩子的时候,总是选序号小的
比如一棵树如图,其bfs序列为 4 3 5 1 2 8 7 6,dfs序列为4 3 1 7 2 6 5 8

       4
     /    \
    3       5
   /  \      \
  2    1      8
  |    | 
  6    7

目的是求树重建后,所有节点的子节点列表.注意,如果树不唯一,随意输出一棵
题目戳这里
方法是:把bfs理解成每个节点离root的距离.
把root入栈, 遍历dfs的每个点:

  • 若是当前点的距离 > 比栈顶元素距离+1, 意味着当前点是栈顶元素的孩子,图里做记录
  • 否则,要么应该是到了某个祖先节点的兄弟了,当前子树已经搜索完毕,不断出栈
#include <iostream>
#include <bits/stdc++.h>
using namespace std;

#define ll long long
#define rep(i,a,b) for(ll i=(a);i<(b);++i)
#define pb push_back
const int maxN = 1e3 + 5;
int N, dis[maxN];
vector<int> G[maxN];


int main() {
    // freopen("data.in", "r", stdin);
    while (~scanf("%d", &N)) {
        int e;
        rep(i, 1, N + 1) {
            scanf("%d", &e);
            G[i].clear();
            dis[e] = i;
        }

        int rt;
        stack<int> st;
        scanf("%d", &rt);
        st.push(rt);

        rep(i, 1, N) {
            scanf("%d", &e);
            while (1) {
                int u = st.top();
                if (u == rt || dis[e] > dis[u] + 1) {
                    G[u].pb(e);
                    st.push(e);
                    break;
                } else {
                    st.pop();
                }
            }
        }

        rep(i, 1, N + 1) {
            printf("%lld:", i);
            rep(j, 0, G[i].size())
                printf(" %d", G[i][j]);
            puts("");
        }
    }
    return 0;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容