概述
链表由一系列不必在内存中相连的结构组成。每个结构都含有表元素和指向包含该元素后继元的结构的指针。
可以使用数组简单地实现一个表,但它通常具有以下缺点:
- 需要对表的大小的最大值进行估计,导致空间的大量浪费
- 插入和删除的运行时间很慢
想象一个简单的链表,并思考以下问题:
- 并不存在从所给定义出发在表的前面插入元素的真正显性的方法
- 从表的前面实行删除是一个特殊的情况,因为它改变表的起始端,编程中的疏忽将会造成表的丢失
- 在一般的删除操作中,虽然指针移动简单,但是删除算法要求我们记住被删除元素前面的表元
使用表头可以较简单地解决上述问题,但是否使用表头因人而异。以下程序全程均使用表头。
表ADT
抽象数据类型(abstract data type)是一些操作的集合。对诸如表、集合、图和它们的操作一起可以看作是抽象数据类型,操作它们就像操作整数、布尔数据类型一样。
下面的例子中,把作为类型的List和Position以及函数的原型都列在头文件中,具体的节点Node声明在c文件中。
#ifndef _LIST_H
#define _LIST_H
struct node;
typedef struct node *ptrnode;
typedef ptrnode list;
typedef ptrnode position;
list makeempty(list l);
int isempty(list l);
int islast(position p, list l);
position find(elementtype x, list l);
void delete(elementtype x, list l);
void insert(elementtype x, list l, position p);
void deletelist(list l);
#endif /* _LIST_H */
struct node {
elementtype element;
position next;
};
表操作
测试表是否为空
/* return true if L is empty*/
int isempty(list l)
{
return l->next == NULL;
}
测试当前位置是否是表末尾
int islast(position p, list l)
{
return p->next == NULL;
}
find例程
/* return pisition of x in l; null if not found */
position find(elementtype x, list l)
{
position p;
p = l->next;
while (p != NULL && p->element != x)
p = p->next;
return p;
}
delete例程
void delete(elementtype x, list l)
{
position p, tmpcell;
p = findprevious(x, l);
if (!islast(p, l)) {
tmpcell = p->next;
p->next = tmpcell->next;
free(tmpcell);
}
}
查找前一个节点
position findprevious(elementtype x, list l)
{
position p;
p = l;
while(p->next != NULL && p->next->element != x)
p = p->next;
return p;
}
insert例程
void insert(elementtype x, list l, position p)
{
position tmpcell;
tmpcell = malloc(sizeof(struct node));
if (tmpcell == NULL)
return -1;
tmpcell->element = x;
tmpcell->next = p->next;
p->next = tmpcell;
}
---
参考资料:
《数据结构与算法分析——c语言描述》