整數對A滿足二叉查找樹,B滿足最大堆
1 題目
給出一組整數對 { (a[0], b[0]), (a[1], b[1]) ... (a[n-1], b[n-1]) },全部 a 值和 b 值分別不反復(隨意 i != j 滿足 a[i] != a[j] 且 b[i] != b[j])。
構造一棵 n 結點的二叉樹,將這 n 個整數對分配到各個結點上。根和全部子樹滿足下面條件:1) 全部結點的 a 值滿足二叉查找樹的順序。即 left->a <root->a && root->a < right->a。2) 全部結點的 b 值滿足最大堆的順序。即 root->b >left->b && root->b > right->b。
問題一:實現 build 函數,輸入 n 個整數對。返回一棵構造好的二叉樹。
struct pair_t { int a,b;};struct node_t { int a, b; node_t *left, *right;};node_t*build(pair_t* pair, int n);
問題二:已知滿足上述條件的二叉樹,設計算法實現插入一個整對 (a, b),使新的二叉樹仍滿足上述條件。該算法比較復雜。候選人僅僅需描寫敘述思路。
若有錯誤歡迎大家指正,若有更好的方法。歡迎大家不吝賜教!
2 分析
該問題的關鍵就是找樹根。
方法一:當前全部整數對的樹根為b中最大值相應的整數對I。由於僅僅有這樣才幹滿足最大堆的性質。然後依據I中的a值將整數對分為比a大於比a小兩組,小的作為左子樹,大的作為右子樹。當整數對個數為0時,返回NULL。該方法時間復雜度O(n2
方法二(華南理工大神ohm提供):將整數對依照b進行逆向排序,然後依照a進行二分叉樹的插入操作就可以。
該方法的時間復雜度為O(nlogn)。
3 實現
方法一實現:
struct pair_t { int a, b; }; struct node_t { int a, b; node_t *left, *right; }; node_t *build(pair_t *pair, int n); int findMaxB(pair_t *pair, int n); int findMaxB(pair_t *pair, int n) { int pos = 0; for (int i = 1; i < n; ++i) { if (pair[pos].b < pair[i].b) { pos = i; } } return pos; } node_t *build(pair_t *pair, int n) { if (0 == n) { return NULL; } node_t *root = new node_t[1]; pair_t *pair1 = new pair_t[n]; pair_t *pair2 = new pair_t[n]; int num1 = 0; int num2 = 0; int maxB = findMaxB(pair, n); root->a = pair[maxB].a; root->b = pair[maxB].b; int maxBA = pair[maxB].a; for (int i = 0; i < maxB; ++i) { if (pair[i].a < maxBA) { pair1[num1].a = pair[i].a; pair1[num1++].b = pair[i].b; } else { pair2[num2].a = pair[i].a; pair2[num2++].b = pair[i].b; } } for (int i = maxB + 1; i < n; ++i) { if (pair[i].a < maxBA) { pair1[num1].a = pair[i].a; pair1[num1++].b = pair[i].b; } else { pair2[num2].a = pair[i].a; pair2[num2++].b = pair[i].b; } } root->left = build(pair1, num1); delete []pair1; root->right = build(pair2, num2); delete []pair2; return root; }
方法二實現:
void insert(node_t *&root, pair_t p) { if (root == NULL) { root = new node_t; root->a = p.a; root->b = p.b; root->left = NULL; root->right = NULL; return; } if (root->a < p.a) { insert(root->right, p); } else { insert(root->left, p); } } node_t *build(pair_t *pair, int n) { if (0 == n) { return NULL; } node_t *root = NULL; sort(pair, pair + n); for (int i = 0; i < n; ++i) { insert(root, pair[i]); } return root; }
4 問題二
設插入整數對為(nA, nB),當前訪問樹中結點為curNode。插入步驟例如以下:
(1) 若curNode.b>nB。則比較curNode.a與nA。若curNode.a>nA,則curNode=curNode->left;反之,curNode=curNode->right。直到curNode.b<nB或curNode=NULL,停止查找。
(2) 若curNode=NULL,則直接將該整數對插入到此位置就可以;反之,將(nA,nB)作為curNode父結點的孩子結點。curNode作為插入結點的孩子結點(依據a的值確定是左孩子還是右孩子)。
(3) curNode作為新插入結點的右(左)孩子。則須要遍歷curNode的左(右)子樹,找到a值小於nA的子樹的根作為新插入結點的左(右)孩子。當然若不存在時先插入結點不存在左(右)孩子。
整數對A滿足二叉查找樹,B滿足最大堆