基于AVL树的图书管理系统

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>
#include <conio.h>
/* status macro definition */
#define OK 1
#define ERROR 0
#define OVER_FLOW -2

/* memory length macro definition */
#define MAXNAMELEN 20
#define MAXBOOKNUMBERLEN 20
#define MAXREADERNUM 20 //the max amount of all readers
#define MAXREADERCODEDIGIT 5 //max reader code digits
#define INDENTATION 0 //for printing the BiTree

/* some macros related to AVLTree */
#define EQ(a,b) (!strcmp((a),(b)))
#define LT(a,b) (strcmp((a),(b))<0)
#define LH +1
#define EH 0
#define RH -1

typedef int Status;
typedef enum { FALSE, TRUE } boolean;
typedef char* KeyType;
typedef char NameType[MAXNAMELEN];
typedef char* BookNum, BookNumType[MAXBOOKNUMBERLEN];
typedef char TeleType[11 + 1]; //telephone: 11digits
typedef unsigned int DateType; //return date
//typedef Book DataType; //data type in TNode
void recommend();
int menu();
void menu1();
void menu2();
void password();
void SearchBST();

typedef struct {
    BookNumType number; //no prefix 'ISBN'
    NameType name;
    NameType author;
    BookNumType press;
    DateType day;
    int price;
    int page;
    int count; //current amount of the book
    int total; //total amount of the book
}Book, DataType;

typedef struct TNode {
    DataType data;
    int bf; //balance factor
    struct TNode* lchild, * rchild;
}TNode, * AVLTree;

AVLTree T;
int searchnum(AVLTree, char[]);
void print(AVLTree);

typedef struct ArcBox {
    BookNumType bknum;//书号
    NameType bknam;//书名
    DateType return_date; //e.g. 20010205
    struct ArcBox* next;
}ArcBox;

typedef struct {
    int code;
    NameType name;
    TeleType tele; //telephone
    ArcBox* first_arc;
}Reader;

typedef struct {
    Reader* readers;
    int length, size;
}AdjList;

class LibManage {//类,强化了的结构体,可以放函数进去,还有自带构造函数(创建对象时调用)和析构函数(main函数后调用)
public://访问权限,public可以让外部访问
    AVLTree tree;
    AdjList reader_list;
    DateType current_date;
    LibManage();//构造函数用于初始化
    ~LibManage() { DestoryTree(tree); }//析构函数用于释放内存
    void Menu();//菜单
    void AddBook();//加书
    void LendBook();//借书
    void ReturnBook();//还书
    void EraseBook();//删除
    void OutputBooks();
    void OutputReaders();//输出读者
    void TestMode();
    void modify();//修改
    TNode* SearchAVLTree(AVLTree T, BookNum bn);
private://private只能内部访问
    void gettime();//获取时间
    void PrintBook(Book b);
    void PrintBiTree_Simple(AVLTree T, int indent);
    void PrintBiTree_Detail(AVLTree T);
    void BookCpy(Book* a, Book b);
    void L_Rotate(AVLTree* t);
    void R_Rotate(AVLTree* t);
    void L_Balance(AVLTree* t);
    void R_Balance(AVLTree* t);
    
    Status InsertAVLTree(AVLTree* T, boolean* taller, DataType elem);
    Status DeleteAVLTree(AVLTree* curT, AVLTree preT, boolean* shorter, KeyType bknum);
    Status InitAdjList(AdjList& list);//初始化列表
    Status AddReader(AdjList& list, const Reader& r);
    Status AddReaderBook(Reader& r, const ArcBox& ab);
    Status SearchReader(AdjList list, int code);
    Status DeleteReader(AdjList& list, int code);
    Status CheckBorrowPermission(Reader r, BookNum bknum = NULL);
    ArcBox* SearchBorrowedBook(Reader r, KeyType bknum, ArcBox*& prep);
    void ReaderCpy(Reader& r1, const Reader& r2);
    void PrintReader(const Reader& r);
    void PrintBorrowedBooks(Reader r);
    void DestoryTree(AVLTree& T);
};

LibManage L;//创建对象

void LibManage::gettime() {
    //get system time and convert it to unsigned int
    time_t rawtime;
    struct tm* ptminfo;
    time(&rawtime); //get time raw info
    ptminfo = localtime(&rawtime); //convert raw time info to processed and readable time info
    current_date = ((ptminfo->tm_year) + 1900) * 10000 + (ptminfo->tm_mon) * 100 + (ptminfo->tm_mday);
    printf("Set current time:%u successfully! \n", current_date);
}

