线性表的链式存储方式(C)


线性结构是一种基本的数据结构,主要用于对具有单一前驱和后继的数据关系进行描述。它的特点是数据元素之间呈现一种线性关系,即是元素”一个接一个排列“。

线性表

线性表是最简单、基本和常用的一种线性结构。

一个线性表是n个元素的有限序列,通常表示为(a1, a2, ... , an),非空线性表的特点如下:

  1. 存在唯一的一个”第一个“的元素。
  2. 存在唯一的一个”最后一个“的元素。
  3. 除第一个元素外,序列中的每个元素均只有一个直接前驱。
  4. 除最后一个元素外,序列中的每个元素均只有一个直接后继。

链式存储

线性表的链式存储是通过指针链接起来的结点来存储数据元素,基本的结点结构如下所示:

数据域 指针域

存储各元素的结点地址并不要求是连续的,因此存储数据元素的同时必须存储元素之间的逻辑关系。同时,结点空间只有在需要的时候才申请,无须事先分配(顺序存储必须事先分配好空间大小)。

根据结点的指针域的设置方式,还有其他的几种链表结构。

  • 双向链表。每个结点包含两个指针:一个指向前驱,一个指向后继。其特点是从表中任意的结点出发,都可以从两个方向遍历链表。
  • 循环链表。在单向链表(或双向链表)的基础上增加了表尾的指针指向链表的第一个结点,构成循环链表。其特点是从表中任意结点都可以遍历链表。
  • 静态链表。借助数组来描述线性表的链式存储结构,用数组元素的下标表示元素所在结点的指针。

C语言实现的单链表

#define TRUE 1
#define FALSE 0
#define ERROR -1
#define NULL -2
#define MAXSIZE 100
typedef int bool;
typedef int ElementType;
typedef int Position;
typedef struct LNode *List;

List MakeEmpty();
Position Find(List L, ElementType X);
bool Insert(List L, ElementType X, Position P);
bool Delete(List L, Position P);

/******************************************/
/*********** 线性表的链式存储实现 ***********/
/******************************************/
typedef struct LNode *PtrToLNode;
struct LNode {
    ElementType Data;
    PtrToLNode Next;
};
typedef PtrToLNode Position;
typedef PtrToLNode List;
 
/* 查找 */
Position Find( List L, ElementType X )
{
    Position p = L; /* p指向L的第1个结点 */
 
    while ( p && p->Data!=X )
        p = p->Next;
 
    /* 下列语句可以用 return p; 替换 */
    if ( p )
        return p;
    else
        return ERROR;
}
 
/* 带头结点的插入 */
bool Insert( List L, ElementType X, Position P )
{ /* 这里默认L有头结点 */
    Position tmp, pre;
 
    /* 查找P的前一个结点 */        
    for ( pre=L; pre&&pre->Next!=P; pre=pre->Next ) ;            
    if ( pre==NULL ) { /* P所指的结点不在L中 */
        printf("插入位置参数错误\n");
        return false;
    }
    else { /* 找到了P的前一个结点pre */
        /* 在P前插入新结点 */
        tmp = (Position)malloc(sizeof(struct LNode)); /* 申请、填装结点 */
        tmp->Data = X; 
        tmp->Next = P;
        pre->Next = tmp;
        return true;
    }
}
 
/* 带头结点的删除 */
bool Delete( List L, Position P )
{ /* 这里默认L有头结点 */
    Position tmp, pre;
 
    /* 查找P的前一个结点 */        
    for ( pre=L; pre&&pre->Next!=P; pre=pre->Next ) ;            
    if ( pre==NULL || P==NULL) { /* P所指的结点不在L中 */
        printf("删除位置参数错误\n");
        return false;
    }
    else { /* 找到了P的前一个结点pre */
        /* 将P位置的结点删除 */
        pre->Next = P->Next;
        free(P);
        return true;
    }
}