来回删除最小值
设有一个带头结点的循环单链表,其结点值均为正整数。设计一个算法,反复找出单链表中结点值最小的结点并输出,然后将该结点从中删除,直到单链表空为止,再删除表头结点。
代码
void minRing(node *&l) {
int min = INT_MAX;
node *s = l->next, *r = l;
node *die, *die_pr;
while (s != l) {
if (s->data < min) {
min = s->data;
die = s;
die_pr = r;
}
r = s;
s = s->next;
}
cout << die->data << "--out" << endl;
die_pr->next = die->next;
delete (die);
if (l != NULL) josephusRing(l);
}
题解
这道题看的时候很像约瑟夫环,最初学习链表时,可能看到这个问题比较绕,随着链表知识的不断深入,这道题我们可以轻松地去解决它。
首先明确一点,每一个遍历周期,我们可以很方便地删除当前链表中data值最小的结点并且删除,这种题前面的文章也提到过,就是找到链表中data最小的结点并用指针指向它的前结点和这个结点,输出这个结点的data值,之后删除这个结点即可。
那么,我们这只是完成了一轮遍历,接下来我们该如何继续删除呢?最简单、最显而易见的方法莫过于递归,即如果当前链表表头l不为NULL,我们继续调用该函数,参数仍为l。直到l为NULL,函数运行结束。
寻找共同后缀起始位置
假定采用带头结点的单链表保存数列,当两个数列有相同的后缀时,可共享相同的后缀存储空间,例如,1919810514和114514,共享结点data值为5、1、4的结点。设a和b分别指向两个数列所在单链表的头结点,设计一个算法,找出由a和b所指向两个链表的共同后缀结点的起始data值。
代码
int search_sameEnd(node *a, node *b) {
node *sa = a->next, *sb = b->next;
int len_a=0,len_b=0;
while(sa!=NULL){
len_a++;
sa=sa->next;
}
while(sb!=NULL){
len_b++;
sb=sb->next;
}
sa=a->next;
sb=b->next;
if(len_a>len_b){
int len=len_a-len_b;
for(int i=0;i<len;i++){
sa=sa->next;
}
}else{
int len=len_b-len_a;
for(int i=0;i<len;i++){
sb=sb->next;
}
}
if(sa==NULL) return -1;
while(sa!=NULL){
if(sa->data==sb->data){
node *tmp_sa=sa,*tmp_sb=sb;
while(tmp_sa!=NULL){
if(tmp_sa->data==tmp_sb->data){
tmp_sa=tmp_sa->next;
tmp_sb=tmp_sb->next;
}else break;
}
if(tmp_sa==NULL) return sa->data;
}
sa=sa->next;
sb=sb->next;
}
return -1;
}
题解
首先遍历a和b两个表,求出两个链表表长,判断哪个表长更长,以及两个链表表长相差多少。之后让表长较长的链表先遍历n个结点(n为两个表长之差),之后的思路等同于昨天所发文章的链表连续子序列,最后返回的值是第一个结点的data值。