单链表整表的创建
单链表整表创建的思路:
- 声明一个结点p和计数器变量i;
- 初始化一个空链表L;
- 让L的头结点的指针指向NULL,即建立一个带头结点的单链表;
- 循环:
生成一新结点赋值给p;
随机生成一数字赋值给p指针的数据域p->data=rand();
将p结点插入到头结点与前一新结点之间。
实现代码如下:
/*随机产生n个元素的值,建立带头结点的单链表L(头插法)*/
void CreatListHead(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)mallloc(sizeof(Node)); /*生成新结点*/
p->data=rand()%100+1;
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=(LinkList)mallloc(sizeof(Node)); /*生成新结点*/
p->data=rand()%100+1;
r->next=p;/*将尾部终端结点的指针指向新结点*/
r=p; /*将当前的新结点定义为表尾终端结点*/
}
r->next=NULL;
}
注意L与r的关系,L是指整个单链表,而r是指向结点的变量,r会随着循环不断地变化结点,而L则是随着循环增长为一个多结点的链表。
单链表整表的删除
单链表整表删除的思路如下:
- 声明一结点p和q;
- 将第一个结点赋值给p;
- 循环:
将下一结点赋值给q;
释放p;
将q赋值给p。
实现代码算法如下:
/*初始条件:顺序线性表L已存在,操作结果:将L重置为空表*/
Status CLearList(LinkList *L)
{
LinkList p,q;
p=(*L)->next;
while(p) /*没到表尾*/
{
q=p->next;
free(p);
p=q;
}
(*L)->next=NULL; /*头结点指针域为空*/
return OK;
}
单链表结构与顺序存储结构优缺点
存储分配方式
- 顺序存储结构用一段连续的存储单元依次存储线性表的数据元素
- 单链表采用链式存储结构,用一组任意的存储单元存放线性表的元素
时间性能
查找
顺序存储结构O(1)
单链表O(n)插入和删除
顺序存储结构需要平均移动表长一半的元素,时间为O(n)
单链表在线出某位置的指针后,插入和删除时间仅为O(1)
空间性能
- 顺序存储结构需要预分配存储空间,分大了,浪费,分小了易发生上溢
- 单链表不需要分配存储空间,只要有就可以分配,元素个数也不受限制