求集合(用单链表表示)的并、交和差运算

编写程序,采用单链表表示集合(假设同一个结合中不存在重复的元素),将其按递增方式排序,构成有序单链表,并求这样的两个集合的并、交和差。
单链表结点类型定义:

typedef int ElemType;    //元素的数据类型

typedef struct LNode {
    ElemType data;        //结点的数据域
    struct LNode *next;    //指向后继结点
} LinkNode;             //单链表结点类型

函数接口定义:

//尾插法建立单链表,细节不表
void CreateListR(LinkNode *&L, ElemType a[], int n);

//输出线性表,细节不表
void DispList(LinkNode *L);

//求两个有序集合的并
void Union(LinkNode *A, LinkNode *B, LinkNode *&C);

//求两个有序集合的交
void InterSect(LinkNode *A, LinkNode *B, LinkNode *&C);

//求两个有序集合的差
void Subs(LinkNode *A, LinkNode *B, LinkNode *&C);

其中 L 和 A 、B、C都是带附加头结点的有序单链表的头指针。 数组a[] 存放创建有序单链表的元素,n为数组长度,其值不超过3000。
裁判测试程序样例:

#include 
#include 

typedef int ElemType;    //元素的数据类型

typedef struct LNode {
    ElemType data;        //结点的数据域
    struct LNode *next;    //指向后继结点
} LinkNode;                 //单链表结点类型

//尾插法建立单链表,细节不表
void CreateListR(LinkNode *&L, ElemType a[], int n);

//输出线性表,细节不表
void DispList(LinkNode *L);

//求两个有序集合的并
void Union(LinkNode *A, LinkNode *B, LinkNode *&C);

//求两个有序集合的交
void InterSect(LinkNode *A, LinkNode *B, LinkNode *&C);

//求两个有序集合的差
void Subs(LinkNode *A, LinkNode *B, LinkNode *&C);

int main() 
{
    LinkNode *A, *B, *C;
    int n, m;

    scanf("%d", &n);
    ElemType a[n];
    for (int i = 0; i < n; i++)
        scanf("%d", &a[i]);

    scanf("%d", &m);
    ElemType b[m];
    for (int i = 0; i < m; i++)
        scanf("%d", &b[i]);

    CreateListR(A, a, n);
    CreateListR(B, b, m);

    Union(A, B, C);
    printf("集合A与B的并: ");
    DispList(C);

    InterSect(A, B, C);
    printf("集合A与B的交: ");
    DispList(C);

    Subs(A, B, C);
    printf("集合A与B的差: ");
    DispList(C);

    return 1;
}

/* 请在下面填写答案 */

输入样例:
输入有4行。
第1行为单链表A的元素个数,接下来的一行为单链表A的元素,以空格分隔。
第3行为单链表B的元素个数,接下来的一行为单链表B的元素,以空格分隔。

5
1 2 3 4 5
3
2 4 6
输出样例:
输出有3行。
第1行为集合A与B的并;第2行为集合A与B的交;第3行为集合A与B的差。
元素之间以一个空格分隔,行尾无多余的空格。

集合A与B的并: 1 2 3 4 5 6
集合A与B的交: 2 4
集合A与B的差: 1 3 5
为什么我的代码老是显示段错误?求解答
a.cpp: In function ‘int main()’:
a.cpp:31:7: warning: ignoring return value of ‘int scanf(const char*, ...)’, declared with attribute warn_unused_result [-Wunused-result]
scanf("%d", &n);

//求两个有序集合的并
void Union(LinkNode *A, LinkNode *B, LinkNode *&C)
{
    C=(LinkNode*)malloc(sizeof(LinkNode));
    LinkNode *p1,*p2,*p3,*p;
    p1=A->next;
    p2=B->next;
    p3=C;
    while(p1&&p2)
    {
        if(p1->data<=p2->data)
        {
            p=(LinkNode*)malloc(sizeof(LinkNode));
            p->data=p1->data;
            p3->next=p;
            p3=p;
            p1=p1->next;
            if(p1->data==p2->data)
                p2=p2->next;
        }
        else
        {
            p=(LinkNode*)malloc(sizeof(LinkNode));
            p->data=p2->data;
            p3->next=p;
            p3=p;
            p2=p2->next;
        }
    }
    p3->next=p1?p1:p2;
}

