第二章线性表——2.3:线性表的链式表示和实现
在上一节我们看到了顺序存储结构在进行插入和删除的时候都需要从起点开始,在移动数据上花费大量的时间,因此人们想出了链式结构来解决这个问题。
一个链表中由很多结点组成,节点中有两个域,分别为数据域和**指针域。**数据域中存储元素信息,指针域中存储下个节点的地址。
学习链表,我们先从单链表学起。单链表又称为线性链表,因为他的每个结点中只有一个指针域。
而一个单链表的存取都是从头指针开始的。头指针中没有元素信息,只有下一个结点的地址,同时单链表中的最后一个结点中的指针为空,即NULL。大家可以拿笔画一画,印象就会很深刻。
单链表的结构指针如下。
typedef struct lnode
{
elemtype data;
struct lnode* next;
}lnode,*linklist;
有时候,我们会设置一个头结点作为头指针的下一个结点,这个头结点我们会放置比如这个链表的长度之类的数据,头结点后面的第一个结点才正式存储我们的数据。
例2.8把链表中第i个结点的值赋值给e,L有头结点。
Status getelem(linklist l, int i, elemtype& e)
{
p = l->next;
j = 1;
while (p && j < i)
{
p = p->next;
j++;
}
if (!p || j > i)return error;
e = p->data;
return ok;
}
例2.9在L的第i个位置之前插入一个元素,L有头结点。
Status listinsert_l(linklist& l, int i, elemtype e)
{
p = l;
j = 0;
while (p && j < i - 1)
{
p = p->next;
++j;
}
if (!p || j > i - 1)return error;
s = (linklist)malloc(sizeof(lnode));
s->data = e;
s->next = p->next;
p->next = s;
return ok;
}
例2.10删除第i个结点
Status listdelete(linklist& l, int i, elemtype& e)
{
p = l;
j = 0;
while (p->next && j < i - 1)
{
p = p->next;
j++;
}
if (!(p->next) || j > i -1) return error;
q = p->next;
p->next = q->next;
e = q->data;
free(q);
return ok;
}
我们之前建立链表是从头输入数据的接下来我们从尾输入数据。
例2.11建立尾部输入数据的链表l。
void creatlist_l(linklist& l, int n)
{
l = (linklist)malloc(sizeof(lnode));
l->null;
for (i = n; i > 0; --i)
{
p = (linklist)malloc(sizeof(lnode));
scanf(&p->data);
p->next = l->next;
l->next = p;
}
例2.12将两个非递减有序链表合成一个新的有序链表
void mergelist_l(linklist& la, linklist& lb, linklist& lc )
{
pa = la->next;
pb = lb->next;
lc = pc = la;
while (pa && pb)
{
if (pa->data <= pb->data)
{
pc->next = pa; pc = pa; pa = pa->next;
}
else
{
pc->next = pb; pc = pb; pb = pb->next;
}
}
pc->next = pa ? pa : pb;
fell(lb);
}
例2.12和2.7相比时间复杂度相等,空降复杂度12小些。
有时候我们不用指针,用一维数组也可以描述线性链表,我们称为静态链表。
#define maxx 1000
typedef struct
{
elemtype data;
int cur;//游标
}component,slinklist[maxx];
我们将静态链表的第零分量看成头结点。
例2.13在静态链表中找到第一个值为e的元素
int locateelem_sl(slinklist s, elemtype e)
{
i = s[0].cur;
while (i && s[i].data != e) i = s[i].cur;
return i;
}
例2.14将一维数组中的各个分量连接成备用链表。备用链表即没有使用过的结点。
int initspace_sl(slinklist& space)
{
for (i = 0; i < maxx - 1; ++i) space[i].cur = i - 1;
space[maxx - 1].cur = 0;
}
例2.15若备用链表非空,返回下标
int malloc_sl(slinklist& space)
{
i = space[0].cur;
if (space[0].cur) space[0].cur = space[i].cur;
return i;
}
例2.16将下标为k的结点收为备用链表
void free_sl(slinklist& space, int k)
{
space[k].cur = space[0].cur;
space[0].cur = k;
}
例2.17建立出(A-B)∪(B-A)的静态链表
各位可以自己试试哦
单项链表过后就是双向链表,双向链表很简单理解不做多解释。