实验1 链表的插入和删除

【实验内容】

设有两个无头结点的单链表,分别为ha,hb,其链中有数据域data,链域next,两链表的数据都按递增序存放。现要求将hb表归到ha表中,且归并后ha仍按递增排序,归并中ha表中已有的数据若与hb相同,则hb中的数据不归并到ha中,hb的链表在算法中不允许破坏。

 

【实验目的】

1、 了解单链表、循环链表和双链表的基本知识;

2、 掌握算法思想和数据结构的描述;

3、 掌握链表的插入、删除的相关语句及基本方法。

 

【实验步骤与要求】

1、 实验前的准备

(1) 了解C语言的基本概念;

(2) 了解C语言的基本段落。

2、 上机操作

(1) 了解链表的基本知识;

(2) 掌握算法思想和数据结构的描述;

(3) 掌握链表的插入、删除的相关语句及基本方法。

 

代码:

#include<stdio.h>
#include<stdlib.h>//malloc函数要用的库
/*
这题的要求是要生成两个链,输入的数据无序但是输出的时候要有序,所以在插入节点的时候就类似于选择排序的写法,
在合适的位置插入就好了。由于要求是无头结点的写法,之前有头结点的做法是生成一个空的节点,然后就可以直接在
该节点的next指针处插入节点就好,无头结点的做法就相当于抓取第一个节点作为头结点,接下来就和有头结点的做法
一样在尾部插入数据就好了,至于在寻找插入位置是为什么要特判第一个,因为链表是(当前节点的->next)->v小于待
插入节点的v的时候往该节点的next插入,也就是从第二个的v值开始判断的,所以要特判一下第一个,如果小于第一个
就特殊处理一波
*/
typedef struct node
{
    int v;//数据域
    struct node* next;//指针域
}list;
list* build(int v)//特殊处理头结点
{
    list*head=malloc(sizeof(list));
    head->next=NULL;
    head->v=v;
    return head;
}
list* insert(list* head,int v)//有序插入
{
    if(head->v>=v)//特殊处理头结点
    {
        list* t=malloc(sizeof(list));
        t->next=head;
        t->v=v;
        return t;
    }
    list* t=head;
    while(t->next&&(t->next)->v<v)//找到当前节点下一个节点的数据正好大于待插入节点的值的位置
    {
        t=t->next;
    }
    list* aft=malloc(sizeof(list));//生成节点
    aft->next=t->next;
    aft->v=v;
    t->next=aft;//断开一个小口子将结点插入
    return head;
}
void bianli(list* head)//遍历链表
{
    list*t=head;
    while(t)
    {
        printf("%d ",t->v);
        t=t->next;
    }
    printf("\n");
}
list* merge(list* heada,list* headb)//有序合并链表并去重
{
    list *head,*t,*ta=heada,*tb=headb;
    if(ta->v<=tb->v)//特殊处理第一个节点
    {
        head=ta;
        head->next=NULL;
        ta=ta->next;
    }
    else
    {
        head=malloc(sizeof(list));
        head->v=tb->v;
        head->next=NULL;
        tb=tb->next;
    }
    t=head;
    while(ta&&tb)//当链表都还有剩余
    {
        while(ta&&ta->v==t->v)//处理旧的a表与新的a表数据重复,跳到下一个
        {
            ta=ta->next;
        }
        if(ta==NULL)//如果到了a表表尾退出
            break;
        while(tb&&tb->v==t->v)
        {
            tb=tb->next;
        }
        if(tb==NULL)//同理
            break;
        if(ta->v<tb->v)//值不重复,当a链的值较小的时候,将该节点加入a链
        {
            t->next=ta;
            t=ta;
            ta=ta->next;
            t->next=NULL;
        }
        else//因为b链不能破坏,所以就新生成一个节点复制下b链节点的信息并加入a链
        {
            list* temp=malloc(sizeof(list));
            temp->v=tb->v;
            temp->next=NULL;
            t->next=temp;
            t=t->next;
            tb=tb->next;
        }
    }
    while(ta)//如果上面退出循环是因为b链到了尾部,而a链没有,直接连接剩下的a链
    {
        while(ta&&ta->v==t->v)//同样去重
        {
            ta=ta->next;
        }
        if(ta==NULL)
            break;
        t->next=ta;
        ta=ta->next;
        t=t->next;
        t->next=NULL;
    }
    while(tb)//和上文同理,上面循环退出原因是a链到了尾部,处理剩下的b链
    {
         while(tb&&tb->v==t->v)
        {
            tb=tb->next;
        }
        if(tb==NULL)
            break;
        list* temp=malloc(sizeof(list));//和上面相同复制节点信息加入
        temp->v=tb->v;
        temp->next=NULL;
        t->next=temp;
        t=t->next;
        tb=tb->next;
    }
    return head;//返回头结点位置
}
int main()
{
    int i,j,n,m;
    printf("input the size of a list:");//输入a链大小
    scanf("%d",&n);
    printf("input the a list:\n");
    list* head_a;
    int v;
    for(i=0;i<n;i++)
    {
        scanf("%d",&v);
        if(i==0)//如果是第一个就将该值作为头结点生成一个链表
            head_a=build(v);
        else
            head_a=insert(head_a,v);//否则就插入该节点
    }
    printf("the a list is:");
    bianli(head_a);//遍历a链
    list* head_b;
    printf("input the size of b list:");
    scanf("%d",&m);
    for(i=0;i<m;i++)
    {
        scanf("%d",&v);
        if(i==0)
            head_b=build(v);
        else
            head_b=insert(head_b,v);
    }
    printf("the b list is:");
    bianli(head_b);
    printf("after merging the a list is:");
    head_a=merge(head_a,head_b);//更新a的头结点,因为合并后a链头结点地址可能改变
    bianli(head_a);
    return 0;
}




  • 6
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值