用于查找两个排序链表的交集的 C 程序
给定两个按升序排序的列表,创建并返回一个表示两个列表交集的新列表。新列表应该用它自己的内存来创建——原始列表不应该改变。
例子:
Input:
First linked list: 1->2->3->4->6
Second linked list be 2->4->6->8,
Output: 2->4->6.
The elements 2, 4, 6 are common in
both the list so they appear in the
intersection list.
Input:
First linked list: 1->2->3->4->5
Second linked list be 2->3->4,
Output: 2->3->4
The elements 2, 3, 4 are common in
both the list so they appear in the
intersection list.
方法一:使用虚拟节点。
方法:
这个想法是在结果列表的开头使用一个临时虚拟节点。指针尾始终指向结果列表中的最后一个节点,因此可以轻松添加新节点。虚拟节点最初给尾巴一个指向的内存空间。这个虚拟节点是有效的,因为它只是临时的,并且是在堆栈中分配的。循环继续,从“a”或“b”中删除一个节点并将其添加到尾部。当遍历给定列表时,结果是虚拟的。接下来,因为这些值是从虚拟的下一个节点分配的。如果两个元素相等,则删除两者并将元素插入尾部。否则删除两个列表中较小的元素。
下面是上述方法的实现:
C
#include
#include
// Link list node
struct Node
{
int data;
struct Node* next;
};
void push(struct Node** head_ref,
int new_data);
/*This solution uses the temporary
dummy to build up the result list */
struct Node* sortedIntersect(struct Node* a,
struct Node* b)
{
struct Node dummy;
struct Node* tail = &dummy;
dummy.next = NULL;
/* Once one or the other
list runs out -- we're done */
while (a != NULL && b != NULL)
{
if (a->data == b->data)
{
push((&tail->next), a->data);
tail = tail->next;
a = a->next;
b = b->next;
}
// Advance the smaller list
else if (a->data < b->data)
a = a->next;
else
b = b->next;
}
return (dummy.next);
}
// UTILITY FUNCTIONS
/* Function to insert a node at
the beginning of the linked list */
void push(struct Node** head_ref,
int new_data)
{
// Allocate node
struct Node* new_node =
(struct Node*)malloc(sizeof(struct Node));
// Put in the data
new_node->data = new_data;
// Link the old list off the
// new node
new_node->next = (*head_ref);
// Move the head to point to the
// new node
(*head_ref) = new_node;
}
/* Function to print nodes in
a given linked list */
void printList(struct Node* node)
{
while (node != NULL)
{
printf("%d ", node->data);
node = node->next;
}
}
// Driver code
int main()
{
// Start with the empty lists
struct Node* a = NULL;
struct Node* b = NULL;
struct Node* intersect = NULL;
/* Let us create the first sorted
linked list to test the functions
Created linked list will be
1->2->3->4->5->6 */
push(&a, 6);
push(&a, 5);
push(&a, 4);
push(&a, 3);
push(&a, 2);
push(&a, 1);
/* Let us create the second sorted
linked list. Created linked list
will be 2->4->6->8 */
push(&b, 8);
push(&b, 6);
push(&b, 4);
push(&b, 2);
// Find the intersection two linked lists
intersect = sortedIntersect(a, b);
printf(
"Linked list containing common items of a & b ");
printList(intersect);
getchar();
}
C
#include
#include
// Link list node
struct Node
{
int data;
struct Node* next;
};
void push(struct Node** head_ref,
int new_data);
// This solution uses the local reference
struct Node* sortedIntersect(struct Node* a,
struct Node* b)
{
struct Node* result = NULL;
struct Node** lastPtrRef = &result;
/* Advance comparing the first
nodes in both lists. When one
or the other list runs out,
we're done. */
while (a != NULL && b != NULL)
{
if (a->data == b->data)
{
// Found a node for the intersection
push(lastPtrRef, a->data);
lastPtrRef = &((*lastPtrRef)->next);
a = a->next;
b = b->next;
}
else if (a->data < b->data)
// Advance the smaller list
a = a->next;
else
b = b->next;
}
return (result);
}
// UTILITY FUNCTIONS
/* Function to insert a node at the
beginning of the linked list */
void push(struct Node** head_ref,
int new_data)
{
// Allocate node
struct Node* new_node =
(struct Node*)malloc(sizeof(struct Node));
// Put in the data
new_node->data = new_data;
// Link the old list off the
// new node
new_node->next = (*head_ref);
// Move the head to point to the
// new node
(*head_ref) = new_node;
}
// Function to print nodes in a
// given linked list
void printList(struct Node* node)
{
while (node != NULL)
{
printf("%d ", node->data);
node = node->next;
}
}
// Driver code
int main()
{
// Start with the empty lists
struct Node* a = NULL;
struct Node* b = NULL;
struct Node* intersect = NULL;
/* Let us create the first sorted
linked list to test the functions
Created linked list will be
1->2->3->4->5->6 */
push(&a, 6);
push(&a, 5);
push(&a, 4);
push(&a, 3);
push(&a, 2);
push(&a, 1);
/* Let us create the second sorted
linked list. Created linked list
will be 2->4->6->8 */
push(&b, 8);
push(&b, 6);
push(&b, 4);
push(&b, 2);
// Find the intersection two linked lists
intersect = sortedIntersect(a, b);
printf(
"Linked list containing common items of a & b ");
printList(intersect);
getchar();
}
C
#include
#include
// Link list node
struct Node
{
int data;
struct Node* next;
};
struct Node* sortedIntersect(struct Node* a,
struct Node* b)
{
// Base case
if (a == NULL || b == NULL)
return NULL;
// If both lists are non-empty
// Advance the smaller list and
// call recursively
if (a->data < b->data)
return sortedIntersect(a->next, b);
if (a->data > b->data)
return sortedIntersect(a, b->next);
// Below lines are executed only
// when a->data == b->data
struct Node* temp =
(struct Node*)malloc(sizeof(struct Node));
temp->data = a->data;
// Advance both lists and call
// recursively
temp->next = sortedIntersect(a->next,
b->next);
return temp;
}
// UTILITY FUNCTIONS
/* Function to insert a node at
the beginning of the linked list */
void push(struct Node** head_ref,
int new_data)
{
// Allocate node
struct Node* new_node =
(struct Node*)malloc(sizeof(struct Node));
// Put in the data
new_node->data = new_data;
// Link the old list off the
// new node
new_node->next = (*head_ref);
// Move the head to point to the
// new node
(*head_ref) = new_node;
}
// Function to print nodes in a
// given linked list
void printList(struct Node* node)
{
while (node != NULL)
{
printf("%d ", node->data);
node = node->next;
}
}
// Driver code
int main()
{
// Start with the empty lists
struct Node* a = NULL;
struct Node* b = NULL;
struct Node* intersect = NULL;
/* Let us create the first sorted
linked list to test the functions
Created linked list will be
1->2->3->4->5->6 */
push(&a, 6);
push(&a, 5);
push(&a, 4);
push(&a, 3);
push(&a, 2);
push(&a, 1);
/* Let us create the second sorted
linked list. Created linked list
will be 2->4->6->8 */
push(&b, 8);
push(&b, 6);
push(&b, 4);
push(&b, 2);
// Find the intersection two linked lists
intersect = sortedIntersect(a, b);
printf(
"Linked list containing common items of a & b ");
printList(intersect);
return 0;
}
输出:
Linked list containing common items of a & b
2 4 6
复杂性分析:
- 时间复杂度: O(m+n) 其中 m 和 n 分别是第一个和第二个链表中的节点数。
只需要遍历一次列表。 - 辅助空间: O(min(m, n))。
输出列表最多可以存储 min(m,n) 个节点。
方法 2 :使用本地引用。
方法:这个解决方案在结构上与上面非常相似,但它避免使用一个虚拟节点,而是维护一个结构节点**指针lastPtrRef,它始终指向结果列表的最后一个指针。这解决了与虚拟节点相同的情况——在结果列表为空时处理结果列表。如果列表在其尾部构建,则可以使用虚拟节点或结构节点**“引用”策略。
下面是上述方法的实现:
C
#include
#include
// Link list node
struct Node
{
int data;
struct Node* next;
};
void push(struct Node** head_ref,
int new_data);
// This solution uses the local reference
struct Node* sortedIntersect(struct Node* a,
struct Node* b)
{
struct Node* result = NULL;
struct Node** lastPtrRef = &result;
/* Advance comparing the first
nodes in both lists. When one
or the other list runs out,
we're done. */
while (a != NULL && b != NULL)
{
if (a->data == b->data)
{
// Found a node for the intersection
push(lastPtrRef, a->data);
lastPtrRef = &((*lastPtrRef)->next);
a = a->next;
b = b->next;
}
else if (a->data < b->data)
// Advance the smaller list
a = a->next;
else
b = b->next;
}
return (result);
}
// UTILITY FUNCTIONS
/* Function to insert a node at the
beginning of the linked list */
void push(struct Node** head_ref,
int new_data)
{
// Allocate node
struct Node* new_node =
(struct Node*)malloc(sizeof(struct Node));
// Put in the data
new_node->data = new_data;
// Link the old list off the
// new node
new_node->next = (*head_ref);
// Move the head to point to the
// new node
(*head_ref) = new_node;
}
// Function to print nodes in a
// given linked list
void printList(struct Node* node)
{
while (node != NULL)
{
printf("%d ", node->data);
node = node->next;
}
}
// Driver code
int main()
{
// Start with the empty lists
struct Node* a = NULL;
struct Node* b = NULL;
struct Node* intersect = NULL;
/* Let us create the first sorted
linked list to test the functions
Created linked list will be
1->2->3->4->5->6 */
push(&a, 6);
push(&a, 5);
push(&a, 4);
push(&a, 3);
push(&a, 2);
push(&a, 1);
/* Let us create the second sorted
linked list. Created linked list
will be 2->4->6->8 */
push(&b, 8);
push(&b, 6);
push(&b, 4);
push(&b, 2);
// Find the intersection two linked lists
intersect = sortedIntersect(a, b);
printf(
"Linked list containing common items of a & b ");
printList(intersect);
getchar();
}
输出:
Linked list containing common items of a & b
2 4 6
复杂性分析:
- 时间复杂度: O(m+n) 其中 m 和 n 分别是第一个和第二个链表中的节点数。
只需要遍历一次列表。 - 辅助空间: O(max(m, n))。
输出列表最多可以存储 m+n 个节点。
方法3 :递归解决方案。
方法:
递归方法与上述两种方法非常相似。构建一个递归函数,它接受两个节点并返回一个链表节点。比较两个列表的第一个元素。
- 如果它们相似,则使用两个列表的下一个节点调用递归函数。用当前节点的数据创建一个节点,并将递归函数返回的节点放到所创建节点的next指针上。返回创建的节点。
- 如果值不相等,则删除两个列表中较小的节点并调用递归函数。
下面是上述方法的实现:
C
#include
#include
// Link list node
struct Node
{
int data;
struct Node* next;
};
struct Node* sortedIntersect(struct Node* a,
struct Node* b)
{
// Base case
if (a == NULL || b == NULL)
return NULL;
// If both lists are non-empty
// Advance the smaller list and
// call recursively
if (a->data < b->data)
return sortedIntersect(a->next, b);
if (a->data > b->data)
return sortedIntersect(a, b->next);
// Below lines are executed only
// when a->data == b->data
struct Node* temp =
(struct Node*)malloc(sizeof(struct Node));
temp->data = a->data;
// Advance both lists and call
// recursively
temp->next = sortedIntersect(a->next,
b->next);
return temp;
}
// UTILITY FUNCTIONS
/* Function to insert a node at
the beginning of the linked list */
void push(struct Node** head_ref,
int new_data)
{
// Allocate node
struct Node* new_node =
(struct Node*)malloc(sizeof(struct Node));
// Put in the data
new_node->data = new_data;
// Link the old list off the
// new node
new_node->next = (*head_ref);
// Move the head to point to the
// new node
(*head_ref) = new_node;
}
// Function to print nodes in a
// given linked list
void printList(struct Node* node)
{
while (node != NULL)
{
printf("%d ", node->data);
node = node->next;
}
}
// Driver code
int main()
{
// Start with the empty lists
struct Node* a = NULL;
struct Node* b = NULL;
struct Node* intersect = NULL;
/* Let us create the first sorted
linked list to test the functions
Created linked list will be
1->2->3->4->5->6 */
push(&a, 6);
push(&a, 5);
push(&a, 4);
push(&a, 3);
push(&a, 2);
push(&a, 1);
/* Let us create the second sorted
linked list. Created linked list
will be 2->4->6->8 */
push(&b, 8);
push(&b, 6);
push(&b, 4);
push(&b, 2);
// Find the intersection two linked lists
intersect = sortedIntersect(a, b);
printf(
"Linked list containing common items of a & b ");
printList(intersect);
return 0;
}
输出:
Linked list containing common items of a & b
2 4 6
复杂性分析:
- 时间复杂度: O(m+n) 其中 m 和 n 分别是第一个和第二个链表中的节点数。
只需要遍历一次列表。 - 辅助空间: O(max(m, n))。
输出列表最多可以存储 m+n 个节点。
有关详细信息,请参阅有关两个排序链表的交集的完整文章!