LibManage::LibManage() {
    tree = NULL; //initialize tree
    InitAdjList(reader_list); //initialize AdjList
    printf("Launch Library Management System Successfully! \n");
    gettime();

    /* Simulate a library, so add some items first */
    //book={number,name,author,press,day,price,page,count,total}
    boolean taller = FALSE;
    Book book1 = { "01","PromisedLand","Obama","wasd",2011127,127,6,8 };
    Book book2 = { "02","Humans","Stanton","工业",2022235,127,4,5 };
    Book book3 = { "03","Becoming","Michelle","工业",204950,127,0,3 };
    Book book4 = { "04","DeepEnd","Kinney","工业",50,127,0,6 };
    InsertAVLTree(&tree, &taller, book1);
    InsertAVLTree(&tree, &taller, book2);
    InsertAVLTree(&tree, &taller, book3);
    InsertAVLTree(&tree, &taller, book4);
    //reader={code,name,telephone,firstarc}
    Reader reader1 = { 1,"Sylvan","95566",NULL };
    Reader reader2 = { 2,"JIXIANG","10086",NULL };
    AddReader(reader_list, reader1);
    AddReader(reader_list, reader2);
    //reader={booknumber,bookname,return date,*next}
    ArcBox arcbox1 = { "01","PromisedLand",20251211,NULL };
    ArcBox arcbox2 = { "02","Humans",20300201,NULL };
    AddReaderBook(reader_list.readers[0], arcbox1);
    AddReaderBook(reader_list.readers[0], arcbox2);
    AddReaderBook(reader_list.readers[1], arcbox1);
}

void LibManage::DestoryTree(AVLTree& T) {
    //free the memory of the tree, using post-order traverse to guarantee that the node's parent won't get lost
    if (!T) return;
    DestoryTree(T->lchild);
    DestoryTree(T->rchild);
    free(T); T = NULL;
}

void LibManage::modify() {
    printf("--------请输入更新书籍的ID--------\n");
    char id[20];
    scanf("%s", id);
    AVLTree t = T;
    /*if (!book.num) {
        cout << "-----------图书库为空-----------" << endl;
        return ;
    }*/
    while (t) {
        if (strcmp(t->data.number, id) > 0) {
            t = t->lchild;
            continue;
        }
        if (strcmp(t->data.number, id) < 0) {
            t = t->rchild;
            continue;
        }
        if (!strcmp(t->data.number, id)) {
            print(t);
            int c = 99;
            while (c) {
                printf("--------请输入更新书籍的信息类别--------");
                printf("--------编号:1 书名:2 作者:3 价格:4 购买时间:5--------");
                printf("-------------结束请输入:0---------------");
                scanf("%d", &c);
                switch (c)
                {
                case 1: printf("--------请输入更新书籍的编号--------"); scanf("%s", t->data.number); break;
                case 2: printf("--------请输入更新书籍的书名--------"); scanf("%s", t->data.name); break;
                case 3: printf("--------请输入更新书籍的作者--------"); scanf("%s", t->data.author); break;
                case 4: printf("--------请输入更新书籍的价格--------"); scanf("%s", t->data.price); break;
                case 5: printf("------请输入更新书籍的购买时间------"); /*cin >> t->book.buyingtime.Y >> t->book.buyingtime.M >> t->book.buyingtime.D;*/ break;
                default: printf("----------------结束----------------"); break;
                }
            }

            return;
        }
    }
    printf("-----------图书库无此书-----------");
}
//the following function is related to AVLTree

void LibManage::L_Rotate(AVLTree* t) {
    //left rotate root node, and update the root
    TNode* rc = (*t)->rchild;
    (*t)->rchild = rc->lchild;
    rc->lchild = *t;
    (*t) = rc;
}
void LibManage::R_Rotate(AVLTree* t) {
    //right rotate root node, and update the root
    TNode* lc = (*t)->lchild;
    (*t)->lchild = lc->rchild;
    lc->rchild = *t;
    (*t) = lc;
}
void LibManage::L_Balance(AVLTree* t) {
    //adjust the root to make left tree balanced
    TNode* lc = (*t)->lchild, * rd;
    switch (lc->bf) { //check condition: LL or LR, through BF of root's lchild
    case EH: //a case when deleting the node
        (*t)->bf = LH; lc->bf = RH;
        R_Rotate(t);
        break;
    case LH: //LL
        (*t)->bf = lc->bf = EH; //modify BF
        R_Rotate(t); //R rotate root node
        break;
    case RH: //LR
        rd = lc->rchild;
        switch (rd->bf) { //modify BF according to different BF conditions
        case LH: lc->bf = rd->bf = EH;  (*t)->bf = RH; break;
        case EH: lc->bf = (*t)->bf = EH; break;
        case RH: rd->bf = (*t)->bf = EH; lc->bf = LH; break;
        }//switch(rd->bf)
        L_Rotate(&((*t)->lchild)); //part Left rotation, firstly
        R_Rotate(t); //root Right rotation, then
        break;
    }//switch(lc->bf)
}
void LibManage::R_Balance(AVLTree* t) {
    //adjust the root to make right tree balanced
    TNode* rc = (*t)->rchild, * ld;
    switch (rc->bf) { //check condition: RL or RR, through BF of root's rchild
    case EH: //a case when deleting the node
        (*t)->bf = RH; rc->bf = LH;
        L_Rotate(t);
        break;
    case RH: //RR
        (*t)->bf = rc->bf = EH; //modify BF
        L_Rotate(t); //L rotate root node
        break;
    case LH: //RL
        ld = rc->lchild;
        switch (ld->bf) { //modify BF according to different BF conditions
        case LH: (*t)->bf = rc->bf = EH; ld->bf = RH; break;
        case EH: rc->bf = (*t)->bf = EH; break;
        case RH: ld->bf = rc->bf = EH; (*t)->bf = LH; break;
        }//switch(rd->bf)
        R_Rotate(&((*t)->rchild)); //part Right rotation, firstly
        L_Rotate(t); //root Left rotation, then
        break;
    }//switch(lc->bf)
}

