当前位置: 代码迷 >> 综合 >> C++使用链表实现《图书管理程序》
  详细解决方案

C++使用链表实现《图书管理程序》

热度:88   发布时间:2023-09-29 05:26:12.0

参考C++数据结构与算法第四版。

图书管理程序涉及一个作者可对应多本书籍,一位借阅人也可对应多本书籍。

为了快速访问作者,会设计一个指针数组,数组索引为‘A’到‘Z’,分别对应首字母为A到Z的作者。

每个指针都会指向一个特定首字母的作者的list,这样就可以在O(1)常数固定时间内通过作者首字母(索引)访问作者。

这样的设计思想很好(数组和链表结合)。

 

共有4个自定义类:

1 class Book:存储书信息和指向该书被借阅的借阅者的指针。(这个类只实现了一本书供一位读者借阅。)

2 class Author:存储书的作者的信息和本作者所著的书籍的list,(由于STL中的list是双向list,有head和tail指针指向整个链表的头节点和尾节点,直接保存list信息并不会占用太多空间)。

3 class Patron: 借阅人类,存储借阅人的信息(name),和本人所借图书的list,这个list中存储的只是图书和作者的引用,不会因为再copy一份图书和作者信息而多占用空间。

4:class CheckedOutBook:为Patron类服务,主要存储了指向作者和书籍的iterator。

