有许多语言都不支持指针,若需要链表又不能使用指针,就必须用另外的实现方法。我们称之为 游标(cursor)实现法。
链表的指针实现中有两个重要特性:
1.数据存储在一组结构体中,每个结构体包含数据以及指向下一个结构体的指针。
2.一个新的结构体可以通过调用malloc而从系统全局内存(global memory)中得到,并可通过调用free释放。
游标法必须能够模仿实现这两条特性。满足条件1的逻辑方法是要有一个全局的结构体数组。数组下标可以用来代表一个地址,要模拟条件2,可以让 CursorSpace数组中的单元来代行 malloc和free的职能,为此我们保留一个表(即freelist),这个表由不在任何表中的单元构成,该表将用单元0作为表头。如下给出链表游标实现的声明:
typedef int Position;
typedef int List;
typedef int ElementType;
struct Node
{
ElementType Element;
Position next;
};
struct Node CursorSpace[SIZE];
对于next,0的值等价于NULL指针。
初始化结构体数组例程:
一开始全为freelist,所以表为顺序相连的一个表,最后一个单元指向空 也即是0。
void InitCursorSpace()
{
int i;
for (i = 0; i < SIZE; i++)
{
CursorSpace[i].element = 0;
CursorSpace[i].next = i + 1;
if (i == SIZE - 1)
CursorSpace[i].next = 0;
}
}
创建表头例程:
List HeaderCreate()
{
List list = CursorAlloc();
if (list)
{
CursorSpace[list].next = 0;
CursorSpace[list].element = 0;
}
return list;
}
声明空间例程:
将freelist中第一个单元的位置,也即CursorSpace[0].next位置的空间赋给p,然后freelist变成了从第二个单元开始的表,第五行将表头指向第二个单元,
Position CursorAlloc()
{
Position p;
p = CursorSpace[0].next;
CursorSpace[0].next = CursorSpace[p].next;
return p;
}
释放空间例程:
释放p位置的空间,就是把p位置的空间放到freelist中,最方便的是放到第一个单元,那么单元p指向原第一单元,再将表头指向单元p,那么p进入freelist中,释放完成。
void CursorFree(Position p)
{
CursorSpace[p].next = CursorSpace[0].next;
CursorSpace[0].next = p;
}
判断表是否为空与某单元是否在表末尾:查找与查找前一个:
Position Find(List list, ElementType x)
{
Position tmpNode;
tmpNode = CursorSpace[list].next;
while (tmpNode && CursorSpace[tmpNode].element != x)
tmpNode = CursorSpace[tmpNode].next;
return tmpNode;
}
Position FindPrevious(List list, ElementType x)
{
if (IsEmpty(list))
return 0;
Position tmpNode = list;
Position nextNode = CursorSpace[tmpNode].next;
while (!IsLast(tmpNode) && CursorSpace[nextNode].element != x)
{
tmpNode = CursorSpace[tmpNode].next;
nextNode = CursorSpace[tmpNode].next;
}
return tmpNode;
}
删除:
这里没写出尾删,读者可以试一试自行写出
void Delete(List list, ElementType x)
{
Position p, tmpNode;
p = FindPrevious(list, x);
if (!IsLast(p))
{
tmpNode = CursorSpace[p].next;
CursorSpace[p].next = CursorSpace[tmpNode].next;
CursorFree(tmpNode);
}
}
插入与尾插:
void Insert(List list, ElementType x, Position p)
{
Position tmpNode = CursorAlloc();
if (!tmpNode)
{
printf("insert failed\n");
return;
}
CursorSpace[tmpNode].element = x;
CursorSpace[tmpNode].next = CursorSpace[p].next;
CursorSpace[p].next = tmpNode;
}
void BackInsert(List list, ElementType x)
{
Position tmpNode = list;
while (CursorSpace[tmpNode].next)
tmpNode = CursorSpace[tmpNode].next;
Insert(list, x, tmpNode);
}
链表的打印:
void PrintList(List list)
{
Position tmpNode = list;
while (CursorSpace[tmpNode].next)
{
printf("%d ", CursorSpace[CursorSpace[tmpNode].next].element);
tmpNode = CursorSpace[tmpNode].next;
}
printf("\n");
}
测试:
int main()
{
InitCursorSpace();
List L = HeaderCreate();
BackInsert(L, 4);
BackInsert(L, 2);
BackInsert(L, 3);
BackInsert(L, 7);
BackInsert(L, 6);
BackInsert(L, 10);
PrintList(L);
Delete(L, 4);
PrintList(L);
Delete(L, 6);
PrintList(L);
return 0;
}
输出结果:
4 2 3 7 6 10
2 3 7 6 10
2 3 7 10
至此链表的游标实现完成。