TNode* LibManage::SearchAVLTree(AVLTree T, BookNum bn) {
    /* if the booknum can be found in AVLTree, then return its address, else return NULL */
    if (!T) return NULL;
    if (EQ(bn, T->data.number)) return T;
    if (LT(bn, T->data.number)) return SearchAVLTree(T->lchild, bn);
    return SearchAVLTree(T->rchild, bn);
}

Status LibManage::InsertAVLTree(AVLTree* T, boolean* taller, DataType elem) {
    /* insert an elem to AVLTree, and adjust the tree to keep its balance. If elem has existed, then return ERROR, else return OK */
    /* parameter 'taller' means that after inserting the elem, the tree is taller or not. */
    if (!*T) { //create a new node
        *T = (TNode*)malloc(sizeof(TNode));
        if (!*T) exit(OVER_FLOW);
        BookCpy(&((*T)->data), elem);
        (*T)->bf = EH;
        (*T)->lchild = (*T)->rchild = NULL;
        *taller = TRUE;
    }
    else if (EQ(elem.number, (*T)->data.number)) {
        //if the node has already existed
        PrintBook((*T)->data);
        printf("ERROR: book <%s> has already been in the AVL Tree. \n", elem.name);
        *taller = FALSE;
        return ERROR;
    }
    else if (LT(elem.number, (*T)->data.number)) {
        //insert its left child tree
        if (!InsertAVLTree(&((*T)->lchild), taller, elem)) return ERROR;
        if (!*taller) return OK;
        switch ((*T)->bf) { //update the BF of the node
        case LH:
            //adjust to make it balanced
            L_Balance(T);
            *taller = FALSE; break;
        case EH: (*T)->bf = LH; *taller = TRUE; break;
        case RH: (*T)->bf = EH; *taller = FALSE; break;
        }//switch((*T)->bf)
    }
    else {
        //insert its right child tree
        if (!InsertAVLTree(&((*T)->rchild), taller, elem)) return ERROR;
        if (!*taller) return OK;
        switch ((*T)->bf) { //update the BF of the node
        case LH: (*T)->bf = EH; *taller = FALSE; break;
        case EH: (*T)->bf = RH; *taller = TRUE; break;
        case RH:
            //adjust to make it balanced
            R_Balance(T);
            *taller = FALSE; break;
        }//switch((*T)->bf)
    }
    return OK;
}

