前言
本文在完成过程中,得到许多朋友的帮助,在此谢谢诸位。本人欢乐无限,技术有限,如有任何问题,欢迎各位不吝赐教。
1 表ADT
N个对象A1,A2,…,AN组成的一个线性序列,称为线性表,简称表。其中Ai是表中的数据元素,N为表的大小。若N=0,则该表为空表。Ai称为Ai+1的前驱,反过来Ai+1为Ai的后继。
在线性表中,数据元素之间的关系是一对一的,也就是说,除第一个元素外,其它元素都只有一个前驱,除最后一个元素,其它元素只有一个后继。
从存储结构上来看,表通常有两种:顺序表和链表。在顺序表中,各个对象的位置是由数组下标决定。而在链表中,对象的位置则由对象里的指针决定。在这里先主要讨论链表的实现(以后有机会再把顺序表补上,嘿嘿)。
链表的主要操作有以下这些:
find(x, L):查找关键字x第一次出现表L中的位置。
insert(x, L, p):将关键字x插入到位置p的后面。
delete(x, L):从表L中删除关键字x。
findPrevious(x, L):查找x的前驱的位置。
retrieve(p):返回位置p上的关键字。
最后,给出链表的递归定义方式(摘自《算法》Robert Sedgewick):链表是一种递归的数据结构,它或者为空,或者是指向一个结点的引用(指针),该结点含有一个泛型的元素和一个指向另一个链表的引用(指针)。在下面的C语言的实现中没有用到这个递归定义,感兴趣的童鞋可以试着用递归实现链表。
2 单链表的实现
2.1 单链表的模型和表示
链表相对于顺序表,具有更好的动态性。下面主要讨论最简单的一种链表——单链表。
在单链表中,表的每一个对象除了含有关键字element外,还有一个指针next。对象中还可以含有其他的辅助数据,称作卫星数据。当我们要移动关键字时,卫星数据也必须要移动。如果对象中含有大量卫星数据,则通常移动指针而不是对象本身。简单起见,我们这里没有卫星数据。所以对象就可以用下面图中的结点表示:
从上面的图中可以看出,结点包含两个域:数据域element和指针域next。现在数据域里面只有关键字没有卫星数据。指针域next指向该结点的后继,注意的是最后一个结点的next为NULL(在图中用^表示)。有了以上模型,链表结点的声明如下:
typedef int ElementType;
typedef struct Node *Position;
struct Node{
ElementType element;
Position next;
};
下面是一个含有5个对象的链表。
在用C语言实现的链表中,结点是动态地分配存储的,即程序在需要时才开辟一个结点的存储单元。C语言标准库<stdlib.h>提供了malloc函数来从操作系统那里获得所需要的存储空间。当然如果你申请的空间不再需要,记得用free函数来回收,以免内存泄漏噢。
为了使删除操作能够更一般的进行(主要为了避免删除第一个节点这种特殊情况),我们在表的第一个节点前面添加了一个头结点。则上面的表可以表示成这样:
2.2 单链表的C程序实现
首先是List.h:
typedef int ElementType;
#ifndef LIST_H
#define LIST_H
struct Node;
typedef struct Node *Position;
typedef struct Node *List;
List makeEmpty( List L );
int isEmpty( List L );
int isLast( Position p, List L );
Position find( ElementType x, List L );
Position findPrevious( ElementType x, List L );
void delete( ElementType x, List L );
void insert( ElementType x, List L, Position p );
void deleteList( List L );
Position header( List L );
Position first( List L );
Position advance( Position p );
ElementType retrieve( Position p );
#endif
Fatal.h:
#include <stdio.h>
#include <stdlib.h>
#define Error( Str ) FatalError( Str )
#define FatalError( Str ) fprintf( stderr, "%s\n", Str ), exit( 1 )
List.c:
#include <stdlib.h>
#include "List.h"
#include "Fatal.h"
struct Node{
ElementType element;
Position next;
};
List makeEmpty( List L )
{
if( L != NULL )
deleteList( L );
else{
L = malloc( sizeof( struct Node ) );
if( L == NULL )
FatalError( "Out of memory!" );
L->next = NULL;
}
return L;
}
int isEmpty( List L )
{
return L->next == NULL;
}
int isLast( Position p, List L )
{
return p->next == NULL;
}
Position find( ElementType x, List L )
{
Position p;
p = L->next;
while( p != NULL && p->element != x )
p = p->next;
return p;
}
/* If X is not found, then Next field of returned value is NULL */
Position findPrevious( ElementType x, List L )
{
Position p;
p = L;
while( p->next != NULL && p->next->element != x )
p = p->next;
return p;
}
/* Delete from a list */
/* Cell pointed to by P->Next is wiped out */
/* Assume that the position is legal */
/* Assume use of a header node */
void delete( ElementType x, List L )
{
Position p, tmpCell;
p = findPrevious( x, L );
if( !isLast( p, L ) ){ /* X is found; delete it */
tmpCell = p->next;
p->next = tmpCell->next; /* Bypass deleted cell */
free( tmpCell );
}
}
void insert( ElementType x, List L, Position p )
{
Position tmpCell;
tmpCell = malloc( sizeof( struct Node ) );
if( tmpCell == NULL )
FatalError( "Out of space!!!" );
tmpCell->element = x;
tmpCell->next = p->next;
p->next = tmpCell;
}
void deleteList( List L )
{
Position p, tmp;
p = L->next; /* Header assumed */
L->next = NULL;
while( p != NULL ){
tmp = p->next;
free( p );
p = tmp;
}
}
Position header( List L )
{
return L;
}
Position first( List L )
{
return L->next;
}
Position advance( Position p )
{
return p->next;
}
ElementType retrieve( Position p )
{
return p->element;
}
main.c:
#include <stdio.h>
#include "List.h"
void printList( const List L )
{
Position p = header( L );
if( isEmpty( L ) )
printf( "Empty list\n" );
else{
do{
p = advance( p );
printf( "%d ", retrieve( p ) );
} while( !isLast( p, L ) );
printf( "\n" );
}
}
int main(int argc, char *argv[])
{
List L;
Position p;
L = makeEmpty( NULL );
p = header( L );
printList( L );
for(int i = 0; i < 5; i++ ){
insert( i, L, p );
printList( L );
p = advance( p );
}
for(int i = 0; i < 5; i += 2 )
delete( i, L );
printf( "Finished deletions\n" );
printList( L );
return 0;
}