2、在单链表L中删除所有值为x的结点,x不唯一
LinkList deletx (LinkList &L,int x)//第二题
{
LNode *r=L->next;//r是rr的前驱
while(rr!=NULL)
{
LNode *rr=r->next;//rr是r的后继
if(rr->data==x) {r->next=rr->next;free(rr);}
r=r->next;//移动
}
return L;
}
就是找到前驱结点,然后建立链接关系就好,这里注意rr的定义是在循环内部的,如果写在外面rr就始终为空了,因为一次free,rr就没了,所以每次要建立一个新的rr。
4、删除单链表中的最小值结点,该最小值是唯一的
LinkList deletemin (LinkList &L,int x)//第四题
{
int min=INT_MAX;
LNode *s=L;
LNode *ss;
ss=(LNode*)malloc(sizeof(LNode));
while(s->next!=NULL)
{
if(s->next->data<=min) {min=s->next->data;ss=s;}//ss存的是s->next的前驱节点
s=s->next;//移动
}
LNode *sss=ss->next;
ss->next=sss->next;
free(sss);
return L;
}
就是找前驱节点,这是要求s从L开始,因为后继结点要求从L->next开始找,即从第一个元素开始。最小值判断始终判断的是后继结点的内容,最小值的存储地址则是前驱结点。
然后就是常规的删除操作了。
21、找倒数第k个元素
int findk(LinkList &L,int k)//第21题
{
if(L->next!=NULL)
return(findk(L,k));
if(L!=NULL)
{
int a=0;
for(int i=1;i<=k;i++)
a=L->data;
return 1;
}
return 0;
}
第一个想法是拿递归或者栈做,但最好的方法还是快慢指针,具体在操作部分有写(上一篇文章)。
22、找两个单链表的共同后缀的其实位置,比如loading和being的起始位置是i。
LNode Thesame(LinkList &L1,LinkList &L2)//第22题
{
LNode *s=L1->next;
LNode *r=L2->next;
while(s->next!=NULL)
{
while(r->next!=NULL)
{
if(s==r) return *s;
else r=r->next;
}
s=s->next;
}
return *s;
}
常规方法当然是两个循环挨个找,更好的方法是先确定两个链表的长度,设置一个快慢指针,快指针指向长的,长的比短的要多走个两个长度差加1步,比如长度为7和长度为5的元素相比,快指针就需要先走个三步,loading走到a的位置,慢指针开始从being的b走,两个一起走,发现一样的直接输出就行了。时间复杂度便从O(n*m)变成O(m+n),或者说O(max(m,n))。
23、对于链表中data绝对值相等的结点,仅仅保存第一次出现的结点,删除其他绝对值相等的结点。
#define inital 100
LinkList deletesame(LinkList &L)//第23题
{
int *a=new int[inital];
LNode *s=L;
while(s->next!=NULL)//s是前驱节点
{
LNode *ss=s->next;
a[abs(ss->data)]++;
if(a[ss->data]>1) {s->next=ss->next;free(ss);}
s=s->next;//移动
}
return L;
}
借助辅助数组,我们可以确定每个元素的出现次数,为了避免第一次的元素刚出现就被删除的问题,这里把查找部分合并在了数组的增值部分,如果大于1再进行删除操作,这样第一个元素就不会被删除,避免了先增值后删除中必须引入first变量的问题。