首页 > 其他分享 >数据结构实验报告1(集合)

数据结构实验报告1(集合)

时间:2024-09-10 17:51:18浏览次数:15  
标签:as2 as1 数据结构 ++ arr ASet 集合 实验报告 size

学习目标:

        掌握抽象数据类型的表示与实现方法。


学习内容:

        描述一个集合的抽象数据类型ASet,其中所有元素为整数且所有元素不相同,集合的基本操作包括:

  1. 由整数数组a[0..n-1]创建一个集合。
  2. 输出集合中的所有元素。
  3. 判断一个元素是否在一个集合中。
  4. 求两个集合的并集,并输出结果。
  5. 求两个集合的差集,并输出结果。
  6. 求两个集合的交集,并输出结果。

实验报告:

        引入 

引入代码所需要的头文件和宏定义

#include <stdio.h>
#include <stdbool.h>

#define MAX_SIZE 105
#define ffi(a) for (int i = 0; i < a; i++)

 结构体(集合)

自定义一个结构体,用于存储我们的集合,以及加上一个size用于记录集合的大小

typedef struct
{
    int arr[MAX_SIZE];
    int size;
} ASet;

排序函数 

         应为集合是不含有重复元素的,所以我们决定建立一个函数用来排序,并辅助后面去重。

// 交换两个变量的值
// 后面的qsort函数需要用到
void swap(int *a, int *b)
{
    int t = *a;
    *a = *b;
    *b = t;
}

// 快速排序算法
void qsort(ASet *as, int l, int r)
{
    if (l >= r)
    {
        return;
    }
    int x = as->arr[(l + r) / 2], i = l - 1, j = r + 1;
    while (i < j)
    {
        do
        {
            i++;
        } while (as->arr[i] < x);
        do
        {
            j--;
        } while (as->arr[j] > x);
        if (i < j)
        {
            swap(&as->arr[i], &as->arr[j]);
        }
    }
    qsort(as, l, j);
    qsort(as, j + 1, r);
}

去重函数 

        而且因为我们已经编写了一个函数用于排序,所以在集合中我们的元素都是有序的。只要有相同的元素,那么他们物理空间上一定在一起(相同的元素排在一起),所以在遍历数组的时候,如果两个元素相同,我们可以直接如果条件成立,将当前元素复制到新数组的 newSize 位置,并将 newSize 加 1。

        最后的as->size = newSize再更新数组的大小,即可完成去重操作。

// 去重算法
void weight_removal(ASet *as)
{
    int newSize = 0; // 去重后的数组大小
    ffi(as->size)
    {
        if (i == 0 || as->arr[i] != as->arr[i - 1])
        {
            as->arr[newSize++] = as->arr[i];
        }
    }
    as->size = newSize; // 更新数组大小
}

输出函数 

         题目中还对我们有要求,需要一个函数输出,所以我们直接遍历数组用于打印集合的元素。

// 打印函数
void print_array(ASet as)
{
    ffi(as.size)
    {
        printf("%d ", as.arr[i]);
        //朴实无华的打印函数
    }
    printf("\n");
}

求并集操作 

        初始化并集集合ASet unionSet;unionSet.size = 0;创建一个新的 ASet 类型的变量 unionSet,并将其大小初始化为 0,用于存储并集结果。再创建i和j两个索引变量,分别遍历as1和as2。并合并,最后如果 as1 或 as2 中还有剩余元素未处理,则将这些剩余元素依次添加到 unionSet 中。

// 求并集算法
ASet union_of_sets(ASet as1, ASet as2)
{
    ASet unionSet;
    unionSet.size = 0;

int i = 0, j = 0;
    // 合并两个集合的元素
    while (i < as1.size && j < as2.size)
    {
        if (as1.arr[i] < as2.arr[j])
        {
            unionSet.arr[unionSet.size++] = as1.arr[i++];
        }
        else if (as1.arr[i] > as2.arr[j])
        {
            unionSet.arr[unionSet.size++] = as2.arr[j++];
        }
        else
        {
            unionSet.arr[unionSet.size++] = as1.arr[i++];
            j++;
        }
}
    // 处理剩余元素
    while (i < as1.size)
    {
        unionSet.arr[unionSet.size++] = as1.arr[i++];
    }
    while (j < as2.size)
    {
        unionSet.arr[unionSet.size++] = as2.arr[j++];
    }
    return unionSet;
}

求交集操作

        初始化交集集合ASet intersectionSet;intersectionSet.size = 0;创建一个新的 ASet 类型的变量 intersectionSet ,并将其大小初始化为 0。用于存储交集结果。intersectionSet 的大小初始化为 0,表示当前交集中没有元素。再和上一个函数一样,创建索引i和j用于遍历。

        在while循环中遍历两个数组,其中一个集合的所有元素都被遍历完,通过比较 as1.arr[i] 和 as2.arr[j] 的大小来决定如何移动索引i和j(前提是我们的数组元素是有序的)。

