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];
else
return 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;
}
同样,我们也不再赘述链表的实现方案了。