1 有序線性表
有序線性表是最基本的可搜尋容器,其提供除了可搜尋容器的操作,還有自己的一些基本操作。那麼什麼是可搜尋容器呢,可搜尋容器定義如下:
class SearchableContainer : public virtual Container{public:virtual bool IsMember (Object const&) const = 0;virtual void Insert (Object&) = 0;virtual void Withdraw (Object&) = 0;virtual Object& Find (Object const&) const = 0;};
也就是說,具有IsMember(判斷是否含有某對象)、Insert(插入某對象)、Withdraw(刪除某對象)和Find(尋找某對象)這四個基本操作的抽象容器就是可搜尋容器。
那麼什麼是有序線性表呢?定義如下:
class Position : public Iterator{};class List : public virtual SearchableContainer{public: virtual Object& operator [] (unsigned int) const = 0; virtual Object& operator [] (Position const&) const = 0; virtual Position& FindPosition (Object const&) const = 0; virtual void Withdraw (Position const&) = 0;};class OrderedList : public virtual List{public: virtual void InsertAfter (Position const&, Object&) = 0; virtual void InsertBefore (Position const&, Object&) = 0;};
我們看到有序線性表OrderedList除了具備可搜尋容器的基本特性,同時還具有以下操作:
virtual Object& operator []
:存取表中某一給定位置上的對象。
virtual Position& FindPosition:尋找對象在表中的位置。
virtual void Withdraw (Position):刪除表中某一給定位置上的對象。
virtual void InsertAfter:把一個對象插在某一給定對象位置之後。
virtual void InsertBefore:把一個對象插在某一給定對象位置之前。
有序線性表的數組標記法:
class ListAsArray : public virtual OrderedList{protected: Array<Object*> array; class Pos;public: ListAsArray (unsigned int); // ... friend class Pos;};ListAsArray::ListAsArray (unsigned int size) : array (size) {}void ListAsArray::Insert (Object& object){ if (count == array.Length ())throw domain_error ("list is full"); array [count] = &object; ++count;}Object& ListAsArray::operator [] (unsigned int offset) const{ if (offset >= count)throw out_of_range ("invalid offset"); return *array [offset];}bool ListAsArray::IsMember (Object const& object) const{ for (unsigned int i = 0; i < count; ++i)if (array [i] == &object) return true; return false;}Object& ListAsArray::Find (Object const& object) const{ for (unsigned int i = 0; i < count; ++i)if (*array [i] == object) return *array [i]; return NullObject::Instance ();}void ListAsArray::Withdraw (Object& object){ if (count == 0)throw domain_error ("list is empty"); unsigned int i = 0; while (i < count && array [i] != &object)++i; if (i == count)throw invalid_argument ("object not found"); for ( ; i < count - 1U; ++i)array [i] = array [i + 1]; --count;}class ListAsArray::Pos : public Position{protected: ListAsArray const& list; unsigned int offset;public: // ... friend class ListAsArray; friend class SortedListAsArray;};Position& ListAsArray::FindPosition (Object const& object) const{ unsigned int i = 0; while (i < count && *array [i] != object)++i; return *new Pos (*this, i);}Object& ListAsArray::operator [] (Position const& arg) const{ Pos const& position = dynamic_cast<Pos const&> (arg); if (&position.list != this || position.offset >= count)throw invalid_argument ("invalid position"); return *array [position.offset];}void ListAsArray::InsertAfter ( Position const& arg, Object& object){ Pos const& position = dynamic_cast<Pos const&> (arg); if (count == array.Length ())throw domain_error ("list is full"); if (&position.list != this || position.offset >= count)throw invalid_argument ("invalid position"); unsigned int const insertPosition = position.offset + 1; for (unsigned int i = count; i > insertPosition; --i)array [i] = array [i - 1U]; array [insertPosition] = &object; ++count;}void ListAsArray::Withdraw (Position const& arg){ Pos const& position = dynamic_cast<Pos const&> (arg); if (count == 0)throw domain_error ("list is empty"); if (&position.list != this || position.offset >= count)throw invalid_argument ("invalid position"); for (unsigned int i = position.offset; i < count-1U; ++i)array [i] = array [i + 1]; --count;}
有序表也可以通過鏈表來實現,有興趣的可以自己去研究一下,不再贅述。
2 排序表
排序表是另一種很有用的可搜尋容器,它跟有序線性表的區別在於,不提供前插和後插的操作,當插入元素後,表中所有的元素應保持有序狀態,來看實現:
class SortedList : public virtual List{};
這可能是全文中最簡單的一個抽象類別實現了,其就是一個廣義表。來看排序表的數組標記法:
class SortedListAsArray : public virtual SortedList, public virtual ListAsArray{ unsigned int FindOffset (Object const&) const;public: SortedListAsArray (unsigned int); // ...};void SortedListAsArray::Insert (Object& object){ if (count == array.Length ())throw domain_error ("list is full"); unsigned int i = count; while (i > 0 && *array [i - 1U] > object) {array [i] = array [i - 1U];--i; } array [i] = &object; ++count;}unsigned int SortedListAsArray::FindOffset ( Object const& object) const{ int left = 0; int right = count - 1; while (left <= right) {int const middle = (left + right) / 2;if (object > *array [middle]) left = middle + 1;else if (object < *array [middle]) right = middle - 1;else return middle; } return count;}Object& SortedListAsArray::Find (Object const& object) const{ unsigned int const offset = FindOffset (object); if (offset < count)return *array [offset]; elsereturn NullObject::Instance ();}Position& SortedListAsArray::FindPosition ( Object const& object) const{ Pos& result = *new Pos (*this); result.offset = FindOffset (object); return result;}void SortedListAsArray::Withdraw (Object& object){ if (count == 0)throw domain_error ("list is empty"); unsigned int const offset = FindOffset (object); if (offset == count)throw invalid_argument ("object not found"); for (unsigned int i = offset; i < count - 1U; ++i)array [i] = array [i + 1]; --count;}
同樣,我們也不再贅述鏈表的實現方案了。