此处,我们设置了三段条件用于决定是否移动索引:

  1. 如果 as1.arr[i] < as2.arr[j],说明 as1 中的当前元素不在 as2 中,因此将 i 增加 1,继续比较下一个元素。
  2. 如果 as1.arr[i] > as2.arr[j],说明 as2 中的当前元素不在 as1 中,因此将 j 增加 1,继续比较下一个元素。
  3. 如果 as1.arr[i] == as2.arr[j],说明当前元素在两个集合中都存在,将其添加到 intersectionSet 中,并将 i 和 j 都增加 1,继续比较下一个元素。
// 求交集算法
ASet intersection_of_sets(ASet as1, ASet as2)
{
    ASet intersectionSet;
    intersectionSet.size = 0;

    int i = 0, j = 0;
    while (i < as1.size && j < as2.size)
    {
        if (as1.arr[i] < as2.arr[j])
        {
            i++;
        }
        else if (as1.arr[i] > as2.arr[j])
        {
            j++;
        }
        else
        {
            intersectionSet.arr[intersectionSet.size++] = as1.arr[i++];
            j++;
        }
    }
    return intersectionSet;
}

求差集操作

与前面的两段代码基本一样,只是说我们的判定逻辑改变了

  1. 如果 as1 中的当前元素小于 as2 中的当前元素,则将 as1 中的当前元素添加到 differenceSet 中,并移动 as1 的索引。
  2. 如果 as1 中的当前元素大于 as2 中的当前元素,则移动 as2 的索引。
  3. 如果两个元素相等,则移动两个集合的索引。

因为我们是as1减去as2,所以只要说我们的as1有剩余,那么就不管他,直接将其添加至differenceSet中。

// 求差集算法
ASet difference_of_sets(ASet as1, ASet as2)
{
    ASet differenceSet;
    differenceSet.size = 0;

    int i = 0, j = 0;
    while (i < as1.size && j < as2.size)
    {
        if (as1.arr[i] < as2.arr[j])
        {
            differenceSet.arr[differenceSet.size++] = as1.arr[i++];
        }
        else if (as1.arr[i] > as2.arr[j])
        {
            j++;
        }
        else
        {
            i++;
            j++;
        }
    }
    while (i < as1.size)
    {
        differenceSet.arr[differenceSet.size++] = as1.arr[i++];
    }
    return differenceSet;
}

判断数字是否在集合中 

 我们选择了直接遍历数组,来判断element这个变量是否在数组中

// 判断元素是否在集合中
bool is_element_in_set(ASet as, int element)
{
    ffi(as.size)
    {
        if (as.arr[i] == element)
        {
            return true; // 元素在集合中
        }
    }
    return false; // 元素不在集合中
}

测试环节 

        在到main函数中编写一段代码用于测试,看我们的结果是否正确。 

ASet as1, as2;
    int n, m;
    // 输入 as1 的大小
    scanf("%d", &n);
    if (n)
    {
        // 输入 as1 的元素
        ffi(n)
        {
            scanf("%d", &as1.arr[i]);
        }
    }
    as1.size = n;
    // 输入 as2 的大小
    scanf("%d", &m);
    if (m)
    {
        // 输入 as2 的元素
        for (int i = 0; i < m; i++)
        {
            scanf("%d", &as2.arr[i]);
        }
    }
    as2.size = m;
    // 打印原始数据
    printf("as1: ");
    print_array(as1);
    printf("as2: ");
    print_array(as2);
    // 对 as1 和 as2 进行排序和去重
    qsort(&as1, 0, as1.size - 1);
    weight_removal(&as1);
    qsort(&as2, 0, as2.size - 1);
    weight_removal(&as2);
    // 打印排序和去重后的数据
    printf("排序和重复数据 1:");
    print_array(as1);
    printf("排序和重复数据为2:");
    print_array(as2);
    // 测试判断元素是否在集合中
    int element;
    printf("输入一个元素,检查它是否在 as1 中:");
    scanf("%d", &element);
    if (is_element_in_set(as1, element))
    {
        printf("%d 在 as1 中。\n", element);
    }
    else
    {
        printf("%d 不在 as1 中。\n", element);
    }
    // 计算并集
    ASet unionSet = union_of_sets(as1, as2);
    printf("as1 和 as2 的并集:");
    print_array(unionSet);
    // 计算交集
    ASet intersectionSet = intersection_of_sets(as1, as2);
    printf("as1 和 as2 的交集:");
    print_array(intersectionSet);
    // 计算差集
    ASet differenceSet = difference_of_sets(as1, as2);
    printf("as1 和 as2 的差集:");
    print_array(differenceSet);

 结果