Status LibManage::DeleteAVLTree(AVLTree* curT, AVLTree preT, boolean* shorter, KeyType bknum) {
    /* delete a node in AVLTree according to its book number, and adjust the tree to keep its balance. If elem has existed, then return OK, else return ERROR *///©SylvanDing
    /* parameter 'shorter' means that after deleting the node, the tree is shorter or not. */
    if (!*curT) {
        //if the node doesn't exist
        printf("ERROR: Can't find BOOK: ISBN %s \n", bknum);
        *shorter = FALSE;
        return ERROR;
    }//if(!*curT)
    else if (EQ(bknum, (*curT)->data.number)) {
        //find the node, and delete it
        if (!((*curT)->lchild)) {
            //if(the node has no left child or has neither left nor right one)
            if (!preT) *curT = (*curT)->rchild;
            //if(the node has no parent)
            else if (LT(bknum, preT->data.number)) preT->lchild = (*curT)->rchild;
            //check the current node is its parent's left child or its right one
            else preT->rchild = (*curT)->rchild;
            *shorter = TRUE;
        }//if(!((*curT)->lchild))
        else if (!((*curT)->rchild)) {
            //if(the node has no right child but has left one)
            if (!preT) *curT = (*curT)->lchild;
            //if(the node has no parent)
            else if (LT(bknum, preT->data.number)) preT->lchild = (*curT)->lchild;
            //check the current node is its parent's left child or its right one
            else preT->rchild = (*curT)->lchild;
            *shorter = TRUE;
        }//else if(!((*curT)->rchild))
        else {
            //if(the node has both right and left child)
            TNode* tempT = (*curT)->lchild; //enter curT's left child
            while (tempT->rchild) //find curNode's precursor in inorder traverse
                tempT = tempT->rchild;
            BookCpy(&((*curT)->data), tempT->data); //assign the precursor's data to the node that needs to be deleted
            DeleteAVLTree(&((*curT)->lchild), NULL, shorter, tempT->data.number); //delete the precursor of the deleted elem in curT's left child
            if (!*shorter) return OK;
            switch ((*curT)->bf) {
            case LH: (*curT)->bf = EH; *shorter = TRUE; break;
            case EH: (*curT)->bf = RH; *shorter = FALSE; break;
            case RH:
                //another 3 conditions need to be considered, according to curT's right child BF
                switch ((*curT)->rchild->bf) {
                case LH: *shorter = TRUE; break;
                case EH: *shorter = FALSE; break;
                case RH: *shorter = TRUE; break;
                }//switch((*curT)->rchild->bf)
                R_Balance(curT);
            }//switch((*curT)->bf)
        }
    }//else if(EQ(bknum,(*curT)->data.number))
    else if (LT(bknum, (*curT)->data.number)) {
        //if the keynum is less than the curT's number
        if (!DeleteAVLTree(&((*curT)->lchild), *curT, shorter, bknum)) return ERROR;
        if (!*shorter) return OK;
        switch ((*curT)->bf) {
        case LH: (*curT)->bf = EH; *shorter = TRUE; break;
        case EH: (*curT)->bf = RH; *shorter = FALSE; break;
        case RH:
            //another 3 conditions need to be considered, according to curT's right child BF
            switch ((*curT)->rchild->bf) {
            case LH: *shorter = TRUE; break;
            case EH: *shorter = FALSE; break;
            case RH: *shorter = TRUE; break;
            }//switch((*curT)->rchild->bf)
            R_Balance(curT);
        }//switch((*curT)->bf)
    }//else if(LT(bknum,(*curT)->data.number))
    else {
        //if the keynum is larger than the curT's number, enter its right child
        if (!DeleteAVLTree(&((*curT)->rchild), *curT, shorter, bknum)) return ERROR;
        if (!*shorter) return OK;
        switch ((*curT)->bf) {
        case LH:
            //another 3 conditions need to be considered, according to curT's left child BF
            switch ((*curT)->lchild->bf) {
            case LH: *shorter = TRUE; break;
            case EH: *shorter = FALSE; break;
            case RH: *shorter = TRUE; break;
            }//switch((*curT)->rchild->bf)
            L_Balance(curT);
        case EH: (*curT)->bf = LH; *shorter = FALSE; break;
        case RH: (*curT)->bf = EH; *shorter = TRUE; break;
        }//switch((*curT)->bf)
    }//else
    return OK;
}

void LibManage::TestMode() {
    //this mode is for testing AVLTree's insertion and deletion quickly and easily
    Book bk = { "","","",0,0 };
    AVLTree testT = NULL; boolean flag;
    printf("- - - Testing Mode - - -\n");
    printf("//This mode allows you to test AVLTree's insertion and deletion quickly and easily. Whenever you insert or delete an item, it will print the AVLTree: KeyValue(BalanceFactor) \n//Have created a new Empty AVLTree for testing... \n//Input numbers(like 01,21,36...) to insert it, input 'end' to stop inserting. \n");
    //©SylvanDing
    do {
        flag = FALSE;
        scanf("%s", bk.number);
        getchar();
        if (EQ(bk.number, "end")) break;
        InsertAVLTree(&testT, &flag, bk);
        printf("* Tree Print * \n");
        PrintBiTree_Simple(testT, INDENTATION);
    } while (1);
    printf("//End inserting, and then you can input the item you wanna delete, input 'quit' to exit testing mode... \n");
    do {
        flag = FALSE;
        scanf("%s", bk.number);
        getchar();
        if (EQ(bk.number, "quit")) break;
        DeleteAVLTree(&testT, NULL, &flag, bk.number);
        printf("* Tree Print * \n");
        PrintBiTree_Simple(testT, INDENTATION);
    } while (1);
    printf("//Exit TESTING MODE... \n");
}

//the following function is about Library Management

void LibManage::Menu() {
    printf("* * * MENU * * *\n");
    printf("(1). 添加书籍\n");
    printf("(2). 借书\n");
    printf("(3). 还书\n");
    printf("(4). 删除\n");
    printf("(5). 输出书\n");
    printf("(6). 输出读者\n");
    printf("(7). *(Testing MODE)\n");
    printf("(0). [ E X I T ]\n");
    printf("* * * * * * * * *\n");
}

