7.0、C语言数据结构——线性表 (3)
我们先来看下单来链表的插入,假设存储元素 e 的结点为 s ,要实现结点 p ,p -> next 和 s 之间逻辑关系的变化,大家参考下图思考一下:
1. 我们思考后发觉根本用不着惊动其他结点,只需要让 s -> next 和 p -> next 的指针做一点改变;
s -> next = p -> next;
p -> next = s;
2. 我们通过图片来解读一下这两句代码 ->
单链表数据插入的总结如下:
1.声明一结点 p 指向链表头结点,初始化 j 从 1 开始;
2. 当 j < 1 时,就遍历链表,让 p 的指针向后移动,不断指向下一结点,j 累加 1;
3. 若到链表末尾 p 为空,则说明第 i 个元素不存在;
4. 否则查找成功,在系统中生成一个空结点 s;
5. 将数据元素 e 赋值给 s -> data;
6. 单链表的插入刚才两个标准语句;
7. 返回成功;
Status ListInsert (LinkList* L , int i , ElemType e) {
int j;
LinkList p , s;
p = *L;
j = 1;
while() {
p = p -> next;
j++;
}
if(!p || j > i) {
return ERROR;
}
s = (LinkList)malloc(sizeof(Node));
s -> data = e;
s -> next = p -> next;
p -> next = s;
return OK;
}
单链表删除操作:
1. 假设元素 a2 的结点为 q ,要实现结点 q 删除单链表的操作,其实就是将它的前驱结点的指针绕过指向后继结点即可;
2. 那我们所要做的,实际上就是一步:
可以这样: p -> next = p -> next -> next;
也可以是:q = p -> next;p -> next = q -> next;
单链表第 i 个数据删除结点的算法思路:
1. 声明结点 p 指向链表第一个结点,初始化 j = 1;
2. 当 j < 1 时,就遍历链表,让 p 的指针向后移动,不断指向下一结点,j 累加 1;
3. 若到链表末尾 p 为空,则说明第 i 个元素不存在;
5.否则查找成功,将欲删除结点 p -> next 赋值给 q ;
6. 单链表的删除标准语句 p -> next = q -> next;
7. 将 q 结点中的数据赋值给 e ,作为返回;
8. 释放q 结点;
Status ListDelete (LinkList* L , int i , ElemType* e) {
int j;
LinkList p , q;
p = *L;
j = 1;
while(p->next && j < i) {
p = p -> next;
++j;
}
if(!(p -> next) || j > i) {
return ERROR;
}
q = p -> next;
p -> next = q -> next;
*e = q -> data;
free(q);
return OK;
}

最后单链表和顺序存储效率比较一下得出结论:
1. 我们最后的环节是效率 PK ,我们发现无论是单链表插入还是删除算法,他们其实都是由两个部分组成:第一部分就是遍历查找第 i 个元素,第二部分就是实现插入和删除元素;
2.从整个算法来说,我们很容易可以推出他们的时间复杂度都是 O ( n );
3. 再详细点分析:如果在我们不知道第 i 个元素的指针位置,单链表数据结构在插入和删除操作上,与线性表的顺序存储结构是没有太大优势的;
4. 但如果,我们希望从第 i 个位置开始,插入连续 10 个元素,对于顺序存储结构意味着,每一次插入都需要移动 n - i 个位置,所以每次都是 O ( n );
5. 而单链表,我们只需要在第一次时,找到第 i 个位置的指针,此时为 O ( n ),接下来只是简单地通过赋值移动指针而已,时间复杂度都是 O ( 1 );
6. 显然,对于插入或删除数据越频繁的操作,单链表的效率优势就越明显;
1964

被折叠的 条评论
为什么被折叠?



