Data_Structure/作業/unit7/Threaded Binary Tree_bit.cpp
2025-01-20 21:30:53 +08:00

525 lines
15 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*Notes: 輸入可為
w={"Mary":10, "Tom":3, "Charlie":5, "Bob":6, "Dickens":20, 4:9, "z":0, "Za":12, "aZ":8}
w={10:10, 20:3, 5:5, 17:6, 23:20, 18:9, 3:0, 9:12}
w={10:10, 5:5, 9:6, 3:20, 7:9}
w={"A":10, "B":3, "C":5, "Bob":6, "D":20}
w={"D":10, "C":3, "B":5, "A":6}
del w["A"]
del w["Dickens"]
del w["Mary"]
del w["aZ"]
del w
w={"B":3, "A":10}
w["A"]=10
w["B"]=20
w["Tom"]+=2
w[4]?
w?
*/
#include <stdio.h> /* for sscanf(), printf() */
#include <stdlib.h>
#include <string.h> /* for strstr(), strtok(), strtok_r() */
#include <conio.h>
/* 定義dict結構 */
typedef struct dict { /* 引線二元搜尋樹節點之資料結構,實作字典 */
char key[20]; /* 紀錄該節點的「鍵」(key)內容 */
int value; /* 紀錄「鍵」對應之「值」(value)內容 */
struct dict *llink; /* 指向左子樹根或引線用途 */
struct dict *rlink; /* 指向右子樹根或引線用途 */
int lbit; /* 指示 llink 是否為正常指標 */
int rbit; /* 指示 rlink 是否為正常指標 */
} dict;
void show(void); /* 輸出函數 */
void insert(char [], int); /* 將資料加入二元搜尋樹 */
void insert_left(struct dict *s, struct dict *t);
void insert_right(struct dict *s, struct dict *t);
void removing(char []); /* 將資料從二元搜尋樹中移除 */
void inorder(struct dict *); /* 資料以中序法輸出 */
void free_all_nodes(struct dict *node);
void find_newroot(void); /* 搜尋新的樹跟節點 */
dict *search_p(struct dict *node);
dict *search(char []); /* 搜尋節點 */
dict *insuc(dict *ptr);
dict *root = NULL, *ptr, *prev ,*head = NULL ;
int main(){
head = (dict *)malloc(sizeof(dict));
if (head == NULL) {
printf("記憶體分配失敗!\n");
return 1;
}
head->lbit = head->rbit = 1;
head->rlink = head;
head->llink = root;
char *token, key[12], line[128];
const char *s = " ={},"; /* 分隔符記的字元 */
int value;
char *rest ,option;
printf("輸入存取字典的陳述,逕按<Enter>結束程式\n");
while (1) {
printf("\n指令 => ");
fgets(line,128,stdin); /* 使用gets()讀取也可以但因gets()未設讀入字元數的限制,可能導致儲存輸入字元的陣列空間爆掉 */
if (line[0]=='\n') break; /* 輸入空字串則跳離此迴圈 */
if (strstr(line,"{")) { /* line含有"{" */
sscanf(line,"w = {%[^}]}",line);
rest = line;
while (token = strtok_r(rest,s,&rest)) { /* strtok_r()的用法可參見 http://bit.ly/3VcvbbZ */
/* printf("%s\n",token); */
if (strstr(token,":")) {/* token含有":" */
sscanf(token,"%[^:]:%d",key,&value);
// printf("key=%s,value=%d\n",key,value);
insert(key,value);
// printf("Token #%d: 鍵=%s; 值=%d\n",++i,key,value);
}
}
}else if (strstr(line,"del")) {
if(sscanf(line,"del w[%[^]]]",key)){
if(strcmp(key,root->key)==0){
// printf("刪除的元素w[%s]為root節點\n",key);
find_newroot();
// printf("新的root節點為w[%s]\n",root->key);
}else removing(key);
}else{
printf("無法判讀將刪除哪一個元素,將刪除整個字典? (y/n) => ");
scanf("%c",&option);
fflush(stdin);
if (option == 'y' || option == 'Y') {
free_all_nodes(root);
root = NULL;
}else{
printf("取消刪除所有字典\n");
}
}
}else if (strstr(line,"+=")) { /* line含有"+=" */
sscanf(line,"w[%[^]]] +=%d",key,&value);
dict *modify_node;
if((modify_node = search(key)) == NULL){ /* 找不到資料則顯示錯誤 */
printf("錯誤! %s 不在此二元搜尋樹中!\n", key);
}else{
modify_node->value += value;
printf("新設w[%s]=%d\n",key,modify_node->value);
}
}else if (strstr(line,"=")) { /* line含有"=" */
sscanf(line,"w[%[^]]] = %d",key,&value);
dict *add_node;
if (root == NULL){
insert(key,value);
printf("新設w[%s]=%d\n",key,root->value);
}else{
if((add_node = search(key)) == NULL){ /* 找不到資料則新增資料 */
insert(key,value);
printf("%s 不在此二元搜尋樹中!\n", key);
printf("新設w[%s]=%d\n",key,value);
}else{
add_node->value = value;
printf("新設w[%s]=%d\n",key,add_node->value);
}
}
}else if (sscanf(line,"w[%[^]]]?",key)==1){
dict *read_node;
if((read_node = search(key)) == NULL){ /* 找不到資料則新增資料 */
printf("錯誤! %s 不在此二元搜尋樹中!\n", key);
}else{
printf("字典元素w[%s]=%d\n",key,read_node->value);
}
}else if (strstr(line,"?")) show();
else printf("語法無法辨認sorry!\n");
}
printf("\n程式結束刪除所有節點bye ~\n");
free_all_nodes(root);
free(head);
return 0;
}
// 修改後的insert函數
void insert(char key[], int value) {
// 檢查是否已存在
if (search(key) != NULL) {
printf("%s 已存在!\n", key);
return;
}
// 建立新節點
ptr = (struct dict *) malloc(sizeof(struct dict));
strcpy(ptr->key, key);
ptr->value = value;
ptr->lbit = ptr->rbit = 0;
ptr->llink = ptr->rlink = NULL; // 明確初始化為 NULL
// 處理空樹的情況
if (root == NULL) {
root = ptr;
head->llink = root; // head 的左鏈結指向 root
root->llink = head; // root 的左執行緒指向 head
root->rlink = head; // root 的右執行緒指向 head
return;
}
// 尋找插入位置
dict *current = root;
dict *parent;
while (1) {
parent = current;
if (strcmp(ptr->key, current->key) < 0) { // 往左走
if (current->lbit == 0) { // 找到插入位置
insert_left(current, ptr);
break;
}
current = current->llink;
}else { // 往右走
if (current->rbit == 0) { // 找到插入位置
insert_right(current, ptr);
break;
}
current = current->rlink;
}
}
}
// 在某節點左方插入新節點
void insert_left(struct dict *s, struct dict *t) {
t->llink = s->llink; // 新節點的左子節點指向原節點的左子節點
t->rlink = s; // 新節點的右子節點指向原節點
t->lbit = s->lbit; // 新節點繼承原節點的左位元值
t->rbit = 0; // 設定右位元為執行緒
s->llink = t; // 原節點的左子節點指向新節點
s->lbit = 1; // 設定左位元為正常鏈結
if (t->lbit == 1) {
dict *p = t->llink;
while (p->rbit == 1)
p = p->rlink;
p->rlink = t;
}
}
// 在某節點右方插入新節點(根據圖片所示)
void insert_right(struct dict *s, struct dict *t) {
t->rlink = s->rlink; // 新節點的右子節點指向原節點的右子節點
t->rbit = s->rbit; // 新節點繼承原節點的右位元值
t->llink = s; // 新節點的左子節點指向原節點
t->lbit = 0; // 設定左位元為執行緒
s->rlink = t; // 原節點的右子節點指向新節點
s->rbit = 1; // 設定右位元為正常鏈結
// 尋找前驅節點並更新引線
if (t->rbit == 1) {
dict *p = t->rlink;
while (p->lbit == 1)
p = p->llink;
p->llink = t;
}
}
/* 將資料從二元搜尋樹中移除 */
void removing(char key[]) {
dict *del_node = search(key);
if (del_node == NULL) {
printf("%s 不在此二元搜尋樹中!\n", key);
return;
}
dict *parent = search_p(del_node);
// Case 1: 葉節點 (沒有子節點)
if (del_node->lbit == 0 && del_node->rbit == 0) {
if (parent == NULL) { // 刪除的是根節點
root = NULL;
head->llink = head;
} else if (parent->llink == del_node) {
parent->llink = del_node->llink; // 繼承左執行緒
parent->lbit = 0;
} else {
parent->rlink = del_node->rlink; // 繼承右執行緒
parent->rbit = 0;
}
free(del_node);
}
// Case 2: 只有左子樹
else if (del_node->lbit == 1 && del_node->rbit == 0) {
dict *left_child = del_node->llink;
dict *successor = del_node->rlink; // 保存後繼節點
// 找到左子樹的最右節點
dict *rightmost = left_child;
while (rightmost->rbit == 1) {
rightmost = rightmost->rlink;
}
// 更新連接
rightmost->rlink = successor;
if (parent == NULL) {
root = left_child;
head->llink = root;
} else if (parent->llink == del_node) {
parent->llink = left_child;
} else {
parent->rlink = left_child;
}
free(del_node);
}
// Case 3: 只有右子樹
else if (del_node->lbit == 0 && del_node->rbit == 1) {
dict *right_child = del_node->rlink;
dict *predecessor = del_node->llink; // 保存前驅節點
// 找到右子樹的最左節點
dict *leftmost = right_child;
while (leftmost->lbit == 1) {
leftmost = leftmost->llink;
}
// 更新連接
leftmost->llink = predecessor;
if (parent == NULL) {
root = right_child;
head->llink = root;
} else if (parent->llink == del_node) {
parent->llink = right_child;
} else {
parent->rlink = right_child;
}
free(del_node);
}
// Case 4: 有兩個子樹
else {
// 找到中序後繼節點(右子樹中最小的節點)
dict *successor = del_node->rlink;
dict *succ_parent = del_node;
while (successor->lbit == 1) {
succ_parent = successor;
successor = successor->llink;
}
// 複製後繼節點的數據到被刪除節點
strcpy(del_node->key, successor->key);
del_node->value = successor->value;
// 移除後繼節點
if (succ_parent == del_node) {
del_node->rlink = successor->rlink;
del_node->rbit = successor->rbit;
} else {
succ_parent->llink = successor->llink;
succ_parent->lbit = successor->lbit;
}
free(successor);
}
printf("刪除w[%s]元素\n", key);
}
void find_newroot() {
struct dict *newroot_node, *prev;
if(root->lbit == 0 && root->rbit == 0 ){
printf("刪除w[%s]元素\n", root->key);
free(root);
root = NULL;
return;
}
if (root->lbit == 1) { // 有左子樹,找左子樹中最大的節點
newroot_node = root->llink;
prev = root;
// 找到左子樹中最大的節點
while (newroot_node->rbit == 1) {
prev = newroot_node;
newroot_node = newroot_node->rlink;
}
// 處理新根節點的連接
if (newroot_node != root->llink) {
// 如果新根不是原根的直接左子節點
prev->rbit = newroot_node->rbit; // 繼承新根的右執行緒狀態
prev->rlink = newroot_node->rlink; // 繼承新根的右執行緒
newroot_node->lbit = root->lbit; // 繼承原根的左指標狀態
newroot_node->llink = root->llink; // 繼承原根的左子樹
newroot_node->rbit = root->rbit; // 繼承原根的右指標狀態
newroot_node->rlink = root->rlink; // 繼承原根的右子樹
} else {
// 如果新根是原根的直接左子節點
newroot_node->rbit = root->rbit; // 繼承原根的右指標狀態
newroot_node->rlink = root->rlink; // 繼承原根的右子樹
}
} else if (root->rbit == 1) { // 有右子樹,找右子樹中最小的節點
newroot_node = root->rlink;
prev = root;
// 找到右子樹中最小的節點
while (newroot_node->lbit == 1) {
prev = newroot_node;
newroot_node = newroot_node->llink;
}
// 處理新根節點的連接
if (newroot_node != root->rlink) {
// 如果新根不是原根的直接右子節點
prev->lbit = newroot_node->lbit; // 繼承新根的左執行緒狀態
prev->llink = newroot_node->llink; // 繼承新根的左執行緒
newroot_node->lbit = root->lbit; // 繼承原根的左指標狀態
newroot_node->llink = root->llink; // 繼承原根的左子樹
newroot_node->rbit = root->rbit; // 繼承原根的右指標狀態
newroot_node->rlink = root->rlink; // 繼承原根的右子樹
} else {
// 如果新根是原根的直接右子節點
newroot_node->lbit = root->lbit; // 繼承原根的左指標狀態
newroot_node->llink = root->llink; // 繼承原根的左子樹
}
}
// 更新頭節點的連接
if(root != NULL){
head->llink = newroot_node;
printf("刪除w[%s]元素\n", root->key);
free(root);
root = newroot_node;
}
}
void show(void) {
if (root == NULL) {
puts("二元搜尋樹是空的!");
return;
}
printf("字典變數內部儲存的元素(keyvalue)如下\n");
inorder(root);
}
// 使用引線特性進行中序遍歷
void inorder(dict *root) {
if (root == NULL) {
printf("二元搜尋樹是空的!\n");
return;
}
dict *current = root;
// 找到最左邊的節點
while (current->lbit == 1) {
current = current->llink;
}
// 使用引線特性遍歷
while (current != head) {
printf("%s%d\n", current->key, current->value);
current = insuc(current);
}
}
// 尋找中序後繼節點
dict *insuc(dict *ptr) {
dict *current;
// 若右指標是執行緒rbit = 0直接返回右指標
if (ptr->rbit == 0) {
return ptr->rlink;
}
// 否則往右走一步後,一直往左走直到到達最左邊的節點
current = ptr->rlink;
while (current->lbit == 1) {
current = current->llink;
}
return current;
}
/* 搜尋target所在節點 */
struct dict *search(char target[]) {
struct dict *node = root;
while (node != NULL && node != head) { // 加入 head 的檢查以防止走到頭節點
int cmp = strcmp(target, node->key);
if (cmp == 0) {
return node; // 找到目標節點
} else if (cmp < 0) { // target 小於目前節點,往左搜尋
if (node->lbit == 0) { // 如果左邊是執行緒
return NULL; // 代表找不到目標
}
node = node->llink;
} else { // target 大於目前節點,往右搜尋
if (node->rbit == 0) { // 如果右邊是執行緒
return NULL; // 代表找不到目標
}
node = node->rlink;
}
}
return NULL; // 找不到目標
}
/* 搜尋node的父節點 */
struct dict *search_p(struct dict *node) {
if (node == NULL || node == root) {
return NULL;
}
struct dict *current = root;
struct dict *parent = NULL;
while (current != NULL && current != head) {
int cmp = strcmp(node->key, current->key);
if (cmp == 0) { // 找到目標節點,返回其父節點
return parent;
}
parent = current; // 更新父節點
if (cmp < 0) { // 目標在左子樹
if (current->lbit == 0) { // 如果是執行緒
return NULL; // 找不到目標
}
current = current->llink;
} else { // 目標在右子樹
if (current->rbit == 0) { // 如果是執行緒
return NULL; // 找不到目標
}
current = current->rlink;
}
}
return NULL; // 沒有找到目標節點
}
// 釋放所有節點的非遞迴版本
void free_all_nodes(struct dict *root) {
if (root == NULL) {
return;
}
dict *current = root;
dict *temp;
// 找到最左邊的節點
while (current->lbit == 1) {
current = current->llink;
}
// 使用引線特性遍歷並釋放節點
while (current != head) {
temp = current;
current = insuc(current);
printf("刪除'w[%s]=%d'節點\n", temp->key, temp->value);
free(temp);
}
root = NULL;
}