408:2019年第41题

2019年(单链表)41.(13分)设线性表L=(a1,a2,a3,...,an-2,an-1,an)采用带头结点的单链表保存,链表中的结点定义如下:

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

请设计一个空间复杂度为O(1)且时间上尽可能高效的算法,重新排列L中的各结点得到线性表:

L=(a,an,a2,an-1,...)。

要求:

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

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

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

解读:首先空间复杂度是0(1)我们不能申请额外的空间,然后找到链表的中间结点,前面一半是链表L,将链表的后半部分给一个新的头结点L2,然后将链表L2进行原地逆置,然后再将L和L2链表进行合并。

代码部分:

/**
 *  *真题2019 41*
 * 1.含头结点的单链表
 * 2.空间复杂度为O(1)
 * 3.将链表分为L1和L2(平均分)
 * 4.L=(a1,an,a2,an-1...)
 * 注意:思路勿与顺序表混在一起
 */
#include <stdio.h>
#include <stdlib.h>

typedef int ElemType;
typedef struct LNode{ //构建一个单链表
    ElemType data;//数据域
    struct LNode *next;//指针域
}LNode,*LinkList;
/**
 * ---尾插法--
 * @param L
 */
void ListTailInsert(LinkList &L){
    L=(LinkList)malloc(sizeof(LNode));
    LinkList r;//尾指针
    r=L;//初始时尾指针指向头结点
    LinkList s ;
    ElemType x;
    scanf("%d",&x);
    while(x!=00){
        s=(LinkList)malloc(sizeof(LNode));
        s->data=x;
        r->next=s;//尾指针指向新结点
        r=s;
        scanf("%d",&x);
    }
    r->next=NULL;
}
/**
 * 将L的后半部分放到L2中
 * @param L
 * @param L2
 */
void ListFindMiddle(LinkList L,LinkList &L2){
    L2=(LinkList)malloc(sizeof(LNode));
    LinkList p,q;
    q=L->next; //同时指向第一个结点
    p=L->next;
    while (q!=NULL){
        q=q->next;//指针q指向第二个结点
        //如果此时指向的结点不为空则指向下一结点,若下一结点也不为空,则将p指针向后移一个结点
        if(q==NULL){
            break;
        }
        q=q->next;
        if(q==NULL){
            break;
        }
        p=p->next;
    }
    L2->next=p->next;//将L2的头指针指向L的中心结点的下一结点
    p->next=NULL; //将L的中间结点的指针域赋值为空
}
/**
 * 将L2逆转
 * @param L2
 */
void ListReverse(LinkList L2){
    LinkList s,r,t;//定义三个指针
    s=L2->next;//s指向L2的第一个结点
    if(s==NULL){ //判断头结点是否为空
        return;
    }
    r=s->next;//r指向第二个结点
    if(r==NULL){//判断第二个结点是否为空
        return;
    }
    t=r->next;//指向第三个结点
    while(t!=NULL){//当t指针指向的结点不为空时,进入循环
        r->next=s;//将链表内两个结点之间的箭头逆转
        s=r;//s指针向右移
        r=t;//r指针向右移
        t=t->next;//t指针向右移
    }
    r->next=s;//当t指针指向的结点为空时,链表尾部两个结点的未发生逆置,此时将两个结点之间的箭头逆转
    L2->next->next=NULL;//将L2链表内第一个结点的指针域赋值为空
    L2->next=r;//将L2的头指针指向r指针指向的结点
}
/**
 * 将L与L2的值联结在一起
 * @param L
 * @param L2
 */
void ListAnastomosis(LinkList L,LinkList L2){
    LinkList s,r,t;//定义三个同类型指针
    s=L->next;//将指针s指向L的第一个结点
    if(s==NULL){//如果L的第一个结点存在,则继续
        return;
    }
    r=L;//指针r指向链表L
    t=L2->next;//指针t指向链表L2的第一个结点
    if(t==NULL){//判断L2的第一个结点是否为空
        return;
    }
    //重新排列L
    while(s!=NULL && t!=NULL){//当指针s和指针t指向的结点不为空时,进入循环
        //将链表L中的一个结点的地址存到指针r的指针域,然后将指针r后移一位,再将链表L2中的一个结点的地址存到指针r的指针域
        //直到指针s或者t出现空值,跳出循环
        r->next=s;
        s=s->next;
        r=r->next;
        r->next=t;
        t=t->next;
        r=r->next;
    }
    //如果(r,t)其中一个指针为空,则另一个为尾结点,尾结点的指针域必须为空
    if(s==NULL){
        r->next=t;
    }
    if(t==NULL){
        r->next=s;
    }
}
/**
   * ----打印输出----
   * @param L
   */
void ListPrint(LinkList L){
    L=L->next;
    while(L!=NULL){
        printf("%d",L->data);//打印当前结点数据
        L=L->next;//指向下一个结点
        if(L!=NULL){
            printf(" ");
        }
    }
    printf("\n");
}
/**
 * -----主函数------
 * 函数的入口
 * @return
 */
int main() {
    LinkList L,L2; //定义两个头指针
    ListTailInsert(L);//尾插法实现链表L
    printf("------------- L2-> -------------\n");
    ListFindMiddle(L,L2);//实现L2
    ListPrint(L);
    ListPrint(L2);
    printf("------------- L2 <- -------------\n");
    ListReverse(L2);//逆置L2
    ListPrint(L2);
    printf("------------- New L -------------\n");
    ListAnastomosis(L,L2);//重排L
    ListPrint(L);
    free(L2);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值