|
//CShelf009.cpp //Author: AOU //2005.12.11 /* data structure: booksOnshelf (firstBook, count, widthOccupied) book (id, width, bookOnRight) functions: init add(bookID, bookWidth) remove(bookID) displayAll end/displayBrief search(booID) */ #include<iostream> #include <fstream> #include <ctime> using namespace std; int const UNDEFINED = -9; int const MIN_SHELF_WIDTH = 5; int const MAX_SHELF_WIDTH = 40;//100; int const MIN_ID = 1; int const MAX_ID = 9; int const TEST_COUNT = 10; /* book with ID=0 is an empty space */ class CBook { private: int id; int width; CBook *bookOnRight; CBook *bookOnLeft; public: CBook(void); friend class CShelf; }; class CShelf { private: CBook *firstBook; CBook *lastBook; int width; int count; int widthOccupied;//sum of bookWidths exclude empty space public: CShelf(void); CShelf(int width); CShelf(char ch); ~CShelf(void); bool insertAtLeft(int bookID, int bookWidth); bool remove(int bookID); void displayDetailed(void) const; void displaySimple(void) const; void displayBrief(void) const; CBook* search(int bookID) const; bool isEmpty(void){return (firstBook==lastBook);} }; void testInsertAtLeft(void); void testConstructor(void); void testRemove(void); void main(void) { srand((unsigned int) time(NULL)); //testInsertAtLeft(); //testConstructor(); testRemove(); } //destructor for CSheld CShelf::~CShelf(void) { while (this->firstBook != NULL) { this->lastBook = this->firstBook->bookOnRight; cout << "Deleting " << this->firstBook->id << " " << this->firstBook->width << endl; delete this->firstBook; this->firstBook = this->lastBook; } cout << "....................................\n"; } void testConstructor(void) { cout << "---------------\n"; cout << "testConstructor\n"; cout << "---------------\n"; for (int t=1; t<=TEST_COUNT; t++) { CShelf myShelf('r'); myShelf.displayBrief(); cout << endl; myShelf.displaySimple();cout << endl; myShelf.displayDetailed(); cout << "------------------------------------\n"; } } /* A constructor to build a populated shelf */ CShelf::CShelf(char ch) { if ('r' == ch) { this->count = 0; this->width = rand()%(MAX_SHELF_WIDTH-MIN_SHELF_WIDTH+1) + MIN_SHELF_WIDTH; this->widthOccupied = 0; this->firstBook = NULL; this->lastBook = NULL; for (int b=1; b<=TEST_COUNT; b++) { int bookID = rand()% (MAX_ID-MIN_ID+1) + MIN_ID; int bookWidth = rand()%((MAX_SHELF_WIDTH-MIN_SHELF_WIDTH)/8+1) + 1; //cout << "bookID=" << bookID << ", booWidth=" << bookWidth << endl; if (this->width >= (this->widthOccupied + bookWidth)) this->insertAtLeft(bookID, bookWidth); else ;//cout << " No room on the shelf\n"; } } else { this->count = 0; this->width = rand()%(MAX_SHELF_WIDTH-MIN_SHELF_WIDTH+1) + MIN_SHELF_WIDTH; this->widthOccupied = 0; this->firstBook = NULL; this->lastBook = NULL; } } void testRemove(void) { cout << "==========\n"; cout << "testRemove\n"; cout << "==========\n"; for (int t=1; t<=TEST_COUNT/TEST_COUNT; t++) { CShelf myShelf('r'); for (int b=1; b<=TEST_COUNT*3; b++) { myShelf.displayBrief(); cout << endl; myShelf.displaySimple();cout << endl; myShelf.displayDetailed();cout << endl; int bookID = rand()% (MAX_ID-MIN_ID+1) + MIN_ID; cout << "About to delete\n"; cout << "bookID = " << bookID << endl << endl; if (myShelf.remove(bookID)) cout << "Remove was a success\n"; else cout << "Remove was not a success\n\n"; myShelf.displayBrief(); cout << endl; myShelf.displaySimple();cout << endl; myShelf.displayDetailed();cout << endl; cout << "------------------------------------\n"; if (myShelf.isEmpty()) break; } cout << "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"; } } /* Possibilities: shelf is empty sought book is not on the shelf book is the rightmost book is not the rightmost (change th id to 0) only book on the shelf Algorithm: if shelf is empty then return false sought book is not on the shelf then return false set the id to 0 delete the rightmost empty space */ bool CShelf::remove(int bookID) { //if shelf is empty then return false if (this->firstBook == NULL) return false; //sought book is not on the shelf then return false CBook *p; p = this->search(bookID); if (NULL == p) return false; //set the id to 0 p->id = 0; this->count--; this->widthOccupied -= p->width; //delete the righmost empty books while (this->lastBook->id == 0) { if (this->lastBook == this->firstBook) { delete this->lastBook; this->lastBook = this->firstBook = NULL; break; } else { p = this->lastBook; this->lastBook = this->lastBook->bookOnLeft; this->lastBook->bookOnRight = NULL; delete p; } } return true; } CBook* CShelf::search(int bookID) const { CBook *p; p = this->firstBook; while (p != NULL) { if (p->id == bookID) return p; p = p->bookOnRight; } return NULL; } void CShelf::displayDetailed(void) const { cout << "Shelf\n"; cout << " count = " << this->count << endl; cout << " width = " << this->width << endl; cout << " widthOccupied = " << this->widthOccupied << endl; cout << " firstBook @ = " << this->firstBook << endl; cout << " lastBook @ = " << this->lastBook << endl; CBook *p; p = this->firstBook; while (p != NULL) { cout << "@" << p <<" [" << p->bookOnLeft << ", " << p->id << ", " << p->width << ", " << p->bookOnRight << "]\n"; p = p->bookOnRight; } } void CShelf::displaySimple(void) const { CBook *p; p = this->firstBook; while (p != NULL) { for (int i=1; i<=p->width; i++) cout << p->id; p = p->bookOnRight; } } void CShelf::displayBrief(void) const { CBook *p; p = this->firstBook; while (p != NULL) { cout << "[" << p->id << ", " << p->width << "] "; p = p->bookOnRight; } } void testInsertAtLeft(void) { for (int t=1; t<=TEST_COUNT/TEST_COUNT; t++) { int shelfWidth = rand()% (MAX_SHELF_WIDTH-MIN_SHELF_WIDTH+1) + MIN_SHELF_WIDTH; CShelf myShelf(shelfWidth); cout << "Shelf width = " << shelfWidth << "\n"; for (int b=1; b<=TEST_COUNT; b++) { int bookID = rand()% (MAX_ID-MIN_ID+1) + MIN_ID; int bookWidth = rand()%(shelfWidth/2+1) + 1; cout << "About to insert\n"; cout << "bookID = " << bookID << endl; cout << "bookWidth = " << bookWidth << endl; if (myShelf.insertAtLeft(bookID, bookWidth)) cout << "Insert was a success\n"; else cout << "Insert was not a success\n"; myShelf.displayBrief(); cout << endl; myShelf.displaySimple();cout << endl; myShelf.displayDetailed();cout << endl; cout << "------------------------------------\n"; } cout << "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"; } } /* insertAtLeft(booID, bookWidth) Description: A new book is pushed on the left end of the shelf, pushing other books to the right as needed. No book moves to the right unless it is pushed by an adjacent (touching) book on its left. Any book that is not entirely on the shelf falls off the right edge. No single book will ever be wider than the given shelf. No book that is currently on the shelf will be added again. Algorithm: if bookWidth > shelfWidth then return false if search(bookID) is true then return false insert book(bookID, bookWidth) at the front count++ if count >1 then occupy empty space (ID=0) on right if necessary space occupied should be equal to bookWidth if widthOccupied > shelfWidth then drop the last book(s), update widthOccupied, update count */ bool CShelf::insertAtLeft(int bookID, int bookWidth) { if (bookWidth > this->width) return false; if (this->search(bookID) != NULL) return false; CBook *p; p = new CBook; p->id = bookID; p->width = bookWidth; p->bookOnLeft = NULL; if (0 == this->count) { p->bookOnRight = NULL; this->firstBook = p; this->lastBook = p; } else { p->bookOnRight = this->firstBook; this->firstBook->bookOnLeft = p; this->firstBook = p; } this->widthOccupied +=bookWidth; this->count++; //drop the last book(s) if necessary while (widthOccupied > this->width) //drop the last book(s), { CBook *p; p = this->lastBook; this->lastBook = this->lastBook->bookOnLeft; this->lastBook->bookOnRight = NULL; this->widthOccupied -=p->width; //cout << "Book id=" << p->id << " of width=" << p->width << " was dropped\n"; delete p; this->count--; } return true; } CShelf::CShelf(int width) { this->count = 0; this->width = width; this->widthOccupied = 0; this->firstBook = NULL; this->lastBook = NULL; } CShelf::CShelf(void) { this->count = 0; this->width = MIN_SHELF_WIDTH; this->widthOccupied = 0; this->firstBook = NULL; this->lastBook = NULL; } CBook::CBook(void) { this->id = this->width = UNDEFINED; this->bookOnLeft = this->bookOnRight = NULL; } |