欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

设以带头结点的双向循环链表表示的线性表L=(a1,a2,……,an)。

程序员文章站 2024-03-21 14:15:04
...

我的思路是拆开链表,然后先插入奇数位的,再插入偶数位的,要注意链表个数有奇数和偶数两种情况。
我不善于解释,注释都写在代码旁了,function函数就是题目要求的算法,其他函数是用来帮忙构建题目说的链表L的,希望能帮到你。

#include<stdio.h>
#include<malloc.h>
#include<assert.h>
#define Elemtype int
typedef struct DCList
{
    Elemtype data;
    struct DCList *next;
    struct DCList *prior;
}Node;

Node* _buynode(Elemtype x);
void initial(Node **head);
void push_back(Node *head,Elemtype x);
void show(Node *head);
void function(Node *head);

int main()
{
    Node *head;
    initial(&head);

    printf("创建一个双向循环链表(-1结束)\n");
    int x;
    while(1)
    {
        scanf("%d",&x);
        if(x==-1)
        break;
        push_back(head,x);
    }
    printf(">>>");
    show(head);

    printf("function过后的链表\n");
    function(head);
    show(head);

    return(1);
}

Node* _buynode(Elemtype x)
{//本算法的功能是申请一个节点,数据域赋值为x
    //最后返回这个节点的指针
    Node *s=(Node*)malloc(sizeof(Node));
    assert(s!=NULL);

    s->data=x;
    s->next=NULL;
    s->prior=NULL;

    return(s);
}

void initial(Node **head)
{//本算法的功能是初始化一个双向循环链表的头指针
    (*head)=(Node*)malloc(sizeof(Node));
    assert((*head)!=NULL);

    (*head)->data=0;//表长为0
    (*head)->next=(*head)->prior=*head;
}

void push_back(Node *head,Elemtype x)
{//本算法的前提是双向循环链表已经初始化
    //本算法的功能是双向循环链表的尾部插入一个新的节点
    //节点的数据域赋值为x
    Node *last=head->prior;//last指向链表的最后一个节点
    Node *s=_buynode(x);

    s->next=last->next;
    head->prior=s;
    last->next=s;
    s->prior=last;//尾部插入

    head->data++;//表长加一
}

void show(Node *head)
{//本算法的前提是链表至少有一个元素
    //本算法的功能依次显示链表中所有的数据元素
    if(head->data==0)
        return;//表长合法性判断

    Node *p=head->next;
    while(p!=head)
    {
        printf("%d-->",p->data);
        p=p->next;
    }
    printf("head.\n");
}

void function(Node *head)
{//本算法的前提是链表中至少有三个元素
    //本算法是按照一定的规则改造链表
    if(head->data<3)
        return;//表长合法性判断

    Node *p=head->next;
    head->prior->next=NULL;
    p->prior=NULL;
    head->prior=head;
    head->next=head;//拆链表

    Node *s,*s_front,*pa;
    s=p;
    pa=s->next;
    s=pa->next;//保存地址

    p->next=head;
    head->prior=p;
    head->next=p;
    p->prior=head;//尾部插入第一个节点
    pa->prior=NULL;

    while(s!=NULL && s->next!=NULL)//节点偶数个或者奇数个两种情况
    {
        p=s;
        s_front=s->next;
        s=s->next->next;
        p->next->prior=p->prior;
        p->prior->next=p->next;//删除p

        Node *last=head->prior;//last指向head链表尾部节点
        p->next=head;
        head->prior=p;
        last->next=p;
        p->prior=last;//尾部插入节点
    }//将a1,a3,a5...a2n-1插入到链表中

    if(s!=NULL && s->next==NULL)//奇数个情况
    {
        s_front->next=s->next;
        Node *last=head->prior;
        s->next=head;
        head->prior=s;
        last->next=s;
        s->prior=last;//插入尾部
    }

    Node *q=s_front;
    while(s_front!=NULL)//插入剩余a2n,a2n-2...a2节点
    {
        q=q->prior;
        Node *last=head->prior;
        s_front->next=head;
        head->prior=s_front;
        last->next=s_front;
        s_front->prior=last;
        s_front=q;
    }
}

时间复杂度方面,前四句话,也就是第一个while循环前面的代码,时间复杂度是O(1),if语句的时间复杂度也是O(1),两个while循环的时间复杂度分别是O(n/2),加起来就是O(n),所以时间复杂度的要求是满足题意的,这个可以用时间函数去验证。