//CShelf008.cpp
//Author: AOU
//2005.12.09
/*
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;
};
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";
}
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
if book is not the rightmost then set the id to 0
if book is the rightmost (or the only book) then delete it and also empty space left of it
*/
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;
//if book is not the rightmost then set the id to 0
//if (this->lastBook != p)
if (p->bookOnRight != NULL)
{
p->id = 0;
this->count--;
this->widthOccupied -= p->width;
return true;
}
//if book is the rightmost (or the only book) then delete it
if (p->bookOnRight == NULL)
{
this->count--;
this->widthOccupied -= p->width;
if (this->count == 0)
{
this->firstBook = this->lastBook = NULL;
delete p;
return true;
}
//if there is empty space left of it then delete it too
while (this->count != 0)
{
this->lastBook = p->bookOnLeft;
this->lastBook->bookOnRight = NULL;
delete p;
if (this->lastBook->id == 0)
p = this->lastBook;
else
return true;
}
}
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;
}
|