测试均使用vscode的Competitive Programming Helper插件辅助进行。

 

 

学习思考(代码优点)

        快速排序:编写了一段代码,用来实现快速排序(时间复杂度平均为 O(n log n)),降低了后面去重的时间(毕竟集合中不能出现重复元素)。

        去重:在排序后,利用相邻元素的比较进行去重,确保集合内元素唯一。

        集合运算的效率:在对于集合的运算中如并集、交集和差集都使用了双指针(定义了i和j两个变量)的操作用于降低函数的时间复杂度用于提高效率。

标签:as2,as1,数据结构,++,arr,ASet,集合,实验报告,size
From: https://blog.csdn.net/shouyeren153/article/details/142104989

相关文章

  • 数据结构—链表
    一:链表1、数组是连续的内存空间;而链表可以不一定是连续的内存空间2、单端链表;从前一个元素指向后一个元素3、链表的功能(1)访问o(n):数组是通过下表或者索引访问元素;链表是通过next指针以此递归的进行查询判断(2)搜索o(n):从头部遍历;知道找到位置(3)插入o(1):(4)删除o(1):4、特......
  • OpenharmonyOS HDC命令集合
    HDC安装下载CommandLineTools并解压hdc文件在command-line-tools/sdk/HarmonyOS-NEXT-DB2/openharmony/toolchains目录下配置电脑环境变量,以macOS为例,在~/.bash_profile或者~/.zshrc文件中添加如下内容:exportHM_SDK_HOME="/Users/develop/command-line-tools/sdk......
  • 数据结构(王道考研书)
    第一章绪论1.1数据结构的基本概念1.1.1基本概念和术语     数据:是信息的载体,是描述客观事物属性的数、字符及所有能输入到计算机中并被计算机程序识别和处理的符号的集合。数据是计算机程序加工的原料。    数据元素:是数据的基本单位,通常作为一个整体......
  • 【数据结构】详细介绍各种排序算法,包含希尔排序,堆排序,快排,归并,计数排序
    目录1.排序1.1概念1.2常见排序算法2.插入排序2.1直接插入排序2.1.1基本思想2.1.2代码实现2.1.3特性2.2 希尔排序(缩小增量排序)2.2.1基本思想2.2.2 单个gap组的比较2.2.3 多个gap组比较(一次预排序)2.2.4 多次预排序2.2.5 特性3.选择排序3.1直......
  • 数据结构期末常见知识点
    1AOV网是一种有向无环图2所有的二叉树都满足度数为0的节点比度数为2的节点数多1,也都满足所有的度数*该度数节点的和等于总节点数减1只有完全二叉树满足当节点个数为奇数时,度数为1的点不存在,总节点个数吧......
  • 浙大数据结构慕课课后题(03-树3 Tree Traversals Again)
    题目翻译:题解:         #include<bits/stdc++.h>usingnamespacestd;voidCreatTree();voidsolve(intpreL,intinL,intpostL,intn);intPre[35],In[35],Post[35];int N;intmain(){ cin>>N; getchar(); CreatTree(); solve(0,0,0,N); for......
  • 数据结构与算法 第12天(排序)
    一、排序方法分类按照数据存储介质:内部排序:数据量不大、数据在内存,无需内外存交换数据外部排序:数据量较大、数据在外存(文件排序)将数据分批调入内存排序,结果放到外存按照比较器个数:串行排序:单处理机(同一时刻比较一对元素)并行排序:多处理机(同一时刻比较多对元素)按主......
  • 数据结构—单链表的基本操作
    目录1.单链表的初始化2.求表长操作3.按序号查找结点4.按值查找表结点5.插入结点操作6.删除结点操作7.头插法建立单链表8.尾插法建立单链表1.单链表的初始化 带头结点: boolInitList(LinkList&L){       //带头结点的单链表的初始化  L=(......
  • 【数据结构】基础学习
    线性数据结构1.链表(LinkedList)链表是一种线性数据结构,每个节点包含数据和指向下一个节点的引用(即指针)。1.链表的基本操作(Java中的LinkedList类)LinkedList是Java标准库中的一个双向链表实现。我们将通过一些插入、删除和获取操作来演示其使用。importjava.util.L......
  • 集合底层学习笔记
    集合的底层原理数据结构中有数组和链表来实现对数据的存储,但这两者基本上就是两个极端。数组:数组存储区间是连续的,占用内存严重,故空间复杂度很大。但数组的二分查找时间复杂度很小,为O(1);数组的特点是:寻址容易,插入和删除困难。链表:链表存储区间不连续,占用内存比较宽松,故空......