二元樹節點含多指標(左、右、父),直接寫入硬碟無意義(記憶體位址下次載入失效)。需將樹結構轉為無指標的純資料結構儲存。
借鑒二元堆積(Binary Heap)的陣列表示法:
即使樹非完全二元樹(稀疏),編號規則依然成立。儲存時只存「有效節點的 (資料, 編號)」,載入時依編號重建指標關係。
typedef struct _TREE_NODE {
int data;
int number; // 堆積式編號
struct _TREE_NODE* left_child;
struct _TREE_NODE* right_child;
} TREE_NODE;
STATUS _insert_node_into_tree(TREE_NODE* pTreeNode, int data) {
TREE_NODE* pNode;
while (1) {
if (data < pTreeNode->data) {
if (NULL == pTreeNode->left_child) {
pNode = create_tree_node(data);
assert(NULL != pNode);
pNode->number = pTreeNode->number << 1; // ×2
pTreeNode->left_child = pNode;
break;
} else pTreeNode = pTreeNode->left_child;
} else {
if (NULL == pTreeNode->right_child) {
pNode = create_tree_node(data);
assert(NULL != pNode);
pNode->number = (pTreeNode->number << 1) + 1; // ×2+1
pTreeNode->right_child = pNode;
break;
} else pTreeNode = pTreeNode->right_child;
}
}
return TRUE;
}
STATUS insert_node_into_tree(TREE_NODE** ppTreeNode, int data) {
if (NULL == ppTreeNode) return FALSE;
if (NULL == *ppTreeNode) {
*ppTreeNode = (TREE_NODE*)create_tree_node(data);
assert(NULL != *ppTreeNode);
(*ppTreeNode)->number = 1; // 根節點編號固定為 1
return TRUE;
}
return _insert_node_into_tree(*ppTreeNode, data);
}
typedef struct _DATA {
int data;
int number;
} DATA;
遍歷樹(任意順序),將每個節點的 `data` 與 `number` 依序寫入檔案。另需記錄總節點數 `count`。
TREE_NODE* load_tree_from_disk(FILE* fp, int count) {
// 1. 分配
TREE_NODE* nodes = (TREE_NODE*)malloc(count * sizeof(TREE_NODE));
DATA* disk_data = (DATA*)malloc(count * sizeof(DATA));
fread(disk_data, sizeof(DATA), count, fp);
// 2. 填充
for (int i = 0; i < count; ++i) {
nodes[i].data = disk_data[i].data;
nodes[i].number = disk_data[i].number;
nodes[i].left_child = nodes[i].right_child = NULL;
}
// 3. 重建連結
for (int i = 1; i < count; ++i) { // 從編號 2 開始
int n = nodes[i].number;
int parent_idx = (n >> 1) - 1;
if (n % 2 == 0)
nodes[parent_idx].left_child = &nodes[i];
else
nodes[parent_idx].right_child = &nodes[i];
}
free(disk_data);
return &nodes[0]; // 根節點
}
| 優點 | 缺點 |
|---|---|
| 實作簡單,無需遞歸序列化 | 編號隨樹高增長呈指數級(深度 30 即超 20 億),長整型易溢位 |
| 載入極快(線性掃描 + 索引運算) | 稀疏樹浪費陣列空間(需分配 max_number 而非 count) |
| 適合靜態/低頻修改的樹 | 頻繁增刪需重新編號或維護空洞 |