void LibManage::BookCpy(Book* a, Book b) {
    //copy b's info and assign it to a
    strcpy(a->number, b.number);
    strcpy(a->name, b.name);
    strcpy(a->author, b.author);
    a->count = b.count;
    a->total = b.total;
}

void LibManage::PrintBook(Book b) {
    printf("- - - - Book Info - - - -\n");
    printf("书名: %s\n", b.name);
    printf("作者: %s\n", b.author);
    printf("书号: ISBN %s\n", b.number);
    printf("价格: %d\n", b.price);
    printf("总计: %d\n", b.total);
    printf("数量: %d\n", b.count);
    printf("- - - - - - - - - - - - -\n");
}

void LibManage::PrintBiTree_Simple(AVLTree T, int indent) {
    if (!T) return;
    printf("%*s%s(%d)\n", indent, "", T->data.number, T->bf);
    PrintBiTree_Simple(T->lchild, indent + 1);
    PrintBiTree_Simple(T->rchild, indent + 1);
}

void LibManage::PrintBiTree_Detail(AVLTree T) {
    if (!T) return;
    PrintBook(T->data);
    PrintBiTree_Detail(T->lchild);
    PrintBiTree_Detail(T->rchild);
}

//添加新书或数量
void LibManage::AddBook() {
    //to add a new book when bknum-related book doesn't exist in AVLTree, or increase its original amount
    AVLTree* T = &tree;
    TNode* node = NULL; char flag;
    BookNumType bknum; int amount;
    printf("- - - - Add Book - - - -\n");
    printf("Book Number: ISBN ");
    scanf("%s", bknum);
    printf("Increment: ");
    scanf("%d", &amount);
    getchar();
    if (!(node = SearchAVLTree(*T, bknum))) {
        boolean taller = FALSE;
        Book new_book; NameType bk_name, aut_name;
        printf("ERROR: Can't find BOOK: ISBN %s \n Would you like to create a new item? (y/n)...\n", bknum);
        scanf("%c", &flag);
        switch (flag) {
        case 'n':
        case 'N': return; break;
        case 'y':
        case 'Y':
            printf("Number: ISBN %s\n", bknum);
            printf("Stock/Total: %d\n", amount);
            printf("Name: ");
            scanf("%s", bk_name);
            printf("Author: ");
            scanf("%s", aut_name);
            strcpy(new_book.number, bknum);
            strcpy(new_book.name, bk_name);
            strcpy(new_book.author, aut_name);
            new_book.count = new_book.total = amount;
            if (!InsertAVLTree(T, &taller, new_book)) return;
            PrintBook(new_book);
            printf("Add new book successfully!  \n");
            break;
        default: printf("Error: Wrong command, try again...\n");
        }//switch(flag)
    }//if(!(node=SearchAVLTree(*T,bknum)))
    else {
        printf("Find the BOOK...\nWould you like to increase it? (y/n)...\n");
        scanf("%c", &flag);
        switch (flag) {
        case 'n':
        case 'N': return; break;
        case 'y':
        case 'Y':
            printf("Original stock: %d \nOriginal total amount: %d \n", node->data.count, node->data.total);
            node->data.count += amount;
            node->data.total += amount;
            PrintBook(node->data);
            printf("Increase successfully! \n");
            break;
        default: printf("Error: Wrong command, try again...\n");
        }//switch(flag)
    }//else
}

void LibManage::LendBook() {
    //to lend books
    int code, index; char flag;
    printf("- - - - Lend Book - - - -\n");
    printf("Reader Code: ");
    scanf("%d", &code);
    getchar();
    if ((index = SearchReader(reader_list, code)) < 0) {
        index = reader_list.length;
        Reader newreader; newreader.first_arc = NULL;
        printf("ERROR: Can't find reader %0*d...\nWould you like to create one? (y/n)...\n", MAXREADERCODEDIGIT, code);
        scanf("%c", &flag);
        switch (flag) {
        case 'n':
        case 'N': return; break;
        case 'y':
        case 'Y':
            printf("Code: %0*d \n", MAXREADERCODEDIGIT, code);
            newreader.code = code;
            printf("Name: ");
            scanf("%s", newreader.name);
            printf("Tele: ");
            scanf("%s", newreader.tele);
            if (!AddReader(reader_list, newreader)) return;
            PrintReader(reader_list.readers[reader_list.length - 1]);
            printf("Add reader successfully! \n");
            break;
        default: printf("Error: Wrong command, try again...\n"); return;
        }//switch(flag)
    }//if(index<0)
    else {
        PrintReader(reader_list.readers[index]);
        if (!CheckBorrowPermission(reader_list.readers[index])) return;
    }//if(index>=0)
    BookNumType bknum; TNode* tptr;
    printf("Book Number to lend: ISBN ");
    scanf("%s", bknum);
    if (!CheckBorrowPermission(reader_list.readers[index], bknum)) return;
    if (!(tptr = SearchAVLTree(tree, bknum)))
        printf("ERROR: Can't find book: %s in Library System... \n", bknum);
    else if (tptr->data.count <= 0)
        printf("ERROR: Book Stock of <%s> is not enough... \n", tptr->data.name);
    else {
        ArcBox* new_arcbox = (ArcBox*)malloc(sizeof(ArcBox));
        if (!new_arcbox) exit(OVER_FLOW);
        --tptr->data.count;
        printf("Return Date(e.g.20201230): ");
        scanf("%u", &(new_arcbox->return_date));
        strcpy(new_arcbox->bknum, bknum);
        strcpy(new_arcbox->bknam, tptr->data.name);
        new_arcbox->next = reader_list.readers[index].first_arc;
        reader_list.readers[index].first_arc = new_arcbox;
        printf("Lend Book Successfully! \n");
    }
}

