插入元素时,要先找到该元素的前一个元素。
a为当前结点;
b为要插入的结点;
c为a之后的结点;
相较删除结点两种思路,插入结点也有两种思路:
头插法:
1、保存c结点
b->next =c;
2、c结点重新赋值
c= b;
尾插法:
1、保存a的next(即c)
b ->next = a->next;
2、a->next重新赋值
a->next = b;
举例:无头结点的单链表为例,插入结点
方法一:理解为头插法,插在结点的前面
//在链表第i个位置插入元素
bool insertList(LinkList &slink,int i ,int e)
{
/*
找到第i个结点,在第i个结点的前面添加
1、计数变量j
2、变量指向当前变量,直至i
3、循环条件,当前结点不为空且j<i
*/
int j = 1;
LinkList q = (LinkList)malloc(sizeof(Node));
LinkList p = slink;
p->data = 100;
if(i<1) return false;
if(i==1)
{
q->next = slink;
slink = q;
return true;
}
while(p&&j<i)//i>1且p不为空,未包含i=1和p为空的情况
{ //发现p为空的情况和i=1的情况是可以合并的。
p = p->next;
j++;
}
if(!p)
return false;
q->next = p;
p = q;
return true;
}
注意:如果始终在第一个位置上插入结点的话,以上代码可以简化如下:
//始终在链表第1个位置插入元素
slink =NULL;
bool insertList(LinkList &slink,int e)
{
int j =0;
LinkList q;
while(j<100)
{
q= (LinkList)malloc(sizeof(Node));
p->data = e;
q->next = slink;
slink = q;
j++;
}
return true;
}
以上的头插法对应的结点释放程序如下:(始终释放第一个结点)
//从头结点开始释放
slink =NULL;
bool dstroyList(LinkList &slink)
{
LinkList q;
while(slink!=NULL)
{
q = slink;
slink = slink->next;
free(q);
}
return true;
}
方法二:可以理解为尾插法,插在结点的后面
//在链表第i个位置插入元素
bool insertList(LinkList &slink,int i ,int e)
{
/*
找到第i-1个结点,在第i-1个结点的后面添加
1、计数变量j
2、变量指向当前变量,直至第i-1
3、循环条件,(一般情况,当前结点不为空,且j<i-1),特殊情况,当前结点为空的情况,
j>i-1的情况.
*/
int j =1;
LinkList p = slink;
LinkList temp = (LinkList)malloc(sizeof(Node));
temp->data = 100;
if(i<1) return false;
if(i==1)//slink为空或者不为空,此条都适用
{ //也就是说为空的时候,也可以当成不为空来理解。
temp->next = slink;
slink = temp;
}
while(p&&j<i-1)//i>2的情况;//少了i=1的情况。//从p=NULL看出少了链表为空的情况;
{ //将链表为空和i=1的情况合并为上面的if语句。
p = p->next;
j++;
}
//if(!p||j>i-1)
if(!p) //此处不用j>i-1, 是因为前面已经排除了i<1的情况了
return false;
temp->next = p->next;
p->next = temp;
return true;
}
总结:
1、写while循环的思路是先排除不满足循环条件的值;
while循环里是一般情况(大多数都满足的值)
跳出循环后,再排除一部分值;
检查没有进入到while循环的情况
最后,检查特殊情况能否合并。
2、头插法若始终在开头处插入数据的话,更简单。
初始状态下(slink=NULL)的时候,插入第一个结点的思路,跟已经有1个结点,要插入第二个结点的思路是一致的。