📅  最后修改于: 2023-12-03 15:21:34.199000             🧑  作者: Mango
在 C 语言中,链表是常用的数据结构之一。链表是通过指针将一组零散的内存块串联起来,从而形成一个可以动态调整大小的数据结构。
本篇文章将介绍如何使用 C 语言实现两个链表的并集和交集操作。代码将包含以下两个部分:
在 C 语言中,链表是通过指针将一组零散的内存块串联起来,从而形成一个可以动态调整大小的数据结构。因此,链表的创建需要动态分配内存。链表的创建分为两步:
// 定义链表节点结构体
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
存储下一个节点的地址。我们使用 typedef
将 struct node
定义为 Node
,以简化代码。createList
函数用于创建链表头节点,它会返回一个指向头节点的指针。
插入元素是链表操作的重要部分之一。在链表中插入元素分为两种情况:在链表头部插入元素和在链表尾部插入元素。代码如下:
// 在链表头部插入元素
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;
}
该代码中,insertHead
和 insertTail
函数分别用于在链表头部和尾部插入元素。我们首先需要动态分配一个节点内存块,并将其值设置为需要插入的值。然后,我们需要修改指针,使逻辑上将该节点插入到链表中。最后,我们需要返回一个指向头节点的指针。
在链表中删除元素同样也需要分为两种情况:删除链表头部元素和删除链表尾部元素。代码如下:
// 删除链表头部元素
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;
}
该代码中,deleteHead
和 deleteTail
函数分别用于删除链表头部和尾部元素。我们需要注意,如果链表为空,则无法进行删除操作,因此我们需要在开始进行删除前进行判断。对于链表头部的删除操作,我们需要将原头部节点的下一个节点设置为新的头部节点,并释放原头部节点的内存。对于链表尾部的删除操作,我们需要遍历整个链表,找到倒数第二个节点,并将其 next
指针设置为 NULL
,释放最后一个节点的内存。
遍历链表是链表操作中的常见操作。我们可以使用循环来遍历整个链表,并访问每个节点的值。代码如下:
void traverseList(Node* head)
{
Node* p = head;
while (p != NULL)
{
printf("%d ", p->val);
p = p->next;
}
printf("\n");
}
该代码中,我们使用循环遍历整个链表,并打印每个节点的值。我们使用一个指针 p
来表示当前遍历到的节点,初始化为头节点。然后,在循环中,我们使用 printf
函数打印节点的值,并将 p
指针移动到下一个节点。
两个链表的并集,即所有元素的集合。我们可以将两个链表的元素插入到一个新的链表中,最后再去除重复元素即可。具体实现代码如下:
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
函数来判断链表中是否存在某个值。
两个链表的交集,即相同元素的集合。我们可以将其中一个链表的元素插入到哈希表中,然后遍历另一个链表,查找是否存在相同的元素。具体实现代码如下:
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 语言实现两个链表的并集和交集操作。我们需要掌握链表的基本操作,包括链表的创建、插入元素、删除元素、遍历链表等。然后,我们可以使用哈希表实现链表的交集算法,使用新链表实现链表的并集算法。