链表
为了避免插入和删除的线性开销,我们可以允许表不连续存储,由此产生了链表。
链表由一系列不必在内存中相连的结构组成,每一个结构均含有元素表和指向包含该元素后继元素元的结构指针(Next指针)。
最后一个单元的Next指针指向NULL,该值由C定义并且不能与指针相混淆。
指针变量就是包含存储另外某个数据的地址变量。 因此,如果某空间被声明为指向一个结构的指针,那么存储在其中的值就会被解释为主存中的一个位置,再在该位置可以找到一个结构。一个指针就是一个数。
删除命令可以通过修改一个指针来实现。即将要删除元素的前一个元素的指针变量指向删除元素的下一个元素,最后释放被删除元素的空间。
插入命令需要使用一次 malloc 调用从系统中得到一个新单元,并在此后执行两次指针调整。
程序设计
因为在实际中可能会出现的各种问题,为了避免这些问题,我们将留出一个标志节点,将之称之为表头。我们约定,表头在位置 0 处。
链表的类型声明:
#ifndef _List_H
struct Node;
typedef struct Node *PtrToNode;
typedef PtrToNode List;
typedef PtrToNode Position;/* position:位置,地方。*/
List MakeEmpty( List L );
int IsEmptype( List L);
int IsLast( Position P, List L);
Position Find( int X, List L);
void Delete( int X, List L);
Position FindPrevious( int X, List L); /* previous:先前的,以往的。*/
void Insert( int X, List L, Position P);/*insert:插入,嵌入。*/
void DeleteList( List L);
Position Header( List L);
Position First( List L);
Position Advance( Position P);/* advance:进展,进步。*/
int Retrieve( Position P);/* retrieve:取回,找回。*/
int NULL = 0;
#endif
struct Node
{
int Element;/* element:要素,基本部分。*/
Position Next;
};
测试一个表是否为空:
int IsEmpty( List L)
{
return L->Next == NULL;
};
测试当前的元素是否为表的最后一个元素:
int IsLast( Position P, List L )
{
return P->Next == NULL;
};
该函数返回某个元素在表中的位置:
Position Find( int X, List L)
{
Position P;
P = L->Next;
while(P != NULL && P->Element != X)
/*上面的式子中,如果运算的前半部分为假*/
/*那么结果就为假,后半部分不再执行*/
P = P->Next;
return P;
};
删除表 L 中的某个元素:
void Delete( int X, List L )
{
Position P, TmpCell;/* template:模板,样板。cell:细胞。*/
P = FindPrevious( X, L );
if( !IsLast( P, L ) )
{
TmpCell = P->Next;
P->Next = TmpCell->Next;
free( TmpCell );
}
};
插入,将要插入的元素和表 L 和位置 P 一起传入:
Position FindPrevious( int X, List L )
{ /*用以知道位置P处前面的元素*/
Position P;
P = L;
while( P->Next != NULL && P->Next->Element != X )
P = P->Next;
return P;
};
void Insert( int X, List L, Position P)
{
Position TmpCell;
TmpCell = malloc( sizeof( struct Node ) );
if( TmpCell == NULL )
FatalError( "Out of space!!!" );/* space:空间。*/
TmpCell->Element = X;
TmpCell->Next = P->Next;
P->Next = TmpCell;
};