用对象的多重数组实现双链表

来源:互联网 发布:数据库中where的用法 编辑:程序博客网 时间:2024/04/30 06:30

   在有些语言(例如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 0x7fffffffusing 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);elselst.insert(-i);}cout << lst << endl;getchar();return 0;}


0 0
原创粉丝点击