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

本文介绍了一种使用多重数组实现双链表的方法,通过逻辑构造和自由链表管理,使得操作如同使用指针一样自然。详细阐述了对象的多重数组表示、动态集合的插入和删除,以及如何通过分配和释放对象来优化空间管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

   在有些语言(例如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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值