在有些语言(例如FORTRAN)中不提供指针与对象数据类型,那么该如何实现双链表呢?我们将介绍运用数组和数组下标在逻辑上来构造双链表,让它表现的就像用指针实现的一样自然。
对象的多重数组表示
如下图是一个用数组实现的双链表的逻辑图:
对一组具有相同域的对象,每一个域都可以用一个数组来表示。上图说明了如何用三个数组实现双链表。动态几何的关键字存储在数组key中,而指针域存储在prev和next中。对于一个给定的下标x,key[x],prev[x],next[x]久共同组成了链表中的一个对象,即节点,在这种解释下,一个指针x即为指向数组key,prev和next的共同下标。
在上图的链表中,关键字4的对象在关键字为16的对象的后面。对应地,关键字出现在key[2]上,关键字16出现在key[5]桑,故有next[5] = 2;prev[2] = 5.虽然常熟NIL(/)出现在表尾的next域和表头的prev域中,但我们通常用一个不指向数组中任何一个位置的整数(在我们的实现代码中,取NOEXIST为-1)来表示之。另外变量L存储了表头元素的下标。
分配和释放对象
为向一个用双链表表示的动态集合中插入一个对象,需要分配一个当前指向链表表示中未被使用的对象的指针,即下标。那么,我们需要对链表中未被使用的空间进行管理,从而方便分配。
在这里,我们利用指针域把自由对象组织成一个单链表,成为自由链表。自由链表仅用到next域,其中存放着下一个自由对象的下标,此链表头存储在free中。当链表L非空时,自由链表和双链表L将相互交错到一起,如下图所示。但是,一个空间要么存在于自由链表中,要么存在于双链表中,不可能同时存在于两者之中。
a)为链表初始时;b)表示插入关键字25之后的结果;c)表示删除关键字16的结果。
自由类似于一个栈,每次分配时取用的空间都是从自由链表头摘取,即最近被释放的那个,下面是分配和回收自由对象的函数。
获得一个自由对象
template <typename T>
inline size_t list<T>::getFree()
{
if (free == NOEXIST)
{//若自由链表已空,则需补充空间
size_t *old_next = next, *old_prev = prev;
T *old_key = key;
size_t old_list_size = list_size;
list_size *= 2;
newList(list_size);//分配新空间
copyList(old_prev, old_key, old_next, old_list_size);//复制内容到新空间
deleteList(old_prev,old_key,old_next);//释放旧空间
setFree(old_list_size);
}
size_t index = free;
free = next[index];
return index;
}
释放一个节点
void addFree(size_t index)
{//添加空闲空间到自由链表
next[index] = free;
free = index;
}
在空间足够时,上面两个过程的时间代价均为O(1),因而很实用。
多重数组表示的双链表的具体实现
我们都知道,普通的数组都有一个缺陷,即不能够动态的改变大小,每次都必须提前分配足够的空间。对于用多重数组来实现双链表,并且要表现的像用指针实现的一样自然,首要解决的就是动态分配以及回收空间的问题。在上面的分配过程getFree中我们已经看到采用的策略是一旦空间不够,即马上分配两倍于原来的大小,并复制原先内容到新空间,然后释放旧空间。
解决了这个问题,那么接下来的实现就很简单了,在逻辑上我们就可以将这两个链表free和L改变成我们熟悉的样子来理解插入和删除等过程。
实现源代码:
#include<iostream>
#define NOEXIST 0x7fffffff
using namespace std;
template <typename T> class list;
template <typename T> ostream& operator<<(ostream&, const list<T> &);
template <typename T>
class list
{
private:
size_t *next;
T *key;
size_t *prev;
size_t free;//管理自由节点链表,单链表即可
size_t head;//管理已用结点链表,双链表
size_t list_size;//链表总大小,包括自由链表
friend ostream& operator<< <T>(ostream&, const list &);
size_t getFree();//获得自由节点
void addFree(size_t index)
{//添加空闲空间到自由链表
next[index] = free;
free = index;
}
void newList(size_t n)
{//分配空间
key = new T[n];
next = new size_t[n];
prev = new size_t[n];
}
void deleteList(size_t *p, T *k, size_t *n)
{//收回空间
delete[] p;
delete[] k;
delete[] n;
}
void copyList(size_t *p, T *k, size_t *n, size_t s)
{//复制链表
copy(p, p + s, prev);
copy(n, n + s, next);
copy(k, k + s, key);
}
void setFree(size_t start_index)
{//设置自由链表
next[list_size - 1] = NOEXIST;
for (size_t i = start_index; i != list_size - 1; ++i)
next[i] = i + 1;
free = start_index;
}
public:
list() :free(NOEXIST), head(NOEXIST), list_size(8)//-1表示空,最初链表有8个空间
{//初始化,设置free链表
newList(list_size);
setFree(0);
}
list(T *beg, T *end) :list() { insert(beg, end); }
void setData(size_t index, const T &t) { key[index] = t; }
T getData(size_t index)const { return key[index]; }
void insert(const T&);
void insert(T*, T*);
size_t locate(const T&);
void erase(const T&);
void erase(size_t);
void edit(const T&, const T&);
bool empty() { return head == NOEXIST; }//链表是否为空
~list()
{
deleteList(prev, key, next);
}
//bool full() { return free == -1; }
};
template <typename T>
inline size_t list<T>::getFree()
{
if (free == NOEXIST)
{//若自由链表已空,则需补充空间
size_t *old_next = next, *old_prev = prev;
T *old_key = key;
size_t old_list_size = list_size;
list_size *= 2;
newList(list_size);
copyList(old_prev, old_key, old_next, old_list_size);
deleteList(old_prev,old_key,old_next);
setFree(old_list_size);
}
size_t index = free;
free = next[index];
return index;
}
template <typename T>
void list<T>::insert(const T &t)
{
size_t index = getFree();
key[index] = t;
if (head == NOEXIST)
{//插入的是第一个节点
next[index] = NOEXIST;
prev[index] = NOEXIST;
head = index;
}
else
{//否则
next[index] = head;
prev[head] = index;
prev[index] = NOEXIST;
head = index;
}
}
template <typename T>
void list<T>::insert(T *beg, T *end)
{
for (; beg != end; ++beg)
insert(*beg);
}
template <typename T>
size_t list<T>::locate(const T &t)
{
size_t p = head;
while (p != NOEXIST && key[p] != t)
p = next[p];
return p;
}
template <typename T>
void list<T>::erase(size_t index)
{
if (index == head)//删除的是头结点
head = next[index];
else
{
next[prev[index]] = next[index];
if (next[index] != NOEXIST)//若删除的不是最后一个节点
prev[next[index]] = prev[index];
}
addFree(index);
}
template <typename T>
void list<T>::erase(const T &t)
{
size_t index = locate(t);
if (index != NOEXIST)
erase(index);
}
template <typename T>
void list<T>::edit(const T &old_key, const T &new_key)
{
size_t index = locate(old_key);
if (index == NOEXIST)
{
cout << old_key << " isn't exist!" << endl;
return;
}
key[index] = new_key;
}
template <typename T>
ostream& operator<<(ostream &out, const list<T> &lst)
{
size_t p = lst.head;
while (p != NOEXIST)
{
out << lst.key[p];
if (lst.next[p] != NOEXIST) out << ' ';
p = lst.next[p];
}
return out;
}
int main()
{
int a[] = { 1, 2, 3, 4, 5, 6 };
list<int> lst(a,a + 6);
cout << lst << endl << endl;
for (int i = 10; i != 20; ++i)
lst.insert(i);
cout << lst << endl << endl;
for (int i = 1; i != 1000; ++i)
{
size_t f = lst.locate(i);
if (f != NOEXIST)
lst.erase(f);
else
lst.insert(-i);
}
cout << lst << endl;
getchar();
return 0;
}