数据结构学习笔记(七)链表算法题(续)

第一题

问题

有一个递增非空单链表,设计一个算法删除值域重复的结点。比如{1,1,2,3,3,3,4,4,7,7,7,9,9,9经过删除后变成{1,2,3,4,7,9}。

解答

解法一:定义指针p指向起始结点。将p所指当前结点值域和其直接后继结点值域比较。如果当前结点值域等于后继结点值域,删除后继结点;否则p指向后继结点,重复以上过程,直到p的后继结点为空。

本题代码如下:

void delsl1(LNode *&L) {  //L是指针且要改变因此用引用指针型
    LNode *p = L->next,*q;

    while(p->next! = NULL){

        if(p->data == p->next->data) {    //找到重复结点删除之
            q = p->next;
            p->next = q->next;
            free(q);
        }
        else
            p=p->next;
    }
}

解法二:依次将原序列中每个连续相等子序列的第一个元素移动到表的前端,将剩余的
元素删除即可,即下图所示过程。

令p指向起始将结点。q从p的后继结点开始扫描,q每来到一个新结点的时候进行检测:当q->data等于p->data的时候,什么也不做,q继续往后走;当两者不相等的时候,p往后走一个位置,然后用q->data取代p->data。之后q继续往后扫描,重复以上过程。当q为空的时候,释放从p之后的所有结点空间。

void delsl2(LNode *&L) {

    LNode *p = L->next,*q = L->next->next,*r;

    while(q != NULL){
        while(q != NULL&&q->data == p->data)
            q = q->next;
            if(q! = NULL) {
                p = p->next;
                p->data = q->data;
            }
        }

        q = p->next;
        p->next = NULL;

        while(q != NULL)  {
            r = q;
            q = q->next;
        }
    }
    free(r);
}

第二题

问题

设计一个算法删除单链表L(有头结点)中的一个最小值结点。

解答

用p从头至尾扫描链表,pre指向*p结点的前驱,用minp保存值最小的结点指针,minpre指向minp的前驱。一边扫描,一边比较,将最小值结点放到minp中。

代码如下:

void delminnode(LNode *&L){
    LNode *pre = L, *p = pre->next, *minp = p, *minpre = pre;

    while(p != NULL) {    //查找最小值结点minp以及前驱结点minpre
        if(p->data < minp->data){
            minp = p;
            minpre = pre;
        }

        pre = p;
        p = p->next;
    }

    minpre->next = minp->next; //删除*minp结点。
    free(minp);
}

第三题

问题

有一个线性表,采用带头结点的单链表L来存储。设计一个算法将其逆置。要求不能建立新结点,只能通过表中已有结点的重新组合来完成。

解答

在前边讲过的算法基础中,提到过关与逆序的问题,那就是链表建立的头插法。头插法完成后,链表中的元素顺序和原数组中元素的顺序相反。这里我们可以将L中的元素作为逆转后L的元素来源,即将L->next设置为空,然后将头结点后的一串结点用头插法逐个插入L中,这样新的L中的元素顺序正好是逆序的。

代码如下:

void Reversel(LNode *&L) {
    LNode *p = L->next,*q;
    L->next = NULL;
    while(p != NULL) {  //p结点始终指向旧的链表的开始结点。
        q = p->next; //q结点作为辅助结点来记录p的直接后继结点的位置。
        p->next = L->next; //将p所指结点插入新的链表中。
        L->next = p;
        p = q; 
        //因为后继结点已经存入q中,因此p仍然可以找到后继
        (即此时的新开始结点)。
    }
}

第四题

问题

设计一个算法将一个头结点为A的单链表(其数据域为整数)分解成两个单链表A

解答

用指针p从头至尾扫描A链表,当发现结点data域为偶数的结点则取下,插入链表B中。要用头插法是用尾插法呢,因为题目要求保持原来数据元素的相对顺序,所以要用尾插法来建立B链表。

代码如下:

void split2(LNode *&A,LNode *&B) {
    LNode *p, *q, *r;
    B = (LNode*)malloc(sizeof(LNode)); //申请链表B的头结点
    B->next = NULL;
    //每申请一个新结点的时候,将其指针域next设置为NULL是个好习惯,这样可以避免很多因链表的终端结点忘记置NULL而产生的错误。

    r = B;
    p = A;

    while(p->next != NULL) { 
        //p始终指向当前被判断结点的前驱结点,这和删除结点类似,因为取下一个结点,就是删除一个结点,只是不释放这个结点的内存空间而已。

        if(p->next->data%2 == 0) {  //判断结点的data域是否为偶数,是则从链表中取下
            q = p->next;  //q指向要从链表中取下的结点
            p->next = q->next;    //从链表中取下这个结点
            q->next = NULL;
            r->next = q;
            r = q;
        }

        p = p->next;   //p后移一个位置,即开始检查下一个结点。
    }
}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值