void LibManage::ReturnBook() {
    //to return books
    int code, index; TNode* tptr;
    BookNumType bknum; ArcBox* abptr, * pre_abptr;
    printf("- - - - Return Book - - - -\n");
    printf("Reader Code: ");
    scanf("%d", &code);
    getchar();
    if ((index = SearchReader(reader_list, code)) < 0) {
        printf("ERROR: Can't find reader %0*d...\n", MAXREADERCODEDIGIT, code);
        return;
    }
    PrintReader(reader_list.readers[index]);
    printf("Book Number to return: ISBN ");
    scanf("%s", bknum);
    if (!(abptr = SearchBorrowedBook(reader_list.readers[index], bknum, pre_abptr))) {
        printf("ERROR: No lended book: %s...\n", bknum);
        return;
    }
    if (!pre_abptr)
        reader_list.readers[index].first_arc = abptr->next;
    else
        pre_abptr->next = abptr->next;
    free(abptr);
    if (!reader_list.readers[index].first_arc) {
        printf("Warning: Reader %s has returned all books, now erase his or her info from the memory... \n", reader_list.readers[index].name);
        DeleteReader(reader_list, index);
        printf("Erased successfully! \n");
    }
    if ((tptr = SearchAVLTree(tree, bknum)))
        ++tptr->data.count;
    printf("Return Successfully! \n");
}

void LibManage::EraseBook() {
    //to erase book
    BookNumType bknum; boolean shorter;
    printf("- - - - Erase Book - - - -\n");
    printf("Book Number to erase: ISBN ");
    scanf("%s", bknum);
    getchar();
    if (DeleteAVLTree(&tree, NULL, &shorter, bknum))
        printf("Delete book successfully! \n");
}

void LibManage::OutputBooks() {
    //in-order traverse the AVLTree
    if (!tree) {
        printf("No book... \n");
        return;
    }
    PrintBiTree_Detail(tree);
}

void LibManage::OutputReaders() {
    if (reader_list.length <= 0) {
        printf("No reader... \n");
        return;
    }
    for (int i = 0; i < reader_list.length; ++i)
        PrintReader(reader_list.readers[i]);
}

//the following function is about Readers Management

Status LibManage::InitAdjList(AdjList& list) {
    //initialize reader adjacency list
    if (!(list.readers = (Reader*)malloc(MAXREADERNUM * sizeof(Reader)))) exit(OVER_FLOW);
    list.length = 0; list.size = MAXREADERNUM;
    return OK;
}

Status LibManage::AddReader(AdjList& list, const Reader& newr) {
    //add a new reader to reader list
    if (list.length >= list.size) {
        printf("ERROR: System unable to hold more readers... \n");
        return ERROR;
    }
    ReaderCpy(list.readers[list.length++], newr);
    return OK;
}

Status LibManage::AddReaderBook(Reader& r, const ArcBox& ab) {
    //for stimulating a whole library management
    //no real function
    ArcBox* abptr = (ArcBox*)malloc(sizeof(ArcBox));
    if (!abptr) exit(OVER_FLOW);
    strcpy(abptr->bknum, ab.bknum);
    strcpy(abptr->bknam, ab.bknam);
    abptr->return_date = ab.return_date;
    abptr->next = r.first_arc;
    r.first_arc = abptr;
    return OK;
}

Status LibManage::SearchReader(AdjList list, int code) {
    //if 'code' exists, then return its index, else return -1
    int index = 0;
    while (index < list.length && code != list.readers[index].code) ++index;
    if (index < list.length) return index;
    else return -1;
}

Status LibManage::DeleteReader(AdjList& list, int index) {
    while (index < list.length) {
        ReaderCpy(list.readers[index], list.readers[index + 1]);
        ++index;
    }
    --list.length;
    return OK;
}

