暑假OJ练习——4 集合的操作

1.问题描述

输入A、B、C、D四个集合(集合中无重复元素,且元素值都大于0),分别存储在不带头结点的链表中。

本程序先将四个集合执行以下操作:

  1. 对A、B、C、D分别进行升序排序;(该功能已实现,见函数sort)。

  2. 做A=A+B操作:先执行两个有序链表A和B的合并,并仍然保持有序,结果存储在A中,然后删除重复元素;(该功能已实现,见函数merge和purge)。

  3. 做A=A-C操作:将C中出现的元素从A中删除;(该功能已实现,见函数subtract)。

  4. 对D中出现的元素,逐一到A中查询:

    1. 如果在A中存在,则从A中删除

    2. 如果在A中不存在,则将元素添加到A中,并保持链表A有序。

请编写函数fun的函数体实现本功能。

5. 输出集合A中的元素。(该功能已实现,见函数displayLink)。

 

需要编写的函数的原型如下:

struct student* fun(struct student* L1, struct student* L2)

形参:

L1:传入的第一个集合,程序中将传入A集合的链表头指针

L2:传入的第二个集合,程序中将传入D集合的链表头指针

返回值:

返回第一个集合的链表的头指针

 

程序部分代码如下(或下载附件LinkSet.zip):

#include <stdio.h>

#include <stdlib.h>

struct student

{

       int  num;

       struct student  *next;

};

 

struct student *createByTail()

{

       struct student *head;

       struct student *p1,*p2;

       int n;

       n=0;

       p1=p2=(struct student*)malloc(sizeof(struct student));

       scanf("%d",&p1->num);

       head=NULL;  //首先置链表为空链表

       while(p1->num!=-1)    //num为-1,意味着用户输入结束

       {

              n=n+1;

              if(n==1)            //创建第一个结点

                     head=p1;

              else

                     p2->next=p1;

              p2=p1;            //p2始终指向最后一个结点(即尾指针)

              p1=(struct student*)malloc(sizeof(struct student)); //p1指向新结点

        scanf("%d",&p1->num);

       }

       p2->next=NULL;  //切记:最后一个结点的next赋值为NULL

       return head;

}

 

//输出链表中的信息(num)

void  displayLink(struct student *head)

{

       struct student *p;

    p=head;

       printf("head-->");

       while(p!= NULL)

       {

              printf("%d-->",p->num);

              p=p->next;

       }

       printf("tail\n");

}

 

struct student *insertNodeInOrder(struct student *head,struct student *stu)

{

       struct student *p0,*p1,*p2;

       p1=head;

       p0=stu;

       if(head== NULL) //目前还是空链表

       {

        p0->next=head;

        head=p0;

       }

       else

       {

              while((p0->num>p1->num)&&(p1->next!= NULL))

              {//查找插入位置,p2指向p1的前驱

                     p2=p1;

                     p1=p1->next;

              }

              //while循环的结束条件有两个,下面需要判断是由哪个条件退出循环

              if(p0->num<=p1->num)

              {//由while循环条件的第一个条件退出循环,因此可插在p1结点之前

            if(head==p1)     head=p0;

            else   p2->next=p0;

            p0->next=p1;

              }

        else

        {//由while循环条件的第二个条件退出循环,因此p0->num最大,要插在最后

            p1->next=p0;

            p0->next= NULL;

        }

       }

       return head;

}

 

struct student *sort(struct student *head)

{

    struct student *p,*s;

    p=head;

    head= NULL;

    while(p)

    {

              s=p;

              p=p->next;

              head=insertNodeInOrder(head, s);

    }

    return head;

}

 

struct student * merge(struct student *LA, struct student *LB)

{

       struct student  *p,*s;

    p=LB;

    while(p)

    {

              s=p;

              p=p->next;

              LA=insertNodeInOrder(LA, s);

    }

    return LA;

}

 

struct student* subtract(struct student* LA, struct student* LB)

{

       struct student *q, * p=LB;

       struct student *pre=NULL;//pre指向q的前驱,所以最开始赋为NULL

    while(p!=NULL) //对LB链表遍历

     {

        q=LA;

        while (q!=NULL && q->num!=p->num)

        {

            pre=q;

            q=q->next; //在LA中查找是否有元素与p->num相同

        }

        if (q!=NULL) //找到了相同的元素,则删除q所指向结点

        {

            if (q==LA) //如果删除第一个结点

            {

                LA = LA -> next;

                free(q);

            }

            else

            {

                 pre->next=q->next;

                 free(q);

            }

        }

        p=p->next;

     }