//求两个有序集合的交
void InterSect(LinkNode *A, LinkNode *B, LinkNode *&C)
{
    C=(LinkNode*)malloc(sizeof(LinkNode));
    LinkNode *p1,*p2,*p3,*p;
    p1=A->next;
    p2=B->next;
    p3=C;
    while(p1&&p2)
    {
            if(p1->data>p2->data)
                p2=p2->next;
        else if(p1->datadata)
            p1=p1->next;
        else
            {
                p=(LinkNode*)malloc(sizeof(LinkNode));
                p->data=p1->data;
                p3->next=p;
                p3=p;
                p1=p1->next;
                p2=p2->next;
            }
    }
    p3->next=NULL;
}
//求两个有序集合的差
void Subs(LinkNode *A, LinkNode *B, LinkNode *&C)
{
    C=(LinkNode*)malloc(sizeof(LinkNode));
    LinkNode *p1,*p2,*p3,*p;
    p1=A->next;
    p2=B->next;
    p3=C;
    if(p1->datadata)
    {
            p=(LinkNode*)malloc(sizeof(LinkNode));
            p->data=p1->data;
            p3->next=p;
            p3=p;
            p1=p1->next;
    }
    else if(p1->data>p2->data)
        p2=p2->next;
    else {
        p1=p1->next;
        p2=p2->next;
    }
    if(p1)
        p3->next=p1;
    else p3->next=NULL;
}

该回答引用GPTᴼᴾᴱᴺᴬᴵ
以下是单链表的并、交、差运算的C++代码实现。注释中已经标注了各个部分的作用。

注意:代码中有一处需要特别注意,即在进行尾插法时,需要在尾结点后加上一个新结点,表示这个集合已经结束。而这个新结点的值应当设置为一个很大的数(这里设置为INT_MAX),以保证该结点永远不会成为两个集合的交集。如果不加这个特殊结点,程序就会运行错误。

同时,如果代码出现了段错误,那么可能是程序中用到了未初始化的指针或者指针访问了已经释放的内存,可以检查代码中是否存在这些问题。

#include <iostream>
#include <climits> // 为了使用INT_MAX
using namespace std;

typedef int ElemType; // 元素的数据类型

typedef struct LNode {
    ElemType data; // 结点的数据域
    struct LNode* next; // 指向后继结点
} LinkNode; // 单链表结点类型

// 尾插法建立单链表
void CreateListR(LinkNode*& L, ElemType a[], int n) {
    L = (LinkNode*)malloc(sizeof(LinkNode)); // 创建头结点
    L->next = NULL; // 初始为空链表
    LinkNode* r = L; // r指向终端结点
    for (int i = 0; i < n; i++) {
        LinkNode* p = (LinkNode*)malloc(sizeof(LinkNode)); // 创建新结点
        p->data = a[i]; // 给新结点赋值
        r->next = p; // 插入到表尾
        r = p; // r指向新的表尾结点
    }
    LinkNode* p = (LinkNode*)malloc(sizeof(LinkNode)); // 创建表示终止的结点
    p->data = INT_MAX; // 用一个很大的数表示终止
    r->next = p; // 将其插入到表尾
    p->next = NULL; // 置空指针
}

// 输出线性表
void DispList(LinkNode* L) {
    LinkNode* p = L->next;
    while (p->data != INT_MAX) { // 如果没有到终止结点
        cout << p->data << " ";
        p = p->next;
    }
    cout << endl;
}

// 求两个有序集合的并
void Union(LinkNode* A, LinkNode* B, LinkNode*& C) {
    C = (LinkNode*)malloc(sizeof(LinkNode)); // 创建头结点
    C->next = NULL; // 初始为空链表
    LinkNode* p1 = A->next;
    LinkNode* p2 = B->next;
    LinkNode* p3 = C; // p3指向C的终端结点
    while (p1->data != INT_MAX && p2->data != INT_MAX) { // 如果还没有到两个集合的终止点
        LinkNode* p = (LinkNode*)malloc(sizeof(LinkNode));
//求两个有序集合的差
void Subs(LinkNode *A, LinkNode *B, LinkNode &C)
{
C=(LinkNode)malloc(sizeof(LinkNode));
LinkNode *p1,*p2,*p3,*p;
p1=A->next;
p2=B->next;
p3=C;
while(p1&&p2)
{
if(p1->data<p2->data)
{
p3->next=p1;
p3=p3->next;
p1=p1->next;
}
else if(p1->data>p2->data)
p2=p2->next;
else
{
p1=p1->next;
p2=p2->next;
}
}
while(p1)
{
p3->next=p1;
p3=p3->next;
p1=p1->next;
}
p3->next=NULL;
p=C;
C=C->next;
free(p);
}

注意:如果两个链表中没有任何相同的元素,则运行结果中集合的差应与集合A完全相同。