Status LibManage::CheckBorrowPermission(Reader r, BookNum bknum) {
    //if the second parameter 'bknum'=NULL, only check whether the borrower has overdue unreturned book, if he does, return 0, else return 1
    //if the 'bknum'!=NULL, then check if there has any same book that he has already borrowed. if he does, return 0, else return 1
    ArcBox* p = r.first_arc;
    if (!bknum) {
        while (p && p->return_date >= current_date)
            p = p->next;
        if (p) {
            printf("No borrow permission: The reader has a book <%s> needs to be returned before %u \n", p->bknam, p->return_date);
            return 0;
        }
        else return 1;
    }//if(!bknum)
    else {
        while (p && !EQ(bknum, p->bknum))
            p = p->next;
        if (p) {
            printf("No borrow permission: The reader has borrowed a same book <%s>. \n", p->bknam);
            return 0;
        }
        else return 1;
    }//else
}

ArcBox* LibManage::SearchBorrowedBook(Reader r, KeyType bknum, ArcBox*& prep) {
    //if bknum can be found in reader's borrowed list, then return its arcbox's address, else return NULL.
    //prep return temp's precursor, when it has no precursor, return NULL
    ArcBox* temp = r.first_arc; prep = NULL;
    while (temp && !EQ(bknum, temp->bknum)) {
        prep = temp;
        temp = temp->next;
    }
    return temp;
}

void LibManage::ReaderCpy(Reader& r1, const Reader& r2) {
    //copy reader's info from r2 to r1
    strcpy(r1.name, r2.name);
    strcpy(r1.tele, r2.tele);
    r1.code = r2.code;
    r1.first_arc = r2.first_arc;
}

void LibManage::PrintReader(const Reader& r) {
    printf("- - - - Reader Info - - - -\n");
    printf("Name: %s\n", r.name);
    printf("Code: %0*d\n", MAXREADERCODEDIGIT, r.code);
    printf("Tele: %s\n", r.tele);
    PrintBorrowedBooks(r);
    printf("- - - - - - - - - - - - -\n");
}

void LibManage::PrintBorrowedBooks(Reader r) {
    printf("Borrowed books: \n");
    if (!r.first_arc) printf("\t(Empty) \n");
    while (r.first_arc) {
        printf("<%s> | ISBN %s |  Deadline:%u(%s)\n", r.first_arc->bknam, r.first_arc->bknum, r.first_arc->return_date, current_date > r.first_arc->return_date ? "![Overdue]!" : "[Normal]");
        r.first_arc = r.first_arc->next;
    }
}

int menu() // 主菜单
{
    int a;
    printf("===========欢迎进入图书信息管理系统==========\n");
    printf("===============请选择您的身份:==============\n");
    printf("===============管理员请输入“1”===============\n");
    printf("===============借阅者请输入“2”===============\n");
    printf("=============返回上一级请输入”0”===========\n");
    scanf("%d", &a);
    getchar();
    switch (a)
    {
    case 1:
        menu1();
        break;
    case 2:
        menu2();
        break;
    case 0:
        //welcome();
        password();
        break;
    default:
        printf("输入错误!请重新输入\n");
        menu();
        break;
    }
    return 0;
}
void menu1() // 管理员菜单
{
    int a;
    printf("--------------------\n");
    printf("  图书信息管理系统\n");
    printf("--------------------\n");
    printf("   01.热门图书推荐    \n");
    printf("   02.查找图书信息    \n");
    printf("   03.浏览图书信息    \n");
    printf("   04.录入图书信息    \n");
    printf("   05.删除图书信息    \n");
    printf("   06.修改图书信息    \n");
    printf("   07.借阅图书     \n");
    printf("   10.归还图书     \n");
    printf("   00.返回上一级       \n");
    printf("--------------------\n");
    printf("  请选择菜单选项00-08:  ");
    scanf("%d", &a);
    switch (a)
    {
    case 00:
        menu();
        break; // 主菜单
    case 01:
        recommend();
        break; // 推荐
    case 02:
        SearchBST();
        break; // 查找
    case 03:
        L.OutputBooks();
        break; // 浏览
    case 04:
        L.AddBook();
        break; // 录入
    case 05:
        L.EraseBook();
        break; // 删除
    case 06:
        L.modify();
        break; // 修改
    case 07:
        L.AddBook();
        break; // 借阅
    case 8:
        L.ReturnBook();
        break; // 归还
    default:
        printf("  选项错误!按任意键继续! ");
        getch();
        system("cls"); // 清除屏幕
    }
    menu1();
}
void menu2() // 学生菜单
{
    int a;
    printf("--------------------\n");
    printf("  图书管理系统\n");
    printf("--------------------\n");
    printf("   01.热门图书推荐    \n");
    printf("   02.查找图书信息    \n");
    printf("   03.浏览图书信息    \n");
    printf("   04.录入图书信息    \n");
    printf("   05.删除图书信息    \n");
    printf("   06.修改图书信息    \n");
    printf("   07.借阅图书     \n");
    printf("   08.归还图书     \n");
    printf("   10.返回上一级       \n");
    printf("--------------------\n");
    printf("  请选择菜单选项00-08:  ");
    scanf("%d", &a);
    switch (a)
    {
    case 00:
        menu();
        break; // 主菜单
    case 01:
        recommend();
        break; // 推荐
    case 02:
        SearchBST();
        break; // 查找
    case 03:
        L.OutputBooks();
        break; // 浏览
    case 04:
        L.AddBook();
        break; // 录入
    case 05:
        L.EraseBook();
        break; // 删除
    case 06:
        L.modify();
        break; // 修改
    case 07:
        L.LendBook();
        break; // 借阅
    case 10:
        L.ReturnBook();
        break; // 归还
    default:
        printf("  选项错误!按任意键继续! ");
        getch();
        system("cls"); // 清除屏幕
    }
    menu2();
}
void password() // 用户身份验证,登录验证
{
    int i;
    char pw[5];
    printf("请输入密码: ");
    scanf("%s", pw);
    if (strcmp(pw, "123") == 0) // 默认密码为123
    {
        printf("密码正确,登录成功!\n");
        printf("按任意键进入主菜单");
        getch();
        system("cls"); // 清除屏幕
        menu();        // 调用主菜单函数
    }
    else
    {
        printf("密码错误,请重新输入密码!\n");
        printf("密码提示:默认密码为123\n");
        password();
    }
}
void recommend() {
    for (int i = 0; i < L.reader_list.length; ++i)
    while (L.reader_list.readers->first_arc) {
        printf("<%s> | ISBN %s \n", L.reader_list.readers->first_arc->bknam, L.reader_list.readers->first_arc->bknum);
        L.reader_list.readers->first_arc = L.reader_list.readers->first_arc->next;
    }
}
void print(AVLTree T) {
    printf("书号:%s ", T->data.number);
    printf("书名:%s ", T->data.name);
    printf("作者:%s ", T->data.author);
    printf("出版社:%s  ", T->data.press);
    printf("价格:%d ", T->data.price);
    printf("出版日期:%d ", T->data.day);
    printf("页码:%d ", T->data.page);
    printf("数量:%d ", T->data.count);
}