     return LA;

}

 

void purge(struct student * head)

{

       struct student  *p,*q;

       if(head== NULL || head->next == NULL)

          return;

       p=head;

       while(p->next!= NULL)

       {

              if(p->num == p->next->num)

              {

                  q=p->next;

                  p->next=q->next;

                  free(q);

              }

              else

              {

                 p=p->next;

           }

       }

}

 

struct student* fun(struct student* L1, struct student* L2)

{

/*******************************编写本函数************************************/

 

 

}

 

int main()

{

    struct student *headA, *headB, *headC, *headD;

    int i,n;

    while(scanf("%d", &n)!= EOF)

    {

        i=0;

        while( i<n)

        {

            headA=createByTail();//创建链表A

            headB=createByTail();//创建链表B

            headC=createByTail();//创建链表C

            headD=createByTail();//创建链表D

            headA = sort(headA);//链表A排序

            headB = sort(headB);//链表B排序

            headC = sort(headC);//链表C排序

            headD = sort(headD);//链表D排序

 

            headA = merge(headA, headB);//将链表B合并到链表A中

            purge(headA);//删除链表A中重复元素

            headA = subtract(headA, headC);//从链表A中减去链表C中元素

            headA=fun(headA, headD);//对链表A和链表D调用fun函数

            displayLink(headA);//输出链表A中的元素

            i++;

        }

    }

return 0;

}

 

2.输入说明

 

首先输入一行,包含一个整数N,表示共测试N组数据。

后面接着输入4*N行,每行为一个集合的元素。

每组数据的第1行为集合A的元素,第2行为集合B的元素,第3行为集合C的元素,第4行为集合D的元素。

每个集合的元素值都为大于0的整数,输入时,-1表示结束。

3.输出说明

 输出的信息以head开头,以tail结尾,以“-->”分隔。如果是空链表,则直接输出“head-->tail”。具体见输出范例。

4.范例

输入范例

2
3 5 8 10 15 9 -1
2 5 8 11 14 -1
2 5 10 -1
3 1 9 -1
3 5 8 10 15 9 -1
2 5 8 11 14 -1
2 5 10 -1
2 3 8 -1

输出范例

head-->1-->8-->11-->14-->15-->tail
head-->2-->9-->11-->14-->15-->tail

5.

#include <stdio.h>

#include <stdlib.h>

struct student

{

    int  num;

    struct student  *next;

};



struct student *createByTail()

{

    struct student *head;

    struct student *p1, *p2;

    int n;

    n = 0;

    p1 = p2 = (struct student*)malloc(sizeof(struct student));

    scanf("%d", &p1->num);

    head = NULL;  //首先置链表为空链表

    while (p1->num != -1)    //num为-1,意味着用户输入结束

    {

        n = n + 1;

        if (n == 1)            //创建第一个结点

            head = p1;

        else

            p2->next = p1;

        p2 = p1;            //p2始终指向最后一个结点(即尾指针)

        p1 = (struct student*)malloc(sizeof(struct student)); //p1指向新结点

        scanf("%d", &p1->num);

    }

    p2->next = NULL;  //切记:最后一个结点的next赋值为NULL

    return head;

}



//输出链表中的信息(num)

void  displayLink(struct student *head)

{

    struct student *p;

    p = head;

    printf("head-->");

    while (p != NULL)

    {

        printf("%d-->", p->num);

        p = p->next;

    }

    printf("tail\n");

}



struct student *insertNodeInOrder(struct student *head, struct student *stu)

{

    struct student *p0, *p1, *p2 = NULL;

    p1 = head;

    p0 = stu;

    if (head == NULL) //目前还是空链表

    {

        p0->next = head;

        head = p0;

    }

    else

    {

        while ((p0->num > p1->num) && (p1->next != NULL))

        {//查找插入位置,p2指向p1的前驱

            p2 = p1;

            p1 = p1->next;

        }

        //while循环的结束条件有两个,下面需要判断是由哪个条件退出循环

        if (p0->num <= p1->num)

        {//由while循环条件的第一个条件退出循环,因此可插在p1结点之前

            if (head == p1)     head = p0;

            else   p2->next = p0;

            p0->next = p1;

        }

        else

        {//由while循环条件的第二个条件退出循环,因此p0->num最大,要插在最后

            p1->next = p0;

            p0->next = NULL;

        }

    }

    return head;

}



struct student *sort(struct student *head)

{

    struct student *p, *s;

    p = head;

    head = NULL;

    while (p)

    {

        s = p;

        p = p->next;

        head = insertNodeInOrder(head, s);

    }

