[记录] 大一下C程设-图书管理系统

懒得加注释了(手动滑稽)
单纯记录一下,还是有很多不完善的地方。。。

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值