静态链表
游标 | 5 | 2 | 3 | 4 | 5 | 6 | 7 | …… | 1 |
数据 |
| A | C | D | E |
|
| …… |
|
下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | …… | 999 |
线性表的静态链表存储结构:
#defineMAXSIZE 1000
typedefstruct
{
ElemType data;
int cur;
}Component,StaticLinkList[MAXSIZE];
对静态链表进行初始化相当于初始化数组:
StatusIninList(StaticLinkList space)
{
int I;
for(i = 0; i < MAXSIZE – 1; i++ )
space[i].cur = i + 1;
space[MAXSIZE - 1].cur = 0;
return OK;
}
cur:游标
注意:
-
对数组的第一个元素和最后一个元素做特殊处理,它们的data不存放数据
-
通常把未使用的数组元素称为备用链表
-
数组的第一个元素,即下标为0的那个元素的cur存放备用链表的第一个结点的下标
-
数组的最后一个元素,即下标为MAXSIZE – 1的cur存储第一个数值元素的下标,相当于单链表的头结点作用
在动态链表中结点的申请和释放分别借用C语言的malloc()和free()两个函数来实现
静态链表的插入操作:
代码部分一:获取空闲分量的下标:
intMalloc_SLL(StaticLinkList space)
{
int i = space[0].cur;
if(space[0].cur)
space[0].cur = space[i].cur; //把它的下一分量用来作为备用
returni;
}
代码部分二:在静态链表L的第i个位置之前插入新的元素e:
StatusListInsert(StaticLinkList L; int i; ElnmType e)
{
int j, k, l;
k = MAX_SIZE – 1; //数组的最后一个元素
if(i < 1 || i >ListLength(L) + 1)
{
return ERROR;
}
j = Malloc_SLL(L); //获取空闲分量的下标
if(j) //判断j不等于0,j的第一个初始值为1
{
L[j].data = e; //空闲分量的数据域赋值为e
for(l = 1; l <= i -1; l++ )
{
k = L[k].cur; //最后一个元素的游标赋值给k
}
L[j].cur = L[k];
L[k].cur = j;
return OK;
}
return ERROR;
}
静态链表的删除操作
实现代码:
删除L中第i个数据元素
StatusListDelete(StatiLinkList L, int i)
{
int j, k;
if(i < 1 || i >ListLength(L) )
{
return ERROR;
}
k = MAX_SIZE – 1;
for(j = 1; j <= i – 1; j++)
{
k = L[k].cur; //总共执行两次循环,第一次执行后k1 =1,k2 = 2
}
j = L[k].cur; // j = 2
L[k].cur = L[j].cur;
Free_SLL(L, j);
return OK;
}
将下标为k的空闲结点回收到备用链表
voidFree_SLL(StaticLinkList space, int k)
{
space[k].cur = space[0].cur; //space[0].cur备用链表第一个元素
space[0].cur = k;
}
返回L中的数据元素个数
intLIstLength(StaticLinkList L)
{
int j = 0;
int i = L[MAXSIZE – 1].cur;
while(i)
{
i = L[i].cur;
j++;
}
return j;
}
静态链表优缺点总结:
优:
在插入和删除操作时,只需要修改游标,不需要移动元素,从而改进了在顺序存储结构中插入和删除操作需要移动大量元素的缺点
缺:
1、没有解决连续存储分配(数组)带来的表长难以确定的问题
2、失去了顺序存储结构随机存取的特性
单链表小结:
题目:快速找到未知长度单链表的中间结点。
-
简单方法:
遍历一遍单链表以确定单链表的长度L;然后再次从头结点出发循环L/2次找到单链表的中间结点(算法复杂度为O(L + L/2) = (3L/2)
-
高级方法
设置快慢指针:
设置两个指针*search、*mid的2倍都指向单链表的头结点;其中,*search的移动速度是*mid的2倍;当*search指向末尾结点的时候,mid正好就在中间
实现代码:
StatusGetMidNode(LinkList L, ElemType *e)
{
LinkList search, mid;
mid = search = L;
while(search -> next !=NULL)
{
//search的移动速度是mid的2倍
if(search -> next ->next !=NULL)
{
search = search -> next ->next;
nid = mid -> next;
}
else
{
search = search -> next;
}
}
*e = mid -> data;
return OK;
}
(单)循环链表
将单链表的终端结点指针由空指针改为指向头结点
循环链表和单链表判断是否为控的条件:
循环链表:head -> next是否等于head
单链表:head -> next是否等于NULL
中断结点用指针rear表示
单循环链表的代码:初始化部分、插入部分、删除部分、返回结点所在位置
初始化循环链表代码:
voidds_init(node **pNode) // **pNode表示一个元素
{
int item;
node *temp;
node *target;
printf(“输入结点的值,输入0完成初始化\n”);
while(1)
{
scanf(“%d”, &item;
fflush(stdin); //清除缓冲区
if(item == 0)
return;
if((*pNode) == NULL)
{
/* 循环链表只有一个结点(空表)*/
*pNode = (node*)malloc(sizeof(struct ClinkList));/*分配空间*/
/* 分配空间失败,返回0 */
if(!(*pNode))
exit(0);
(*pNode) -> data = item; /*传递数据 */
(*pNode) -> next = *pNode; /*传递地址(*pNode头结点) */
}
else
{
/* 找到next指向第一个结点的结点 */
for(target = (*pNode); target -> next != (*pNode); target = target-> target); /* 寻找*pNodde(循环链表的插入在链表最尾部插入) */
/* 生成一个新结点 */
temp = (node *)malloc(sizeof(structCLinkList));
if(!temp) /* 生成新结点失败,退出 */
exit(0);
temp -> data = item; /* temp生成的新结点 */
temp -> next = *pNode;
target -> next = temp;
}
}
}
循环链表插入代码:
/* 链表存储结构定义 */
typedefstruct CLinkList
{
int data;
struct CLinkList *next;
}node;
/* 插入结点 */
/* 参数:链表的第一个结点,插入位置 */
voidds_insert(node **pNode, int i)
{
node *temp;
node *target;
node *p;
int item;
int j = 1;
printf(“输入要插入的结点的值:”);
scanf(“%d”, &item);
if(i == 1)
{
//新插入的结点作为第一个结点
temp = (node *)malloc(sizeof(struct CLinkList));
if(!temp)
exit(0);
temp -> data = item;
/* 寻找到最后一个结点 */
for(target = (*pNode);target -> next != (*pNode); target = target -> next) /* 分配一个空间 */
temp -> next = (*pNode);
target -> next = temp;
*pNode = temp;
}
else
{ /* 插入位置不是第一个结点处 */
target = *pNode; /* target是目标指针 */
for((j = 1; j < (i – 1); ++j)
{
target = target -> next;
} //target指向第三个元素
temp = (node *)malloc(sizeof(struct CLinkList);/*分配内存 */
if(!temp)
exit(0);
temp -> data = item; //item是我们要插入的值
p = target -> next; //temp产生的新空间
target -> next =temp;
temp -> next = p;
}
}
单项循环链表删除代码:
/* 删除结点 */
voidds_delete(node **pNode, int i)
{
node *target;
node *temp;
int j = 1;
if(i == 1)
{
//删除的是第一个结点
/* 找到最后一个结点 */
for(target = *pNodde; target -> next != *pNode; target = target ->next)
temp = *pNode;
*pNode = (*pNode) ->next;
target -> next = *pNode;
free(temp);
}
else
{
target = *pNode;
for(j =1; j < i - 1; ++j)
{
target = target -> next;
}
temp = targrt -> next;
target -> next = temp -> next;
free(temp);
}
}
返回结点所在位置的代码(search):
/* 返回结点所在的位置 */
intds_search(node *pNode, int elem)
{
node *target;
int I;
for(target = pNode; target -> data!= elem && target -> next != pNode; ++i) //elem查找到的元素
{
target = target -> next;
}
if(target -> next == pNode) /*表中不存在该元素 */
return 0;
else
return i;
}