C實現二叉樹
阿新 • • 發佈:2019-01-01
建立介面
/*tree.h -- 二叉查詢樹*/ #pragma once //只編譯一次 #define SLEN 20 /*根據具體情況定義Item*/ typedef struct item { char petname[SLEN]; char petkind[SLEN]; }Item; #define MAXITEMS 10 typedef struct trnode { Item item; struct trnode *left; struct trnode *right; }Trnode; typedef struct tree { Trnode *root; int size; }Tree; void InitializeTree(Tree *ptree); //初始化 bool TreeIsEmpty(const Tree *ptree); //判斷是否為空 bool TreeIsFull(const Tree *ptree); //判斷是否已滿 int TreeItemCount(const Tree *ptree); //返回樹的項數 bool AddItem(const Item *pi, Tree *ptree); //新增項 bool InTree(const Item *pi, const Tree *ptree); //查詢 bool DeleteItem(const Item *pi, Tree *ptree); //刪除項 /*把函式應用於樹中的每一項(遍歷樹)*/ void Traverse(const Tree *ptree, void(*pfun)(Item item)); void DeleteAll(Tree *ptree); //清空樹
實現介面
/*function.cpp,實現介面*/ #include<stdio.h> #include<stdlib.h> #include<string.h> #include"tree.h" /*區域性資料型別*/ typedef struct pair { /*包含兩個指向樹節點的指標*/ Trnode *child; /*用於SeekItem()函式*/ Trnode *parent; }Pair; ///////////////////////////////////////////////////// /*區域性函式的原型*/ static Trnode *MakeNode(const Item *pi); static bool ToLeft(const Item *i1, const Item *i2); static bool ToRight(const Item *i1, const Item *i2); static void AddNode(Trnode *new_node, Trnode *root); static void DeleteNode(Trnode **ptr); static Pair SeekItem(const Item *pi, const Tree *ptree); static void InOrder(const Trnode *root, void(*pfun)(Item item)); static void DeleteAllNodes(Trnode *root); ////////////////////////////////////////////////////// /*為新節點分配記憶體 MakeNode()函式*/ static Trnode * MakeNode(const Item *pi) { Trnode *new_node; new_node = (Trnode *)malloc(sizeof(Trnode)); if (new_node != NULL) { new_node->item = *pi; new_node->left = NULL; new_node->right = NULL; } return new_node; } /*新增節點到非空樹中 AddNode()函式*/ static bool ToLeft(const Item *i1, const Item *i2) { int comp1; if ((comp1 = strcmp(i1->petname, i2->petname)) < 0) return true; else if (comp1 == 0 && strcmp(i1->petkind, i2->petkind) < 0) return true; else return false; } static bool ToRight(const Item *i1, const Item *i2) { int comp1; if ((comp1 = strcmp(i1->petname, i2->petname)) > 0) return true; else if (comp1 == 0 && strcmp(i1->petkind, i2->petkind) > 0) return true; else return false; } static void AddNode(Trnode *new_node, Trnode *root) { if (ToLeft(&new_node->item, &root->item)) { if (root->left == NULL) root->left = new_node; else AddNode(new_node, root->left); } else if (ToRight(&new_node->item, &root->item)) { if (root->right == NULL) root->right = new_node; else AddNode(new_node, root->right); } else { fprintf(stderr, "location error in AddNode()\n"); exit(1); } } /*查詢項 SeekItem()函式*/ static Pair SeekItem(const Item *pi, const Tree *ptree) { Pair look; look.parent = NULL; look.child = ptree->root; if (look.child == NULL) return look; //提前退出 while (look.child != NULL) { if (ToLeft(pi, &(look.child->item))) { look.parent = look.child; look.child = look.child->left; } else if (ToRight(pi, &(look.child->item))) { look.parent = look.child; look.child = look.child->right; } else //如果兩種情況都不滿足,則必定相等 break; //look,child目標項的節點 } return look; } /*刪除一個節點,用於DeleteItem()*/ static void DeleteNode(Trnode **ptr) /*ptr是指向目標節點的父節點指標成員的地址*/ { Trnode *temp; if ((*ptr)->left == NULL) { temp = *ptr; *ptr = (*ptr)->right; free(temp); } else if ((*ptr)->right == NULL) { temp = *ptr; *ptr = (*ptr)->left; free(temp); } else /*被刪除的節點有兩個子節點*/ { /*找到重新連線右子樹的位置*/ for (temp = (*ptr)->left; temp->right != NULL; temp = temp->right) continue; temp->right = (*ptr)->right; temp = *ptr; *ptr = (*ptr)->left; free(temp); } } /*InOrder()用於Traverse()*/ static void InOrder(const Trnode *root, void(*pfun)(Item item)) { if (root != NULL) { InOrder(root->left, pfun); (*pfun)(root->item); InOrder(root->right, pfun); } } /*DeleteAllNodes()用於DeleteAll()*/ static void DeleteAllNodes(Trnode *root) //主要作用為釋放記憶體 { Trnode *pright; if (root != NULL) { pright = root->right; DeleteAllNodes(root->left); free(root); DeleteAllNodes(pright); } } //------------------------------------------------------------------------------- /*$初始化*/ void InitializeTree(Tree *ptree) { ptree->root = NULL; ptree->size = 0; } /*$判斷樹是否為空*/ bool TreeIsEmpty(const Tree *ptree) { if (ptree->root == NULL) return true; else return false; } /*$判斷樹是否已滿*/ bool TreeIsFull(const Tree *ptree) { if (ptree->size == MAXITEMS) return true; else return false; } /*$返回樹的項數*/ int TreeItemCount(const Tree *ptree) { return ptree->size; } /*$新增項*/ bool AddItem(const Item *pi, Tree *ptree) { Trnode *new_node; if (TreeIsFull(ptree)) { fprintf(stderr, "Tree is full!\n"); return false; } if (SeekItem(pi, ptree).child != NULL) { fprintf(stderr, "Attempted to add duplicate item\n"); return false; } new_node = MakeNode(pi); if (new_node == NULL) { fprintf(stderr, "couldn't create node\n"); return false; } /*成功建立了一個新的節點*/ ptree->size++; if (ptree->root == NULL) /*情況1:樹為空*/ ptree->root = new_node; /*新節點是根節點*/ else /*情況2:樹不為空*/ AddNode(new_node, ptree->root);/*在樹中新增一個節點*/ return true; } /*$查詢項*/ bool InTree(const Item *pi, const Tree *ptree) { return (SeekItem(pi, ptree).child == NULL )? false : true; } /*$刪除一個項(承接上面,主要功能為將節點與特定項關聯)*/ bool DeleteItem(const Item *pi, Tree *ptree) { Pair look; look = SeekItem(pi, ptree); if (look.child == NULL) return false; if (look.parent == NULL) //刪除根節點 DeleteNode(&ptree->root);//此時根節點即為所尋找的節點 else if (look.parent->left == look.child) DeleteNode(&look.parent->left); else DeleteNode(&look.parent->right); ptree->size--; return true; } /*$遍歷樹*/ void Traverse(const Tree *ptree, void(*pfun)(Item item)) { if (ptree != NULL) InOrder(ptree->root, pfun); } /*$清空樹*/ void DeleteAll(Tree *ptree) { if (ptree != NULL) DeleteAllNodes(ptree->root); ptree->root = NULL; ptree->size = 0; }
使用介面
/*petclub.cpp--使用二叉樹*/ #include<stdio.h> #include<string.h> #include<ctype.h> #include"tree.h" char menu(void); void addpet(Tree *pt); void droppet(Tree *pt); void showpets(const Tree *pt); void findpet(const Tree *pt); void printitem(Item item); void uppercase(char *str); char *s_gets(char *st, int n); int main() { Tree pets; char choice; InitializeTree(&pets); while ((choice = menu()) != 'q') { switch (choice) { case 'a':addpet(&pets);break; case 'l':showpets(&pets); break; case 'f':findpet(&pets); break; case 'n':printf("%d pets in club\n", TreeItemCount(&pets)); break; case 'd':droppet(&pets); break; default:puts("Switching error"); } } DeleteAll(&pets); puts("Bye!"); return 0; } // char menu(void) { int ch; puts("Enter the letter corresponding to your choice:"); puts("a.add a pet l.show list of pets"); puts("n.number of pets f.find pets"); puts("d.delete a pet q.quit"); while ((ch = getchar()) != EOF) { while (getchar() != '\n') continue; ch = tolower(ch); if (strchr("alnfdgq", ch) == NULL) puts("please enter an a,l,n,f,d,g,q:"); else break; } if (ch == EOF) ch = 'q'; return ch; } void addpet(Tree *pt) { Item temp; if (TreeIsFull(pt)) puts("No room in the club!"); else { puts("Please enter name of pet:"); s_gets(temp.petname, SLEN); puts("Please enter petkind:"); s_gets(temp.petkind, SLEN); uppercase(temp.petname); uppercase(temp.petkind); AddItem(&temp, pt); } } void showpets(const Tree *pt) { if (TreeIsEmpty(pt)) puts("No entries!"); else Traverse(pt, printitem); } void printitem(Item item) { printf("Pet:%-19s kind:%-19s\n", item.petname, item.petkind); } void findpet(const Tree *pt) { Item temp; if (TreeIsEmpty(pt)) { puts("empty!"); return; } puts("Please enter name:"); s_gets(temp.petname, SLEN); puts("And then enter kind:"); s_gets(temp.petkind, SLEN); uppercase(temp.petname); uppercase(temp.petkind); printf("%s the %s", temp.petname, temp.petkind); if (InTree(&temp, pt)) printf("is a member.\n"); else printf("is not a member.\n"); } void droppet(Tree *pt) { Item temp; if (TreeIsEmpty(pt)) { puts("No members."); return; } puts("Enter the name:"); s_gets(temp.petname, SLEN); puts("Then enter kind:"); s_gets(temp.petkind, SLEN); uppercase(temp.petname); uppercase(temp.petkind); printf("%s the %s", temp.petname, temp.petkind); if (DeleteItem(&temp, pt)) printf("Done!\n"); else puts("Fault!"); } void uppercase(char *str) { while (*str) { *str = toupper(*str); str++; } } char *s_gets(char *st, int n) { char *ret_val; char *find; ret_val = fgets(st, n, stdin); if (ret_val) { find = strchr(st, '\n'); //查詢換行符 if (find) *find = '\0'; //在此處放置一個空字元 else while (getchar() != '\n') continue; //處理輸入行的剩餘內容 } return ret_val; }