线性表
一、定义:
l 线性表是由称为元素(element)的数据项组成的一种有限且有序的序列。
l 线性表中不包括任何元素时,称之为空表。当前存储的元素数目称之为线性表的长度(length)。线性表的开始节点称为表头(head),结尾节点称为表尾(tail)。表中元素的值与它的未知之间可以有联系也可以没有联系。
l 线性表的第一个元素使用0来表示的。
l 线性表有两种实现方式:顺序表和链表。
l ADT:
template <typename E> classList {
public:
List(){}
virtual ~List() {}
virtual void append( E& item) = 0;
virtual E remove() = 0;
virtual void insert() = 0;
virtual void moveToStart() = 0;
virtual void moveToEnd() = 0;
virtual void moveToPos(int pos) = 0;
virtual void prev() = 0;
virtual void next() = 0;
virtual int length() = 0;
virtual int currPos() = 0;
virtual const E& getValue() const = 0;
};
二、顺序表:
l AList:
template <typenameE>
class AList :publicList < E > {
private:
int maxSize; //顺序表的最大长度
int listSize; //当前顺序表中的元素个数
int curr; //当前的元素
E* listArray; //数组
public:
AList(int size = defaultSize){
maxSize = size;
listSize = curr = 0;
listArray = new E[maxSize];
}
~AList(){ delete[] listArray; }
void clear() //清空
{
delete[] listArray;
listSize = curr = 0;
listArray = new E[maxSize];
}
void insert(const E& it) //插入
{
assert(listSize < maxSize,"List capacity exceeded");
for (int i = listSize; i >curr; i--)
listArray[i] =listArray[i - 1];
listArray[curr] = it;
listSize++;
}
void moveToStart() { curr = 0; } //移动到开头
void moveToEnd() { curr = listSize; }//移动到结尾
void prev() { if(curr != 0) curr--; } //上一个
void next() { if(curr<listSize)curr++; }//下一个
int length() const { return listSize; } //当前顺序表长度
int currPos() const { return curr; } //当前位置
void append(E& item) //在末尾添加元素
{
assert(listSize < maxSize,"List capacity exceeded");
listArray[listSize++] = item;
}
void moveToPos(int pos) //移动到某一个位置
{
assert((pos >= 0)&& (pos < listSize), "No element");
curr = pos;
}
E remove() //删除某一元素
{
assert((curr >= 0)&& (curr < listSize), "No element");
E it = listArray[curr];
for (int i = curr; i <listSize-1; i++)
listArray[i] =listArray[i + 1];
listSize--;
return it;
}
const E& getValue() const //当前位置的值
{
assert((curr>0) &&(curr < listSize), "No current element");
return listArray[curr];
}
};
l 平均来说,插入和删除要移动一半的元素,即需要Θ(n)时间。
三、链表:
l 利用指针实现线性表,链表是动态的,它能够按照需要为表中新的元素分配存储空间。
l 链表是由一系列称为表的节点的对象组成的。
l 节点的定义:
Link:
template <typename E> class Link {
public:
Eelement; //节点的值
Link*next; //指向下一个节点
//构造函数
Link(constE& elemval, Link* nextval = NULL)
{
element= elemval;
next= nextval;
}
Link(Link*nextval = NULL) { next = nextval; }
};
l 链表类的定义:
template<typenameE> class LList : public Link < E > {
private:
Link<E>* head; //链表的头指针
Link<E>* tail; //链表的尾部
Link<E>* curr; //当前位置
int cnt; //链表的长度
void init(){
curr = tail = head = new Link< E > ;
cnt = 0;
}
void removeall(){
while (head != NULL)
{
curr = head;
head = head->next;
delete curr;
}
}
public:
LList(int size = defaultSize){ init(); }
~LList(){ removeall(); }
void print() //打印链表元素
{
Link* temp = head->next;
for (int i = 0; i < cnt; i++)
{
cout <<temp->element << " ";
temp = temp->next;
}
cout << endl;
}
void clear(){ removeall(); init(); }
void insert(const E& it)
{
curr->next = newLink<E>(it, curr->next);
if (tail == curr) tail =curr->next;
cnt++;
}
void append(const E& it) //添加链表元素
{
tail = tail->next = newLink<E>(it, NULL);
cnt++;
}
const E& getValue() const //获取值
{
assert(curr->next != NULL,"No value");
returncurr->next->element;
}
E remove() //移除当前节点
{
assert(curr->next != NULL,"No Element!");
E it =curr->next->element;
Link<E>* ltemp =curr->next;
curr->nect =curr->next->next;
delete ltemp;
cnt--;
return it;
}
void moveToEnd()
{
curr = head;
}
void moveToStart()
{
curr = tail;
}
void prev() //上一个结点
{
if (curr == head) return;
Link < E>* temp = head;
while (temp->next != curr)temp = temp->next;
curr= temp;
}
void next() //下一个结点
{
if (curr == tail) return;
curr = curr->next;
}
int length() const
{
return cnt;
}
int currPos() const //当前结点
{
Link<E>* temp = head;
int i = 0;
while (temp != curr)
{
temp = temp->next;
i++;
}
return i;
}
void moveToPos(int pos) //移到当前结点
{
assert((pos >= 0) &&(pos <= cnt), "position out of range");
curr = head;
for (int i = 0; i < pos; i++)
curr = curr->next;
}
};
l 可利用空间表
Link类能管理自己的可利用空间表(freelist),以取代反复调用的new和delete。可利用空间表存放当前那些不用的线性表,从一个链表中删除的结点就可以放到可利用空间表的首端。当需要把一个新元素增加到链表中时,先检查可利用空间表,看看是否有可用的线性表节点。如果有空结点,则从可利用空间表中取走一个结点。只有当可利用空间表为空时,才会调用标准操作符new。
l 可利用空间表的实现方法:在Link类实现中增加两个新函数,以替代标准的存储分配和回收管理例程new和delete。