📜  两个链表的并集和交集的 C 程序(1)

📅  最后修改于: 2023-12-03 15:21:34.199000             🧑  作者: Mango

两个链表的并集和交集的 C 程序介绍

在 C 语言中,链表是常用的数据结构之一。链表是通过指针将一组零散的内存块串联起来,从而形成一个可以动态调整大小的数据结构。

本篇文章将介绍如何使用 C 语言实现两个链表的并集和交集操作。代码将包含以下两个部分:

  1. 链表基本操作:创建链表、插入元素、删除元素、遍历链表等;
  2. 链表并集和交集算法实现。
链表基本操作
1. 创建链表

在 C 语言中,链表是通过指针将一组零散的内存块串联起来,从而形成一个可以动态调整大小的数据结构。因此,链表的创建需要动态分配内存。链表的创建分为两步:

  1. 定义链表节点类型;
  2. 创建链表头节点。
// 定义链表节点结构体
typedef struct node
{
    int val;
    struct node* next;
}Node;

// 创建链表头节点
Node* createList(int value)
{
    Node* head = (Node*)malloc(sizeof(Node));
    head->val = value;
    head->next = NULL;
    return head;
}

该代码中,我们定义了一个链表结构体 Node,包含两个成员:int val 存储节点的值,struct node* next 存储下一个节点的地址。我们使用 typedefstruct node 定义为 Node,以简化代码。createList 函数用于创建链表头节点,它会返回一个指向头节点的指针。

2. 插入元素

插入元素是链表操作的重要部分之一。在链表中插入元素分为两种情况:在链表头部插入元素和在链表尾部插入元素。代码如下:

// 在链表头部插入元素
Node* insertHead(Node* head, int value)
{
    Node* newHead = (Node*)malloc(sizeof(Node));
    newHead->val = value;
    newHead->next = head;
    return newHead;
}

// 在链表尾部插入元素
Node* insertTail(Node* head, int value)
{
    Node* tail = head;
    while (tail->next != NULL)
    {
        tail = tail->next;
    }
    Node* newTail = (Node*)malloc(sizeof(Node));
    newTail->val = value;
    newTail->next = NULL;
    tail->next = newTail;
    return head;
}

该代码中,insertHeadinsertTail 函数分别用于在链表头部和尾部插入元素。我们首先需要动态分配一个节点内存块,并将其值设置为需要插入的值。然后,我们需要修改指针,使逻辑上将该节点插入到链表中。最后,我们需要返回一个指向头节点的指针。

3. 删除元素

在链表中删除元素同样也需要分为两种情况:删除链表头部元素和删除链表尾部元素。代码如下:

// 删除链表头部元素
Node* deleteHead(Node* head)
{
    if (head == NULL)
    {
        return NULL;
    }
    Node* newHead = head->next;
    free(head);
    return newHead;
}

// 删除链表尾部元素
Node* deleteTail(Node* head)
{
    if (head == NULL)
    {
        return NULL;
    }
    Node* tail = head;
    while (tail->next->next != NULL)
    {
        tail = tail->next;
    }
    free(tail->next);
    tail->next = NULL;
    return head;
}

该代码中,deleteHeaddeleteTail 函数分别用于删除链表头部和尾部元素。我们需要注意,如果链表为空,则无法进行删除操作,因此我们需要在开始进行删除前进行判断。对于链表头部的删除操作,我们需要将原头部节点的下一个节点设置为新的头部节点,并释放原头部节点的内存。对于链表尾部的删除操作,我们需要遍历整个链表,找到倒数第二个节点,并将其 next 指针设置为 NULL,释放最后一个节点的内存。

4. 遍历链表

遍历链表是链表操作中的常见操作。我们可以使用循环来遍历整个链表,并访问每个节点的值。代码如下:

void traverseList(Node* head)
{
    Node* p = head;
    while (p != NULL)
    {
        printf("%d ", p->val);
        p = p->next;
    }
    printf("\n");
}

该代码中,我们使用循环遍历整个链表,并打印每个节点的值。我们使用一个指针 p 来表示当前遍历到的节点,初始化为头节点。然后,在循环中,我们使用 printf 函数打印节点的值,并将 p 指针移动到下一个节点。

链表并集和交集算法实现
1. 链表并集

两个链表的并集,即所有元素的集合。我们可以将两个链表的元素插入到一个新的链表中,最后再去除重复元素即可。具体实现代码如下:

Node* unionList(Node* head1, Node* head2)
{
    if (head1 == NULL) 
    {
        return head2;
    }
    if (head2 == NULL) 
    {
        return head1;
    }

    Node* newHead = NULL;
    Node* tail = NULL;
    Node* p = head1;

    // 复制 head1 链表
    while (p != NULL)
    {
        if (newHead == NULL)
        {
            newHead = (Node*)malloc(sizeof(Node));
            newHead->val = p->val;
            newHead->next = NULL;
            tail = newHead;
        }
        else
        {
            Node* newNode = (Node*)malloc(sizeof(Node));
            newNode->val = p->val;
            newNode->next = NULL;
            tail->next = newNode;
            tail = newNode;
        }
        p = p->next;
    }

    // 复制 head2 链表,并去除重复元素
    p = head2;
    while (p != NULL)
    {
        if (hasNode(newHead, p->val) == false)
        {
            Node* newNode = (Node*)malloc(sizeof(Node));
            newNode->val = p->val;
            newNode->next = NULL;
            tail->next = newNode;
            tail = newNode;
        }
        p = p->next;
    }

    return newHead;
}

bool hasNode(Node* head, int val)
{
    Node* p = head;
    while (p != NULL)
    {
        if (p->val == val)
        {
            return true;
        }
        p = p->next;
    }
    return false;
}

该代码中,我们通过循环遍历两个链表,将其中一个链表的元素逐一插入到新的链表中。在插入之前,我们需要判断新链表是否已经存在该元素,如果已经存在,则不重复插入。我们使用 hasNode 函数来判断链表中是否存在某个值。

2. 链表交集

两个链表的交集,即相同元素的集合。我们可以将其中一个链表的元素插入到哈希表中,然后遍历另一个链表,查找是否存在相同的元素。具体实现代码如下:

Node* intersectList(Node* head1, Node* head2)
{
    if (head1 == NULL || head2 == NULL) 
    {
        return NULL;
    }
    
    Node* newHead = NULL;
    Node* tail = NULL;
    Node* p = head1;
    bool hash[100000] = { false };

    // 将 head1 的元素插入哈希表
    while (p != NULL)
    {
        hash[p->val] = true;
        p = p->next;
    }

    // 遍历 head2,查找是否存在相同元素
    p = head2;
    while (p != NULL)
    {
        if (hash[p->val] == true)
        {
            if (newHead == NULL)
            {
                newHead = (Node*)malloc(sizeof(Node));
                newHead->val = p->val;
                newHead->next = NULL;
                tail = newHead;
            }
            else
            {
                Node* newNode = (Node*)malloc(sizeof(Node));
                newNode->val = p->val;
                newNode->next = NULL;
                tail->next = newNode;
                tail = newNode;
            }
        }
        p = p->next;
    }

    return newHead;
}

该代码中,我们首先将其中一个链表的元素插入到哈希表中,然后遍历另一个链表,查找是否存在相同的元素。如果存在,则将其插入到新链表中。

结语

本篇文章介绍了如何使用 C 语言实现两个链表的并集和交集操作。我们需要掌握链表的基本操作,包括链表的创建、插入元素、删除元素、遍历链表等。然后,我们可以使用哈希表实现链表的交集算法,使用新链表实现链表的并集算法。