Untitled
unknown
plain_text
9 months ago
16 kB
16
Indexable
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <stdexcept>
class BookShelfManager {
private:
// Represents the infinitely long bookshelf.
// The index in the vector is the book's position.
std::vector<std::string> shelf;
// The index of the book where the bookmark is attached.
// -1 can represent "no bookmark" or an empty shelf state.
int bookmarkIndex;
/**
* @brief Helper function to validate an index against the current shelf size.
* @param index The index to validate.
* @param inclusiveMax Whether the index can be equal to the size (e.g., for insertion).
*/
void validateIndex(int index, bool inclusiveMax = false) const {
if (index < 0) {
throw std::out_of_range("Index cannot be negative.");
}
int max_val = inclusiveMax ? shelf.size() : shelf.size() - 1;
if (index > max_val) {
throw std::out_of_range("Index out of bounds. Max valid index is " + std::to_string(max_val) +
" for an inclusive-max context, or " + std::to_string(shelf.size()) +
" for an exclusive-max context (like insertion at the end).");
}
}
public:
/**
* @brief Constructor: Initializes an empty bookshelf and sets the bookmark to -1 (no bookmark).
*/
BookShelfManager() : bookmarkIndex(-1) {}
// ----------------------------------------------------------------------
// Book Management Methods
// ----------------------------------------------------------------------
/**
* @brief Inserts a list of books starting at toIndex.
* @param toIndex The starting index for insertion.
* @param list A vector of book titles (strings) to insert.
*/
void addBooks(int toIndex, const std::vector<std::string>& list) {
// toIndex can be from 0 to shelf.size() (inclusive)
if (toIndex < 0 || toIndex > shelf.size()) {
throw std::out_of_range("Invalid insertion index.");
}
// Use std::vector::insert
shelf.insert(shelf.begin() + toIndex, list.begin(), list.end());
// Update bookmark: If the bookmark was before or at toIndex, it moves right.
if (bookmarkIndex != -1 && bookmarkIndex >= toIndex) {
bookmarkIndex += list.size();
}
// If the shelf was empty and books were added at index 0, the bookmark should probably remain -1
// until explicitly set, or could be set to the first book (index 0).
// We'll keep it at -1 unless explicitly set, as per the initial state.
}
/**
* @brief Removes all books from fromIndex to toIndex (toIndex is inclusive).
* @param fromIndex The starting index for removal (inclusive).
* @param toIndex The ending index for removal (inclusive).
*/
void removeBooks(int fromIndex, int toIndex) {
if (fromIndex < 0 || toIndex >= shelf.size() || fromIndex > toIndex) {
throw std::out_of_range("Invalid removal indices or range.");
}
// Use std::vector::erase
shelf.erase(shelf.begin() + fromIndex, shelf.begin() + toIndex + 1);
// Update bookmark:
int numRemoved = toIndex - fromIndex + 1;
if (bookmarkIndex != -1) {
if (bookmarkIndex < fromIndex) {
// Bookmark is before the removed segment; no change.
} else if (bookmarkIndex > toIndex) {
// Bookmark is after the removed segment; it shifts left.
bookmarkIndex -= numRemoved;
} else {
// Bookmark was inside the removed segment.
// Reset to -1 or, if the shelf is not empty, set to the book now at fromIndex.
// Let's reset it to -1 as it's the safest assumption.
bookmarkIndex = -1;
}
}
}
/**
* @brief Moves size number of books from fromIndex to toIndex.
* @param fromIndex The starting index of the books to move.
* @param toIndex The destination index where the books will be inserted.
* @param size The number of books to move.
* * Note: toIndex is the *new* starting index of the moved block.
*/
void moveBooks(int fromIndex, int toIndex, int size) {
if (size <= 0) return; // Nothing to move
// Validate basic indices
if (fromIndex < 0 || fromIndex + size > shelf.size() || toIndex < 0 || toIndex > shelf.size()) {
throw std::out_of_range("Invalid move indices or size.");
}
// Check for self-move (no-op)
if (fromIndex == toIndex) return;
// 1. Extract the books to move
std::vector<std::string> booksToMove;
booksToMove.reserve(size);
std::copy(shelf.begin() + fromIndex, shelf.begin() + fromIndex + size,
std::back_inserter(booksToMove));
// 2. Remove the books from the original location
// The bookmark logic is complex here, so we will handle the bookmark *after* the move is complete.
shelf.erase(shelf.begin() + fromIndex, shelf.begin() + fromIndex + size);
// Adjust toIndex because the shelf has shrunk by 'size' books.
// If fromIndex < toIndex, the original toIndex is now smaller by 'size'.
int adjustedToIndex = toIndex;
if (fromIndex < toIndex) {
adjustedToIndex -= size;
}
// 3. Insert the books at the new location
shelf.insert(shelf.begin() + adjustedToIndex, booksToMove.begin(), booksToMove.end());
// 4. Update bookmark:
if (bookmarkIndex != -1) {
int oldBookmarkIndex = bookmarkIndex;
int newBookmarkIndex = -1;
bool wasInMovedBlock = (oldBookmarkIndex >= fromIndex && oldBookmarkIndex < fromIndex + size);
if (wasInMovedBlock) {
// The book with the bookmark moved. Calculate its new position.
int offsetInBlock = oldBookmarkIndex - fromIndex;
newBookmarkIndex = adjustedToIndex + offsetInBlock;
} else {
// The book with the bookmark did not move.
// It was at oldBookmarkIndex. Now we need to find its new location.
// Case 1: Bookmark was *before* both the 'from' and 'to' ranges (or toIndex if it's earlier).
if (oldBookmarkIndex < std::min(fromIndex, toIndex)) {
// No change to its index.
newBookmarkIndex = oldBookmarkIndex;
}
// Case 2: Bookmark was in the 'gap' created by the move.
// The book at oldBookmarkIndex shifted *back* when the block was removed.
else if (oldBookmarkIndex >= fromIndex && oldBookmarkIndex >= fromIndex + size) {
// This case is actually impossible because if oldBookmarkIndex >= fromIndex + size,
// the index will be adjusted.
}
// A simpler approach for non-moved books:
// If the bookmark was before the 'from' block, its index stays the same *unless* // the 'to' block is inserted before it.
if (oldBookmarkIndex < fromIndex) {
if (toIndex <= oldBookmarkIndex) {
// The moved block was inserted *before* the bookmark's original location.
newBookmarkIndex = oldBookmarkIndex + size;
} else {
// The moved block was inserted *after* the bookmark's original location.
newBookmarkIndex = oldBookmarkIndex;
}
}
// If the bookmark was after the 'from' block, its index is reduced by 'size'
// *unless* the 'to' block is inserted after it.
else { // oldBookmarkIndex >= fromIndex + size
// The old index is effectively reduced by 'size' when the block is removed.
newBookmarkIndex = oldBookmarkIndex - size;
if (toIndex <= oldBookmarkIndex) { // toIndex is the original toIndex
// The moved block was inserted at or before the bookmark's new location.
// The reduction is cancelled out by the insertion shift.
// However, we need to consider the adjustedToIndex which is what matters.
// Let's use the actual indices in the final vector:
// The book was at oldBookmarkIndex. When the 'from' block (fromIndex to fromIndex+size-1)
// was removed, its index became oldBookmarkIndex - size.
int tempIndex = oldBookmarkIndex - size;
// If the 'to' block (size elements) was inserted at adjustedToIndex,
// and tempIndex is >= adjustedToIndex, the index shifts by 'size'.
if (tempIndex >= adjustedToIndex) {
newBookmarkIndex = tempIndex + size; // Back to original index, which is wrong.
} else {
newBookmarkIndex = tempIndex;
}
}
// Simpler logic for non-moved:
int shift = 0;
// If the book was *after* the original 'from' block (and didn't move)
if (oldBookmarkIndex >= fromIndex + size) {
// It shifts left by 'size' when the block is removed.
shift -= size;
}
// If the book is *at or after* the new insertion point (adjustedToIndex)
if (oldBookmarkIndex + shift >= adjustedToIndex) {
// It shifts right by 'size' when the block is inserted.
shift += size;
}
newBookmarkIndex = oldBookmarkIndex + shift;
}
}
bookmarkIndex = newBookmarkIndex;
}
}
// ----------------------------------------------------------------------
// Query Methods
// ----------------------------------------------------------------------
/**
* @brief Returns a list of all books.
* @return A const reference to the internal bookshelf vector.
*/
const std::vector<std::string>& getBooks() const {
return shelf;
}
/**
* @brief Returns the index of the book where the bookmark is attached.
* @return The bookmark index, or -1 if no bookmark is set.
*/
int getBookmarkIndex() const {
return bookmarkIndex;
}
/**
* @brief Set the bookmark index at newBookmarkIndex.
* @param newBookmarkIndex The new index for the bookmark.
*/
void setBookmarkIndex(int newBookmarkIndex) {
if (newBookmarkIndex == -1) {
bookmarkIndex = -1;
return;
}
// Check for valid index (it must point to an existing book)
if (shelf.empty() || newBookmarkIndex < 0 || newBookmarkIndex >= shelf.size()) {
throw std::out_of_range("Invalid index for setting bookmark. Shelf is empty or index is out of bounds.");
}
bookmarkIndex = newBookmarkIndex;
}
};
// ----------------------------------------------------------------------
// Example Usage and Testing
// ----------------------------------------------------------------------
void printShelf(const BookShelfManager& manager) {
const auto& books = manager.getBooks();
std::cout << "Shelf: [";
for (size_t i = 0; i < books.size(); ++i) {
std::cout << "\"" << books[i] << "\"" << (i < books.size() - 1 ? ", " : "");
}
std::cout << "]\n";
std::cout << "Bookmark Index: " << manager.getBookmarkIndex() << "\n";
if (manager.getBookmarkIndex() != -1 && !books.empty()) {
std::cout << "Book at Bookmark: \"" << books[manager.getBookmarkIndex()] << "\"\n";
}
std::cout << std::string(30, '-') << "\n";
}
int main() {
BookShelfManager shelfManager;
std::cout << "--- Initial State ---\n";
printShelf(shelfManager);
// 1. Add Books
std::cout << "--- addBooks: Insert 'A', 'B', 'C' at index 0 ---\n";
shelfManager.addBooks(0, {"A", "B", "C"});
printShelf(shelfManager); // Shelf: ["A", "B", "C"], Bookmark: -1
// 2. Set Bookmark
std::cout << "--- setBookmarkIndex: Set at index 1 ('B') ---\n";
shelfManager.setBookmarkIndex(1);
printShelf(shelfManager); // Shelf: ["A", "B", "C"], Bookmark: 1
std::cout << "--- addBooks: Insert 'X', 'Y' at index 1 ---\n";
shelfManager.addBooks(1, {"X", "Y"});
// New Shelf: ["A", "X", "Y", "B", "C"]
// Bookmark was at 1 ('B'). 'B' is now at index 3. Bookmark should be 3.
printShelf(shelfManager);
// 3. Remove Books
std::cout << "--- removeBooks: Remove from index 0 to 2 ('A', 'X', 'Y') ---\n";
shelfManager.removeBooks(0, 2);
// New Shelf: ["B", "C"]
// Bookmark was at 3 ('B'). 'B' is now at index 0. Bookmark should be 0.
printShelf(shelfManager);
std::cout << "--- setBookmarkIndex: Set at index 1 ('C') ---\n";
shelfManager.setBookmarkIndex(1);
printShelf(shelfManager); // Bookmark: 1
std::cout << "--- addBooks: Insert 'P', 'Q', 'R' at index 1 ---\n";
shelfManager.addBooks(1, {"P", "Q", "R"});
// New Shelf: ["B", "P", "Q", "R", "C"]
// Bookmark was at 1 ('C'). 'C' is now at index 4. Bookmark should be 4.
printShelf(shelfManager);
std::cout << "--- removeBooks: Remove from index 1 to 3 ('P', 'Q', 'R'). Bookmark ('C') is at 4 ---\n";
shelfManager.removeBooks(1, 3);
// New Shelf: ["B", "C"]
// Bookmark was at 4. Now shifts left by 3. Bookmark should be 1.
printShelf(shelfManager);
// 4. Move Books
std::cout << "--- addBooks: Add books for move test ---\n";
shelfManager.addBooks(2, {"D", "E", "F", "G", "H"});
// Current Shelf: ["B", "C", "D", "E", "F", "G", "H"]
// set bookmark to 'D' at index 2
shelfManager.setBookmarkIndex(2);
printShelf(shelfManager);
std::cout << "--- moveBooks: Move 3 books ('D', 'E', 'F') from index 2 to index 6 ---\n";
shelfManager.moveBooks(2, 6, 3);
// New Shelf: ["B", "C", "G", "H", "D", "E", "F"]
// Bookmark was at 'D' (index 2 in old shelf). 'D' is now at index 4. Bookmark should be 4.
printShelf(shelfManager);
std::cout << "--- setBookmarkIndex: Set to 'G' at index 2 ---\n";
shelfManager.setBookmarkIndex(2);
printShelf(shelfManager);
std::cout << "--- moveBooks: Move 3 books ('D', 'E', 'F') from index 4 to index 0 ---\n";
shelfManager.moveBooks(4, 0, 3);
// Old Shelf: ["B", "C", "G", "H", "D", "E", "F"]
// New Shelf: ["D", "E", "F", "B", "C", "G", "H"]
// Bookmark was at 'G' (index 2 in old shelf). It shifts right by 3. Bookmark should be 5.
printShelf(shelfManager);
return 0;
}Editor is loading...
Leave a Comment