【数据结构】第2章 线性表 实验4:求两个集合LA和LB(用单链表表示)的并和交集

【单链表的初始化、表长、取值、查找、遍历、后插法(尾插法)创建、合并(并集、交集)】实验报告+完整代码


题目: 求两个集合LA和LB(用单链表表示)的并和交集

一、实验目的和要求

(1)熟悉C++的上机环境,进一步掌握C++的结构特点;
(2)掌握求两个集合LA和LB(用单链表表示)的并和交集的方法。

二、实验环境

Windows10, CodeBlocks.

三、实验内容及实施

【实验内容】
在实验2的基础上,使用单链表表示集合。编写两个算法(求交算法和求并算法),并输出最终的结果。
测试用例:集合A为{3,4,1,6},集合A为{2,3,6,7},交集为{3,6},并集为{1,2,3,4,6,7}
【程序流程】

【源程序】

#include<bits/stdc++.h>
using namespace std;
typedef int Status;
typedef int ElemType;
#define OVERFLOW -1
#define ERROR 0
#define OK 1

//-----单链表的储存结构-----
typedef struct LNode
{
    ElemType data;              //结点的数据域
    struct LNode *next;         //结点的指针域
}LNode, *LinkList;              //LinkList为指向结构体LNode的指针类型

LinkList LA, LB, LC;

//1、单链表初始化 O(1)
Status InitList(LinkList &L)
{//构造一个带头结点的空单链表L
    L = new LNode;              //生成新的结点作为头结点,用头指针L指向头结点
    L->next = NULL;             //头结点的指针域置空
    return OK;
}

//5、单链表表长 O(n)
Status ListLength(LinkList L)
{//返回带头结点的单链表的长度
    LNode *p = L;                   //p指向头结点
    int j = 0;                      //计数器j初值赋为0
    while(p->next)                  //直到p的后继为空时停止
    {
        p = p->next;                //p指向下一个结点
        j++;                        //计数器j相应加1
    }
    return j;
}

//6、单链表取值 O(n)
Status GetElem(LinkList L, int i, ElemType &e)
{//在带头结点的单链表L中根据序号i获取元素的值,用e返回L中第i个元素的值
    LNode *p = L->next;             //p指向首元结点
    int j = 1;                      //计数器j初值赋为1
    while(p && j < i)               //直到p为空或p指向第i个元素时停止
    {
        p = p->next;                //p指向下一个结点               
        j++;                        //计数器j相应加1                       
    }
    if(!p || j > i)                 //i值不合法,即i > n或i < 1
        return ERROR;
    e = p->data;                    //取第i个结点的数据域
    return OK;
}

//7、单链表查找 O(n)
LNode *LocateElem(LinkList L, ElemType e)
{//在带头结点的单链表中查找值为e的元素,返回e的地址(所以LNode *LocateElem)
    LNode *p = L->next;             //p指向首元结点
    while(p && p->data != e)        //直到p为空或p所指结点的数据域等于e时停止
        p = p->next;                //p指向下一个结点
    return p;                       //查找成功返回值为e的结点地址p,查找失败p为NULL
}

//10、单链表插入 O(n)
Status ListInsert(LinkList &L, int i, ElemType e)
{//在带头结点的单链表L中第i个位置插入值为e的新结点
    LNode *p = L;                   //p指向头结点
    int j = 0;                      //计数器j初值赋为0
    while(p && j < i - 1)           //直到p为空或p指向第i-1个结点时停止
    {
        p = p->next;                //p指向下一个结点
        j++;                        //计数器j相应加1
    }                               
    if(!p || j > i - 1)             //i值不合法,即i > n + 1或i < 1
        return ERROR;
    LNode *s = new LNode;           //生成新结点*s
    s->data = e;                    //将结点*s的数据域置为e
    s->next = p->next;              //先接后链
    p->next = s;                    //再接前链
    return OK; 
}

//12、单链表遍历 O(n)
Status TraverseList(LinkList L)
{
    LNode *p = L->next;             
    while(p->next)
    {
        cout<<p->data<<' ';
        p = p->next;
    }
    cout<<p->data<<'\n';
    return OK;
}

//14、后插法创建单链表 O(n)
void CreateList_R(LinkList &L, int n)
{//正位序输入n个元素的值,建立带头结点的单链表L
    L = new LNode;                  //先初始化一个带头结点的空链表
    L->next = NULL;                 
    LNode *r = L;                   //尾指针r先指向头结点
    for(int i = 0; i < n; i++)
    {
        LNode *p = new LNode;       //生成新结点*p
        cin>>p->data;               //输入元素值赋给新结点*p的数据域
        p->next = NULL;             //后置空后链             
        r->next = p;                //再接前链
        r = p;                      //r指向新的尾结点*p
    }
}

//16、单链表合并_求并集 O(m * n)
void MergeList(LinkList &LA, LinkList LB)
{//将所有在线性表LB中但不在LA中的数据元素插入到LA中
    int m = ListLength(LA), n = ListLength(LB);     //求线性表长度
    for(int i = 1; i <= n; i++) 
    {
        ElemType e;
        GetElem(LB, i, e);                          //取LB中的第i个元素赋给e
        if(!LocateElem(LA, e))                      //LA中不存在与e相同的数据元素
            ListInsert(LA, ++m, e);                 //将e插在LA的最后,先++,再传值
    }
}

//16、单链表合并_求交集 O(m * n)
void MixList(LinkList LA, LinkList LB, LinkList &LC)
{//将线性表LB中和LA中共有的数据元素插入到LC中
    int m = ListLength(LA), n = ListLength(LB);     //求线性表长度
    int k = 0;
    for(int i = 1; i <= n; i++) 
    {
        ElemType e;
        GetElem(LB, i, e);                          //取LB中的第i个元素赋给e
        if(LocateElem(LA, e))                       //LA中存在与e相同的数据元素
            ListInsert(LC, ++k, e);                 //将e插在LC的最后,先++,再传值
    }
}

//实验4:求两个集合LA和LB(用单链表表示)的并和交集
int main()
{
    int n;
    cout<<"请输入集合A的元素个数:";
    cin>>n;
    cout<<"请按顺序输入这"<<n<<"个元素:";
    CreateList_R(LA, n);
    cout<<"请输入集合B的元素个数:";
    cin>>n;
    cout<<"请按顺序输入这"<<n<<"个元素:";
    CreateList_R(LB, n);
    cout<<'\n';
    cout<<"集合A为:";
    TraverseList(LA);
    cout<<"集合B为:";
    TraverseList(LB);
    InitList(LC);
    MixList(LA, LB, LC);
    cout<<"A与B的交集为:";
    TraverseList(LC);
    MergeList(LA, LB);
    cout<<"A与B的并集为:";
    TraverseList(LA);
    return 0;
}

四、实验结果

在这里插入图片描述

五、实验讨论

(1)熟悉了C++的上机环境,进一步掌握C++的结构特点;
(2)掌握了求两个集合LA和LB(用单链表表示)的并和交集的方法。

  • 8
    点赞
  • 81
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_碗碗儿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值