链表及其实现

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

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_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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值