单链表的变换(2019年考研统考真题)

【问题描述】设线性表L={a1,a2,a3,...,an-2,an-1,an}采用带头结点的单链表保存,请设计一个空间复杂度为O(1)且时间上尽可能高效的算法,重新排列L中的各结点,得到线性表L'={a1,an,a2,an-1,a3,an-2,...)。【2019统考真题】

【样例输入1】1 2 3 4 5 0

【样例输出1】1 5 2 4 3

【样例输入2】1 2 3 4 5 6 0

【样例输出2】1 6 2 5 3 4

【提示】0代表输入结束

先说算法思想吧。观察题目样例输入可知,a1+an=a2+an-1=a3+an-2....以此类推。所以解决问题的关键是要把结点配对起来,并且通过插入操作实现。那么,要解决的问题有如下几个:

①建立链表应该使用头插法还是尾插法? 每个节点该怎么配对?

②找到与当前结点配对的结点之后,要插入的结点应该插到哪个位置?要插入的结点是否应该在原结点处删除?

③如果输入是倒序如9 8 7 6 5 4 3 2 1 0该如何解决?

 

 经过分析,问题应该这样解决:

①在建链表时应该采用尾插法,保持输入各点数据顺序不变。并且定义两个全局变量MAXINPUT和MININPUT,MININPUT+MAXINPUT即为每一对元素的和(a1+an=a2+an-1=a3+an-2....),在遍历链表时,用元素的和MININPUT+MAXINPUT减去当前结点的值就可以得到配对结点的值。

②在定义时,给每一个结点一个数据域index,依次为1,2,3,...观察发现,要插入的结点应该插入的位置为2,4,6,也就是index*2。要插入的结点应该在原结点处删除(MatchNode函数中实现),否则会导致数据重复。

③输入是倒序同样可以解决,因为这个方法解决问题依赖于每一对元素之和而不是输入数据的顺序。如输入1 2 3 4 5 6 7 8 9 0,输出为1 9 2 8 3 7 4 6 5 ,输入9 8 7 6 5 4 3 2 1 0,输出则为9 1 8 2 7 3 6 4 5。

//【问题描述】设线性表L={a1,a2,a3,...,an-2,an-1,an}采用带头结点的单链表保存,
//请设计一个空间复杂度为O(1)且时间上尽可能高效的算法,重新排列L中的各结点,
//得到线性表L'={a1,an,a2,an-1,a3,an-2,...)。【2019统考真题】
//【样例输入1】1 2 3 4 5 0
//【样例输出1】1 5 2 4 3
//【样例输入2】1 2 3 4 5 6 0
//【样例输出2】1 6 2 5 3 4
//【提示】0代表输入结束
#include<iostream>
using namespace std;
#include<cstdlib>
#define OK 1
#define ERROR 0
int MAXINPUT=-9999;
int MININPUT=9999;
typedef struct Node
{
    int data;
    int index;
    Node*next;
}Node,*LinkList;
void InitList(LinkList *L)
{
    *L=(Node*)malloc(sizeof(Node));
    (*L)->next=NULL;
}
/*void CrtFromHead(LinkList L)
{
    Node*s=L;
    int c;
    int d=1;
    while(cin>>c&&c!=0)
    {
        s=(Node*)malloc(sizeof(Node));
        s->next=L->next;
        L->next=s;
        s->data=c;
        s->index=d;
        d++;
        if(c>MAXINPUT)
            MAXINPUT=c;
    }
}*/
void CrtFromTail(LinkList L)
{
    Node*r,*s;
    int i=0,n;
    r=L;
    while(cin>>n&&n!=0)
    {
        if(n>MAXINPUT)
            MAXINPUT=n;
        if(n<MININPUT)
            MININPUT=n;
        s=(Node*)malloc(sizeof(Node));
        r->next=s;
        r=s;
        s->data=n;
        s->index=i;
        i++;
        s->next=NULL;
    }
}
int MatchNode(LinkList L,int e)
{
    int t;
    Node*pre=L;
    Node*p=L->next;
    while(p!=NULL&&p->data!=e)
    {
        pre=pre->next;
        p=p->next;
    }
    if(p==NULL)
        return -1;
    else
    {
        t=p->data;
        pre->next=p->next;
        free(p);
        return t;
    }
}
void InsList(LinkList L,int i,int e)
{
    Node*pre,*s;
    int k;
    pre=L;
    k=0;
    while(pre!=NULL&&k<i-1)
    {
        pre=pre->next;
        k++;
    }
    if(pre==NULL)
    {
        return;
    }
    else
    {
        s=(Node*)malloc(sizeof(Node));
        s->next=pre->next;
        pre->next=s;
        s->data=e;
        s->index=0;
    }

}
int maxindex(LinkList L)
{
    Node*p=L->next;
    int MAX=0;
    while(p)
    {
        MAX=p->index;
        p=p->next;
    }
    return MAX;

}
int main()
{
    int i,paircount;
    Node*p,*q;
    LinkList L;
    InitList(&L);
    //CrtFromHead(L);
    CrtFromTail(L);
    paircount=maxindex(L)/2;//求有多少对,向下取整
    p=L->next;
    for(i=1;i<=paircount;i++)//第一对插到2,第二对插到4,以此类推
    {
        InsList(L,2*i,MatchNode(L,MAXINPUT+MININPUT-p->data));
        p=(p->next)->next;//插入新元素之后插入的结点成为了p->next,所以要移动两步指针,
        //移到下一个要插入的(要配对的)结点前
    }
    q=L->next;
    while(q)
    {
        cout<<q->data<<' ';
        q=q->next;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值