链表及其实现

来源:互联网 发布:时时彩娱乐平台源码 编辑:程序博客网 时间:2024/06/07 02:54

前言
  本文在完成过程中,得到许多朋友的帮助,在此谢谢诸位。本人欢乐无限,技术有限,如有任何问题,欢迎各位不吝赐教。

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。对象中还可以含有其他的辅助数据,称作卫星数据。当我们要移动关键字时,卫星数据也必须要移动。如果对象中含有大量卫星数据,则通常移动指针而不是对象本身。简单起见,我们这里没有卫星数据。所以对象就可以用下面图中的结点表示:
1
  从上面的图中可以看出,结点包含两个域:数据域element和指针域next。现在数据域里面只有关键字没有卫星数据。指针域next指向该结点的后继,注意的是最后一个结点的next为NULL(在图中用^表示)。有了以上模型,链表结点的声明如下:

typedef int ElementType;typedef struct Node *Position;struct Node{    ElementType element;    Position    next;};

  下面是一个含有5个对象的链表。
2
  在用C语言实现的链表中,结点是动态地分配存储的,即程序在需要时才开辟一个结点的存储单元。C语言标准库<stdlib.h>提供了malloc函数来从操作系统那里获得所需要的存储空间。当然如果你申请的空间不再需要,记得用free函数来回收,以免内存泄漏噢。
  为了使删除操作能够更一般的进行(主要为了避免删除第一个节点这种特殊情况),我们在表的第一个节点前面添加了一个头结点。则上面的表可以表示成这样:
3

2.2 单链表的C程序实现

  首先是List.h:

typedef int ElementType;#ifndef LIST_H#define LIST_Hstruct 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;}
0 0