1、静态链表的定义
- 顺序表数组中的元素由两个数据域组成:data和next;
- data域用于存储数据;
- next域用于存储下一个元素在数组中的下标;
- 静态链表的大小是固定的;
静态链表本质上就是一个结构体数组;
静态链表是在顺序表的基础上利用数组实现的单链表!
2、相关数据结构定义
#ifdef WIN32
typedef unsigned int LPDATA;
#else
typedef unsigned long LPDATA;
#endif
/*
LPDATA data; 成员用于保存被插入元素的地址,
Windows下为4字节,Linux下为8字节
int next; 成员用于保存下一个元素在数组中的下标,
也可理解为相对于数组起始地址的相对地址
*/
typedef struct _struct_staticlistnode
{
LPDATA data;
int next;
}TStaticlistNode;
/*
int capacity; 用于保存静态链表的最大容量
TStaticlistNode header; 专门用于保存链表的头结点信息,
防止误操作或者丢失,是node[0]的一个拷贝
TStaticlistNode node[]; 这里使用了C的柔性数组,
node[0]中存放着当前链表的头结点信息
*/
typedef struct _struct_staticlist
{
int capacity;
TStaticlistNode header;
TStaticlistNode node[];
}TStaticlist;
3、创建静态链表操作
/*
该方法用于创建并且返回一个空的线性表
*/
Staticlist* List_Create(int capacity)
{
TStaticlist *tlist = NULL;
if(capacity > 0)
{
/*
柔性数组,TStaticlist结构体最后一个数据成员TStaticlistNode node[];没有指定数组
大小,所以它是一个不完整的成员,sizeof(TStaticlist) 后得到的大小并不包含该成员;
具体请参考我的博客中的[【C语言复习(二)】struct 与 union 的分析](http://blog.csdn.net/cmbug/article/details/30256043) 因为数组0号元素被用来存放数组头结点信息,所以这里要多分配一个空间:(capacity + 1)
*/
tlist = (TStaticlist*)malloc(sizeof(TStaticlist) + sizeof(TStaticlistNode) *(capacity + 1));
}
if(tlist != NULL)
{
tlist->capacity = capacity;
tlist->header.data = 0;
tlist->header.next = 0;
//初次建立后,标记数组所有位置可用
for(int i = 1; i<=capacity; i++)
{
tlist->node[i].next = AVAILABLE;
}
}
return tlist;
}
4、插入元素操作
/*
该方法用于向一个线性表list的pos位置处插入新元素node
返回值为1表示插入成功,0表示插入失败
node 实际上是要被插入的元素的地址
pos 表示插入位置,从0开始计数
*/
int List_Insert(Staticlist* list, StaticlistNode* node, int pos)
{
int iret = 1,emptyIndex = 0,current = 0;
TStaticlist *tlist = (TStaticlist*)list;
iret = iret && (tlist != NULL) && (node != NULL) && (pos >=0);
if(iret)
{
//将头结点信息复制到数组的第一个位置
tlist->node[0] = tlist->header;
//先找个空位置,把数据放进去
for(int i = 1;i<=tlist->capacity;i++)
{
if(tlist->node[i].next == AVAILABLE)
{
emptyIndex = i;
break;
}
}
//放置要插入的数据,实际上是一个地址
tlist->node[emptyIndex].data = (LPDATA)node;
//再做排序操作
/*(i<pos) && (tlist->node[current].next != 0)
该条件保证了当要插入的位置大于了当前链表已有的数据长度时,将该元素插入到最后的位置,
而不会跳跃插入*/
for(int i = 0;(i<pos) && (tlist->node[current].next != 0);i++)
{
current = tlist->node[current].next;
}
tlist->node[emptyIndex].next = tlist->node[current].next;
tlist->node[current].next = emptyIndex;
//更新链表的头结点数据,并及时拷贝备份到header中
tlist->node[0].data++;
tlist->header = tlist->node[0];
}
return iret;
}
5、获取元素操作
/*
该方法用于获取一个线性表list的pos位置处的元素
返回值为pos位置处的元素,NULL表示获取失败
*/
StaticlistNode* List_Get(Staticlist* list, int pos)
{
TStaticlistNode *ret = NULL;
int current = 0;
TStaticlist *tlist = (TStaticlist*)list;
if(tlist != NULL)
{
if(pos>=0 && pos < tlist->header.data)
{
tlist->node[0] = tlist->header;
/*因为pos从0开始计数,而实际保存元素的位置是从数组的1号位置开始的,
所以循环条件为:i<= pos
*/
for(int i = 0;i<= pos;i++)
{
current = tlist->node[current].next;
}
//得到数据
ret = (StaticlistNode*)tlist->node[current].data;
}
}
return ret;
}
6、删除元素操作
/*
该方法用于删除一个线性表list的pos位置处的元素
返回值为被删除的元素,NULL表示删除失败
*/
StaticlistNode* List_Delete(Staticlist* list, int pos)
{
TStaticlistNode *ret = NULL;
int current = 0,delnode = 0;
TStaticlist *tlist = (TStaticlist*)list;
if(tlist != NULL)
{
if(pos >= 0 && pos < tlist->header.data)
{
//先找到要删除元素的前一个元素,因为等会要修正它的next成员数据
for(int i = 0; i<pos;i++)
{
current = tlist->node[current].next;
}
//获取要被删除的元素
delnode = tlist->node[current].next;
//开始删除操作
tlist->node[current].next = tlist->node[delnode].next;
tlist->node[delnode].next = AVAILABLE;
//得到被删除的元素的数据,用于返回
ret = (StaticlistNode*)tlist->node[delnode].data;
//更新头结点数据
tlist->node[0].data--;
tlist->header = tlist->node[0];
}
}
return ret;
}
7、完整源码下载
文件名:staticlist-1.0.tar.gz
链接: http://pan.baidu.com/s/1c0lPo0S 密码: 58wq
编译步骤:
0.1 解压缩:tar -zxvf staticlist-1.0.tar.gz
0.2 进入目录:./configure
0.3 生成Seqlist:make
0.4 运行程序:./Staticlist