用有序整数链表表示集合,求两个集合的和、差、交

问题描述:用有序整数链表表示整数集合(这里默认的是不带辅助表元的链表),编写已知两个集合求集合和(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(或其他没有意义的数)的头指针指向每一个链表。这样,操作时的插入新表元不需要考虑是否是头指针了,大体的程序是一样的。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值