考研题-第2章线性表-链表3-循环链表和双向链表 头歌

此题解仅供参考!倘若你有更好的方法,请积极在评论区分享并@我。(,,´•ω•)ノ"(´っω•`。)

题目来源入标题相同,主要的考察是单双链表的排序,本内容只针对后两道题。

第3关:循环单链表输出非递减序列

任务描述

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

相关知识

为了完成本关任务,你需要掌握:1.如何创建循环链表,2.如何遍历链表。

编程要求

根据提示,在右侧编辑器Begin和End之间补充代码。

输入输出说明

输入包含两行,第一行为元素个数n,第二行为相应的链表元素。 输出包含一行,为输出的非递减链表元素

测试说明

平台会对你编写的代码进行测试:

测试输入: 5

                   5 2 1 3 4

预期输出: 1 2 3 4 5


开始你的任务吧,祝你成功!

分析

做这个题,主要思路就是用排序,我用的是冒泡排序。 其中还有一些小坑,在接下来的代码中我们来看一下。

挖坑代码如下:

Status Init(LinkList &L)
{
	L = new LNode;
	if(!L) return ERROR;
	L->next = L;//此题的坑就在这里,可以看到我们的届就是它不等于NULL而等于L;
	return OK;
}

冒泡排序的代码如下:

主要思想就是在冒泡排序中我们只需要改变data就行,而指针的位置不用改变。!!最后的循环截止范围是NULL!!

while(p)
    {
        q=p->next;
        while(q)
        {
            if(p->data>q->data)
            {
                swap(p->data,q->data);//用swap函数或者用中间量temp也可以
            }
            q=q->next;
        }
        p=p->next;
    }

总代码

void Del_All(LinkList &L)
{
	/********************Begin*****************/
    LinkList p,q;
    p=L->next;
    while(p!=L)//注意!
    {
        q=p->next;
        while(q!=L)
        {
            if(p->data>q->data)
            {
                swap(p->data,q->data);
            }
            q=q->next;
        }
        p=p->next;
    }
    p=L->next;
    while(p != L)
	{
		cout << p->data << ' ';
		p = p->next;
	}
    /*********************End*******************/
}

第4关:非循环双向链表的访问

任务描述

本关任务:设头指针为L的带有表头节点的非循环双向链表,其每个结点中除有pre(前驱指针),data(数据),next(后继指针)外,还有一个访问频度域freq,在链表被启用前,其均值初始化为0。每当链表中进行一次Locate(L,x)运算时,令元素值为x的结点中的freq域增1,并使链表中的结点保持访问频度非增(递减)的顺序排列,同时最近访问的结点排在频度相同的结点的前面,以便使频繁访问的结点总是靠近表头。试编写符合上述要求的Locate(L,x)运算的算法,该运算为函数过程。

相关知识

为了完成本关任务,你需要掌握:1.如何创建双向链表,2.如何遍历链表。

编程要求

根据提示,在右侧编辑器Begin和End之间补充代码。

输入输出说明

输入:第一行为元素个数n,第二行为相应的链表元素,第三行为Locate的操作次数w,最后一行为wx值。 输出包含n行,2列,第一列为freq非增的元素,第二列为访问次数freq。

测试说明

平台会对你编写的代码进行测试:

测试输入: 5

                   5 2 1 3 4

                   3

                   2 2 4

预期输出: 2 2 4 1 5 0 1 0 3 0

——————————————

开始你的任务吧,祝你成功!

分析

这个题的做法很多,我用了两种,但大体上思路都是先改变freq的值,然后再进行调换。

(1)方法一:插入排序

先找到与x相同的节点,然后freq加1,再把它从链表中删除,最后再插入链表(排序)。

void Locate(DLinkList &L, int x)
{
	/***************Begin********************/
    
    DLinkList p,t;
    p=L->next;
    //从链表删除x
    while(p)
    {
        if(p->data==x)
        {
            p->freq=p->freq+1;
            t=p;
            if(p->next!=NULL)//如果x在尾部,则不要这一步骤
            p->next->pre=p->pre;
            p->pre->next=p->next;
            break;
        }
        p=p->next;
    }
    //把t插入链表
    p=L->next;
    while(p)
    {
        if(t->freq>=p->freq)
        {
            t->pre=p->pre;
            p->pre->next=t;
            t->next=p;
            p->pre=t;
            break;
        }
        p=p->next;
    }
    /***************End**********************/
}

(2)方法二:冒泡排序

void Locate(DLinkList &L, int x)
{
	/***************Begin********************/
    DLinkList p,q;
    p=L->next;
    //改变freq的值
    while(p)
    {
        if(p->data==x)
        {
            p->freq=p->freq+1;
            break;
        }
        p=p->next;
    }
    //冒泡排序
    p=L->next;
    while(p)
    {
        q=p->next;
        while(q)
        {
            if(p->freq<=q->freq)
            {
                swap(p->freq,q->freq);
                swap(p->data,q->data);
            }
            q=q->next;
        }
        p=p->next;
    }
    /***************End**********************/
}

在本题中只能用方法一,因为我们的测试集就是按照插入排序来产生答案的。 

如果能够帮助你,就点个赞吧O(∩_∩)O哈哈~

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值