/*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, "Charlie":5, "Bob":6, "Dickens":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["Mary"]=1 w["Tom"]+=2 w[4]? w? */ #include /* for sscanf(), printf() */ #include #include /* for strstr(), strtok(), strtok_r() */ #include #define MAX_STACK 100 // 定義堆疊大小 /* 定義dict結構 */ typedef struct dict { /* 引線二元搜尋樹節點之資料結構,實作字典 */ char key[20]; /* 紀錄該節點的「鍵」(key)內容 */ int value; /* 紀錄「鍵」對應之「值」(value)內容 */ struct dict *llink; /* 指向左子樹根或引線用途 */ struct dict *rlink; /* 指向右子樹根或引線用途 */ int lbit; /* 指示 llink 是否為正常指標 */ int rbit; /* 指示 rlink 是否為正常指標 */ } dict; // 定義堆疊結構 typedef struct { dict* data[MAX_STACK]; int top; } Stack; void show(void); /* 輸出函數 */ void insert(char [], int); /* 將資料加入二元搜尋樹 */ 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 *root = NULL, *ptr, *prev ,*head = NULL ; // 堆疊操作函數 void initStack(Stack *s) { s->top = -1; } int isEmpty(Stack *s) { return s->top == -1; } int isFull(Stack *s) { return s->top == MAX_STACK - 1; } void push(Stack *s, dict* node) { if (!isFull(s)) { s->data[++(s->top)] = node; } } dict* pop(Stack *s) { if (!isEmpty(s)) { return s->data[(s->top)--]; } return NULL; } void inorder(struct dict *root) { if (root == NULL) { return; } Stack stack; initStack(&stack); dict *current = root; while (current != NULL || !isEmpty(&stack)) { // 將所有左子節點推入堆疊 while (current != NULL) { push(&stack, current); current = current->llink; } // 從堆疊中取出節點並處理 current = pop(&stack); if (current != NULL) { printf("%s:%d\n", current->key, current->value); // 移動到右子節點 current = current->rlink; } } } // 非遞迴方式釋放所有節點 void free_all_nodes(struct dict *root) { if (root == NULL) { return; } Stack stack; initStack(&stack); dict *current = root; dict *last_processed = NULL; while (current != NULL || !isEmpty(&stack)) { if (current != NULL) { push(&stack, current); current = current->llink; } else { dict *peek = stack.data[stack.top]; // 如果右子節點存在且尚未處理 if (peek->rlink != NULL && last_processed != peek->rlink) { current = peek->rlink; } else { peek = pop(&stack); printf("刪除'w[%s]=%d'節點\n", peek->key, peek->value); last_processed = peek; free(peek); current = NULL; } } } } void show(void) { if (root == NULL) { puts("二元搜尋樹是空的!"); return; } printf("字典變數內部儲存的元素(key:value)如下\n"); inorder(root); } 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("輸入存取字典的陳述,逕按結束程式\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); 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; } /* 處理二元搜尋樹,將新增資料加入至二元搜尋樹中 */ void insert(char key[], int value){ struct dict *node, *prev; /* 資料已存在則顯示錯誤 */ if (search(key) != NULL) { printf("%s 已存在!\n", key); return; } ptr = (struct dict *) malloc(sizeof(struct dict)); strcpy(ptr->key, key); ptr->value = value; ptr->llink = ptr->rlink = NULL; ptr->lbit = ptr->rbit = 0; if (root == NULL){/* 當根節點為NULL的狀況 */ root = ptr; ptr->lbit = ptr->rbit = 1; }else{ /* 當根節點不為NULL的狀況 */ node = root; while (node != NULL) { /* 搜尋資料插入點 */ prev = node; if(strcmp(ptr->key, node->key) < 0) node = node->llink; else node = node->rlink; } if (strcmp(ptr->key, prev->key) < 0){ prev->llink = ptr; prev->lbit = 1; }else{ prev->rlink = ptr; prev->rbit = 1; } } } /* 將資料從二元搜尋樹中移除 */ void removing(char key[]){ dict *del_node = search(key); if (del_node == NULL) { printf("%s 不在此二元搜尋樹中!\n", key); return; } dict *parent = search_p(del_node); // 處理沒有子節點的情況 if (del_node->llink == NULL && del_node->rlink == NULL) { if (parent == NULL) { // 刪除的是根節點 root = NULL; } else if (parent->llink == del_node) { parent->llink = NULL; } else { parent->rlink = NULL; } }else if (del_node->llink == NULL || del_node->rlink == NULL) { // 處理一邊有子節點的情況 dict *child = (del_node->llink != NULL) ? del_node->llink : del_node->rlink; if (parent == NULL) { //刪除的是根節點 root = child; } else if (parent->llink == del_node) { parent->llink = child; } else { parent->rlink = child; } }else{ //處理兩邊有子節點的情況 if(del_node == parent->rlink){ parent->rlink = del_node->llink; if(del_node->llink->rlink != NULL){ //若刪除的節點的子節點還有右節點的情況 dict *child = del_node->llink->rlink; printf("%s\n",child->key); while(child->rlink!= NULL){ //找右節點直到最底 child = child->rlink; printf("%s\n",child->key); } child->rlink = del_node->rlink; }else parent->rlink->rlink = del_node->rlink; //沒有則直接替換 }else{ parent->llink = del_node->llink; if(del_node->rlink->llink != NULL){ //若刪除的節點的子節點還有左節點的情況 dict *child = del_node->rlink->llink; printf("%s\n",child->key); while(child->llink!= NULL){ //找左節點直到最底 child = child->llink; printf("%s\n",child->key); } child->llink = del_node->llink; }else parent->llink->rlink = del_node->rlink; //沒有則直接替換 } } free(del_node); /* 釋放記憶體 */ printf("刪除w[%s]元素\n",key); } void find_newroot(){ /* 搜尋新的樹跟節點 左連結最大值*/ struct dict *newroot_node ,*prev; if(root->llink!=NULL){ //找左連結的最大值 newroot_node = root->llink; while(newroot_node->rlink!=NULL){ //找根的替代節點 prev = newroot_node; newroot_node = newroot_node->rlink; } if(newroot_node->llink!=NULL){ //若新的根節點有左節點 prev->rlink = newroot_node->llink; }else prev->rlink = NULL; if(newroot_node != root->llink ){ //若新的根節點不等於原本根的左節點 newroot_node->llink = root->llink; newroot_node->rlink = root->rlink; }else{ //若新的根節點等於原本根的左節點 newroot_node->rlink = root->rlink; } printf("刪除w[%s]元素\n",root->key); free(root); root = newroot_node; }else if(root->rlink!=NULL){ //找右連結的最小值 newroot_node = root->rlink; while(newroot_node->llink!=NULL){ //找根的替代節點 prev = newroot_node; newroot_node = newroot_node->llink; } if(newroot_node->rlink!=NULL){ //若新的根節點有右節點 prev->llink = newroot_node->rlink; }else prev->llink = NULL; if(newroot_node != root->rlink ){ //若新的根節點不等於原本根的右節點 newroot_node->llink = root->llink; newroot_node->rlink = root->rlink; }else{ //若新的根節點等於原本根的右節點 newroot_node->llink = root->llink; } printf("刪除w[%s]元素\n",root->key); free(root); root = newroot_node; } } /* 搜尋target所在節點 */ struct dict *search(char target[]){ struct dict *node; node = root; while(node != NULL) { if (strcmp(target, node->key) == 0) return node; else /* target小於目前節點,往左搜尋 */ if (strcmp(target, node->key) < 0) node = node->llink; else /* target大於目前節點,往右搜尋 */ node = node->rlink; } return node; } /* 搜尋node的父節點 */ struct dict *search_p(struct dict *node){ struct dict *parent; parent = root; while (parent != NULL) { if (strcmp(node->key, parent->key) < 0) { if (strcmp(node->key, parent->llink->key) == 0) return parent; else parent = parent->llink; } else { if (strcmp(node->key, parent->rlink->key) == 0) return parent; else parent = parent->rlink; } } return NULL; }