图书管理系统
懒得加注释了(手动滑稽)
单纯记录一下,还是有很多不完善的地方。。。
BMS.h
typedef struct BOOK {
unsigned int number;
char name[81];
char author[81];
char press[81];
char intro[501];
unsigned char type;
double price;
unsigned int quantity;
unsigned int borrowNum;
unsigned int borrower[10];
struct BOOK *next, *left, *right, *parent;
int height;
}Book;
typedef struct ACCOUNT {
unsigned int number;
char name[81];
char password[21];
unsigned int totalBook;
unsigned int book[10];
bool admini;
struct ACCOUNT *next;
}Account;
bool appendToAny(void **h, void *p, void *next(void *p), void nextToAny(void *p, void *q));
void *nextBook(void *p);
void nextToBook(void *p, void *q);
void *nextAccount(void *p);
void nextToAccount(void *p, void *q);
bool insertHashTree(Book *p);
Book *insertTree(Book *node, Book *root, Book *parent);
void inOrderTraverse(Book *root);
void setBookNumber(Book *p);
void setAccountNumber(Account *p);
int getHash(char s[]);
void *deleteAny(void **h, int total, void *unknown, int (*cmpAny)(void *unknown, void *p),
void *next(void *p), void (*nextToAny)(void *p, void *q));
Book *deleteTreeNode(Book *p, Book *root);
Book *searchByNumberInTree(int number, Book *root);
Book *searchByNameInTree(char str[]);
void *searchCertainAnyInList(void *h, int total, void *unknown, int (*cmpAny)(void *unknown, void *p),
void *next(void *p));
int searchAnyInList(void *h, int total, void *unknown, int (*cmpAny)(void *unknown, void *p),
void *next(void *p));
int cmpBookName(void *unknown, void *p);
int cmpBookNumber(void *unknown, void *p);
int cmpBookAuthor(void *unknown, void *p);
int cmpBookPress(void *unknown, void *p);
int cmpBookIntro(void *unknown, void *p);
int cmpBookPrice(void *unknown, void *p);
int cmpAccountName(void *unknown, void *p);
int cmpAccountNumber(void *unknown, void *p);
void SortAnyInList(void *h, int total, void *nextAny(void *p), int (*ifAnyLwr)(void *fst, void *snd),
void (*xchgAny)(void *fst, void *snd), int key);
void *nextBookNode(void *p);
int ifNumberLwr(void *fst, void *snd);
int ifNameLwr(void *fst, void *snd);
int ifAuthorLwr(void *fst, void *snd);
int ifPressLwr(void *fst, void *snd);
int ifIntroLwr(void *fst, void *snd);
int ifPriceLwr(void *fst, void *snd);
void xchgNode(void *fst, void *snd);
bool memoryBook(char *fName, Book *h, int total);
bool readBook(char *fName, Book **h, int *total);
bool memoryAccount(char *fName, Account *h, int total);
bool readAccount(char *fName, Account **h, int *total);
bool memorySettings();
bool readSettings();
void printDelimiter();
void scanBook(Book *p);
void scanAccount(Account *p);
void printBook(void *p);
void printAccount(void *p);
int inputNextStr(FILE *in, char s[], int size);
int inputNextPassword(char s[], int size);
int loginMenu();
int operationMenu(Account *q);
int settingMenu(Account *q);
int searchMenu();
int searchMenuA();
int detailMenu();
int againMenu();
int readWriteMenu();
int classMenu();
int sortMenu();
main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "BMS.h"
#define UNSET(h, k1, k2) h[k1][ k2/8] ^= 0x01 << (k2 % 8)
char FName[21] = "Book.txt", FNameA[21] = "Account.txt", Color[9] = "color 07";
//提前声明、定义,防止预读取设置时出错
int main(int argc, char *argv[]) {
extern Book *HashTable[6];
extern char Hits[1064][13];
extern char HitsA[8][125];
int i, j, n, t, total = 0, totalA = 0, num, again, key;
int state = 0; //状态量,0为登录,1为操作,2为设置
char str[81];
double f;
Book *p, *q, *head = NULL;
Account *pA, *qA = NULL, *headA = NULL;
//预读取
readSettings();
readBook(FName, &head, &total);
readAccount(FNameA, &headA, &totalA);
printDelimiter();
//开始
while(1)
switch(state) {
case 0:
while(state == 0 && (n = loginMenu()) >= 0 && n <= 4) {//登录界面
printDelimiter();
switch(n) {
case 0:
printDelimiter();
return 0;
case 1: //登录
if(headA == NULL) {
printf("Here is no valid Account\n");
break;
}
printf("Please enter Account name and Password\n");
printf("Account name (end with |) (Up to 80 characters):\n");
inputNextStr(stdin, str, 81);
if((qA = searchCertainAnyInList(headA, totalA, str, cmpAccountName, nextAccount)) != NULL) {
printf("Password (between 8 to 20 characters):\n");
i = inputNextPassword(str, 21);
for(j = 0; j < i; j++)
putchar('*');
putchar('\n');
if(!strcmp(str, qA->password)){
printf("Congratulations\n");
state = 1;
}
else
printf("Wrong Password\n");
}
else
printf("Wrong Name\n");
printDelimiter();
break;
case 2: //注册账号并插入链表中
if(!(pA = (Account *)malloc(sizeof(Account)))) {
printf("Out Of Space!\n");
break;
}
scanAccount(pA);
if((qA = searchCertainAnyInList(headA, totalA, pA->name, cmpAccountName, nextAccount)) != NULL) {
printf("This name has been registered\n");
free(pA);
}
else if(appendToAny((void **)&headA, pA, nextAccount, nextToAccount)) {
setAccountNumber(pA);
printf("It\'s number is %d\n", pA->number);
pA->totalBook = 0;
pA->admini = false;
totalA++;
}
else
printf("ERROR!\n");
printDelimiter();
break;
case 3: //游客模式
state = 1;
printDelimiter();
break;
case 4: //设置
state = 2;
printDelimiter();
break;
}
}
break;
case 1:
while(state == 1 && (n = operationMenu(qA)) >= 0 && n <= 12 ) { //操作界面
printDelimiter();
switch(n) {
case 0:
printDelimiter();
return 0;
case 1: //添加图书
do {
if(!(p = (Book *)malloc(sizeof(Book)))) {
printf("Out Of Space!\n");
break;
}
scanBook(p);
if((q = searchByNameInTree(p->name))) {
printf("Here has had this book\n");
printf("So automatically plus the quantity\n");
q->quantity += p->quantity;
free(p);
}
else if(appendToAny((void **)&head, p, nextBook, nextToBook) && insertHashTree(p)) {
setBookNumber(p);
printf("It\'s number is %d\n", p->number);
p->borrowNum = 0;
total++;
}
else
printf("ERROR\n");
}while((again = againMenu()) == 1);
if(again == 0)
return 0;
printDelimiter();
break;
case 2: //删除图书
do {
if(head == NULL) {
printf("Here is no book\n");
break;
}
num = detailMenu();
switch(num) {
case 0:
break;
case 1:
printf("Please enter deleted book\'s name (end with |) (Up to 80 characters):\n");
inputNextStr(stdin, str, 81);
if((q = (Book *)deleteAny((void **)&head, total, str, cmpBookName, nextBook, nextToBook)) != NULL) {
printf("%s has been deleted\n", q->name);
HashTable[q->type] = deleteTreeNode(q, HashTable[q->type]);
UNSET(Hits, q->number/100, q->number%100);
free(q);
total--;
}
else
printf("ERROR\n");
break;
case 2:
printf("Please enter deleted book\'s number:\n");
scanf("%d", &key);
if((q = (Book *)deleteAny((void **)&head, total, &key, cmpBookNumber, nextBook, nextToBook)) != NULL) {
printf("%s has been deleted\n", q->name);
HashTable[q->type] = deleteTreeNode(q, HashTable[q->type]);
UNSET(Hits, q->number/100, q->number%100);
free(q);
total--;
}
else
printf("ERROR\n");
break;
}
}while(num != 0 && (again = againMenu()) == 1);
if(num != 0 && again == 0)
return 0;
printDelimiter();
break;
case 4: //写入文件
if(head == NULL) {
printf("Here is no book\n");
break;
}
if(headA == NULL) {
printf("Here is no Account\n");
break;
}
num = readWriteMenu();
switch(num) {
case 0:
break;
case 1:
if(memoryBook(FName, head, total) && memoryAccount(FNameA, headA, totalA))
printf("Memory successfully\n");
else
printf("ERROR\n");
break;
case 2:
printf("Please enter the file name\n");
scanf("%s", str);
if(strstr(str, ".txt") || strstr(str, ".bat")) {
if(!strcmp(str, FName) || !strcmp(str, FNameA)) {
printf("Conflict\n");
break;
}
else if(memoryBook(str, head, total) && memoryBook(FName, head, total) && memoryAccount(FNameA, headA, totalA))
printf("Wirte Book successfully\n");
else
printf("Write Book ERROR\n");
}
else {
printf("Format of FIle ERROR\n");
}
break;
case 3:
printf("Please enter the file name\n");
scanf("%s", str);
if(strstr(str, ".txt") || strstr(str, ".bat")) {
if(!strcmp(str, FName) || !strcmp(str, FNameA)) {
printf("Conflict\n");
break;
}
else if(memoryAccount(str, headA, totalA) && memoryBook(FName, head, total) && memoryAccount(FNameA, headA, totalA))
printf("Wirte Account successfully\n");
else
printf("Write Account ERROR\n");
}
else {
printf("Format of FIle ERROR\n");
}
break;
}
printDelimiter();
break;
case 5: //从文件中读取
num = readWriteMenu();
switch(num) {
case 0:
break;
case 1:
printf("Please enter File Name\n");
scanf("%s", str);
if(!strstr(str, ".txt") || !strstr(str, ".bat"))
printf("Format of FIle ERROR\n");
else if(strcmp(FName, str))
printf("You couldn\'t read default file again\n");
else if(readBook(FName, &head, &total))
printf("Memory successfully\n");
else
printf("ERROR\n");
break;
case 2:
printf("Please enter File Name\n");
scanf("%s", str);
if(!strstr(str, ".txt") || !strstr(str, ".bat"))
printf("Format of FIle ERROR\n");
else if(strcmp(FNameA, str))
printf("You couldn\'t read default file again\n");
else if(readAccount(FNameA, &headA, &totalA))
printf("Memory successfully\n");
else
printf("ERROR\n");
break;
}
printDelimiter();
break;
case 8: //借书
case 3: //修改图书数据
case 6: //查找图书
if(head == NULL){
printf("Here is no book\n");
break;
}
do {
printf("Search\n");
num = searchMenu();
switch(num) {
case 0:
break;
case 1:
printf("Name (end with |) (Up to 80 characters):\n");
inputNextStr(stdin, str, 81);
if((q = searchByNameInTree(str)) == NULL)
printf("ERROR\n");
else
printBook(q);
break;
case 2:
printf("Number:\n");
scanf("%d", &key);
if((q = searchByNumberInTree(key, HashTable[key/10000-1])) == NULL)
printf("ERROR\n");
else
printBook(q);
break;
case 3:
printf("Author (end with |) (Up to 80 characters):\n");
inputNextStr(stdin, str, 81);
if(!searchAnyInList(head, total, str, cmpBookAuthor, nextBook))
printf("ERROR\n");
break;
case 4:
printf("Press (end with |) (Up to 80 characters):\n");
inputNextStr(stdin, str, 81);
if(!searchAnyInList(head, total, str, cmpBookPress, nextBook))
printf("ERROR\n");
break;
case 5:
printf("Introduction (end with |) (Up to 500 characters):\n");
inputNextStr(stdin, str, 501);
if(!searchAnyInList(head, total, str, cmpBookIntro, nextBook))
printf("ERROR\n");
break;
case 6:
printf("Price:\n");
scanf("%lf", &f);
if(!searchAnyInList(head, total, &f, cmpBookPrice, nextBook))
printf("ERROR\n");
break;
case 7:
printf("Type:\n");
scanf("%d", &key);
if(HashTable[key] == NULL)
printf("ERROR");
else
inOrderTraverse(HashTable[key]);
break;
case 8:
for(i = 0, q = head; i < total; i++, q = q->next)
printBook(q);
break;
}
if(num != 0 && (n == 3 || n == 8)) { //修改或借书
if(num > 2 && num <= 6) { //非编号或名字查询,不具有唯一性,需要再次筛选
printf("Narrow the range\n");
num = detailMenu();
if(num == 1) {
printf("Name (end with |) (Up to 80 characters):\n");
inputNextStr(stdin, str, 81);
if((q = searchByNameInTree(str)) == NULL)
printf("ERROR\n");
else
printBook(q);
break;
}
else {
printf("Number:\n");
scanf("%d", &key);
if((q = searchByNumberInTree(key, HashTable[key/10000-1])) == NULL)
printf("ERROR\n");
else
printBook(q);
break;
}
}
if(num != 0 && n == 3) { //修改
printf("What do you want to revise?\n");
num = searchMenu();
switch(num) {
case 0:
break;
case 1:
printf("Name (end with |) (Up to 80 characters):\n");
inputNextStr(stdin, str, 81);
strcpy(q->name, str);
deleteTreeNode(q, HashTable[p->number/10000-1]);
UNSET(Hits, q->number/100, q->number%100);
setBookNumber(q);
insertHashTree(q);
break;
case 2:
printf("It\'s not allowed\n");
break;
case 3:
printf("Author (end with |) (Up to 80 characters):\n");
inputNextStr(stdin, str, 81);
strcpy(q->author, str);
break;
case 4:
printf("Press (end with |) (Up to 80 characters):\n");
inputNextStr(stdin, str, 81);
strcpy(q->press, str);
break;
case 5:
printf("Introduction (end with |) (Up to 500 characters):\n");
inputNextStr(stdin, str, 501);
strcpy(q->intro, str);
break;
case 6:
printf("Price:\n");
scanf("%lf", &f);
q->price = f;
break;
case 7:
printf("Type:\n");
scanf("%d", &key);
deleteTreeNode(q, HashTable[p->number/10000-1]);
UNSET(Hits, q->number/100, q->number%100);
q->type = key;
setBookNumber(q);
insertHashTree(q);
break;
}
}
//借书
else //若账号登录状态,则可以借书
if(num != 0 && qA->totalBook >= 10){ //借书上限为十本,超过不可以借书
printf("You has borrowed 10 books!\n");
}
else if(num != 0 && qA->totalBook < 10){
printf("The number of %s is %d\n", q->name, q->quantity - q->borrowNum);
printf("How many books do you want to borrow?\n");
scanf("%d", &key);
if(key > q->quantity - q->borrowNum)
printf("Here hasn\'st so many books\n");
else if(key + qA->totalBook > 10)
printf("You couldn\'t borrow so many books\n");
else {
for(; key > 0; key--) {
q->borrower[q->borrowNum++] = qA->number;
qA->book[qA->totalBook++] = q->number;
}
printf("Borrow complete\n");
}
}
}
}while(num != 0 && (again = againMenu()) == 1);
if(num != 0 && again == 0)
return 0;
printDelimiter();
break;
case 7: //排序
if(head == NULL){
printf("Here is no book\n");
break;
}
do {
key = sortMenu();
num = searchMenu();
switch(num) {
case 0:
break;
case 1:
SortAnyInList(&head, total, nextBookNode, ifNameLwr, xchgNode, key);
break;
case 2:
SortAnyInList(&head, total, nextBookNode, ifNumberLwr, xchgNode, key);
break;
case 3:
SortAnyInList(&head, total, nextBookNode, ifAuthorLwr, xchgNode, key);
break;
case 4:
SortAnyInList(&head, total, nextBookNode, ifPressLwr, xchgNode, key);
break;
case 5:
SortAnyInList(&head, total, nextBookNode, ifIntroLwr, xchgNode, key);
break;
case 6:
SortAnyInList(&head, total, nextBookNode, ifPriceLwr, xchgNode, key);
break;
}
if(num != 0) {
printf("Sort Successfully\n");
}
}while(num != 0 && (again = againMenu()) == 1);
if(num != 0 && again == 0)
return 0;
printDelimiter();
break;
case 9: //还书
if(!qA->totalBook) {
printf("You hadn\'t borrowed any book!\n");
}
else {
printf("You had borrowed these books:\n");
for(i = 0; i < qA->totalBook; i++) {
printf("[%d]%d\n", i, qA->book[i]);
}
printf("Choose index to return book\n");
scanf("%d", &key);
if(key >= 0 && key < qA->totalBook) {
q = searchByNumberInTree(qA->book[key], HashTable[qA->book[key]/10000-1]);
i = 0;
while(i < q->borrowNum && q->borrower[i] != qA->number)
i++;
if(i < q->borrowNum) {
//将数组中最后一个有效位覆盖要移除的那一位数据,并把最后一个有效位移除
q->borrower[i] = q->borrower[q->borrowNum-1];
q->borrower[q->borrowNum-1] = 0;
q->borrowNum--;
qA->book[key] = qA->book[qA->totalBook-1];
qA->book[qA->totalBook-1] = 0;
qA->totalBook--;
printf("Return Book complete\n");
}
else {
printf("ERROR\n");
}
}
else {
printf("Out of Range\n");
}
}
printDelimiter();
break;
case 10: //删除账号
do {
if(headA == NULL) {
printf("Here is no Account\n");
break;
}
num = detailMenu();
switch(num) {
case 0:
break;
case 1:
printf("Please enter deleted Account\'s name (end with |) (Up to 80 characters):\n");
inputNextStr(stdin, str, 81);
if(!strcmp(str, qA->name))
printf("You couldn\'t delete the account you are using\n");
else if((pA = (Account *)deleteAny((void **)&headA, totalA, str, cmpAccountName, nextAccount, nextToAccount)) != NULL) {
printf("%s has been deleted\n", pA->name);
UNSET(HitsA, pA->number/100, pA->number%100);
free(pA);
totalA--;
}
else
printf("ERROR\n");
break;
case 2:
printf("Please enter deleted Account\'s number:\n");
scanf("%d", &key);
if(key == qA->number)
printf("You couldn\'t delete the account you are using\n");
else if((pA = (Account *)deleteAny((void **)&headA, totalA, &key, cmpAccountNumber, nextAccount, nextToAccount)) != NULL) {
printf("%s has been deleted\n", pA->name);
UNSET(HitsA, pA->number/100, pA->number%100);
free(pA);
totalA--;
}
else
printf("ERROR\n");
break;
}
}while(num != 0 && (again = againMenu()) == 1);
if(num != 0 && again == 0)
return 0;
printDelimiter();
break;
case 11: //查找账号
if(headA == NULL) {
printf("Here is no Account\n");
break;
}
do {
num = searchMenuA();
switch(num) {
case 0:
break;
case 1:
printf("Name (end with |) (Up to 80 characters):");
inputNextStr(stdin, str, 81);
if((pA = searchCertainAnyInList(headA, totalA, str, cmpAccountName, nextAccount)) == NULL)
printf("ERROR\n");
else
printAccount(pA);
break;
case 2:
printf("Number:");
scanf("%d", &key);
if((pA = searchCertainAnyInList(headA, totalA, &key, cmpAccountNumber, nextAccount)) == NULL)
printf("ERROR\n");
else
printAccount(pA);
break;
case 3:
for(i = 0, pA = headA; i < totalA; i++, pA = pA->next)
printAccount(pA);
break;
}
}while(num != 0 && (again = againMenu()) == 1);
if(num != 0 && again == 0)
return 0;
printDelimiter();
break;
case 12: //设置
state = 2;
printDelimiter();
break;
}
}
break;
case 2: //设置界面
while(state == 2 && (n = settingMenu(qA)) >= 0 && n <= 7) {
printDelimiter();
switch(n) {
case 0:
if(memorySettings())
printf("Set successfully\n");
memoryBook(FName, head, total);
memoryAccount(FNameA, headA, totalA);
printDelimiter();
return 0;
case 1:
qA = NULL;
state = 0;
printDelimiter();
break;
case 2:
printf("[0]Black [1]Blue [2]Green [3]Lake Blue\n");
printf("[4]Red [5]Purple [6]Yellow [7]White\n");
printf("[8]Gray [9]Light Blue [10]Light Green [11]Cyan\n");
printf("[12]Light Red [13]Light Purple [14]Light Yellow [15]Light White\n");
printf("Set Background Color\n");
scanf("%d", &n);
Color[6] = (n < 10) ? n+48 : n+87;
printf("Set Font Color\n");
scanf("%d", &n);
Color[7] = (n < 10) ? n+48 : n+87;
system(Color);
printDelimiter();
break;
case 3:
printf("Useless\n");
printDelimiter();
break;
case 4:
if(qA->admini){
printf("You has been Administrator\n");
}
else {
printf("Please enter secret code:\n");
scanf("%s", str);
if(strcmp(str, "INDEX"))
printf("Nope, Nin 8 Pei\n");
else{
qA->admini = true;
printf("Now you are Adminitreator!\n");
}
}
printDelimiter();
break;
case 5:
qA->admini = false;
printf("Remove successfully\n");
printDelimiter();
break;
case 6:
num = fileMenu();
switch(num) {
case 0:
return 0;
case 1:
case 2:
printf("Please enter the file name\n");
scanf("%s", str);
if(strstr(str, ".txt") || strstr(str, ".bat")) {
if(!strcmp(str, FName) || !strcmp(str, FNameA)) {
printf("Conflict\n");
break;
}
if(num == 1)
strcpy(FName, str);
if(num == 2)
strcpy(FNameA, str);
printf("Modify File Name successfully\n");
}
else {
printf("Format of FIle ERROR\n");
}
break;
}
printDelimiter();
break;
case 7:
if(qA)
state = 1;
else
state = 0;
if(memorySettings())
printf("Set successfully\n");
memoryBook(FName, head, total);
memoryAccount(FNameA, headA, totalA);
printDelimiter();
break;
}
}
break;
}
return 0;
}
Add.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "BMS.h"
void *nextBook(void *p) {
return ((Book *)p)->next;
}
void nextToBook(void *p, void *q) {
((Book *)p)->next = (Book *)q;
}
void *nextAccount(void *p) {
return ((Account *)p)->next;
}
void nextToAccount(void *p, void *q) {
((Account *)p)->next = (Account *)q;
}
bool appendToAny(void **h, void *p, void *nextAny(void *p), void (*nextToAny)(void *p, void *q)) {
void *q;
if(p == NULL || h == NULL)
return false;
if(*h == NULL) {
//头指针为空,说明链表内无节点
*h = p;
nextToAny(p, p);
return true;
}
//头指针非空,查找到链表末端,并插入
q = *h;
while(nextAny(q) != *h) q = nextAny(q);
nextToAny(q, p);
nextToAny(p, *h);
return true;
}
Book *HashTable[6];
bool insertHashTree(Book *p) {
//对于Book是将number的首位作为哈希值进行操作
int i = p->number / 1e6 - 1;
if(p == NULL)
return false;
HashTable[i] = insertTree(p, HashTable[i], NULL);
return true;
}
Delete.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "BMS.h"
#define UNSET(h, k1, k2) h[k1][ k2/8] ^= 0x01 << (k2 % 8)
void *deleteAny(void **h, int total, void *unknown, int (*cmpAny)(void *unknown, void *p),
void *next(void *p), void (*nextToAny)(void *p, void *q)) {
int i;
void *p = *h, *q;
if(h == NULL || *h == NULL)
return NULL;
if(next(p) == p) //若当前链表只有一个节点
if(!cmpAny(unknown, p)) {
*h = NULL;
return p;
}
else
return NULL;
for(i = 0; i < total; i++, p = next(p)) //寻找目标节点的前一节点
if(!cmpAny(unknown, next(p))) {
q = next(p);
if(q == *h)
*h = next(q);
nextToAny(p, next(q));
return q;
}
return NULL;
}
Search.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "BMS.h"
Book *searchByNumberInTree(int number, Book *root) {
//在树中用编号递归查找
Book *ans = NULL;
if(root == NULL)
return NULL;
if(number < root->number)
ans = searchByNumberInTree(number, root->left);
else if(number > root->number)
ans = searchByNumberInTree(number, root->right);
else
return root;
return ans;
}
Book *searchByNameInCertainTree(char str[], Book *root) {
//在树中用名字递归查找
Book *ans = NULL;
if(root == NULL || str[0] == '\0')
return NULL;
if(getHash(str) < (root->number/100) % 100)
ans = searchByNameInCertainTree(str, root->left);
else if(getHash(str) > (root->number/100) % 100)
ans = searchByNameInCertainTree(str, root->right);
//若hash函数值相同,不得不同时向左右子树查找
else if(strcmp(str, root->name) != 0) {
if((ans = searchByNameInCertainTree(str, root->left)) == NULL)
ans = searchByNameInCertainTree(str, root->right);
}
else
ans = root;
return ans;
}
Book *searchByNameInTree(char str[]) {
extern Book *HashTable[6];
int i;
Book *ans = NULL;
//只有书名无法确定在哪棵树中,所以采用遍历查询
for(i = 0; i < 6; i++)
if((ans = searchByNameInCertainTree(str, HashTable[i])) != NULL)
return ans;
return ans;
}
void *searchCertainAnyInList(void *h, int total, void *unknown, int (*cmpAny)(void *unknown, void *p),
void *next(void *p)) {
int i;
void *p;
if(h == NULL)
return NULL;
for(i = 0, p = h; i < total; i++, p = next(p))
if(cmpAny(unknown, p) == 0)
return p;
return NULL;
}
int searchAnyInList(void *h, int total, void *unknown, int (*cmpAny)(void *unknown, void *p),
void *next(void *p)) {
int i, flag = 0;
void *p;
if(h == NULL)
return 0;
for(i = 0, p = h; i < total; i++, p = next(p))
if(cmpAny(unknown, p) == 0) {
printBook(p);
flag++;
}
return flag;
}
int cmpBookName(void *unknown, void *p) {
char *str = (char *)unknown;
return strcmp(str, ((Book *)p)->name);
}
int cmpBookNumber(void *unknown, void *p) {
int n = *((int *)unknown);
return n - ((Book *)p)->number;
}
int cmpBookAuthor(void *unknown, void *p) {
char *str = (char *)unknown;
return strcmp(str, ((Book *)p)->author);
}
int cmpBookPress(void *unknown, void *p) {
char *str = (char *)unknown;
return strcmp(str, ((Book *)p)->press);
}
int cmpBookIntro(void *unknown, void *p) {
char *str = (char *)unknown;
return strcmp(str, ((Book *)p)->intro);
}
int cmpBookPrice(void *unknown, void *p) {
double n = *((double *)unknown);
return (int)(n - ((Book *)p)->price);
}
int cmpAccountName(void *unknown, void *p) {
char *str = (char *)unknown;
return strcmp(str, ((Account *)p)->name);
}
int cmpAccountNumber(void *unknown, void *p) {
int n = *((int *)unknown);
return n - ((Account *)p)->number;
}
Sort.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "BMS.h"
Book *searchByNumberInTree(int number, Book *root) {
//在树中用编号递归查找
Book *ans = NULL;
if(root == NULL)
return NULL;
if(number < root->number)
ans = searchByNumberInTree(number, root->left);
else if(number > root->number)
ans = searchByNumberInTree(number, root->right);
else
return root;
return ans;
}
Book *searchByNameInCertainTree(char str[], Book *root) {
//在树中用名字递归查找
Book *ans = NULL;
if(root == NULL || str[0] == '\0')
return NULL;
if(getHash(str) < (root->number/100) % 100)
ans = searchByNameInCertainTree(str, root->left);
else if(getHash(str) > (root->number/100) % 100)
ans = searchByNameInCertainTree(str, root->right);
//若hash函数值相同,不得不同时向左右子树查找
else if(strcmp(str, root->name) != 0) {
if((ans = searchByNameInCertainTree(str, root->left)) == NULL)
ans = searchByNameInCertainTree(str, root->right);
}
else
ans = root;
return ans;
}
Book *searchByNameInTree(char str[]) {
extern Book *HashTable[6];
int i;
Book *ans = NULL;
//只有书名无法确定在哪棵树中,所以采用遍历查询
for(i = 0; i < 6; i++)
if((ans = searchByNameInCertainTree(str, HashTable[i])) != NULL)
return ans;
return ans;
}
void *searchCertainAnyInList(void *h, int total, void *unknown, int (*cmpAny)(void *unknown, void *p),
void *next(void *p)) {
int i;
void *p;
if(h == NULL)
return NULL;
for(i = 0, p = h; i < total; i++, p = next(p))
if(cmpAny(unknown, p) == 0)
return p;
return NULL;
}
int searchAnyInList(void *h, int total, void *unknown, int (*cmpAny)(void *unknown, void *p),
void *next(void *p)) {
int i, flag = 0;
void *p;
if(h == NULL)
return 0;
for(i = 0, p = h; i < total; i++, p = next(p))
if(cmpAny(unknown, p) == 0) {
printBook(p);
flag++;
}
return flag;
}
int cmpBookName(void *unknown, void *p) {
char *str = (char *)unknown;
return strcmp(str, ((Book *)p)->name);
}
int cmpBookNumber(void *unknown, void *p) {
int n = *((int *)unknown);
return n - ((Book *)p)->number;
}
int cmpBookAuthor(void *unknown, void *p) {
char *str = (char *)unknown;
return strcmp(str, ((Book *)p)->author);
}
int cmpBookPress(void *unknown, void *p) {
char *str = (char *)unknown;
return strcmp(str, ((Book *)p)->press);
}
int cmpBookIntro(void *unknown, void *p) {
char *str = (char *)unknown;
return strcmp(str, ((Book *)p)->intro);
}
int cmpBookPrice(void *unknown, void *p) {
double n = *((double *)unknown);
return (int)(n - ((Book *)p)->price);
}
int cmpAccountName(void *unknown, void *p) {
char *str = (char *)unknown;
return strcmp(str, ((Account *)p)->name);
}
int cmpAccountNumber(void *unknown, void *p) {
int n = *((int *)unknown);
return n - ((Account *)p)->number;
}
GetNumber.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "BMS.h"
#define IFSET(h, k, c) h[k][ c[k] / 8] & (0x01 << (c[k] % 8))
#define SET(h, k, c) h[k][ c[k] / 8] |= 0x01 << (c[k] % 8)
int Count[1064] = {0};
char Hits[1064][13] = {0};
int CountA[8] = {0};
char HitsA[8][125] = {0};
int getHash(char s[]) {
unsigned char c, sum = 0;
while(c = *s++) sum += c;
//取sum的前三位与sum的后六位异或,再与上0x3f以保证大小在64以内
return ((sum>>5) ^ (sum&0x3f)) & 0x3f;
}
static int getBookNum(int num) {
int key = num / 100, k = 0;
Count[key] %= 100;
//书本的编号由最高位的种类,其次两位关于name的hash值,最后在此函数中得到最后两位
//因此返回值在0~99之间,对于char类型,依靠位运算则需要至少13个char,才能满足
//k是计数器,预防Hits全部已经被占用的情况,1000时表明容量满了,则赋值失败
while(IFSET(Hits, key, Count)) {
if(Count[key]++ >= 99)
Count[key] %= 100;
if(++k == 100)
return -1;
}
SET(Hits, key, Count);
return Count[key]++;
}
void setBookNumber(Book *p) {
p->number = p->type * 1e4 + getHash(p->name) * 1e2;
p->number += getBookNum(p->number);
//本函数并未设置检查 getBookNum获取失败的情况
return;
}
static int getAccountNum(int num) {
int key = num / 1000, k = 0;
Count[key] %= 1000;
//账号的编号最高两位两位关于name的hash值,最后在此函数中得到最后三位位
//因此返回值在0~999之间,对于char类型,依靠位运算则需要至少125个char,才能满足
//k是计数器,预防Hits全部已经被占用的情况,100时表明容量满了,则赋值失败
while(IFSET(HitsA, key, CountA)) {
if(CountA[key]++ >= 999)
CountA[key] %= 1000;
if(++k == 1000)
return -1;
}
SET(HitsA, key, CountA);
return Count[key]++;
}
void setAccountNumber(Account *p) {
p->number = getHash(p->name) % 8 * 1e3;
p->number += getAccountNum(p->number);
//本函数并未设置检查 getAccountNum获取失败的情况
return;
}
FileFunction.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "BMS.h"
#define PRESET(h, k1, k2) h[k1][ k2/8] |= 0x01 << (k2%8)
#define IFSET2(h, k1, k2) h[k1][ k2/8] & (0x01 << (k2%8))
bool memoryBook(char *fName, Book *h, int total) {
int i = total;
Book *p = h;
FILE *fp;
if((fp = fopen(fName, "wb")) == NULL) {
printf("Open File ERROR\n");
return false;
}
fwrite(&i, sizeof(i), 1, fp);
if(ferror(fp)){\
fclose(fp);
return false;
}
for(; i > 0; i--, p = p->next){
fwrite(p, sizeof(Book), 1, fp);
if(ferror(fp)){
fclose(fp);
return false;
}
}
fclose(fp);
return true;
}
bool readBook(char *fName, Book **h, int *total) {
extern char Hits[1064][13];
int i;
Book *p;
FILE *fp;
if((fp = fopen(fName, "rb")) == NULL) {
printf("Open File ERROR\n");
return false;
}
fread(total, sizeof(i), 1, fp);
if(ferror(fp)) {
fclose(fp);
return false;
}
for(i = 0; i < *total; i++) {
if(!(p = (Book *)malloc(sizeof(Book)))) {
printf("Out Of Space\n");
return false;
}
fread(p, sizeof(Book), 1, fp);
if(ferror(fp)) {
fclose(fp);
return false;
}
//检查获得的书本节点的number是否已经被占用
if(IFSET2(Hits, p->number/100, p->number%100))
setBookNumber(p);
PRESET(Hits, p->number/100, p->number%100);
//接入树和链表中
if(insertHashTree(p) && !(appendToAny((void **)h, p, nextBook, nextToBook))) {
printf("Append Book ERROR\n");
return false;
}
}
fclose(fp);
return true;
}
bool memoryAccount(char *fName, Account *h, int total) {
int i = total;
Account *p = h;
FILE *fp;
if((fp = fopen(fName, "wb")) == NULL) {
printf("Open File ERROR\n");
return false;
}
fwrite(&i, sizeof(i), 1, fp);
if(ferror(fp)){
fclose(fp);
return false;
}
for(; i > 0; i--, p = p->next){
fwrite(p, sizeof(Account), 1, fp);
if(ferror(fp)){
fclose(fp);
return false;
}
}
fclose(fp);
return true;
}
bool readAccount(char *fName, Account **h, int *total) {
extern char HitsA[1064][13];
int i;
Account *p;
FILE *fp;
if((fp = fopen(fName, "rb")) == NULL) {
printf("Open File ERROR\n");
return false;
}
fread(total, sizeof(i), 1, fp);
if(ferror(fp)) {
fclose(fp);
return false;
}
for(i = 0; i < *total; i++) {
if(!(p = (Account *)malloc(sizeof(Account)))) {
printf("Out Of Space\n");
return false;
}
fread(p, sizeof(Account), 1, fp);
if(ferror(fp)) {
fclose(fp);
return false;
}
//检查获得的账号节点的number是否已经被占用
if(IFSET2(HitsA, p->number/100, p->number%100))
setAccountNumber(p);
PRESET(HitsA, p->number/1000, p->number%1000);
//接入链表中
if(!appendToAny((void **)h, p, nextAccount, nextToAccount)) {
printf("Append Account ERROR\n");
return false;
}
}
fclose(fp);
return true;
}
bool memorySettings() {
extern char FName[21], FNameA[21], Color[9];
FILE *fp;
if((fp = fopen("Set.txt", "wb")) == NULL)
return false;
fwrite(FName, 21, 1, fp);
if(ferror(fp)) {
fclose(fp);
return false;
}
fwrite(FNameA, 21, 1, fp);
if(ferror(fp)) {
fclose(fp);
return false;
}
fwrite(Color, 9, 1, fp);
if(ferror(fp)) {
fclose(fp);
return false;
}
return true;
}
bool readSettings() {
extern char FName[21], FNameA[21], Color[9];
FILE *fp;
if((fp = fopen("Set.txt", "rb")) == NULL)
return false;
fread(FName, 21, 1, fp);
if(ferror(fp)) {
fclose(fp);
return false;
}
fread(FNameA, 21, 1, fp);
if(ferror(fp)) {
fclose(fp);
return false;
}
fread(Color, 9, 1, fp);
if(ferror(fp)) {
fclose(fp);
return false;
}
return true;
}
InputOutput.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <ctype.h>
#include <conio.h>
#include "BMS.h"
void printDelimiter() {
int i;
putchar('\n');
for(i = 0; i < 64; i++)
putchar('+');
printf("\n\n");
}
int inputNextStr(FILE *in, char s[], int size) {
//获取一段字符串函数,以'|'结束输入
static int state = 0;
int i = 0;
char ch;
memset(s, 0, size);
while(1) {
ch = getc(in);
switch(state) {
case 0:
//此阶段略去所有空格和回车,遇到非'|'的字符进入1阶段
//遇到'|'进入2阶段
if(ch == ' ' || ch == '\n')
continue;
else if(ch == '|' || i == size)
state = 2;
else {
s[i++] = ch;
state = 1;
}
break;
case 1:
//此阶段接收非回车、'|',如果遇到空格,则读取它并进入0阶段
//遇到'|'进入2阶段
if(ch == '|')
state = 2;
else if(ch == '\n')
state = 0;
else if(ch == ' ' && i != size) {
s[i++] = ch;
state = 0;
}
else if(i != size)
s[i++] = ch;
else
state = 2;
break;
case 2:
//结束阶段,并判断读取的字节数是否在size以内
if(i <= size)
s[i] = '\0';
state = 0;
return (i <= size) ? i : -1;
}
}
}
void scanBook(Book *p) {
int n;
while(1) {
printf("Please enter the name (end with |) (Up to 80 characters):\n");
n = inputNextStr(stdin, p->name, 81);
if(n == 0)
printf("Name couldn\'t be Blank!\n");
else if(n == -1)
printf("Out Of Space!\n");
else
break;
}
while(1) {
printf("Please enter the author (end with |) (Up to 80 characters):\n");
n = inputNextStr(stdin, p->author, 81);
if(n == 0)
printf("Author couldn\'t be Blank!\n");
else if(n == -1)
printf("Out Of Space!\n");
else
break;
}
while(1) {
printf("Please enter the press (end with |) (Up to 80 characters):\n");
n = inputNextStr(stdin, p->press, 81);
if(n == 0)
printf("Press couldn\'t be Blank!\n");
else if(n == -1)
printf("Out Of Space!\n");
else
break;
}
printf("All Type:[1]Textbook [2]Reference book [3]Science fiction\n");
printf(" [4]Non-fiction [5]Dictionary [6]Novel\n");
printf("Please enter the type:\n");
scanf("%d", &p->type);
printf("Please enter the price:\n");
scanf("%lf", &p->price);
while(1) {
printf("Please enter the introduction (end with |) (Up to 500 characters):\n");
n = inputNextStr(stdin, p->intro, 501);
if(n == 0)
printf("Introduction couldn\'t be Blank!\n");
else if(n == -1)
printf("Out Of Space!\n");
else
break;
}
do {
printf("Please enter the quantity:\n");
scanf("%d", &n);
if(n > 0)
p->quantity = n;
else if(n < 0)
printf("Quantity couldn\'t be nagetive!\n");
else
printf("Quantity couldn\'t be zero!\n");
}while(n <= 0);
}
void printBook(void *p) {
int i = 0;
Book *q = (Book *)p;
printf("\nNumber: %d\n", q->number);
printf("Name: %s\n", q->name);
printf("Author: %s\n", q->author);
printf("Press: %s\n", q->press);
printf("Type:");
switch(q->type) {
case 1:
printf("Textbook\n");
break;
case 2:
printf("Reference book\n");
break;
case 3:
printf("Science fiction\n");
break;
case 4:
printf("Non-fiction\n");
break;
case 5:
printf("Dictionary\n");
break;
case 6:
printf("Novel\n");
break;
}
printf("Price: %.2f\n", q->price);
printf("Remaining quantity: %d\n", q->quantity - q->borrowNum);
if(q->borrowNum) {
printf("Borrowers\' number: %d\n", q->borrower[0]);
for(i = 1; i < q->borrowNum; i++)
printf("\t\t %d\n", q->borrower[i]);
}
printf("Introduction: %s\n", q->intro);
printf("\n");
}
void printAccount(void *p) {
int i = 0;
Account *q = (Account *)p;
printf("\nNumber: %d\n", q->number);
printf("Name: %s\n", q->name);
printf("Borrow quantity: %d\n", q->totalBook);
if(q->totalBook) {
printf("Borrowed Books\' number: %d\n", q->book[0]);
for(i = 1; i < q->totalBook; i++)
printf("\t\t\t%d\n", q->book[i]);
}
printf("\n");
}
int inputNextPassword(char s[], int size) {
//此函数专门用于读取密码,利用getch()可以不显示输入流,遇到回车停止读取
int n = 0;
char ch;
memset(s, 0, size);
while(1) {
while((ch = getch()) != '\r')
if(isalnum(ch) && n <= 20)
s[n++] = ch;
else if(n > 20)
printf("Out Of Space!\n");
else {
printf("ERROR:Please enter again\n");
n = 0;
memset(s, 0, size);
}
if(n >= 8)
break;
else {
printf("Too Short:Please enter again\n");
n = 0;
memset(s, 0, size);
}
}
s[n] = '\0';
return n;
}
void scanAccount(Account *p) {
int n, i, j;
char ch, str[21];
while(1) {
printf("Please enter your name (end with |) (Up to 80 characters):\n");
n = inputNextStr(stdin, p->name, 81);
if(n == 0)
printf("Name couldn\'t be Blank!\n");
else if(n == -1)
printf("Out Of Space!\n");
else
break;
}
while(1) {
printf("Please enter your password (between 8 to 20 characters):\n");
i = inputNextPassword(p->password, 21);
for(j = 0; j < i; j++)
putchar('*');
putchar('\n');
printf("Please enter again to confirm your password (between 8 to 20 characters):\n");
i = inputNextPassword(str, 21);
for(j = 0; j < i; j++)
putchar('*');
putchar('\n');
if(strcmp(p->password, str)) {
printf("Two input password must be consistent!\n");
printf("Please enter again!\n");
continue;
}
break;
}
}
Menu.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "BMS.h"
int loginMenu() {
int n;
printf("\t\t ************\n");
printf("\t\t||Login Menu||\n");
printf("\t\t ************\n\n");
printf("Please enter a number to select\n\n");
printf("[0]Exit\n");
printf("[1]Log in\n");
printf("[2]Sign up\n");
printf("[3]Visitor Mode\n");
printf("[4]Settings\n");
scanf("%d", &n);
return n;
}
int operationMenu(Account *q) {
int n;
printf("\t\t ****************\n");
printf("\t\t||Operation Menu||\n");
printf("\t\t ****************\n\n");
if(q)
printf("Hello, %s\n\n", q->name);
else
printf("Visitor Mode\n\n");
printf("Please enter a number to select\n\n");
printf("[0]Exit\n");
if(q)
if(q->admini){
printf("[1]Add a Book\n");
printf("[2]Delete a Book\n");
printf("[3]Revise a Book\n");
printf("[4]Save Object to a file\n");
printf("[5]Read Object from a file\n");
}
printf("[6]Search Book\n");
printf("[7]Sort Book\n");
if(q) {
printf("[8]Borrow Book\n");
printf("[9]Return Book\n");
}
if(q)
if(q->admini) {
printf("[10]Delete Account\n");
printf("[11]Search Account\n");
}
printf("[12]Settings\n");
scanf("%d", &n);
return n;
}
int settingMenu(Account *q) {
int n;
printf("\t\t **************\n");
printf("\t\t||Setting Menu||\n");
printf("\t\t **************\n\n");
if(q)
printf("Hello, %s\n\n", q->name);
else
printf("Visitor Mode\n\n");
printf("Please enter a number to select\n\n");
printf("[0]Exit\n");
if(q)
printf("[1]Log Out\n");
printf("[2]Color Setting\n");
printf("[3]Language\n");
if(q) {
printf("[4]Get Administrator\n");
if(q->admini) {
printf("[5]Remove Administrator\n");
printf("[6]Modify Default Read-Write File\n");
}
}
printf("[7]Back\n");
scanf("%d", &n);
return n;
}
int searchMenu() {
int n;
printf("\nWhat kind of operation do you want to choose?\n");
printf("Please enter a number to select\n\n");
printf("[0]Back\n");
printf("[1]By Name\n");
printf("[2]By Number\n");
printf("[3]By Author\n");
printf("[4]By Press\n");
printf("[5]By Introduction\n");
printf("[6]By Price\n");
printf("[7]By Type\n");
printf("[8]All\n");
scanf("%d", &n);
return n;
}
int searchMenuA() {
int n;
printf("\nWhat kind of search do you want to choose?\n");
printf("Please enter a number to select\n\n");
printf("[0]Back\n");
printf("[1]By Name\n");
printf("[2]By Number\n");
printf("[3]All\n");
scanf("%d", &n);
return n;
}
int againMenu() {
int n;
printf("\nRepeat this operation?\n");
printf("Please enter a number to select\n\n");
printf("[0]Exit\n");
printf("[1]Repeat\n");
printf("[2]Back to home\n");
scanf("%d", &n);
return n;
}
int detailMenu() {
int n;
printf("\nPlease enter a number to narrow search range\n\n");
printf("[0]Back\n");
printf("[1]By Name\n");
printf("[2]By Number\n");
scanf("%d", &n);
return n;
}
int readWriteMenu() {
int n;
printf("\nWhich Object do you want to choose?\n");
printf("Please enter a number to select\n\n");
printf("[0]Back\n");
printf("[1]Default file\n");
printf("[2]Another Book file\n");
printf("[3]Another Account file\n");
scanf("%d", &n);
return n;
}
int classMenu() {
int n;
printf("\nWhich Object do you want to choose?\n");
printf("Please enter a number to select\n\n");
printf("[0]Back\n");
printf("[1]Book\n");
printf("[2]Account\n");
scanf("%d", &n);
return n;
}
int sortMenu() {
int n;
printf("\nWhat kind of sort do you want to choose?\n");
printf("Please enter a number to select\n\n");
printf("[1]Ascending\n");
printf("[2]Descending\n");
scanf("%d", &n);
return n;
}
int fileMenu() {
int n;
printf("\nWhich Object do you want to choose?\n");
printf("Please enter a number to select\n\n");
printf("[0]Back\n");
printf("[1]Book\n");
printf("[2]Account\n");
scanf("%d", &n);
return n;
}
TreeFunction.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "BMS.h"
#define MAX(x1, x2) (x1 > x2) ? x1 : x2
void inOrderTraverse(Book *root) {
if(root == NULL)
return;
inOrderTraverse(root->left);
printBook(root);
inOrderTraverse(root->right);
}
static int getHeight(Book *node) {
if(node == NULL)
return -1;
else
return node->height;
}
static Book *singleLeftRotate(Book *pos1) {
Book *pos2 = pos1->right;
pos1->right = pos2->left;
if(pos2->left != NULL)
pos2->left->parent = pos1;
pos2->left = pos1;
pos2->parent = pos1->parent;
pos1->parent = pos2;
pos1->height = MAX(getHeight(pos1->left), getHeight(pos1->right)) + 1;
pos2->height = MAX(getHeight(pos2->left), getHeight(pos2->right)) + 1;
return pos2;
}
static Book *singleRightRotate(Book *pos1) {
Book *pos2 = pos1->left;
pos1->left = pos2->right;
if(pos2->right != NULL)
pos2->right->parent = pos1;
pos2->right = pos1;
pos2->parent = pos1->parent;
pos1->parent = pos2;
pos1->height = MAX(getHeight(pos1->left), getHeight(pos1->right)) + 1;
pos2->height = MAX(getHeight(pos2->left), getHeight(pos2->right)) + 1;
return pos2;
}
static Book *doubleLeftRotate(Book *pos) {
pos->right = singleRightRotate(pos->right);
return singleLeftRotate(pos);
}
static Book *doubleRightRotate(Book *pos) {
pos->left = singleLeftRotate(pos->left);
return singleRightRotate(pos);
}
Book *insertTree(Book *node, Book *root, Book *parent) {
if(node == NULL)
return NULL;
if(root == NULL) { //当前根节点为空,说明还没有节点接入
root = node;
root->left = NULL;
root->right = NULL;
root->parent = parent;
}
//利用number寻找空位
else if(node->number < root->number) {
root->left = insertTree(node, root->left, root);
//判断树是否平衡
if(getHeight(root->left) - getHeight(root->right) == 2)
if(node->number < root->left->number)
//左-左型,向右单旋转
root = singleRightRotate(root);
else
//左-右型,左-右旋转
root = doubleRightRotate(root);
}
else if(node->number > root->number) {
root->right = insertTree(node, root->right, root);
//判断树是否平衡
if(getHeight(root->right) - getHeight(root->left) == 2)
if(node->number > root->right->number)
//右-右型,向左单旋转
root = singleLeftRotate(root);
else
//右-左型,右-左旋转
root = doubleLeftRotate(root);
}
else
printf("This tree has already had %s\n", node->number);
root->height = MAX(getHeight(root->left), getHeight(root->right)) + 1;
return root;
}
static Book *findMin(Book *root) {
if(root == NULL)
return NULL;
else if(root->left == NULL)
return root;
else
return findMin(root->left);
}
Book *deleteTreeNode(Book *p, Book *root) {
Book *t;
if(root == NULL || p == NULL)
return NULL;
//通过number寻找
else if(p->number < root->number)
root->left = deleteTreeNode(p, root->left);
else if(p->number > root->number)
root->right = deleteTreeNode(p, root->right);
else if(root->left && root->right) {
//若需要删除的节点同时具有左右节点,则寻找右节点中的最小项 m
//并修改指针使 m接到需要删除的节点的所在位置
//随后递归删除 m
Book *m = findMin(root->right);
if(p->parent != NULL)
if(p->number < p->parent->number)
p->parent->left = m;
else
p->parent->right = m;
if(m->parent != p) {
m->left = p->left;
m->right = p->right;
deleteTreeNode(m, root->right);
}
else
m->left = p->left;
root = m;
}
else {
//若需要删除的节点只有左节点或右节点,则让其直接接上即可
if(root->left) {
if(p->parent != NULL)
if(p->number < p->parent->number)
p->parent->left = p->left;
else
p->parent->right = p->left;
p->left->parent = p->parent;
root = p->left;
}
else if(root->right) {
if(p->parent != NULL)
if(p->number < p->parent->number)
p->parent->left = p->right;
else
p->parent->right = p->right;
p->right->parent = p->parent;
root = p->right;
}
//需要删除的节点没有左右节点,直接删除
else {
if(p->parent != NULL)
if(p->number < p->parent->number)
p->parent->left = NULL;
else
p->parent->right = NULL;
root = NULL;
}
}
//检查是否需要旋转操作
if(root != NULL) {
root->height = MAX(getHeight(root->left), getHeight(root->right)) + 1;
if(getHeight(root->left) - getHeight(root->right) == 2)
root = singleRightRotate(root);
if(getHeight(root->right) - getHeight(root->left) == 2)
root = singleLeftRotate(root);
}
return root;
}