int searchnum(AVLTree T, char number[])
{
    if (T) {
        searchnum(T->lchild, number);//遍历当前结点的左子树
        if (strcmp(T->data.number, number) == 0) print(T);     //访问当前结点
        searchnum(T->rchild, number);//遍历当前结点的右子树
    }
    return 0;
}
int searchname(AVLTree T, char* bkname)
{
    if (T) {
        searchname(T->lchild, bkname);//遍历当前结点的左子树
        if (strcmp(T->data.name, bkname) == 0) print(T);     //访问当前结点
        searchname(T->rchild, bkname);//遍历当前结点的右子树
    }
    return 0;
}
int searchauthor(AVLTree T, char athor[])
{
    if (T) {
        searchauthor(T->lchild,athor);//遍历当前结点的左子树
        if (strcmp(T->data.author, athor) == 0) print(T);     //访问当前结点
        searchauthor(T->rchild,athor);//遍历当前结点的右子树
    }
    return 0;
}

void SearchBST() // 查询
{
    int a;
    do{
        char number[20], bkname[20], athor[20];
        printf("·····欢迎进入图书信息查询界面·····\n");
        printf("·······1.搜索书号查询········\n");
        printf("·······2.搜索书名查询········\n");
        printf("·······3.搜索作者查询········\n");
        printf("·······0.退出返回主菜单·······\n");
        printf("请输入序号: \n");
        scanf("%d", &a);
        getchar();
        switch (a)
        {
        case 0:break;
        case 1:
            printf("请输入书号:\n");
            scanf("%s", number);
            //searchnum(L.tree, number);
            print(L.SearchAVLTree(L.tree, number));
            //printf("抱歉!您所查询的图书不存在!\n");
            printf("按任意键返回上一级\n");
            getch();
            
            break;
        case 2:
            printf("请输入书名:\n");
            scanf("%s", bkname);
            searchname(L.tree, bkname);
            //printf("抱歉!您所查询的图书不存在!\n");
            printf("按任意键返回上一级\n");
            getch();
            //SearchBST();
            break;
        case 3:
            printf("请输入作者:\n");
            scanf("%s", athor);
            searchauthor(L.tree, athor);
            printf("按任意键返回上一级\n");
            getch();
            break;
        default:
            printf("  选项错误!按任意键继续! ");
            getch();
            system("cls"); // 清除屏幕
        }
    }while (a);
}

int main(int argc, char* argv[]) {
    password();
    //LibManage LMSystem;
    int opt;
   
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值