问题描述:用有序整数链表表示整数集合(这里默认的是不带辅助表元的链表),编写已知两个集合求集合和(S=S1∪S2)、集合差(S=S1-S2)、集合交(S=S1∩S2)的函数。
这里的三种集合操作,我们都可以采用双指针历遍链表的方法。
求集合的并集,用双指针依次历遍,将比较的表元中较小者,放入新链表,如果相等,则放入其中一个(表元类型是Node*,creatNode为创建新表元的函数,将展示在完整代码中)。
Node* unionSets(Node* S1, Node* S2) {
Node* result = NULL;//result为新链表头指针
Node* tail = NULL;//新链表尾指针
Node* currentS1 = S1;
Node* currentS2 = S2;
//双指针分别遍历S1和S2,直到其中一个被遍历完,按从小到大的顺序添加节点到结果中
while (currentS1 != NULL && currentS2 != NULL) {
if (currentS1->value < currentS2->value) {
Node* newNode = createNode(currentS1->value);
if (result == NULL) {
result = newNode;
tail = newNode;
}
else {
tail->next = newNode;
tail = newNode;
}
currentS1 = currentS1->next;
}
else if (currentS1->value > currentS2->value) {
Node* newNode = createNode(currentS2->value);
if (result == NULL) {
result = newNode;
tail = newNode;
}
else {
tail->next = newNode;
tail = newNode;
}
currentS2 = currentS2->next;
}
else {//比较的两者相同,插入其中的一个
Node* newNode = createNode(currentS1->value);
if (result == NULL) {
result = newNode;
tail = newNode;
}
else {
tail->next = newNode;
tail = newNode;
}
//相等时双指针均后移
currentS1 = currentS1->next;
currentS2 = currentS2->next;
}
}
//对于s1,s2中剩下的表元(如果有)
while (currentS1 != NULL) {
Node* newNode = createNode(currentS1->value);
if (result == NULL) {
result = newNode;
tail = newNode;
}
else {
tail->next = newNode;
tail = newNode;
}
currentS1 = currentS1->next;
}
while (currentS2 != NULL) {
Node* newNode = createNode(currentS2->value);
if (result == NULL) {
result = newNode;
tail = newNode;
}
else {
tail->next = newNode;
tail = newNode;
}
currentS2 = currentS2->next;
}
return result;
}
求集合的差(S1-S2),思路就是对于S2中的所有数,将S1中相等的元素删除,我们有两种实现方法,一是双指针依次历遍,将S1中比S2取出的表元较小者全部放入新表元,再将S1后移,如果相同,不插入,均后移(利用到了链表有序)。
Node* differenceSets(Node* S1, Node* S2) {
Node* result = NULL;
Node* tail = NULL;
Node* currentS1 = S1;
Node* currentS2 = S2;
while (currentS1 != NULL && currentS2 != NULL) {
//对于S2中的每一个节点值,添加S1中比其小的所有节点到结果中
if (currentS1->value < currentS2->value) {
Node* newNode = createNode(currentS1->value);
if (result == NULL) {
result = newNode;
tail = newNode;
}
else {
tail->next = newNode;
tail = newNode;
}
currentS1 = currentS1->next;
}
else if (currentS1->value > currentS2->value) {
currentS2 = currentS2->next;
}
else {
currentS1 = currentS1->next;
currentS2 = currentS2->next;
}
}
while (currentS1 != NULL) {
//添加S1剩余节点到结果中
Node* newNode = createNode(currentS1->value);
if (result == NULL) {
result = newNode;
tail = newNode;
}
else {
tail->next = newNode;
tail = newNode;
}
currentS1 = currentS1->next;
}
return result;
}
也还有二,依次历遍S2中的每一个数,再历遍S1查看是否有相同的元素,如果有,直接删去,这里就需要先复制链表S1。用到链表复制函数:
Node* copyList(Node* head) {
if (NULL == head) {
return NULL;
}
Node* newHead = createNode(head->value);
Node* current = head->next;
Node* newCurrent = newHead;
while (current != NULL) {
Node* newNode = createNode(current->value);
newCurrent->next = newNode;
newCurrent = newCurrent->next;
current = current->next;
}
return newHead;
}
和删除特定表元的函数:
Node* delete(Node* head, int x)
{
Node* w, * p;
if (head == NULL)return NULL;
p = head;
w = head;
while (p != NULL && p->value != x)
{
w = p;
p = p->next;
}
if (p != NULL)
{
if (p == head)
head = p->next;
else
w->next = p->next;
}
return head;
}
这样的函数如下:(虽然增加了复杂度,但是并不要求链表有序)
Node* Difference(Node* head1, Node* head2)
{
Node* copy = copyList(head1);
Node* q = head2;
while (q!= NULL)
{
int x = q->value;
copy = delete(copy, x);
q = q->next;
}
return copy;
}
求集合的交集,最简单的,还是直接用双指针依次历遍,如果遇到了相同的元素,就放入新链表(依旧充分利用了链表有序):
Node* intersectionSets(Node* S1, Node* S2) {
Node* result = NULL;
Node* tail = NULL;
Node* currentS1 = S1;
Node* currentS2 = S2;
while (currentS1 != NULL && currentS2 != NULL) {
if (currentS1->value < currentS2->value) {
currentS1 = currentS1->next;
}
else if (currentS1->value > currentS2->value) {
currentS2 = currentS2->next;
}
else {
//相等时添加节点到结果中
Node* newNode = createNode(currentS1->value);
if (result == NULL) {
result = newNode;
tail = newNode;
}
else {
tail->next = newNode;
tail = newNode;
}
currentS1 = currentS1->next;
currentS2 = currentS2->next;
}
}
return result;
}
当然,也还有另一种方法,利用删除表元的函数,对于S1(复制出来的)中每一个元素,查看S2中是否有相等的元素,如果没有就将它删去,这样依旧是可以实现无序集合的处理:
Node* Intersection(Node* head1, Node* head2)
{
Node* copy = copyList(head1);
Node* p = copy;
while (p != NULL)
{
int x = p->value, flag = 0;
Node* q = head2;
while (q)
{
if (q->value == x)
{
flag = 1;
break;
}
q = q->next;
}
if (flag == 0)
{
copy = delete(copy, x);
}
p = p->next;
}
return copy;
}
以下是完整的程序和样例:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int value;
struct Node* next;
} Node;
// 创建新节点
Node* createNode(int value) {
Node* newNode = (Node*)malloc(sizeof(Node));
if (newNode == NULL) {
printf("Memory allocation failed.\n");
exit(1);
}
newNode->value = value;
newNode->next = NULL;
return newNode;
}
// 创建原始链表
Node* createOriginalList() {
Node* head = NULL;
Node* tail = NULL;
int n;
printf("Enter the number of nodes in the linked list:");
scanf("%d", &n);
printf("Enter the values of the linked list nodes:\n");
for (int i = 0; i < n; i++) {
int value;
printf("Value of Node %d:", i + 1);
scanf("%d", &value);
Node* newNode = createNode(value);
if (NULL == head) {
head = newNode;
tail = newNode;
}
else {
tail->next = newNode;
tail = newNode;
}
}
return head;
}
// 打印链表
void printList(Node* head) {
if (head == NULL) {
printf("链表为空。\n");
return;
}
Node* current = head;
while (current != NULL) {
printf("%d ", current->value);
current = current->next;
}
printf("\n");
}
// 释放链表内存
void freeList(Node* head) {
Node* current = head;
Node* next;
while (current != NULL) {
next = current->next;
free(current);
current = next;
}
}
// 求集合的并集
Node* unionSets(Node* S1, Node* S2) {
Node* result = NULL;//result为新链表头指针
Node* tail = NULL;//新链表尾指针
Node* currentS1 = S1;
Node* currentS2 = S2;
//双指针分别遍历S1和S2,直到其中一个被遍历完,按从小到大的顺序添加节点到结果中
while (currentS1 != NULL && currentS2 != NULL) {
if (currentS1->value < currentS2->value) {
Node* newNode = createNode(currentS1->value);
if (result == NULL) {
result = newNode;
tail = newNode;
}
else {
tail->next = newNode;
tail = newNode;
}
currentS1 = currentS1->next;
}
else if (currentS1->value > currentS2->value) {
Node* newNode = createNode(currentS2->value);
if (result == NULL) {
result = newNode;
tail = newNode;
}
else {
tail->next = newNode;
tail = newNode;
}
currentS2 = currentS2->next;
}
else {//比较的两者相同,插入其中的一个
Node* newNode = createNode(currentS1->value);
if (result == NULL) {
result = newNode;
tail = newNode;
}
else {
tail->next = newNode;
tail = newNode;
}
//相等时双指针均后移
currentS1 = currentS1->next;
currentS2 = currentS2->next;
}
}
//对于s1,s2中剩下的表元(如果有)
while (currentS1 != NULL) {
Node* newNode = createNode(currentS1->value);
if (result == NULL) {
result = newNode;
tail = newNode;
}
else {
tail->next = newNode;
tail = newNode;
}
currentS1 = currentS1->next;
}
while (currentS2 != NULL) {
Node* newNode = createNode(currentS2->value);
if (result == NULL) {
result = newNode;
tail = newNode;
}
else {
tail->next = newNode;
tail = newNode;
}
currentS2 = currentS2->next;
}
return result;
}
// 求集合的差集
Node* differenceSets(Node* S1, Node* S2) {
Node* result = NULL;
Node* tail = NULL;
Node* currentS1 = S1;
Node* currentS2 = S2;
while (currentS1 != NULL && currentS2 != NULL) {
//对于S2中的每一个节点值,添加S1中比其小的所有节点到结果中
if (currentS1->value < currentS2->value) {
Node* newNode = createNode(currentS1->value);
if (result == NULL) {
result = newNode;
tail = newNode;
}
else {
tail->next = newNode;
tail = newNode;
}
currentS1 = currentS1->next;
}
else if (currentS1->value > currentS2->value) {
currentS2 = currentS2->next;
}
else {
currentS1 = currentS1->next;
currentS2 = currentS2->next;
}
}
while (currentS1 != NULL) {
//添加S1剩余节点到结果中
Node* newNode = createNode(currentS1->value);
if (result == NULL) {
result = newNode;
tail = newNode;
}
else {
tail->next = newNode;
tail = newNode;
}
currentS1 = currentS1->next;
}
return result;
}
// 求集合的交集
Node* intersectionSets(Node* S1, Node* S2) {
Node* result = NULL;
Node* tail = NULL;
Node* currentS1 = S1;
Node* currentS2 = S2;
while (currentS1 != NULL && currentS2 != NULL) {
if (currentS1->value < currentS2->value) {
currentS1 = currentS1->next;
}
else if (currentS1->value > currentS2->value) {
currentS2 = currentS2->next;
}
else {
//相等时添加节点到结果中
Node* newNode = createNode(currentS1->value);
if (result == NULL) {
result = newNode;
tail = newNode;
}
else {
tail->next = newNode;
tail = newNode;
}
currentS1 = currentS1->next;
currentS2 = currentS2->next;
}
}
return result;
}
int main() {
printf("Creating the first set:\n");
Node* S1 = createOriginalList();
printf("Creating the second set:\n");
Node* S2 = createOriginalList();
printf("Set 1: ");
printList(S1);
printf("Set 2: ");
printList(S2);
printf("Union of Set 1 and Set 2: ");
Node* unionResult = unionSets(S1, S2);
printList(unionResult);
printf("Difference of Set 1 and Set 2: ");
Node* differenceResult = differenceSets(S1, S2);
printList(differenceResult);
printf("Intersection of Set 1 and Set 2: ");
Node* intersectionResult = intersectionSets(S1, S2);
printList(intersectionResult);
freeList(intersectionResult);
freeList(differenceResult);
freeList(unionResult);
freeList(S2);
freeList(S1);
return 0;
}
对于这一类问题,还有每个链表都带辅助表元的情况,我们也就可以用一个值为0(或其他没有意义的数)的头指针指向每一个链表。这样,操作时的插入新表元不需要考虑是否是头指针了,大体的程序是一样的。