集合的操作

Posted lancelee98

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了集合的操作相关的知识,希望对你有一定的参考价值。

问题描述 :

 

输入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集合的链表头指针

返回值:

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

 

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

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

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

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

 

 

输出说明 :

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

 

输入范例 :

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

 

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
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
");
}
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有序。*/
struct student* fun(struct student* L1, struct student* L2)
{
    /*******************************编写本函数************************************/
    struct student* pl2 = L2,*pl1,*q,*pl1_pre;
    while (pl2)//循环L2
    {
        pl1_pre = NULL;
        pl1 = L1;
        while (pl1 && pl1->num < pl2->num)
        {
            pl1_pre = pl1;
            pl1 = pl1->next;
        }
        if (!pl1||(pl2->num != pl1->num))//这里意思是不存在该元素
        {
            q= (struct student*)malloc(sizeof(struct student)); //p1指向新结点 
            q->num = pl2->num;
            L1 = insertNodeInOrder(L1, q);
        }
        else//存在该元素pl1指向该元素
        {
            if (pl1 == L1)//若是头
            {
                q = pl1;
                L1 = pl1->next;
                free(q);
            }
            else//不是头
            {
                q = pl1;
                pl1_pre->next = pl1->next;
                free(q);
            }
        }
        pl2 = pl2->next;
    }
    return L1;
}
int main()
{
    struct student* headA, * headB, * headC, * headD;
    int i = 0, n;
    scanf("%d", &n);
    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;
}

 

以上是关于集合的操作的主要内容,如果未能解决你的问题,请参考以下文章

金蝶handler中 collection 代码片段理解

Alfred常见使用

比较 C# 中的字符串片段并从集合中删除项目

带有红宝石集合/可枚举的酷技巧和富有表现力的片段[关闭]

VSCode自定义代码片段——git命令操作一个完整流程

VSCode自定义代码片段15——git命令操作一个完整流程