#include <iostream>
#include <string>
#include <list>
#include <algorithm>using namespace std;class Patron;class Book {
public:Book() {patron = nullptr;}bool operator==(const Book &bk) const {return strcmp(title, bk.title) == 0;}
private:char *title;Patron *patron;ostream &printBook(ostream &) const;friend ostream &operator<<(ostream &out, const Book &bk) {return bk.printBook(out);}friend class CheckedOutBook;friend Patron;friend void includeBook();friend void checkOutBook();friend void returnBook();
};class Author {
public:Author() {}bool operator==(const Author &ar) const {return strcmp(name, ar.name) == 0;}
private:char *name;list<Book> books;ostream &printAuthors(ostream &out) const;friend ostream &operator<<(ostream &out, const Author &ar) {return ar.printAuthors(out);}friend void includeBook();friend void checkOutBook();friend void returnBook();friend class CheckedOutBook;friend Patron;
};class CheckedOutBook {
public:CheckedOutBook(list<Author>::iterator ar, list<Book>::iterator bk) :author(ar), book(bk) {  }bool operator==(const CheckedOutBook & bk) const {return strcmp(author->name, bk.author->name) == 0 &&strcmp(book->title, bk.book->title) == 0;}
private:list<Author>::iterator author;list<Book>::iterator book;friend void checkOutBook();friend void returnBook();friend Patron;
};class Patron {
public:Patron() {     }bool operator==(const Patron &pn) const {return strcmp(name, pn.name) == 0;}
private:char *name;list<CheckedOutBook> books;ostream& printPatron(ostream&) const;friend ostream& operator<< (ostream& out, const Patron& pn) {return pn.printPatron(out);}friend void checkOutBook();friend void returnBook();friend Book;
};ostream &Author::printAuthors(ostream &out) const
{out << name << endl;list<Book>::const_iterator ref = books.cbegin();for (; ref != books.cend(); ++ref)out << *ref << endl;return out;
}ostream &Book::printBook(ostream &out) const
{out << " * " << title;if (patron != nullptr)out << " - checked out to " << patron->name << endl;return out;
}ostream &Patron::printPatron(ostream &out) const
{out << name;if (!books.empty()) {out << " has the following books:\n";list<CheckedOutBook>::const_iterator bk = books.cbegin();for (; bk != books.cend(); ++bk)out << " * " << bk->author->name << ", "<< bk->book->title << endl;}elseout << " has no books\n";return out;
}template<class T>
ostream &operator<<(ostream &out, const list<T> &lst)
{//capture out by referencefor_each(lst.begin(), lst.end(), [&out](const T &item) { out << item << endl; });return out;
}list<Author> catalog['Z' + 1];
list<Patron> people['Z' + 1];void status()
{register int i;cout << "Library has the following books:\n\n";for (i = 'A'; i <= 'Z'; ++i)if (!catalog[i].empty())cout << catalog[i];cout << "\nThe following people are using the library:\n";for (i = 'A'; i <= 'Z'; ++i)if (!people[i].empty())cout << people[i];
}//名字存储为char*太复杂 改进可以存储为string
char *getString(const char *msg)
{cout << msg << endl;char s[82], *destin;int i, len = 0;// cin.get(80);cin.getline(s, 80);destin = new char[(len = strlen(s)) + 1];destin[len] = '\0';for (i = 0; destin[i] = toupper(s[i]); ++i)continue;return destin;
}void includeBook()
{Author newAuthor;Book newBook;newAuthor.name = getString("Enter author's name: ");newBook.title = getString("Enter the title of the book: ");list<Author>::iterator oldAuthor =find(catalog[newAuthor.name[0]].begin(),catalog[newAuthor.name[0]].end(), newAuthor);if (oldAuthor == catalog[newAuthor.name[0]].end()) {//在这里暂时忽略了newBook的Patron *patron成员,默认为空newAuthor.books.push_back(newBook);	catalog[newAuthor.name[0]].push_front(newAuthor);}else(*oldAuthor).books.push_front(newBook);
}//借书
void checkOutBook()
{Patron patron;Author author;patron.name = getString("Enter patron's name: ");list<Author>::iterator authorRef;while (true) {author.name = getString("Enter author's name: ");authorRef = find(catalog[author.name[0]].begin(),catalog[author.name[0]].begin(), author);if (authorRef == catalog[author.name[0]].end())cout << "Misspelled author's name.\n";elsebreak;}Book book;list<Book>::iterator bookRef;while (true) {book.title = getString("Enter the title of the book: ");bookRef = find((*authorRef).books.begin(),(*authorRef).books.end(), book);if (bookRef == (*authorRef).books.end())cout << "Misspelled title.\n";elsebreak;}list<Patron>::iterator patronRef;patronRef = find(people[patron.name[0]].begin(),people[patron.name[0]].end(), patron);CheckedOutBook checkedOutBook(authorRef, bookRef);if (patronRef == people[patron.name[0]].end()) {	//a new patron//在people的patron为节点的链表中构造一个patron成员节点,//patron成员所借的书用引用(指针,地址)表示出来,而不是再构造一个author和book。patron.books.push_front(checkedOutBook);people[patron.name[0]].push_front(patron);}else {(*patronRef).books.push_front(checkedOutBook);//把要借的书的作者的特定的要借的书的patron成员指向这个借阅人patron(*bookRef).patron = &*patronRef;	}
}void returnBook()
{Patron patron;Book book;Author author;list<Patron>::iterator patronRef;list<Book>::iterator bookRef;list<Author>::iterator authorRef;while (true) {patron.name = getString("Enter patron's name: ");patronRef = find(people[patron.name[0]].begin(),people[patron.name[0]].end(), patron);if (patronRef == people[patron.name[0]].end())cout << "Patron's name misspelled\n";else break;}while (true) {author.name = getString("Enter author's name: ");authorRef = find(catalog[author.name[0]].begin(),catalog[author.name[0]].end(), author);if (authorRef == catalog[author.name[0]].end())cout << "Misspelled author's name\n";else break;}while (true) {book.title = getString("Enter the title of the book: ");bookRef = find((*authorRef).books.begin(),(*authorRef).books.end(), book);if (bookRef == (*authorRef).books.end())cout << "Misspelled title\n";else break;}CheckedOutBook checkedOutBook(authorRef, bookRef);(*bookRef).patron = nullptr;(*patronRef).books.remove(checkedOutBook);
}int menu()
{int option;cout << "\nEnter one of the following options:\n"<< "1. Include a book in the catalog\n2. Check out a book\n"<< "3. Return a book\n4. Status\n5. Exit\n"<< "Your option? ";cin >> option;cin.get();         // discard '\n';return option;
}int main()
{while (true)switch (menu()) {case 1: includeBook();  break;case 2: checkOutBook(); break;case 3: returnBook();   break;case 4: status();       break;case 5: return 0;default: cout << "Wrong option, try again: ";}return 0;
}

 

  相关解决方案