二叉樹ADT

二叉查找樹

       二叉查找樹是一種結合了二分查找策略的鏈接結構。二叉樹的每個節點都包含一個項和兩個指向其他節點(稱爲子節點:左節點/右節點)的指針。其順序按照按照如下規定:左節點的項在父節點的項的前面;右節點的項在父節點的項的後面

二叉樹

二叉樹ADT

樹定義

二叉查找樹接口(tree.h)

接口中的函數是使用二叉樹ADT的程序員可以操作的:

#ifndef _TREE_H_
#define _TREE_H_
#include<stdbool.h>

#define SLEN 20
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, Tree * ptree);

//在樹中刪除一個項

bool DeleteItem(const Item * pi, Tree * ptree);

//把函數應用於樹中每一項

void Traverse(const Tree * ptree, void (*pfun) (Item item));

//刪除樹中所有內容

void DeteleAll(Tree * ptree);

#endif

二叉樹的實現(tree.c)

//樹的支持函數
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include"tree.h"

//局部數據類型
typedef struct pair {
    Trnode * parent;
    Trnode * child;
} 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 InOrder(const Trnode * root, void (*pfun) (Item item));
static Pair SeekItem(const Item * pi, const Tree * ptree);
static void DeleteNode(Trnode **ptr);
static void DeleteAllNodes(Trnode * root);

//函數定義
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)   //樹爲空 
        ptree->root = new_node;
    else                         //樹不爲空 
        AddNode(new_node, ptree->root);

    return true; 
}

bool InTree(const Item * pi, 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;
    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;
}

//局部函數
static void InOrder(const Trnode * root, void (*pfun) (Item item))
{
    if(root != NULL)
    {
        InOrder(root->left, pfun);
        (*pfun)(root->item);
        InOrder(root->right, pfun);  
    }
}

static void DeleteAllNodes(Trnode * root)//使用遞歸從左至右刪除
{
    Trnode * pright;

    if (root != NULL)
    {
        pright = root->right;
        DeleteAllNodes(root->left);
        free(root);
        DeleteAllNodes(pright);
    }

}

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);
    }
}

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 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;
}

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;  //如果前兩項都不滿足,則必定是相等的情況 
    }

    return look;
}

static void DeleteNode(Trnode **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); 
    }
}

主程序(petclub.c)

//使用二叉樹查找數 
#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(void)
{
    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("Nerfville Pet Club Membership Program");
    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')  /* discard rest of line */
            continue;
        ch = tolower(ch);
        if (strchr("alrfndq",ch) == NULL)
            puts("Please enter an a, l, f, n, d, or q:");
        else
            break;
    }
    if (ch == EOF)       /* make EOF cause program to quit */
        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 pet kind:");
        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("No entries!");
        return;     /* quit function if tree is empty */
    }

    puts("Please enter name of pet you wish to find:");
    s_gets(temp.petname, SLEN);
    puts("Please enter pet 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 entries!");
        return;     /* quit function if tree is empty */
    }

    puts("Please enter name of pet you wish to delete:");
    s_gets(temp.petname, SLEN);
    puts("Please enter pet 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("is dropped from the club.\n");
    else
        printf("is not a member.\n");
}

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');   // look for newline
        if (find)                  // if the address is not NULL,
            *find = '\0';          // place a null character there
        else
            while (getchar() != '\n')
                continue;          // dispose of rest of line
    }
    return ret_val;
}
發佈了27 篇原創文章 · 獲贊 7 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章