แนวคิด
กำหนด Binary Search Tree (BST) หา Median:
- จำนวนโหนดคู่: Median = (โหนดที่ n/2 + โหนดที่ (n+1)/2) / 2
- จำนวนโหนดคี่: Median = โหนดที่ (n+1)/2
ตัวอย่าง
BST (7 โหนด): Inorder = 2, 4, 5, 7, 8, 9, 10 → Median = 7
BST (6 โหนด): Inorder = 2, 4, 5, 7, 8, 9 → Median = (5+7)/2 = 6
วิธีแก้: Morris Inorder Traversal
Inorder ของ BST ให้ค่าที่เรียงลำดับ ต้องหา Median โดยไม่ใช้พื้นที่เพิ่ม (O(1) space) → ใช้ Morris Inorder Traversal ซึ่งไม่ต้องใช้ Stack หรือ Recursion
Morris Inorder Traversal
- current = root
- While current != NULL:
- ถ้าไม่มีลูกซ้าย: visit current, current = current->right
- มิฉะนั้น: หา Inorder Predecessor (โหนดขวามากสุดใน subtree ซ้าย) ทำ Thread ไป current, current = current->left
ขั้นตอนหา Median
- นับจำนวนโหนดทั้งหมดด้วย Morris Traversal
- ทำ Morris Traversal อีกครั้ง นับจำนวนโหนดที่ผ่านมา ตรวจสอบว่าถึงตำแหน่ง Median แล้วหรือยัง
- กรณีโหนดคู่: เก็บ pointer โหนดก่อนหน้า (prev) ไว้
โค้ดตัวอย่าง
#include <bits/stdc++.h>
using namespace std;
struct Node1 {
int data1;
struct Node1 *left1, *right1;
};
struct Node1* newNode(int item1) {
struct Node1* temp1 = new Node1;
temp1->data1 = item1;
temp1->left1 = temp1->right1 = NULL;
return temp1;
}
struct Node1* insert(struct Node1* node1, int key1) {
if (node1 == NULL) return newNode(key1);
if (key1 < node1->data1)
node1->left1 = insert(node1->left1, key1);
else if (key1 > node1->data1)
node1->right1 = insert(node1->right1, key1);
return node1;
}
int counNodes(struct Node1* root1) {
struct Node1 *current1, *pre1;
int count1 = 0;
if (root1 == NULL) return count1;
current1 = root1;
while (current1 != NULL) {
if (current1->left1 == NULL) {
count1++;
current1 = current1->right1;
} else {
pre1 = current1->left1;
while (pre1->right1 != NULL && pre1->right1 != current1)
pre1 = pre1->right1;
if (pre1->right1 == NULL) {
pre1->right1 = current1;
current1 = current1->left1;
} else {
pre1->right1 = NULL;
count1++;
current1 = current1->right1;
}
}
}
return count1;
}
int findMedian(struct Node1* root1) {
if (root1 == NULL) return 0;
int count1 = counNodes(root1);
int currCount1 = 0;
struct Node1 *current1 = root1, *pre1, *prev1;
while (current1 != NULL) {
if (current1->left1 == NULL) {
currCount1++;
if (count1 % 2 != 0 && currCount1 == (count1+1)/2)
return current1->data1;
else if (count1 % 2 == 0 && currCount1 == (count1/2)+1)
return (prev1->data1 + current1->data1) / 2;
prev1 = current1;
current1 = current1->right1;
} else {
pre1 = current1->left1;
while (pre1->right1 != NULL && pre1->right1 != current1)
pre1 = pre1->right1;
if (pre1->right1 == NULL) {
pre1->right1 = current1;
current1 = current1->left1;
} else {
pre1->right1 = NULL;
prev1 = pre1;
currCount1++;
if (count1 % 2 != 0 && currCount1 == (count1+1)/2)
return current1->data1;
else if (count1 % 2 == 0 && currCount1 == (count1/2)+1)
return (prev1->data1 + current1->data1) / 2;
prev1 = current1;
current1 = current1->right1;
}
}
}
return 0;
}
int main() {
// BST 7 โหนด (คี่)
struct Node1* root1 = NULL;
root1 = insert(root1, 7);
insert(root1, 4); insert(root1, 2); insert(root1, 5);
insert(root1, 9); insert(root1, 8); insert(root1, 10);
cout << "Median of BST is (odd nodes): " << findMedian(root1) << endl;
// BST 6 โหนด (คู่)
struct Node1* root2 = NULL;
root2 = insert(root2, 7);
insert(root2, 4); insert(root2, 2); insert(root2, 5);
insert(root2, 9); insert(root2, 8);
cout << "Median of BST is (even nodes): " << findMedian(root2);
return 0;
}
ผลลัพธ์
Median of BST is (odd nodes): 7 Median of BST is (even nodes): 6