综合应用题——线性表的链式表示(每日更新中...)

一、练习题

01题

在带头结点的单链表L中,删除所有值为x的结点,并释放其空间,假设值为x的结点不唯一,试编写算法以实现上述操作。

【解法1】用p从头至尾扫描单链表,pre指向*p结点的前驱。若p所指结点的值为x,则删除,并让p移向下一个结点,否则让pre、p指针同步后移一个结点。

void Del_X_1(Linklist &L,ElemType x){
    LNode *p=L->next,*pre=L,*q;//置p和pre的初始值
    while(p!=NULL){
        if(p->data==x){
            q=p;               //q指向被删结点
            p=p->next;
            pre->next=p;       //将*q结点从链表中断开;
            free(q);           //释放*q结点的空间
         }
         else{                 //否则,pre和p同步后移
             pre=p;
             p=p->next;
         }//else
     }//while
}

本算法是在无序单链表中删除满足某种条件的所有结点,条件是结点的值为x。条件是可以任意指定的,只要修改if条件即可。比如,要求删除介于mink和maxk之间的所有结点,只需将if语句修改为if(p->data>mink&&p->data->maxk)。

【解法2】采用尾插法建立单链表。用p指针扫描L的所有结点,当其值不为x时,将其链接到L之后,否则将其释放。

void Del_X_2(Linklist &L,ElemType x){
    LNode *p=L->next,*r=L,*q;    //r指向尾结点,其初值为头结点
    while(p!=NULL){
        if(p->data!=x){          //*p结点值不为x时将其链接到L尾部
            r->next=p;
            r=p;
            p=p->next;           //继续扫描
         }
         else{                   //*p结点值为x时将其释放
            q=p;
            p=p->next;           //继续扫描
            free(q);             //释放空间
         }
     }//while
     r->next=NULL;               //插入结束后置尾结点指针为NULL
}

上述两个算法扫描一遍链表,时间复杂度为O(n),空间复杂度为O(1)。

二、统考真题

【2019年统考真题】

设线性表L=({a_{1},a_{2},a_{3},...,a_{n-2},a_{n-1},a_{n}})采用带头结点的单链表保存,链表中的结点定义如下:

typedef struct node
{    int data;
     struct node*next;
}NODE;

 请设计一个空间复杂度为O(1)且时间上尽可能高效的算法,重新排列L中的各结点,得到线性表L'=(a_{1},a_{n},a_{2},a_{n-1},a_{3},a_{n-2},...)。要求:

1)给出算法的基本设计思想。

2)根据设计思想,采用C或C++语言描述算法,关键之处给出注释。

3)说明你所设计的算法的时间复杂度。

【解答】

1)算法的基本设计思想

先观察L=({a_{1},a_{2},a_{3},...,a_{n-2},a_{n-1},a_{n}})L'=(a_{1},a_{n},a_{2},a_{n-1},a_{3},a_{n-2},...),发现L'是由L摘取第一个元素元素,再摘取倒数第一个元素......依次合并而成的。为方便链表后半段取元素,需要将L后半段原地逆置[题目要求空间复杂度为O(1),不能借助栈],否则每取最后一个结点都需要遍历一次链表。a.先找出链表L的中间结点,为此设置两个指针p和q,指针p每次走一步,指针q每次走两步,当指针q到达链尾时,指针p正好在链表的中间结点;b.然后将L的后半段结点原地逆置;c.从单链表前后两段中依次各取一个结点,按要求重排。

2)算法实现

void change_list(NODE*h){
    NODE *p,*q,*r,*s;
    p=q=h;
    while(q->next!=NULL){            //寻找中间结点
        p=p->next;                   //p走一步
        q=q->next;
        if(q->next!=NULL) q=q->next; //q走两步
    }
    q=p->next;                       //p所指结点为中间结点,q为后半段链表的首结点
    p->next=NULL;
    while(q!=NULL){                  //将链表后半段逆置
        r=q->next;
        q->next=p->next;
        p->next=q;
        q=r;
    }
    s=h->next;                       //s指向前半段的第一个数据结点,即插入点
    q=p->next;                       //q指向后半段的第一个数据结点
    p->next=NULL;
    while(q!=NULL){                  //将链表后半段的结点插入到指定位置
        r=q->next;                   //r指向后半段的下一个结点
        q->next=s-next;              //将q所指结点插入到s所指结点之后
        s-next=q;
        s=q->next;                   //s指向前半段的下一个插入点
        q=r;
    }
}

3)第一步找中间结点的时间复杂度为O(n),第二步逆置的时间复杂度为O(n),第三步合并链表的时间复杂度为O(n),所以算法的时间复杂度为O(n)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LucyLee04

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值