    return head;

}



struct student * merge(struct student *LA, struct student *LB)

{

    struct student  *p, *s;

    p = LB;

    while (p)

    {

        s = p;

        p = p->next;

        LA = insertNodeInOrder(LA, s);

    }

    return LA;

}



struct student* subtract(struct student* LA, struct student* LB)

{

    struct student *q, *p = LB;

    struct student *pre = NULL;//pre指向q的前驱,所以最开始赋为NULL

    while (p != NULL) //对LB链表遍历

    {

        q = LA;

        while (q != NULL && q->num != p->num)

        {

            pre = q;

            q = q->next; //在LA中查找是否有元素与p->num相同

        }

        if (q != NULL) //找到了相同的元素,则删除q所指向结点

        {

            if (q == LA) //如果删除第一个结点

            {

                LA = LA->next;

                free(q);

            }

            else

            {

                pre->next = q->next;

                free(q);

            }

        }

        p = p->next;

    }

    return LA;

}



void purge(struct student * head)

{

    struct student  *p, *q;

    if (head == NULL || head->next == NULL)

        return;

    p = head;

    while (p->next != NULL)

    {

        if (p->num == p->next->num)

        {

            q = p->next;

            p->next = q->next;

            free(q);

        }

        else

        {

            p = p->next;

        }

    }

}

/*对D中出现的元素,逐一到A中查询:

 如果在A中存在,则从A中删除

 如果在A中不存在,则将元素添加到A中,并保持链表A有序。
*/

/*
形参:

L1:传入的第一个集合,程序中将传入A集合的链表头指针

L2:传入的第二个集合,程序中将传入D集合的链表头指针

返回值:

返回第一个集合的链表的头指针
*/
/*注意:链表均不带头结点*/
struct student* fun(struct student* L1, struct student* L2)

{
    /*
    struct student *p, *q = L2, *pre, *s, *tmp;

    //对D中出现的元素,逐一到A中查询:如果在A中存在,则从A中删除
    while (q != NULL)//逐个遍历L2中的元素
    {
        p = L1;
        pre = NULL;
        while (p != NULL && p->num < q->num)
        {
            p = p->next;
            pre = p;
        }
        //在L1中找不到该元素,则插入q指向的结点,并保持链表A有序。
        if (!p || p->num != q->num)//L1已经被遍历完或者L1中找不到符合的元素
        {
            tmp = (struct student*)malloc(sizeof(struct student));//新增结点
            tmp->num = q->num;
            //将结点插入到L1中并保持有序
            L1 = insertNodeInOrder(L1, tmp);
        }
        else//在L1表中删除重复的元素
        {

            //删除头结点
            if (p == L1)
            {
                s = p;
                p = p->next;
                free(s);
            }
            else
            {
                s = p;
                pre->next = s->next;
                free(s);
            }

        }
        q = q->next;
    }
    */

    struct student *p1, *p2 = L2;
    struct student *pre = NULL;    //pre为p1的前驱    
    while (p2) {
        p1 = L1;//每次都从L1头结点开始比较
        while (p1 != NULL && p1->num != p2->num) {
            pre = p1;
            p1 = p1->next;
        }
        if (p1 == NULL) {    //L1中没有这个元素
            student *node = new student;
            node->num = p2->num;
            L1 = insertNodeInOrder(L1, node);

        }
        else {
            if (p1 == L1) {    //要删除的元素为L1的头节点
                L1 = L1->next;
            }
            else {
                pre->next = p1->next;
            }
            free(p1);
        }
        p2 = p2->next;
    }
    return L1;
}



int main()

{

    struct student *headA, *headB, *headC, *headD;

    int i, n;

    while (scanf("%d", &n) != EOF)

    {

        i = 0;

        while (i < n)

        {

            headA = createByTail();//创建链表A

            headB = createByTail();//创建链表B

            headC = createByTail();//创建链表C

            headD = createByTail();//创建链表D

            headA = sort(headA);//链表A排序

            headB = sort(headB);//链表B排序

            headC = sort(headC);//链表C排序

            headD = sort(headD);//链表D排序



            headA = merge(headA, headB);//将链表B合并到链表A中

            purge(headA);//删除链表A中重复元素

            headA = subtract(headA, headC);//从链表A中减去链表C中元素

            headA = fun(headA, headD);//对链表A和链表D调用fun函数

            displayLink(headA);//输出链表A中的元素

            i++;

        }

    }

    return 0;

}

 

posted @ 2022-06-26 20:58  努力奋斗的小企鹅  阅读(72)  评论(0)    收藏  举报