417 lines
12 KiB
C++
417 lines
12 KiB
C++
/*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 <stdio.h> /* for sscanf(), printf() */
|
||
#include <stdlib.h>
|
||
#include <string.h> /* for strstr(), strtok(), strtok_r() */
|
||
#include <conio.h>
|
||
#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("輸入存取字典的陳述,逕按<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);
|
||
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;
|
||
}
|