P5076 【深基16.例7】普通二叉樹(簡化版)題解
阿新 • • 發佈:2021-08-02
一、陣列+lower_bound+upper_bound模擬
#include <bits/stdc++.h> using namespace std; const int N = 10010; int a[N]; int q, cmd, number, cnt; long long p; //解法1:暴力(使用二分優化查詢) //lower_bound(begin,end,number)函式是求begin-end中(排好序)第一個大於等於 number的數 //upper_bound(begin,end,number)函式是求begin-end中(排好序)第一個大於 number的數 int main() { //q次詢問 cin >> q; while (q--) { cin >> cmd; //1-5共5個命令 switch (cmd) { case 1: cin >> number; cout << lower_bound(a + 1, a + cnt + 1, number) - a << endl; break; case 2: cin >> number; cout << a[number] << endl; break; case 3: cin >> number; p = lower_bound(a + 1, a + cnt + 1, number) - a; if (p == 1) cout << -2147483647 << endl; else cout << a[p - 1] << endl; break; case 4: cin >> number; p = upper_bound(a + 1, a + cnt + 1, number) - a; if (p == cnt + 1) cout << 2147483647 << endl; else cout << a[p] << endl; break; case 5: cin >> number; a[++cnt] = number; sort(a + 1, a + cnt + 1); break; } } return 0; }
二、BST二叉搜尋樹
#include <bits/stdc++.h> using namespace std; //題解 //https://www.cnblogs.com/do-while-true/p/13566274.html //const int INF = 2147483647; 這個 2147483647的十六進位制表示:0x7fffffff,是等價的 const int INF = 0x7fffffff; const int N = 1000010; int cnt; struct Node { int left; //左兒子 int right; //右兒子 int size; //以該節點為根結點的子樹的結點個數 int value; //該結點的權值 int num; //該結點權值出現的次數 } tree[N]; int q, opt, x; /** * 測試用例: 7 5 1 5 3 5 5 1 3 2 2 3 3 4 3 參考答案: 2 3 1 5 */ //查詢數x的排名(找出以root為根的樹中,有多少個結點值小於查詢數x) int queryVal(int root, int x) { //root==0表示進入到一個結點,準備再向下,結果再向下沒有了,就是:表示找不到權值為x的數,返回0 if (root == 0) return 0; //如果x等於樹根的value值,那麼比它小的有tree[tree[root].left].size個, // 它是第tree[tree[root].left].size+1個 if (x == tree[root].value) return tree[tree[root].left].size; //如果x小於樹根的value值,那麼需要到左子樹中去計算排名 if (x < tree[root].value) return queryVal(tree[root].left, x); //如果x大於樹根的value值,那麼需要到右子樹中去計算排名,同時,需要加上左子樹的 // 結點個數+root的結點個數 return queryVal(tree[root].right, x) + tree[tree[root].left].size + tree[root].num; } //查詢排名為x的數 int queryRank(int root, int x) { //root==0表示進入到一個結點,準備再向下,結果再向下沒有了,就是:表示找不到排名為x的數,返回0 if (root == 0) return 0;//其實這裡的有坑的,找不到題目沒有說明是返回INF,還是返回0, // 實測返回INF也是可以AC的。 //如果左子樹中包含這個排名,那麼遞迴到左子樹去找 if (tree[tree[root].left].size >= x) return queryRank(tree[root].left, x); //如果根結點的排名==x,那麼返回根結點的權值 if (tree[tree[root].left].size + tree[root].num >= x) return tree[root].value; //如果右子樹中包含這個排名,那麼遞迴到右子樹中去找,這個子排名就是減去左子樹的總結點個數 // 再減去root的個數 return queryRank(tree[root].right, x - tree[tree[root].left].size - tree[root].num); } //向二叉搜尋樹中增加一個權值為x的數字 void insert(int root, int x) { //由於增加了一個結點,root的總結點個數+1 //這一步是遞迴的必要步驟,表示以它為根的家族中增加了一個結點 tree[root].size++; //如果新增加的數字x與root根的權值相等,那麼num++ if (tree[root].value == x) { tree[root].num++; } else if (tree[root].value > x) {//如果root的權值大於x,左子樹 //如果左子樹不空,則遞歸向左子樹插入結點x if (tree[root].left != 0) insert(tree[root].left, x); else { //如果左子樹為空,那麼需要建立一個新結點 tree[++cnt].value = x; //新的陣列位置用來儲存x tree[cnt].size = 1; //新增加的結點,下面沒有子樹,所以size=1 tree[cnt].num = 1; //權值為x的目前只有1個 tree[root].left = cnt; //新增為左子樹 } } else { //如果root的權值小於x,右子樹 //如果右子樹不空,則遞歸向右子樹插入結點x if (tree[root].right != 0) insert(tree[root].right, x); else { //如果右子樹為空,那麼需要建立一個新結點 tree[++cnt].value = x; //新的陣列位置用來儲存x tree[cnt].size = 1; //新增加的結點,下面沒有子樹,所以size=1 tree[cnt].num = 1; //權值為x的目前只有1個 tree[root].right = cnt; //新增為右子樹 } } } /** * 功能:查詢前驅 * @param root 以root為根的樹 * @param x 要查詢的數字x * @param ans 暫存的前驅值,待更新成最合理的前驅值 * @return 數字x的前驅 */ int queryPrev(int root, int x, int ans) { //如果根結點值大於x,那麼需要去左子樹中去找 if (tree[root].value >= x) { //如果左子樹為空的,將前面獲取到的最優解返回就可以了 if (tree[root].left == 0) return ans; else //到左子樹中去查詢 return queryPrev(tree[root].left, x, ans); } else { //如果根結點值小於x,那麼需要到右子樹中去找 //如果右子樹為空,那麼就是根結點的value值 if (tree[root].right == 0) return tree[root].value; //右子樹不為空,遞迴到右子樹去查詢 return queryPrev(tree[root].right, x, tree[root].value); } } /** * 功能:查詢後繼 * @param root 以root為根的樹 * @param x 要查詢的數字x * @param ans 暫存的後繼值,待更新成最合理的後繼值 * @return 數字x的後繼 */ int queryNext(int root, int x, int ans) { //如果根結點的權值小於等於x,需要向右子樹去找 if (tree[root].value <= x) { //如果右子樹為空,則沒有比它更大的,返回暫存的最合理值ans if (tree[root].right == 0) return ans; else //如果右子樹不空,則遞迴到右子樹中去找 return queryNext(tree[root].right, x, ans); } else { //向左子樹中去找 //如果左子樹為空,那麼就是根的value值 if (tree[root].left == 0) return tree[root].value; //如果左子樹不空,遞迴到左子樹去找 return queryNext(tree[root].left, x, tree[root].value); } } int main() { //q次詢問 cin >> q; while (q--) { //操作命令和操作的值 cin >> opt >> x; switch (opt) { case 1: //查詢x數的排名,注意這後面的+1,其實,rnk就是在根為root的子樹中, // 找到比x值小的結點的個數,然後再加1,就是x的排名 cout << queryVal(1, x) + 1 << endl; break; case 2: //查詢排名為x的數 cout << queryRank(1, x) << endl; break; case 3: //求x的前驅 cout << queryPrev(1, x, -INF) << endl; break; case 4: //求x的後繼 cout << queryNext(1, x, INF) << endl; break; case 5: //插入一個數 x if (cnt == 0) { //一個都沒有,那麼,第一個是根結點 cnt++; //陣列中1號位置 tree[cnt].num = 1; //權值是x的數量目前是1個 tree[cnt].size = 1; //它+子樹結點的總結點個數是1個 tree[cnt].value = x; //權值是x } else insert(1, x); //將數x插入到根為1的二叉搜尋樹中 break; } } return 0; }