数据结构-链表题(23.4.19)

137 阅读2分钟

来回删除最小值

设有一个带头结点的循环单链表,其结点值均为正整数。设计一个算法,反复找出单链表中结点值最小的结点并输出,然后将该结点从中删除,直到单链表空为止,再删除表头结点。

代码

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值。