1、图示(截图来自网易云课堂鱼C工作室《数据结构和算法》课程视频)
2、 要想将结点s插入到ai与ai+1之间,不需要移动数据元素,只需要在ai与ai+1之间插入一个新的结点,也就是我们要插入的结点s。关键就是要修改结点p的指针域,使得结点s称为其后继。修改指针的链接的主要操作语句是:
s->next=p->next; //把结点p的后继作为结点s的后继;
p->next=s; //把结点s作为结点p的后继;
- 1
- 2
注意这两个语句的顺序不能调换不能调换不能调换!!!
为什么呢?如果调换①和②的顺序,那么插入操作就无法完成,并且会丢失ai结点的地址以及ai及其后面所有结点的信息。
3、下面演示插入操作的算法:
bool ListInsert_L(LinkList &L,int i,ElemType e)
{ //在带有头结点的单链表L中的第i个结点前插入元素e
LinkList p,s;
int j;
p=L;j=0; //①声明一结点p指向链表头结点,初始化j从0开始;
while(p->next&&j<i-1){
p=p->next;
j++;
} //②寻找第i-1个结点并让p指向此结点
if(j!=i-1) return false; //③若i的位置不合理则报错
if((s=(LNode*)malloc(sizeof(LNode)))==NULL) exit(1); //④查找成功,在系统中生成一个空结点s;
s->data=e; //⑤将数据元素e复制给s->data;
s->next=p->next;p->next=s; //⑥插入操作(关键语句)
return true; //⑦返回成功;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
二、单链表的删除操作
1、删除图示(图片出处同上)
2、删除操作和插入类似,在删除一个结点时,不需要移动元素,仅需要修改相应的指针链接,改变其前驱和后继的关系即可。
主要操作语句为:
p->next=q->next; //结点q的后继成为结点p的后继
e=q->data; //将被删除的元素的值赋给e
free(q); //释放被删除结点的空间
- 1
- 2
- 3
3、下面演示删除元素的算法,注释含有步骤解释。
bool ListInsert_L(LinkList &L,int i,ElemType e)
{ //删除带有头结点的单链表L中的第i个结点,并饶让e返回其值
LinkList p,q;
int j;
p=L;j=0; //①声明一结点p指向链表头结点,初始化j从0开始;
while(p->next->next&&j<i-1&&p->next){
p=p->next;
j++;
} //②寻找第i-1个结点并让p指向此结点
if(j!=i-1) return false; //③若i的位置不合理则报错
q=p->next; //④若查找成功,q指向其后继
p->next=p->next; //⑤结点q的后继成为结点p的后继
e=q->data;
free(q); //⑥将被删除的元素的值赋给e,释放被删除结点的空间
return true; //⑦返回成功;
} //LinkDelete_L
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
三、关于顺序存储与链式存储中插入删除操作的效率PK
1、无论是单链表的插入操作还是删除操作,都是由两部分组成的:一是遍历查找第i个元素,二是实现插入或删除操作。
就整个算法而言,他们的时间复杂度都是O(n),这样来看的话,再不知道要找的第i个元素所处的位置时,单链表的插入删除操作和顺序存储是没有什么优越性的。
但是!如果知道要插入或者删除的元素的位置时,链式存储就表现出它的优越性了。假如我们要在a10与a11之间插入10个元素,那么顺序存储每插入一个元素后面的元素就要移动一次位置,每次都是O(n)。而链式存储,只需要第一次时找到要插入的那个位置,后面的就只是赋值移动指针而已,时间复杂度为O(1)。
因此,可以得出一个结论:对于插入或者删除操作越频繁的操作,单链表的效率优势就越是明显。