n个结点链结成一个链表,即为线性表的链式存储结构,因为此链表的每个结点中只包含一个指针域,所以叫做单链表。
线性表的单链表存储结构:
typedef struct Node
{
ElemType data;
struct Node *next;
}Node;
typedef struct Node *LinkList; /* 定义LinkList */
单链表的读取:
/* 初始条件:顺序线性表L已存在,1<=i<=ListLength(L) */
/* 操作结果:用e返回L中第i个数据元素的值 */
Status GetElem( LinkList L, int i, ElemType *e )
{
int j;
LinkList p; /* 申明一个指针p */
p = L->next; /* 让p指向链表L的第一个结点 */
j = 1; /* j为计数器 */
while( p && j < i ) /* p不为空且计数器j还没有等于i时,循环继续 */
{
p = p->next; /* 让p指向下个结点 */
++j;
}
if( !p || j > i )
return ERROR; /* 第i个结点不存在 */
*e = p->data; /* 取第i个结点的数据 */
return OK;
}
单链表的插入:
/* 初始条件:顺序线性表L已存在,1<=i<=ListLength(L) */
/* 操作结果:在L中第i个结点位置之前插入新的数据元素e,L的长度加1 */
Status ListInsert( LinkList *L, int i,ElemType e )
{
int j;
LinkList p, s;
p = *L;
j = 1;
while( p && j < i ) /* 寻找第i-1个结点 */
{
p = p->next;
++j;
}
if( !p || j > i )
return ERROR; /* 第i个结点不存在 */
s = ( LinkList )malloc( sizeof( Node ) ); /* 生成新节点(C标准函数) */
s->data = e;
s->next = p->next; /* 将p的后继结点赋值给s的后继 */
p->next = s; /* 将s赋值给p的后继 */
return OK;
}
单链表的删除:
/* 初始条件:顺序线性表L已存在,1<=i<=ListLength */
/* 操作结果:删除L的第i个结点,并用e返回其值,L的长度减1 */
Status ListDelete( LinkList *L, int i, ElemType *e )
{
int j;
LinkList p, q;
p = *L;
j = 1;
while( p->next && j < i ) /* 遍历寻找第i-1个结点 */
{
p = p->next;
++j;
}
if( !( p->next ) || j > i )
return ERROR; /* 第i个结点不存在 */
q = p->next;
p->next = q->next; /* 将q的后继赋值给p的后继 */
*e = q->data; /* 将q结点中的数据给e */
free( q ); /* 让系统回收此结点,释放内存 */
return OK;
}
单链表的整表创建(头插法):
/* 随机产生n个元素的值,建立带表头结点的单链线性表L(头插法) */
void CreateListHead( LinkList *L, int n )
{
LinkList p;
int i;
srand( time( 0 ) ); /* 初始化随机数种子 */
*L = ( LinkList )malloc( sizeof( Node ) );
( *L )->next = NULL; /* 先建立一个带头结点的单链表 */
for( i = 0; i < n; i++ )
{
p = ( LinkList )malloc( sizeof( Node ) ); /* 生成新结点 */
p->data = rand() % 100 + 1; /* 随机生成100以内的数字 */
p->next = ( *L )->next;
( *L )->next = p; /* 插入到表头 */
}
}
单链表的整表创建(尾插法):
/* 随机产生n个元素的值,建立带表头结点的单链线性表L(尾插法) */
void CreateListTail( LinkList *L, int n )
{
LinkList p, r;
int i;
srand( time( 0 ) ); /* 初始化随机数种子 */
*L = ( LinkList )malloc( sizeof( Node ) ); /* 为整个线性表 */
r = *L; /* r为指向尾部的结点 */
for( i = 0; i < n; i++ )
{
p = ( Node * )malloc( sizeof( Node ) ); /* 生成新结点 */
p->data = rand() % 100 + 1; /* 随机生成100以内的数字 */
r->next = p; /* 将表尾终端结点的指针指向新结点 */
r = p; /* 将当前的新结点定义为表尾终端结点 */
}
r->next = NULL; /* 表示当前链表结束 */
}
单链表的整表删除:
/* 初始条件:顺序线性表L已存在 */
/* 操作结果:将L重置为空表 */
Status ClearList( LinkList *L )
{
LinkList p, q;
p = ( *L )->next; /* p指向第一个结点 */
while( p )
{
q = p->next;
free( p );
p = q;
}
( *L )->next = NULL; /* 头结点指针域为空 */
return OK;
}
适用范围:
1,需要频繁插入和删除
2,线性表中的元素个数变化较大或不知道有多大时
对比与顺序存储结构,优缺点:
1,存储分配方式
顺序存储结构用一段连续的存储单元依次存储线性表的数据元素;
单链表采用链式存储结构,用一组任意的存储单元存放线性表的元素。
2,时间性能
在查找方面,顺序存储结构为O(1),单链表为O(n);
在插入和删除方面,顺序存储结构需要平均移动表长一半的元素,时间为O(n),而单链表仅为O(1)。
3,空间性能
顺序存储结构需要预分配存储空间,分大了,浪费,分小了易发生上溢;
单链表不需要预分配存储空间,只要有就可以分配,元素个数也不受限制。